diff --git a/README-Combo.md b/README-Combo.md index 096d94e697..8e2677bc35 100644 --- a/README-Combo.md +++ b/README-Combo.md @@ -55,16 +55,20 @@ Setup: - Set low cartridge alarm to your liking - Enable keylock (can also be set on the pump directly, see usage section on reasoning) - Get Android Studio 3 https://developer.android.com/studio/index.html -- Clone ruffy from https://github.com/jotomo/ruffy (branch `combo-scripter-v2`) -- Pair the pump, if it doesn't work after multiple attempts, switch to the `pairing` branch, pair, +- Follow the link http://ruffy.AndroidAPS.org and clone via git (branch `combo-scripter-v2`) +- Pair the pump using ruffy, if it doesn't work after multiple attempts, switch to the `pairing` branch, pair, then switch back the original branch. If the pump is already paired and can be controlled via ruffy, installing the above version is sufficient. If AAPS is already installed, switch to the MDI plugin to avoid the Combo plugin from interfering with ruffy during the pairing process. - Note that the pairing processing is somewhat fragile and may need a few attempts; + Note that the pairing processing is somewhat fragile (but only has to be done once) + and may need a few attempts; quickly acknowledge prompts and when starting over, remove the pump device from the bluetooth settings beforehand. -- Clone AndroidAPS from https://github.com/jotomo/AndroidAPS (Branch `combo-scripter-v2`) + When AAPS is using ruffy, the ruffy app can't be used. The easiest way is to just + reboot the phone after the pairing process and let AAPS start ruffy in the background. +- Clone AndroidAPS from https://github.com/jotomo/AndroidAPS (branch `combo-scripter-v2`) + and build AAPS using the instructions in the wiki http://wiki.AndroidAPS.org - Before enabling the Combo plugin in AAPS make sure your profile is set up correctly and your basal profile is up to date as AAPS will sync the basal profile to the pump. @@ -85,6 +89,8 @@ Usage: - The integration of the Combo with AndroidAPS is designed with the assumption that all inputs are made via AndroidAPS. Boluses entered on the pump will NOT be detected by AAPS and may therefore result in too much insulin being delivered. +- The pump's first basal rate profile is read on app start and is updated by AAPS. Manually changing + the pump's basal rate profile will lead to wrong basals being delivered and is NOT supported. - It's recommended to enable key lock on the pump to prevent bolusing from the pump, esp. when the pump was used before and quick bolusing was a habit. Also, with keylock enabled, accidentally pressing a key will NOT interrupt a running command @@ -124,21 +130,17 @@ Usage: both of these issues can be resolved in future versions. Known issues: -- On phones with low memory (or aggressive power saving settings), Android may kill - AAPS frequently (if the buttons on the overview screen aren't displayed when opening - AAPS, the app was started again after Android killed it). - This may trigger false 'pump unreachable alarms' on start. - See the Combo tab's "last connection" field to check when the pump was last connected. - This may drain the pump's battery quicker since on startup the basal profile is read - from the pump. This may also increase the chance to hit the bug that makes the pump - reject all incoming connections until a button on the pump is pressed. -- Occasionally (every couple of days or less) AAPS might fail to automatically cancel - a TBR CANCELLED alert and needs to be dealt with (press the refresh button in AAPS - to transfer the warning to AAPS or confirm the alert on the pump). Similarly, the - 'pump unreachable' bug may occur from time to time. +- Occasionally (every couple of days or so) AAPS might fail to automatically cancel + a TBR CANCELLED alert the user then needs to deal with (press the refresh button in AAPS + to transfer the warning to AAPS or confirm the alert on the pump). +- Similarly, the 'pump unreachable' bug may occur from time to time, which requires confirming + the alert on the pump to get the pump to accept connections again. - Overall the integration seems rather robust, but there are limits to the way the pump is controlled and how stable BT is, so there will be minor issues like the above from time to time, though they're small compared to what works well. +- AAPS might be unresponsive for 10-30s or so when starting and calculating sensitivity. + AAPS might also be unresponsive when doing background work, e.g. after receiving a new + glucose reading. Reporting bugs: - Note the precise time the problem occurred and describe the circumstances and steps that caused @@ -153,4 +155,4 @@ Components/Layers (developers): - ComboPlugin - ruffy-spi (RuffyCommands interface to plug in lower layer) - Scripting layer (ruffyscripter) / Command layer -- Driver layer (ruffy) \ No newline at end of file +- Driver layer (ruffy) diff --git a/Testing-Combo.md b/Testing-Combo.md index 56e39c07eb..f47aa4e0b2 100644 --- a/Testing-Combo.md +++ b/Testing-Combo.md @@ -74,12 +74,19 @@ - [ ] Check displayed data (state, battery, reservoir, temp basal) is the same as on the pump - [ ] Unsafe usage - - [ ] An extended or multiwave bolus given within the last six hour must raise an alert and - restrict the loop functionality to low-suspend only (setting maxIOB to zero) + - [ ] An active extended or multiwave bolus must raise an alert and + restrict the loop functionality to low-suspend only for the next 6h (setting maxIOB to zero) + and cancel an active TBR. - [ ] Closed loop functionality must resume 6 h after the last ext/multiwave bolus - - [ ] An active ext/multiwave bolus must also raise an alert and restrict the loop - - [ ] If a basal rate other than profile 1 is activated, this must also raise an alert and disable - the restrict the loop + - [ ] If a basal rate other than profile 1 is active on start, the pump must refuse to finish + initialization and disable the loop. When setting the profile to 1 and refreshing, + the pump must finish initialization and enable the loop (the overview screen will + still show "closed loop", but the Combo and Loop tabs will say the loop is disabled + due to a constraint violation). + - [ ] When changing profile to one other than the first after AAPS has started and read the first + basal profile, a warning must be shown, the loop must be disabled and the active TBR be cancelled. + - [ ] A request to change the AAPS profil (e.g. increase to 110%) must be rejected if the pump + doesn't have profile one active. - [ ] Reading/setting basal profile - [ ] AAPS reads basal rate properly - [ ] Test profile with 115% (or something like that) change to ask the diff --git a/app/build.gradle b/app/build.gradle index 669d6d5802..e5e9edaf9c 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -192,4 +192,7 @@ dependencies { compile 'com.google.code.gson:gson:2.7' compile 'com.google.guava:guava:20.0' compile project(path: ':ruffyscripter') + + compile 'net.danlew:android.joda:2.9.9.1' + testCompile 'joda-time:joda-time:2.9.4.2' } diff --git a/app/src/main/java/info/nightscout/androidaps/MainApp.java b/app/src/main/java/info/nightscout/androidaps/MainApp.java index 2422e4ade6..3395c73b9b 100644 --- a/app/src/main/java/info/nightscout/androidaps/MainApp.java +++ b/app/src/main/java/info/nightscout/androidaps/MainApp.java @@ -15,6 +15,8 @@ import com.squareup.otto.Bus; import com.squareup.otto.LoggingBus; import com.squareup.otto.ThreadEnforcer; +import net.danlew.android.joda.JodaTimeAndroid; + import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -97,6 +99,7 @@ public class MainApp extends Application { super.onCreate(); Fabric.with(this, new Crashlytics()); Fabric.with(this, new Answers()); + JodaTimeAndroid.init(this); Crashlytics.setString("BUILDVERSION", BuildConfig.BUILDVERSION); log.info("Version: " + BuildConfig.VERSION_NAME); log.info("BuildVersion: " + BuildConfig.BUILDVERSION); diff --git a/app/src/main/java/info/nightscout/androidaps/PreferencesActivity.java b/app/src/main/java/info/nightscout/androidaps/PreferencesActivity.java index 14b1f099c1..33a0483468 100644 --- a/app/src/main/java/info/nightscout/androidaps/PreferencesActivity.java +++ b/app/src/main/java/info/nightscout/androidaps/PreferencesActivity.java @@ -167,12 +167,6 @@ public class PreferencesActivity extends PreferenceActivity implements SharedPre addPreferencesFromResourceIfEnabled(VirtualPumpPlugin.getPlugin(), PluginBase.PUMP); } - /* No usable settings yet - if (Config.COMBO) { - addPreferencesFromResourceIfEnabled(ComboPlugin.getPlugin(), PluginBase.PUMP); - } - */ - addPreferencesFromResourceIfEnabled(InsulinOrefFreePeakPlugin.getPlugin(), PluginBase.INSULIN); addPreferencesFromResourceIfEnabled(NSClientInternalPlugin.getPlugin(), PluginBase.GENERAL); diff --git a/app/src/main/java/info/nightscout/androidaps/data/Profile.java b/app/src/main/java/info/nightscout/androidaps/data/Profile.java index ea662e434d..e022969e32 100644 --- a/app/src/main/java/info/nightscout/androidaps/data/Profile.java +++ b/app/src/main/java/info/nightscout/androidaps/data/Profile.java @@ -17,9 +17,13 @@ import java.util.TimeZone; import info.nightscout.androidaps.Constants; import info.nightscout.androidaps.MainApp; import info.nightscout.androidaps.R; +import info.nightscout.androidaps.interfaces.PumpDescription; +import info.nightscout.androidaps.interfaces.PumpInterface; +import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin; import info.nightscout.androidaps.plugins.Overview.notifications.Notification; import info.nightscout.androidaps.plugins.Overview.events.EventDismissNotification; import info.nightscout.androidaps.plugins.Overview.events.EventNewNotification; +import info.nightscout.utils.DateUtil; import info.nightscout.utils.DecimalFormatter; import info.nightscout.utils.ToastUtils; @@ -160,15 +164,19 @@ public class Profile { for (Integer index = 0; index < array.length(); index++) { try { final JSONObject o = array.getJSONObject(index); - long tas = getShitfTimeSecs((int) o.getLong("timeAsSeconds")); + long tas = 0; + try { + tas = getShitfTimeSecs((int) o.getLong("timeAsSeconds")); + } catch (JSONException e) { + String time = o.getString("time"); + tas = getShitfTimeSecs(DateUtil.toSeconds(time)); + //log.debug(">>>>>>>>>>>> Used recalculated timeAsSecons: " + time + " " + tas); + } Double value = o.getDouble("value") * multiplier; sparse.put(tas, value); } catch (JSONException e) { log.error("Unhandled exception", e); - try { - log.error(array.getJSONObject(index).toString()); - } catch (JSONException e1) { - } + log.error(json.toString()); } } @@ -327,8 +335,27 @@ public class Profile { } public Double getBasal(Integer timeAsSeconds) { - if (basal_v == null) + if (basal_v == null) { basal_v = convertToSparseArray(basal); + // Check for minimal basal value + PumpInterface pump = ConfigBuilderPlugin.getActivePump(); + if (pump != null) { + PumpDescription description = pump.getPumpDescription(); + for (int i = 0; i < basal_v.size(); i++) { + if (basal_v.valueAt(i) < description.basalMinimumRate) { + basal_v.setValueAt(i, description.basalMinimumRate); + MainApp.bus().post(new EventNewNotification(new Notification(Notification.MINIMAL_BASAL_VALUE_REPLACED, MainApp.sResources.getString(R.string.minimalbasalvaluereplaced), Notification.NORMAL))); + } + } + return getValueToTime(basal_v, timeAsSeconds); + } else { + // if pump not available (at start) + // do not store converted array + Double value = getValueToTime(basal_v, timeAsSeconds); + basal_v = null; + return value; + } + } return getValueToTime(basal_v, timeAsSeconds); } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/Overview/QuickWizard.java b/app/src/main/java/info/nightscout/androidaps/data/QuickWizard.java similarity index 50% rename from app/src/main/java/info/nightscout/androidaps/plugins/Overview/QuickWizard.java rename to app/src/main/java/info/nightscout/androidaps/data/QuickWizard.java index 2962575a68..587d7f86a2 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/Overview/QuickWizard.java +++ b/app/src/main/java/info/nightscout/androidaps/data/QuickWizard.java @@ -1,4 +1,4 @@ -package info.nightscout.androidaps.plugins.Overview; +package info.nightscout.androidaps.data; import android.content.SharedPreferences; import android.preference.PreferenceManager; @@ -9,11 +9,7 @@ import org.json.JSONObject; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.util.Date; - import info.nightscout.androidaps.MainApp; -import info.nightscout.androidaps.data.Profile; -import info.nightscout.utils.DateUtil; /** * Created by mike on 12.10.2016. @@ -22,84 +18,7 @@ import info.nightscout.utils.DateUtil; public class QuickWizard { private static Logger log = LoggerFactory.getLogger(QuickWizard.class); - public class QuickWizardEntry { - public JSONObject storage; - public int position; - - /* - { - buttonText: "Meal", - carbs: 36, - validFrom: 8 * 60 * 60, // seconds from midnight - validTo: 9 * 60 * 60, // seconds from midnight - } - */ - public QuickWizardEntry() { - String emptyData = "{\"buttonText\":\"\",\"carbs\":0,\"validFrom\":0,\"validTo\":86340}"; - try { - storage = new JSONObject(emptyData); - } catch (JSONException e) { - log.error("Unhandled exception", e); - } - position = -1; - } - - public QuickWizardEntry(JSONObject entry, int position) { - storage = entry; - this.position = position; - } - - public Boolean isActive() { - return Profile.secondsFromMidnight() >= validFrom() && Profile.secondsFromMidnight() <= validTo(); - } - - public String buttonText() { - try { - return storage.getString("buttonText"); - } catch (JSONException e) { - log.error("Unhandled exception", e); - } - return ""; - } - - public Integer carbs() { - try { - return storage.getInt("carbs"); - } catch (JSONException e) { - log.error("Unhandled exception", e); - } - return 0; - } - - public Date validFromDate() { - return DateUtil.toDate(validFrom()); - } - - public Date validToDate() { - return DateUtil.toDate(validTo()); - } - - public Integer validFrom() { - try { - return storage.getInt("validFrom"); - } catch (JSONException e) { - log.error("Unhandled exception", e); - } - return 0; - } - - public Integer validTo() { - try { - return storage.getInt("validTo"); - } catch (JSONException e) { - log.error("Unhandled exception", e); - } - return 0; - } - - } - - JSONArray storage = new JSONArray(); + private JSONArray storage = new JSONArray(); public void setData(JSONArray newData) { storage = newData; diff --git a/app/src/main/java/info/nightscout/androidaps/data/QuickWizardEntry.java b/app/src/main/java/info/nightscout/androidaps/data/QuickWizardEntry.java new file mode 100644 index 0000000000..70dd37a6ab --- /dev/null +++ b/app/src/main/java/info/nightscout/androidaps/data/QuickWizardEntry.java @@ -0,0 +1,242 @@ +package info.nightscout.androidaps.data; + +import org.json.JSONException; +import org.json.JSONObject; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.Date; + +import info.nightscout.androidaps.MainApp; +import info.nightscout.androidaps.R; +import info.nightscout.androidaps.db.BgReading; +import info.nightscout.androidaps.db.TempTarget; +import info.nightscout.androidaps.interfaces.TreatmentsInterface; +import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin; +import info.nightscout.androidaps.plugins.IobCobCalculator.AutosensData; +import info.nightscout.androidaps.plugins.IobCobCalculator.IobCobCalculatorPlugin; +import info.nightscout.androidaps.plugins.Loop.LoopPlugin; +import info.nightscout.utils.BolusWizard; +import info.nightscout.utils.DateUtil; +import info.nightscout.utils.SP; + +/** + * Created by mike on 25.12.2017. + */ + +public class QuickWizardEntry { + private static Logger log = LoggerFactory.getLogger(QuickWizardEntry.class); + + public JSONObject storage; + public int position; + + public static final int YES = 0; + public static final int NO = 1; + public static final int POSITIVE_ONLY = 2; + public static final int NEGATIVE_ONLY = 3; + + /* + { + buttonText: "Meal", + carbs: 36, + validFrom: 8 * 60 * 60, // seconds from midnight + validTo: 9 * 60 * 60, // seconds from midnight + useBG: 0, + useCOB: 0, + useBolusIOB: 0, + useBasalIOB: 0, + useTrend: 0, + useSuperBolus: 0, + useTemptarget: 0 + } + */ + public QuickWizardEntry() { + String emptyData = "{\"buttonText\":\"\",\"carbs\":0,\"validFrom\":0,\"validTo\":86340}"; + try { + storage = new JSONObject(emptyData); + } catch (JSONException e) { + log.error("Unhandled exception", e); + } + position = -1; + } + + public QuickWizardEntry(JSONObject entry, int position) { + storage = entry; + this.position = position; + } + + public Boolean isActive() { + return Profile.secondsFromMidnight() >= validFrom() && Profile.secondsFromMidnight() <= validTo(); + } + + public BolusWizard doCalc(Profile profile, TempTarget tempTarget, BgReading lastBG) { + BolusWizard wizard = new BolusWizard(); + + //BG + double bg = 0; + if (lastBG != null && useBG() == YES) { + bg = lastBG.valueToUnits(profile.getUnits()); + } + + // COB + double cob = 0d; + AutosensData autosensData = IobCobCalculatorPlugin.getLastAutosensData(); + if (autosensData != null && useCOB() == YES) { + cob = autosensData.cob; + } + + // Temp target + if (useTempTarget() == NO) { + tempTarget = null; + } + + // Bolus IOB + boolean bolusIOB = false; + if (useBolusIOB() == YES) { + bolusIOB = true; + } + + // Basal IOB + TreatmentsInterface treatments = MainApp.getConfigBuilder(); + treatments.updateTotalIOBTempBasals(); + IobTotal basalIob = treatments.getLastCalculationTempBasals().round(); + boolean basalIOB = false; + if (useBasalIOB() == YES) { + basalIOB = true; + } else if (useBasalIOB() == POSITIVE_ONLY && basalIob.iob > 0) { + basalIOB = true; + } else if (useBasalIOB() == NEGATIVE_ONLY && basalIob.iob < 0) { + basalIOB = true; + } + + // SuperBolus + boolean superBolus = false; + if (useSuperBolus() == YES && SP.getBoolean(R.string.key_usesuperbolus, false)) { + superBolus = true; + } + final LoopPlugin activeloop = ConfigBuilderPlugin.getActiveLoop(); + if (activeloop != null && activeloop.isEnabled(activeloop.getType()) && activeloop.isSuperBolus()) + superBolus = false; + + // Trend + GlucoseStatus glucoseStatus = GlucoseStatus.getGlucoseStatusData(); + boolean trend = false; + if (useTrend() == YES) { + trend = true; + } else if (useTrend() == POSITIVE_ONLY && glucoseStatus != null && glucoseStatus.short_avgdelta > 0) { + trend = true; + } else if (useTrend() == NEGATIVE_ONLY && glucoseStatus != null && glucoseStatus.short_avgdelta < 0) { + trend = true; + } + + wizard.doCalc(profile, tempTarget, carbs(), cob, bg, 0d, bolusIOB, basalIOB, superBolus, trend); + return wizard; + } + + public String buttonText() { + try { + return storage.getString("buttonText"); + } catch (JSONException e) { + log.error("Unhandled exception", e); + } + return ""; + } + + public Integer carbs() { + try { + return storage.getInt("carbs"); + } catch (JSONException e) { + log.error("Unhandled exception", e); + } + return 0; + } + + public Date validFromDate() { + return DateUtil.toDate(validFrom()); + } + + public Date validToDate() { + return DateUtil.toDate(validTo()); + } + + public Integer validFrom() { + try { + return storage.getInt("validFrom"); + } catch (JSONException e) { + log.error("Unhandled exception", e); + } + return 0; + } + + public Integer validTo() { + try { + return storage.getInt("validTo"); + } catch (JSONException e) { + log.error("Unhandled exception", e); + } + return 0; + } + + public int useBG() { + try { + return storage.getInt("useBG"); + } catch (JSONException e) { + log.error("Unhandled exception", e); + } + return YES; + } + + public int useCOB() { + try { + return storage.getInt("useCOB"); + } catch (JSONException e) { + log.error("Unhandled exception", e); + } + return NO; + } + + public int useBolusIOB() { + try { + return storage.getInt("useBolusIOB"); + } catch (JSONException e) { + log.error("Unhandled exception", e); + } + return YES; + } + + public int useBasalIOB() { + try { + return storage.getInt("useBasalIOB"); + } catch (JSONException e) { + log.error("Unhandled exception", e); + } + return YES; + } + + public int useTrend() { + try { + return storage.getInt("useTrend"); + } catch (JSONException e) { + log.error("Unhandled exception", e); + } + return NO; + } + + public int useSuperBolus() { + try { + return storage.getInt("useSuperBolus"); + } catch (JSONException e) { + log.error("Unhandled exception", e); + } + return NO; + } + + public int useTempTarget() { + try { + return storage.getInt("useTempTarget"); + } catch (JSONException e) { + log.error("Unhandled exception", e); + } + return NO; + } +} diff --git a/app/src/main/java/info/nightscout/androidaps/db/DatabaseHelper.java b/app/src/main/java/info/nightscout/androidaps/db/DatabaseHelper.java index b9a34ddb58..b89da43de4 100644 --- a/app/src/main/java/info/nightscout/androidaps/db/DatabaseHelper.java +++ b/app/src/main/java/info/nightscout/androidaps/db/DatabaseHelper.java @@ -46,6 +46,7 @@ import info.nightscout.androidaps.events.EventTreatmentChange; import info.nightscout.androidaps.plugins.IobCobCalculator.events.EventNewHistoryData; import info.nightscout.androidaps.plugins.PumpDanaR.activities.DanaRNSHistorySync; import info.nightscout.androidaps.plugins.PumpVirtual.VirtualPumpPlugin; +import info.nightscout.utils.PercentageSplitter; public class DatabaseHelper extends OrmLiteSqliteOpenHelper { private static Logger log = LoggerFactory.getLogger(DatabaseHelper.class); @@ -1633,6 +1634,8 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper { } } } + // look for already added percentage from NS + profileSwitch.profileName = PercentageSplitter.pureName(profileSwitch.profileName); getDaoProfileSwitch().create(profileSwitch); log.debug("PROFILESWITCH: New record from: " + Source.getString(profileSwitch.source) + " " + profileSwitch.toString()); scheduleProfileSwitchChange(); diff --git a/app/src/main/java/info/nightscout/androidaps/interfaces/ConstraintsInterface.java b/app/src/main/java/info/nightscout/androidaps/interfaces/ConstraintsInterface.java index 34b50e315f..aac7918bdc 100644 --- a/app/src/main/java/info/nightscout/androidaps/interfaces/ConstraintsInterface.java +++ b/app/src/main/java/info/nightscout/androidaps/interfaces/ConstraintsInterface.java @@ -15,6 +15,8 @@ public interface ConstraintsInterface { boolean isAMAModeEnabled(); + boolean isSMBModeEnabled(); + Double applyBasalConstraints(Double absoluteRate); Integer applyBasalConstraints(Integer percentRate); diff --git a/app/src/main/java/info/nightscout/androidaps/interfaces/InsulinInterface.java b/app/src/main/java/info/nightscout/androidaps/interfaces/InsulinInterface.java index 0803f65373..48efa587d8 100644 --- a/app/src/main/java/info/nightscout/androidaps/interfaces/InsulinInterface.java +++ b/app/src/main/java/info/nightscout/androidaps/interfaces/InsulinInterface.java @@ -21,5 +21,5 @@ public interface InsulinInterface { String getFriendlyName(); String getComment(); double getDia(); - public Iob iobCalcForTreatment(Treatment treatment, long time, Double dia); + public Iob iobCalcForTreatment(Treatment treatment, long time, double dia); } diff --git a/app/src/main/java/info/nightscout/androidaps/interfaces/PumpInterface.java b/app/src/main/java/info/nightscout/androidaps/interfaces/PumpInterface.java index e57a041a30..a85a7f3421 100644 --- a/app/src/main/java/info/nightscout/androidaps/interfaces/PumpInterface.java +++ b/app/src/main/java/info/nightscout/androidaps/interfaces/PumpInterface.java @@ -38,7 +38,7 @@ public interface PumpInterface { PumpEnactResult deliverTreatment(DetailedBolusInfo detailedBolusInfo); void stopBolusDelivering(); PumpEnactResult setTempBasalAbsolute(Double absoluteRate, Integer durationInMinutes, boolean enforceNew); - PumpEnactResult setTempBasalPercent(Integer percent, Integer durationInMinutes); + PumpEnactResult setTempBasalPercent(Integer percent, Integer durationInMinutes, boolean enforceNew); PumpEnactResult setExtendedBolus(Double insulin, Integer durationInMinutes); //some pumps might set a very short temp close to 100% as cancelling a temp can be noisy //when the cancel request is requested by the user (forced), the pump should always do a real cancel diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/Actions/ActionsFragment.java b/app/src/main/java/info/nightscout/androidaps/plugins/Actions/ActionsFragment.java index 910f032fc5..d6f56e501b 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/Actions/ActionsFragment.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/Actions/ActionsFragment.java @@ -8,7 +8,6 @@ import android.support.v4.app.FragmentManager; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; -import android.widget.Button; import com.crashlytics.android.Crashlytics; import com.crashlytics.android.answers.Answers; @@ -33,6 +32,7 @@ import info.nightscout.androidaps.plugins.Careportal.Dialogs.NewNSTreatmentDialo import info.nightscout.androidaps.plugins.Careportal.OptionsToShow; import info.nightscout.androidaps.plugins.Common.SubscriberFragment; import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin; +import info.nightscout.utils.SingleClickButton; /** * A simple {@link Fragment} subclass. @@ -45,13 +45,13 @@ public class ActionsFragment extends SubscriberFragment implements View.OnClickL return actionsPlugin; } - Button profileSwitch; - Button tempTarget; - Button extendedBolus; - Button extendedBolusCancel; - Button tempBasal; - Button tempBasalCancel; - Button fill; + SingleClickButton profileSwitch; + SingleClickButton tempTarget; + SingleClickButton extendedBolus; + SingleClickButton extendedBolusCancel; + SingleClickButton tempBasal; + SingleClickButton tempBasalCancel; + SingleClickButton fill; public ActionsFragment() { super(); @@ -64,13 +64,13 @@ public class ActionsFragment extends SubscriberFragment implements View.OnClickL try { View view = inflater.inflate(R.layout.actions_fragment, container, false); - profileSwitch = (Button) view.findViewById(R.id.actions_profileswitch); - tempTarget = (Button) view.findViewById(R.id.actions_temptarget); - extendedBolus = (Button) view.findViewById(R.id.actions_extendedbolus); - extendedBolusCancel = (Button) view.findViewById(R.id.actions_extendedbolus_cancel); - tempBasal = (Button) view.findViewById(R.id.actions_settempbasal); - tempBasalCancel = (Button) view.findViewById(R.id.actions_canceltempbasal); - fill = (Button) view.findViewById(R.id.actions_fill); + profileSwitch = (SingleClickButton) view.findViewById(R.id.actions_profileswitch); + tempTarget = (SingleClickButton) view.findViewById(R.id.actions_temptarget); + extendedBolus = (SingleClickButton) view.findViewById(R.id.actions_extendedbolus); + extendedBolusCancel = (SingleClickButton) view.findViewById(R.id.actions_extendedbolus_cancel); + tempBasal = (SingleClickButton) view.findViewById(R.id.actions_settempbasal); + tempBasalCancel = (SingleClickButton) view.findViewById(R.id.actions_canceltempbasal); + fill = (SingleClickButton) view.findViewById(R.id.actions_fill); profileSwitch.setOnClickListener(this); tempTarget.setOnClickListener(this); diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/Actions/dialogs/FillDialog.java b/app/src/main/java/info/nightscout/androidaps/plugins/Actions/dialogs/FillDialog.java index 8391f93492..2901ad862f 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/Actions/dialogs/FillDialog.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/Actions/dialogs/FillDialog.java @@ -100,6 +100,8 @@ public class FillDialog extends DialogFragment implements OnClickListener { if (button1.getVisibility() == View.GONE && button2.getVisibility() == View.GONE && button3.getVisibility() == View.GONE) { divider.setVisibility(View.GONE); } + + setCancelable(false); return view; } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/Actions/dialogs/NewExtendedBolusDialog.java b/app/src/main/java/info/nightscout/androidaps/plugins/Actions/dialogs/NewExtendedBolusDialog.java index fbb9fafd9b..aea4f4f4aa 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/Actions/dialogs/NewExtendedBolusDialog.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/Actions/dialogs/NewExtendedBolusDialog.java @@ -54,14 +54,9 @@ public class NewExtendedBolusDialog extends DialogFragment implements View.OnCli view.findViewById(R.id.ok).setOnClickListener(this); view.findViewById(R.id.cancel).setOnClickListener(this); - return view; - } - @Override - public void onResume() { - super.onResume(); - if (getDialog() != null) - getDialog().getWindow().setLayout(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT); + setCancelable(false); + return view; } @Override diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/Actions/dialogs/NewTempBasalDialog.java b/app/src/main/java/info/nightscout/androidaps/plugins/Actions/dialogs/NewTempBasalDialog.java index e734cd4f96..0337166fd6 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/Actions/dialogs/NewTempBasalDialog.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/Actions/dialogs/NewTempBasalDialog.java @@ -102,6 +102,8 @@ public class NewTempBasalDialog extends DialogFragment implements View.OnClickLi view.findViewById(R.id.ok).setOnClickListener(this); view.findViewById(R.id.cancel).setOnClickListener(this); basalTypeRadioGroup.setOnCheckedChangeListener(this); + + setCancelable(false); return view; } @@ -155,7 +157,7 @@ public class NewTempBasalDialog extends DialogFragment implements View.OnClickLi } }; if (setAsPercent) { - ConfigBuilderPlugin.getCommandQueue().tempBasalPercent(finalBasalPercent, finalDurationInMinutes, callback); + ConfigBuilderPlugin.getCommandQueue().tempBasalPercent(finalBasalPercent, finalDurationInMinutes, true, callback); } else { ConfigBuilderPlugin.getCommandQueue().tempBasalAbsolute(finalBasal, finalDurationInMinutes, true, callback); } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/Careportal/Dialogs/NewNSTreatmentDialog.java b/app/src/main/java/info/nightscout/androidaps/plugins/Careportal/Dialogs/NewNSTreatmentDialog.java index b284acff91..40eab27a5e 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/Careportal/Dialogs/NewNSTreatmentDialog.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/Careportal/Dialogs/NewNSTreatmentDialog.java @@ -175,7 +175,7 @@ public class NewNSTreatmentDialog extends DialogFragment implements View.OnClick profileSpinner.setAdapter(adapter); // set selected to actual profile for (int p = 0; p < profileList.size(); p++) { - if (profileList.get(p).equals(MainApp.getConfigBuilder().getProfileName())) + if (profileList.get(p).equals(MainApp.getConfigBuilder().getProfileName(false))) profileSpinner.setSelection(p); } @@ -360,6 +360,7 @@ public class NewNSTreatmentDialog extends DialogFragment implements View.OnClick showOrHide((ViewGroup) view.findViewById(R.id.careportal_newnstreatment_reuse_layout), options.profile && ps != null && ps.isCPP); showOrHide((ViewGroup) view.findViewById(R.id.careportal_newnstreatment_temptarget_layout), options.tempTarget); + setCancelable(false); return view; } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/ConfigBuilder/ConfigBuilderPlugin.java b/app/src/main/java/info/nightscout/androidaps/plugins/ConfigBuilder/ConfigBuilderPlugin.java index 3dfd8dcd55..03f0f60341 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/ConfigBuilder/ConfigBuilderPlugin.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/ConfigBuilder/ConfigBuilderPlugin.java @@ -16,9 +16,9 @@ import info.nightscout.androidaps.Config; import info.nightscout.androidaps.MainApp; import info.nightscout.androidaps.R; import info.nightscout.androidaps.data.DetailedBolusInfo; +import info.nightscout.androidaps.data.Intervals; import info.nightscout.androidaps.data.IobTotal; import info.nightscout.androidaps.data.MealData; -import info.nightscout.androidaps.data.Intervals; import info.nightscout.androidaps.data.Profile; import info.nightscout.androidaps.data.ProfileIntervals; import info.nightscout.androidaps.data.PumpEnactResult; @@ -38,8 +38,8 @@ import info.nightscout.androidaps.interfaces.SensitivityInterface; import info.nightscout.androidaps.interfaces.TreatmentsInterface; import info.nightscout.androidaps.plugins.Loop.APSResult; import info.nightscout.androidaps.plugins.Loop.LoopPlugin; -import info.nightscout.androidaps.plugins.Overview.notifications.Notification; import info.nightscout.androidaps.plugins.Overview.events.EventNewNotification; +import info.nightscout.androidaps.plugins.Overview.notifications.Notification; import info.nightscout.androidaps.plugins.PumpVirtual.VirtualPumpPlugin; import info.nightscout.androidaps.queue.Callback; import info.nightscout.androidaps.queue.CommandQueue; @@ -482,8 +482,7 @@ public class ConfigBuilderPlugin implements PluginBase, ConstraintsInterface, Tr @Override public boolean isAMAModeEnabled() { - SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(MainApp.instance().getApplicationContext()); - boolean result = preferences.getBoolean("openapsama_useautosens", false); + boolean result = SP.getBoolean("openapsama_useautosens", false); ArrayList constraintsPlugins = MainApp.getSpecificPluginsListByInterface(ConstraintsInterface.class); for (PluginBase p : constraintsPlugins) { @@ -494,6 +493,19 @@ public class ConfigBuilderPlugin implements PluginBase, ConstraintsInterface, Tr return result; } + @Override + public boolean isSMBModeEnabled() { + boolean result = true; // TODO update for SMB // SP.getBoolean("openapsama_useautosens", false); + + ArrayList constraintsPlugins = MainApp.getSpecificPluginsListByInterface(ConstraintsInterface.class); + for (PluginBase p : constraintsPlugins) { + ConstraintsInterface constrain = (ConstraintsInterface) p; + if (!p.isEnabled(PluginBase.CONSTRAINTS)) continue; + result = result && constrain.isSMBModeEnabled(); + } + return result; + } + @Override public Double applyBasalConstraints(Double absoluteRate) { Double rateAfterConstrain = absoluteRate; @@ -736,6 +748,10 @@ public class ConfigBuilderPlugin implements PluginBase, ConstraintsInterface, Tr return getProfileName(System.currentTimeMillis()); } + public String getProfileName(boolean customized) { + return getProfileName(System.currentTimeMillis(), customized); + } + public String getProfileName(long time) { return getProfileName(time, true); } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/ConstraintsObjectives/ObjectivesPlugin.java b/app/src/main/java/info/nightscout/androidaps/plugins/ConstraintsObjectives/ObjectivesPlugin.java index d898d48388..1f0e6704c3 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/ConstraintsObjectives/ObjectivesPlugin.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/ConstraintsObjectives/ObjectivesPlugin.java @@ -14,9 +14,14 @@ import info.nightscout.androidaps.BuildConfig; import info.nightscout.androidaps.Config; import info.nightscout.androidaps.MainApp; import info.nightscout.androidaps.R; +import info.nightscout.androidaps.interfaces.APSInterface; import info.nightscout.androidaps.interfaces.ConstraintsInterface; import info.nightscout.androidaps.interfaces.PluginBase; import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin; +import info.nightscout.androidaps.plugins.ConstraintsSafety.SafetyPlugin; +import info.nightscout.androidaps.plugins.Loop.LoopPlugin; +import info.nightscout.androidaps.plugins.NSClientInternal.NSClientInternalPlugin; +import info.nightscout.androidaps.plugins.PumpVirtual.VirtualPumpPlugin; import info.nightscout.utils.SP; /** @@ -152,14 +157,35 @@ public class ObjectivesPlugin implements PluginBase, ConstraintsInterface { RequirementResult requirementsMet(Integer objNum) { switch (objNum) { case 0: - return new RequirementResult(bgIsAvailableInNS && pumpStatusIsAvailableInNS, + boolean isVirtualPump = VirtualPumpPlugin.getPlugin().isEnabled(PluginBase.PUMP); + boolean vpUploadEnabled = SP.getBoolean("virtualpump_uploadstatus", false); + boolean vpUploadNeeded = !isVirtualPump || vpUploadEnabled; + + boolean apsEnabled = false; + APSInterface usedAPS = ConfigBuilderPlugin.getActiveAPS(); + if (usedAPS != null && ((PluginBase) usedAPS).isEnabled(PluginBase.APS)) + apsEnabled = true; + + return new RequirementResult(bgIsAvailableInNS && pumpStatusIsAvailableInNS && NSClientInternalPlugin.getPlugin().hasWritePermission() && LoopPlugin.getPlugin().isEnabled(PluginBase.LOOP) && apsEnabled && vpUploadNeeded, MainApp.sResources.getString(R.string.objectives_bgavailableinns) + ": " + yesOrNo(bgIsAvailableInNS) - + " " + MainApp.sResources.getString(R.string.objectives_pumpstatusavailableinns) + ": " + yesOrNo(pumpStatusIsAvailableInNS)); + + " " + MainApp.sResources.getString(R.string.nsclienthaswritepermission) + ": " + yesOrNo(NSClientInternalPlugin.getPlugin().hasWritePermission()) + + (isVirtualPump ? " " + MainApp.sResources.getString(R.string.virtualpump_uploadstatus_title) + ": " + yesOrNo(vpUploadEnabled) : "") + + " " + MainApp.sResources.getString(R.string.objectives_pumpstatusavailableinns) + ": " + yesOrNo(pumpStatusIsAvailableInNS) + + " " + MainApp.sResources.getString(R.string.loopenabled) + ": " + yesOrNo(LoopPlugin.getPlugin().isEnabled(PluginBase.LOOP)) + + " " + MainApp.sResources.getString(R.string.apsselected) + ": " + yesOrNo(apsEnabled) + ); case 1: return new RequirementResult(manualEnacts >= manualEnactsNeeded, MainApp.sResources.getString(R.string.objectives_manualenacts) + ": " + manualEnacts + "/" + manualEnactsNeeded); case 2: return new RequirementResult(true, ""); + case 3: + boolean closedModeEnabled = SafetyPlugin.getPlugin().isClosedModeEnabled(); + return new RequirementResult(closedModeEnabled, MainApp.sResources.getString(R.string.closedmodeenabled) + ": " + yesOrNo(closedModeEnabled)); + case 4: + double maxIOB = MainApp.getConfigBuilder().applyMaxIOBConstraints(1000d); + boolean maxIobSet = maxIOB > 0; + return new RequirementResult(maxIobSet, MainApp.sResources.getString(R.string.maxiobset) + ": " + yesOrNo(maxIobSet)); default: return new RequirementResult(true, ""); } @@ -212,7 +238,13 @@ public class ObjectivesPlugin implements PluginBase, ConstraintsInterface { MainApp.sResources.getString(R.string.objectives_6_objective), "", new Date(0), - 14, + 28, + new Date(0))); + objectives.add(new Objective(7, + MainApp.sResources.getString(R.string.objectives_7_objective), + "", + new Date(0), + 28, new Date(0))); } @@ -260,7 +292,7 @@ public class ObjectivesPlugin implements PluginBase, ConstraintsInterface { **/ @Override public boolean isLoopEnabled() { - return objectives.get(1).started.getTime() > 0; + return objectives.get(0).started.getTime() > 0; } @Override @@ -278,6 +310,11 @@ public class ObjectivesPlugin implements PluginBase, ConstraintsInterface { return objectives.get(6).started.getTime() > 0; } + @Override + public boolean isSMBModeEnabled() { + return objectives.get(7).started.getTime() > 0; + } + @Override public Double applyMaxIOBConstraints(Double maxIob) { if (objectives.get(4).started.getTime() > 0 || objectives.get(2).accomplished.getTime() == 0) diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/ConstraintsSafety/SafetyPlugin.java b/app/src/main/java/info/nightscout/androidaps/plugins/ConstraintsSafety/SafetyPlugin.java index ecb7aad47d..42f50d52dd 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/ConstraintsSafety/SafetyPlugin.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/ConstraintsSafety/SafetyPlugin.java @@ -116,6 +116,11 @@ public class SafetyPlugin implements PluginBase, ConstraintsInterface { return true; } + @Override + public boolean isSMBModeEnabled() { + return true; + } + @Override public Double applyBasalConstraints(Double absoluteRate) { Double origAbsoluteRate = absoluteRate; diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/Insulin/InsulinFastactingPlugin.java b/app/src/main/java/info/nightscout/androidaps/plugins/Insulin/InsulinFastactingPlugin.java index c7164ea60e..6218a2ecfe 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/Insulin/InsulinFastactingPlugin.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/Insulin/InsulinFastactingPlugin.java @@ -107,7 +107,7 @@ public class InsulinFastactingPlugin implements PluginBase, InsulinInterface { } @Override - public Iob iobCalcForTreatment(Treatment treatment, long time, Double dia) { + public Iob iobCalcForTreatment(Treatment treatment, long time, double dia) { Iob result = new Iob(); double scaleFactor = 3.0 / dia; diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/Insulin/InsulinFastactingProlongedPlugin.java b/app/src/main/java/info/nightscout/androidaps/plugins/Insulin/InsulinFastactingProlongedPlugin.java index 99c35a6c0b..4155a9be56 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/Insulin/InsulinFastactingProlongedPlugin.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/Insulin/InsulinFastactingProlongedPlugin.java @@ -107,7 +107,7 @@ public class InsulinFastactingProlongedPlugin implements PluginBase, InsulinInte } @Override - public Iob iobCalcForTreatment(Treatment treatment, long time, Double dia) { + public Iob iobCalcForTreatment(Treatment treatment, long time, double dia) { Iob result = new Iob(); //Double scaleFactor = 3.0 / dia; diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/Insulin/InsulinOrefBasePlugin.java b/app/src/main/java/info/nightscout/androidaps/plugins/Insulin/InsulinOrefBasePlugin.java index 6210f91c9a..cbe5f2ff64 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/Insulin/InsulinOrefBasePlugin.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/Insulin/InsulinOrefBasePlugin.java @@ -64,7 +64,7 @@ public abstract class InsulinOrefBasePlugin implements PluginBase, InsulinInterf } @Override - public Iob iobCalcForTreatment(Treatment treatment, long time, Double dia) { + public Iob iobCalcForTreatment(Treatment treatment, long time, double dia) { Iob result = new Iob(); int peak = getPeak(); diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/IobCobCalculator/events/BasalData.java b/app/src/main/java/info/nightscout/androidaps/plugins/IobCobCalculator/BasalData.java similarity index 71% rename from app/src/main/java/info/nightscout/androidaps/plugins/IobCobCalculator/events/BasalData.java rename to app/src/main/java/info/nightscout/androidaps/plugins/IobCobCalculator/BasalData.java index 4e1dcc1bf6..d8bde8acbb 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/IobCobCalculator/events/BasalData.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/IobCobCalculator/BasalData.java @@ -1,4 +1,4 @@ -package info.nightscout.androidaps.plugins.IobCobCalculator.events; +package info.nightscout.androidaps.plugins.IobCobCalculator; /** * Created by mike on 10.06.2017. diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/IobCobCalculator/IobCobCalculatorPlugin.java b/app/src/main/java/info/nightscout/androidaps/plugins/IobCobCalculator/IobCobCalculatorPlugin.java index 34417735dd..a0a6ebc581 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/IobCobCalculator/IobCobCalculatorPlugin.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/IobCobCalculator/IobCobCalculatorPlugin.java @@ -31,7 +31,6 @@ import info.nightscout.androidaps.events.EventNewBasalProfile; import info.nightscout.androidaps.events.EventPreferenceChange; import info.nightscout.androidaps.interfaces.PluginBase; import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin; -import info.nightscout.androidaps.plugins.IobCobCalculator.events.BasalData; import info.nightscout.androidaps.plugins.IobCobCalculator.events.EventAutosensCalculationFinished; import info.nightscout.androidaps.plugins.IobCobCalculator.events.EventNewHistoryData; @@ -364,6 +363,8 @@ public class IobCobCalculatorPlugin implements PluginBase { // check if data already exists long bgTime = bucketed_data.get(i).date; bgTime = roundUpTime(bgTime); + if (bgTime > System.currentTimeMillis()) + continue; Profile profile = MainApp.getConfigBuilder().getProfile(bgTime); AutosensData existing; @@ -544,6 +545,10 @@ public class IobCobCalculatorPlugin implements PluginBase { //log.debug(">>> getAutosensData Cache hit " + data.log(time)); return data; } else { + if (time > now) { + // data may not be calculated yet, use last data + return getLastAutosensData(); + } //log.debug(">>> getAutosensData Cache miss " + new Date(time).toLocaleString()); return null; } @@ -555,7 +560,7 @@ public class IobCobCalculatorPlugin implements PluginBase { if (autosensDataTable.size() < 1) return null; AutosensData data = autosensDataTable.valueAt(autosensDataTable.size() - 1); - if (data.time < System.currentTimeMillis() - 5 * 60 * 1000) { + if (data.time < System.currentTimeMillis() - 11 * 60 * 1000) { return null; } else { return data; diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/Loop/LoopPlugin.java b/app/src/main/java/info/nightscout/androidaps/plugins/Loop/LoopPlugin.java index 736dbeec44..539b9991a3 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/Loop/LoopPlugin.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/Loop/LoopPlugin.java @@ -259,18 +259,6 @@ public class LoopPlugin implements PluginBase { if (!isEnabled(PluginBase.LOOP)) return; - if (isSuspended()) { - log.debug(MainApp.sResources.getString(R.string.loopsuspended)); - MainApp.bus().post(new EventLoopSetLastRunGui(MainApp.sResources.getString(R.string.loopsuspended))); - return; - } - - if (pump.isSuspended()) { - log.debug(MainApp.sResources.getString(R.string.pumpsuspended)); - MainApp.bus().post(new EventLoopSetLastRunGui(MainApp.sResources.getString(R.string.pumpsuspended))); - return; - } - if (MainApp.getConfigBuilder().getProfile() == null) { log.debug(MainApp.sResources.getString(R.string.noprofileselected)); MainApp.bus().post(new EventLoopSetLastRunGui(MainApp.sResources.getString(R.string.noprofileselected))); @@ -280,7 +268,7 @@ public class LoopPlugin implements PluginBase { // Check if pump info is loaded if (pump.getBaseBasalRate() < 0.01d) return; - APSInterface usedAPS = MainApp.getConfigBuilder().getActiveAPS(); + APSInterface usedAPS = ConfigBuilderPlugin.getActiveAPS(); if (usedAPS != null && ((PluginBase) usedAPS).isEnabled(PluginBase.APS)) { usedAPS.invoke(initiator); result = usedAPS.getLastAPSResult(); @@ -303,6 +291,20 @@ public class LoopPlugin implements PluginBase { lastRun.source = ((PluginBase) usedAPS).getName(); lastRun.setByPump = null; + NSUpload.uploadDeviceStatus(); + + if (isSuspended()) { + log.debug(MainApp.sResources.getString(R.string.loopsuspended)); + MainApp.bus().post(new EventLoopSetLastRunGui(MainApp.sResources.getString(R.string.loopsuspended))); + return; + } + + if (pump.isSuspended()) { + log.debug(MainApp.sResources.getString(R.string.pumpsuspended)); + MainApp.bus().post(new EventLoopSetLastRunGui(MainApp.sResources.getString(R.string.pumpsuspended))); + return; + } + if (constraintsInterface.isClosedModeEnabled()) { if (result.changeRequested) { final PumpEnactResult waiting = new PumpEnactResult(); @@ -363,7 +365,6 @@ public class LoopPlugin implements PluginBase { } MainApp.bus().post(new EventLoopUpdateGui()); - NSUpload.uploadDeviceStatus(); } finally { if (Config.logFunctionCalls) log.debug("invoke end"); diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/NSClientInternal/NSClientInternalPlugin.java b/app/src/main/java/info/nightscout/androidaps/plugins/NSClientInternal/NSClientInternalPlugin.java index cdca4e5b41..a51ea18cc7 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/NSClientInternal/NSClientInternalPlugin.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/NSClientInternal/NSClientInternalPlugin.java @@ -222,4 +222,8 @@ public class NSClientInternalPlugin implements PluginBase { public String url() { return NSClientService.nsURL; } + + public boolean hasWritePermission() { + return nsClientService.hasWriteAuth; + } } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/NSClientInternal/receivers/DBAccessReceiver.java b/app/src/main/java/info/nightscout/androidaps/plugins/NSClientInternal/receivers/DBAccessReceiver.java index 3411659d0d..4590490ecf 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/NSClientInternal/receivers/DBAccessReceiver.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/NSClientInternal/receivers/DBAccessReceiver.java @@ -30,14 +30,6 @@ public class DBAccessReceiver extends BroadcastReceiver { PowerManager powerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE); PowerManager.WakeLock wakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, DBAccessReceiver.class.getSimpleName()); - NSClientInternalPlugin nsClientInternalPlugin = MainApp.getSpecificPlugin(NSClientInternalPlugin.class); - if (!nsClientInternalPlugin.isEnabled(PluginBase.GENERAL)) { - return; - } - if (SP.getBoolean(R.string.key_ns_noupload, false)) { - log.debug("Upload disabled. Message dropped"); - return; - } wakeLock.acquire(); try { Bundle bundles = intent.getExtras(); @@ -83,16 +75,22 @@ public class DBAccessReceiver extends BroadcastReceiver { } if (action.equals("dbRemove")) { - DbRequest dbr = new DbRequest(action, collection, nsclientid.toString(), _id); - UploadQueue.add(dbr); + if (shouldUpload()) { + DbRequest dbr = new DbRequest(action, collection, nsclientid.toString(), _id); + UploadQueue.add(dbr); + } } else { DbRequest dbr = new DbRequest(action, collection, nsclientid.toString(), data); // this is not used as mongo _id but only for searching in UploadQueue database // if record has to be removed from queue before upload dbr._id = nsclientid.toString(); - UploadQueue.add(dbr); - if (collection.equals("treatments")) + + if (shouldUpload()) { + UploadQueue.add(dbr); + } + if (collection.equals("treatments")) { genereateTreatmentOfflineBroadcast(dbr); + } } } finally { @@ -101,6 +99,11 @@ public class DBAccessReceiver extends BroadcastReceiver { } + public boolean shouldUpload() { + NSClientInternalPlugin nsClientInternalPlugin = MainApp.getSpecificPlugin(NSClientInternalPlugin.class); + return nsClientInternalPlugin.isEnabled(PluginBase.GENERAL) && !SP.getBoolean(R.string.key_ns_noupload, false); + } + public void genereateTreatmentOfflineBroadcast(DbRequest request) { if (request.action.equals("dbAdd")) { try { diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/Overview/Dialogs/CalibrationDialog.java b/app/src/main/java/info/nightscout/androidaps/plugins/Overview/Dialogs/CalibrationDialog.java index fdc58e92f4..32b34b6f85 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/Overview/Dialogs/CalibrationDialog.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/Overview/Dialogs/CalibrationDialog.java @@ -76,6 +76,7 @@ public class CalibrationDialog extends DialogFragment implements View.OnClickLis unitsView = (TextView) view.findViewById(R.id.overview_calibration_units); unitsView.setText(units); + setCancelable(false); return view; } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/Overview/Dialogs/EditQuickWizardDialog.java b/app/src/main/java/info/nightscout/androidaps/plugins/Overview/Dialogs/EditQuickWizardDialog.java index 95bcea7908..2751b800bc 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/Overview/Dialogs/EditQuickWizardDialog.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/Overview/Dialogs/EditQuickWizardDialog.java @@ -9,7 +9,6 @@ import android.view.ViewGroup; import android.view.Window; import android.view.WindowManager; import android.widget.ArrayAdapter; -import android.widget.Button; import android.widget.EditText; import android.widget.Spinner; @@ -17,13 +16,13 @@ import org.json.JSONException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.text.SimpleDateFormat; import java.util.ArrayList; import info.nightscout.androidaps.MainApp; import info.nightscout.androidaps.R; +import info.nightscout.androidaps.data.QuickWizard; +import info.nightscout.androidaps.data.QuickWizardEntry; import info.nightscout.androidaps.plugins.Overview.OverviewPlugin; -import info.nightscout.androidaps.plugins.Overview.QuickWizard; import info.nightscout.androidaps.plugins.Overview.events.EventQuickWizardChange; import info.nightscout.utils.DateUtil; import info.nightscout.utils.SafeParse; @@ -31,19 +30,25 @@ import info.nightscout.utils.SafeParse; public class EditQuickWizardDialog extends DialogFragment implements View.OnClickListener { private static Logger log = LoggerFactory.getLogger(EditQuickWizardDialog.class); - QuickWizard.QuickWizardEntry entry = new QuickWizard().newEmptyItem(); + QuickWizardEntry entry = new QuickWizard().newEmptyItem(); QuickWizard quickWizard = MainApp.getSpecificPlugin(OverviewPlugin.class).quickWizard; EditText buttonEdit; EditText carbsEdit; Spinner fromSpinner; Spinner toSpinner; - Button okButton; + Spinner useBGSpinner; + Spinner useCOBSpinner; + Spinner useBolusIOBSpinner; + Spinner useBasalIOBSpinner; + Spinner useTrendSpinner; + Spinner useSuperBolusSpinner; + Spinner useTempTargetSpinner; public EditQuickWizardDialog() { } - public void setData(QuickWizard.QuickWizardEntry data) { + public void setData(QuickWizardEntry data) { entry = data; } @@ -58,8 +63,16 @@ public class EditQuickWizardDialog extends DialogFragment implements View.OnClic carbsEdit = (EditText) view.findViewById(R.id.overview_editquickwizard_carbs_edit); fromSpinner = (Spinner) view.findViewById(R.id.overview_editquickwizard_from_spinner); toSpinner = (Spinner) view.findViewById(R.id.overview_editquickwizard_to_spinner); - okButton = (Button) view.findViewById(R.id.overview_editquickwizard_ok_button); - okButton.setOnClickListener(this); + useBGSpinner = (Spinner) view.findViewById(R.id.overview_editquickwizard_usebg_spinner); + useCOBSpinner = (Spinner) view.findViewById(R.id.overview_editquickwizard_usecob_spinner); + useBolusIOBSpinner = (Spinner) view.findViewById(R.id.overview_editquickwizard_usebolusiob_spinner); + useBasalIOBSpinner = (Spinner) view.findViewById(R.id.overview_editquickwizard_usebasaliob_spinner); + useTrendSpinner = (Spinner) view.findViewById(R.id.overview_editquickwizard_usetrend_spinner); + useSuperBolusSpinner = (Spinner) view.findViewById(R.id.overview_editquickwizard_usesuperbolus_spinner); + useTempTargetSpinner = (Spinner) view.findViewById(R.id.overview_editquickwizard_usetemptarget_spinner); + + view.findViewById(R.id.ok).setOnClickListener(this); + view.findViewById(R.id.cancel).setOnClickListener(this); int posFrom = 0; int posTo = 95; @@ -83,6 +96,14 @@ public class EditQuickWizardDialog extends DialogFragment implements View.OnClic fromSpinner.setSelection(posFrom); toSpinner.setSelection(posTo); + setSelection(useBGSpinner, entry.useBG()); + setSelection(useCOBSpinner, entry.useCOB()); + setSelection(useBolusIOBSpinner, entry.useBolusIOB()); + setSelection(useBasalIOBSpinner, entry.useBasalIOB()); + setSelection(useTrendSpinner, entry.useTrend()); + setSelection(useSuperBolusSpinner, entry.useSuperBolus()); + setSelection(useTempTargetSpinner, entry.useTempTarget()); + return view; } @@ -96,7 +117,7 @@ public class EditQuickWizardDialog extends DialogFragment implements View.OnClic @Override public void onClick(View v) { switch (v.getId()) { - case R.id.overview_editquickwizard_ok_button: + case R.id.ok: if (fromSpinner.getSelectedItem() == null) return; if (toSpinner.getSelectedItem() == null) return; try { @@ -106,13 +127,64 @@ public class EditQuickWizardDialog extends DialogFragment implements View.OnClic entry.storage.put("validFrom", validFromInt); int validToInt = DateUtil.toSeconds(toSpinner.getSelectedItem().toString()); entry.storage.put("validTo", validToInt); + entry.storage.put("useBG", getSelection(useBGSpinner)); + entry.storage.put("useCOB", getSelection(useCOBSpinner)); + entry.storage.put("useBolusIOB", getSelection(useBolusIOBSpinner)); + entry.storage.put("useBasalIOB", getSelection(useBasalIOBSpinner)); + entry.storage.put("useTrend", getSelection(useTrendSpinner)); + entry.storage.put("useSuperBolus", getSelection(useSuperBolusSpinner)); + entry.storage.put("useTempTarget", getSelection(useTempTargetSpinner)); } catch (JSONException e) { log.error("Unhandled exception", e); } quickWizard.addOrUpdate(entry); dismiss(); MainApp.bus().post(new EventQuickWizardChange()); - break; + break; + case R.id.cancel: + dismiss(); + break; + } + } + + int getSelection(Spinner spinner) { + String value = spinner.getSelectedItem().toString(); + if (value.equals(MainApp.sResources.getString(R.string.yes))) + return QuickWizardEntry.YES; + if (value.equals(MainApp.sResources.getString(R.string.no))) + return QuickWizardEntry.NO; + if (value.equals(MainApp.sResources.getString(R.string.positiveonly))) + return QuickWizardEntry.POSITIVE_ONLY; + if (value.equals(MainApp.sResources.getString(R.string.negativeonly))) + return QuickWizardEntry.NEGATIVE_ONLY; + return QuickWizardEntry.NO; + } + + void setSelection(Spinner spinner, int value) { + String selection; + switch (value) { + case QuickWizardEntry.YES: + selection = MainApp.sResources.getString(R.string.yes); + break; + case QuickWizardEntry.NO: + selection = MainApp.sResources.getString(R.string.no); + break; + case QuickWizardEntry.POSITIVE_ONLY: + selection = MainApp.sResources.getString(R.string.positiveonly); + break; + case QuickWizardEntry.NEGATIVE_ONLY: + selection = MainApp.sResources.getString(R.string.negativeonly); + break; + default: + selection = MainApp.sResources.getString(R.string.no); + break; + } + + for (int i = 0; i < spinner.getCount(); i++) { + if (spinner.getItemAtPosition(i).toString().equalsIgnoreCase(selection)) { + spinner.setSelection(i); + break; + } } } } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/Overview/Dialogs/NewTreatmentDialog.java b/app/src/main/java/info/nightscout/androidaps/plugins/Overview/Dialogs/NewTreatmentDialog.java index 5b18b7c385..902de4cf62 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/Overview/Dialogs/NewTreatmentDialog.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/Overview/Dialogs/NewTreatmentDialog.java @@ -101,6 +101,7 @@ public class NewTreatmentDialog extends DialogFragment implements OnClickListene editCarbs.setParams(0d, 0d, (double) maxCarbs, 1d, new DecimalFormat("0"), false, textWatcher); editInsulin.setParams(0d, 0d, maxInsulin, ConfigBuilderPlugin.getActivePump().getPumpDescription().bolusStep, new DecimalFormat("0.00"), false, textWatcher); + setCancelable(false); return view; } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/Overview/Dialogs/WizardDialog.java b/app/src/main/java/info/nightscout/androidaps/plugins/Overview/Dialogs/WizardDialog.java index 464c422596..af2266582b 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/Overview/Dialogs/WizardDialog.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/Overview/Dialogs/WizardDialog.java @@ -53,6 +53,8 @@ import info.nightscout.androidaps.db.TempTarget; import info.nightscout.androidaps.events.EventNewBG; import info.nightscout.androidaps.events.EventRefreshOverview; import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin; +import info.nightscout.androidaps.plugins.IobCobCalculator.AutosensData; +import info.nightscout.androidaps.plugins.IobCobCalculator.IobCobCalculatorPlugin; import info.nightscout.androidaps.plugins.Loop.LoopPlugin; import info.nightscout.androidaps.plugins.OpenAPSAMA.OpenAPSAMAPlugin; import info.nightscout.androidaps.plugins.OpenAPSMA.events.EventOpenAPSUpdateGui; @@ -102,7 +104,6 @@ public class WizardDialog extends DialogFragment implements OnClickListener, Com Integer calculatedCarbs = 0; Double calculatedTotalInsulin = 0d; JSONObject boluscalcJSON; - boolean cobAvailable = false; Context context; @@ -138,25 +139,6 @@ public class WizardDialog extends DialogFragment implements OnClickListener, Com MainApp.bus().unregister(this); } - @Subscribe - public void onStatusEvent(final EventOpenAPSUpdateGui e) { - Activity activity = getActivity(); - if (activity != null) - activity.runOnUiThread(new Runnable() { - @Override - public void run() { - if (ConfigBuilderPlugin.getActiveAPS() instanceof OpenAPSAMAPlugin && ConfigBuilderPlugin.getActiveAPS().getLastAPSResult() != null && ConfigBuilderPlugin.getActiveAPS().getLastAPSRun().after(new Date(System.currentTimeMillis() - 11 * 60 * 1000L))) { - cobLayout.setVisibility(View.VISIBLE); - cobAvailable = true; - } else { - cobLayout.setVisibility(View.GONE); - cobAvailable = false; - } - calculateInsulin(); - } - }); - } - @Subscribe public void onStatusEvent(final EventNewBG e) { Activity activity = getActivity(); @@ -251,6 +233,7 @@ public class WizardDialog extends DialogFragment implements OnClickListener, Com editCarbTime.setParams(0d, -60d, 60d, 5d, new DecimalFormat("0"), false); initDialog(); + setCancelable(false); return view; } @@ -344,7 +327,7 @@ public class WizardDialog extends DialogFragment implements OnClickListener, Com activeloop.superBolusTo(System.currentTimeMillis() + 2 * 60L * 60 * 1000); MainApp.bus().post(new EventRefreshOverview("WizardDialog")); } - ConfigBuilderPlugin.getCommandQueue().tempBasalAbsolute(0d, 120, true, new Callback() { + ConfigBuilderPlugin.getCommandQueue().tempBasalPercent(0, 120, true, new Callback() { @Override public void run() { if (!result.success) { @@ -438,14 +421,6 @@ public class WizardDialog extends DialogFragment implements OnClickListener, Com bolusIobInsulin.setText(DecimalFormatter.to2Decimal(-bolusIob.iob) + "U"); basalIobInsulin.setText(DecimalFormatter.to2Decimal(-basalIob.basaliob) + "U"); - // COB only if AMA is selected - if (ConfigBuilderPlugin.getActiveAPS() instanceof OpenAPSAMAPlugin && ConfigBuilderPlugin.getActiveAPS().getLastAPSResult() != null && ConfigBuilderPlugin.getActiveAPS().getLastAPSRun().after(new Date(System.currentTimeMillis() - 11 * 60 * 1000L))) { - cobLayout.setVisibility(View.VISIBLE); - cobAvailable = true; - } else { - cobLayout.setVisibility(View.GONE); - cobAvailable = false; - } calculateInsulin(); } @@ -482,13 +457,11 @@ public class WizardDialog extends DialogFragment implements OnClickListener, Com // COB Double c_cob = 0d; - if (cobAvailable && cobCheckbox.isChecked()) { - if (ConfigBuilderPlugin.getActiveAPS().getLastAPSResult() != null && ConfigBuilderPlugin.getActiveAPS().getLastAPSRun().after(new Date(System.currentTimeMillis() - 11 * 60 * 1000L))) { - try { - c_cob = SafeParse.stringToDouble(ConfigBuilderPlugin.getActiveAPS().getLastAPSResult().json().getString("COB")); - } catch (JSONException e) { - log.error("Unhandled exception", e); - } + if (cobCheckbox.isChecked()) { + AutosensData autosensData = IobCobCalculatorPlugin.getLastAutosensData(); + + if(autosensData != null) { + c_cob = autosensData.cob; } } @@ -530,7 +503,7 @@ public class WizardDialog extends DialogFragment implements OnClickListener, Com bgTrendInsulin.setText(DecimalFormatter.to2Decimal(wizard.insulinFromTrend) + "U"); // COB - if (cobAvailable && cobCheckbox.isChecked()) { + if (cobCheckbox.isChecked()) { cob.setText(DecimalFormatter.to2Decimal(c_cob) + "g IC: " + DecimalFormatter.to1Decimal(wizard.ic)); cobInsulin.setText(DecimalFormatter.to2Decimal(wizard.insulinFromCOB) + "U"); } else { diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/Overview/OverviewFragment.java b/app/src/main/java/info/nightscout/androidaps/plugins/Overview/OverviewFragment.java index c1ea15a1cf..d694b9d0a8 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/Overview/OverviewFragment.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/Overview/OverviewFragment.java @@ -53,7 +53,6 @@ import java.util.concurrent.ScheduledFuture; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; -import info.nightscout.androidaps.BuildConfig; import info.nightscout.androidaps.Config; import info.nightscout.androidaps.Constants; import info.nightscout.androidaps.MainApp; @@ -62,6 +61,7 @@ import info.nightscout.androidaps.data.DetailedBolusInfo; import info.nightscout.androidaps.data.GlucoseStatus; import info.nightscout.androidaps.data.IobTotal; import info.nightscout.androidaps.data.Profile; +import info.nightscout.androidaps.data.QuickWizardEntry; import info.nightscout.androidaps.db.BgReading; import info.nightscout.androidaps.db.CareportalEvent; import info.nightscout.androidaps.db.DatabaseHelper; @@ -79,6 +79,7 @@ import info.nightscout.androidaps.events.EventTempBasalChange; import info.nightscout.androidaps.events.EventTempTargetChange; import info.nightscout.androidaps.events.EventTreatmentChange; import info.nightscout.androidaps.interfaces.PluginBase; +import info.nightscout.androidaps.interfaces.PumpDescription; import info.nightscout.androidaps.interfaces.PumpInterface; import info.nightscout.androidaps.plugins.Careportal.CareportalFragment; import info.nightscout.androidaps.plugins.Careportal.Dialogs.NewNSTreatmentDialog; @@ -98,6 +99,7 @@ import info.nightscout.androidaps.plugins.Overview.Dialogs.CalibrationDialog; import info.nightscout.androidaps.plugins.Overview.Dialogs.ErrorHelperActivity; import info.nightscout.androidaps.plugins.Overview.Dialogs.NewTreatmentDialog; import info.nightscout.androidaps.plugins.Overview.Dialogs.WizardDialog; +import info.nightscout.androidaps.plugins.Overview.activities.QuickWizardListActivity; import info.nightscout.androidaps.plugins.Overview.events.EventDismissNotification; import info.nightscout.androidaps.plugins.Overview.events.EventSetWakeLock; import info.nightscout.androidaps.plugins.Overview.graphData.GraphData; @@ -113,9 +115,10 @@ import info.nightscout.utils.NSUpload; import info.nightscout.utils.OKDialog; import info.nightscout.utils.Profiler; import info.nightscout.utils.SP; +import info.nightscout.utils.SingleClickButton; import info.nightscout.utils.ToastUtils; -public class OverviewFragment extends Fragment implements View.OnClickListener, CompoundButton.OnCheckedChangeListener { +public class OverviewFragment extends Fragment implements View.OnClickListener, CompoundButton.OnCheckedChangeListener, View.OnLongClickListener { private static Logger log = LoggerFactory.getLogger(OverviewFragment.class); TextView timeView; @@ -156,11 +159,11 @@ public class OverviewFragment extends Fragment implements View.OnClickListener, LinearLayoutManager llm; LinearLayout acceptTempLayout; - Button treatmentButton; - Button wizardButton; - Button calibrationButton; - Button acceptTempButton; - Button quickWizardButton; + SingleClickButton treatmentButton; + SingleClickButton wizardButton; + SingleClickButton calibrationButton; + SingleClickButton acceptTempButton; + SingleClickButton quickWizardButton; CheckBox lockScreen; @@ -244,16 +247,17 @@ public class OverviewFragment extends Fragment implements View.OnClickListener, bgGraph = (GraphView) view.findViewById(R.id.overview_bggraph); iobGraph = (GraphView) view.findViewById(R.id.overview_iobgraph); - treatmentButton = (Button) view.findViewById(R.id.overview_treatmentbutton); + treatmentButton = (SingleClickButton) view.findViewById(R.id.overview_treatmentbutton); treatmentButton.setOnClickListener(this); - wizardButton = (Button) view.findViewById(R.id.overview_wizardbutton); + wizardButton = (SingleClickButton) view.findViewById(R.id.overview_wizardbutton); wizardButton.setOnClickListener(this); - acceptTempButton = (Button) view.findViewById(R.id.overview_accepttempbutton); + acceptTempButton = (SingleClickButton) view.findViewById(R.id.overview_accepttempbutton); if (acceptTempButton != null) acceptTempButton.setOnClickListener(this); - quickWizardButton = (Button) view.findViewById(R.id.overview_quickwizardbutton); + quickWizardButton = (SingleClickButton) view.findViewById(R.id.overview_quickwizardbutton); quickWizardButton.setOnClickListener(this); - calibrationButton = (Button) view.findViewById(R.id.overview_calibrationbutton); + quickWizardButton.setOnLongClickListener(this); + calibrationButton = (SingleClickButton) view.findViewById(R.id.overview_calibrationbutton); if (calibrationButton != null) calibrationButton.setOnClickListener(this); @@ -320,6 +324,7 @@ public class OverviewFragment extends Fragment implements View.OnClickListener, return view; } catch (Exception e) { Crashlytics.logException(e); + log.debug("Runtime Exception", e); } return null; @@ -331,6 +336,7 @@ public class OverviewFragment extends Fragment implements View.OnClickListener, super.onCreateContextMenu(menu, v, menuInfo); if (v == apsModeView) { final LoopPlugin activeloop = ConfigBuilderPlugin.getActiveLoop(); + final PumpDescription pumpDescription = ConfigBuilderPlugin.getActivePump().getPumpDescription(); if (activeloop == null) return; menu.setHeaderTitle(MainApp.sResources.getString(R.string.loop)); @@ -341,7 +347,8 @@ public class OverviewFragment extends Fragment implements View.OnClickListener, menu.add(MainApp.sResources.getString(R.string.suspendloopfor2h)); menu.add(MainApp.sResources.getString(R.string.suspendloopfor3h)); menu.add(MainApp.sResources.getString(R.string.suspendloopfor10h)); - menu.add(MainApp.sResources.getString(R.string.disconnectpumpfor30m)); + if (pumpDescription.tempDurationStep <= 30) + menu.add(MainApp.sResources.getString(R.string.disconnectpumpfor30m)); menu.add(MainApp.sResources.getString(R.string.disconnectpumpfor1h)); menu.add(MainApp.sResources.getString(R.string.disconnectpumpfor2h)); menu.add(MainApp.sResources.getString(R.string.disconnectpumpfor3h)); @@ -480,7 +487,7 @@ public class OverviewFragment extends Fragment implements View.OnClickListener, } else if (item.getTitle().equals(MainApp.sResources.getString(R.string.disconnectpumpfor30m))) { activeloop.disconnectTo(System.currentTimeMillis() + 30L * 60 * 1000); updateGUI("suspendmenu"); - ConfigBuilderPlugin.getCommandQueue().tempBasalAbsolute(0d, 30, true, new Callback() { + ConfigBuilderPlugin.getCommandQueue().tempBasalPercent(0, 30, true, new Callback() { @Override public void run() { if (!result.success) { @@ -493,7 +500,7 @@ public class OverviewFragment extends Fragment implements View.OnClickListener, } else if (item.getTitle().equals(MainApp.sResources.getString(R.string.disconnectpumpfor1h))) { activeloop.disconnectTo(System.currentTimeMillis() + 1 * 60L * 60 * 1000); updateGUI("suspendmenu"); - ConfigBuilderPlugin.getCommandQueue().tempBasalAbsolute(0d, 60, true, new Callback() { + ConfigBuilderPlugin.getCommandQueue().tempBasalPercent(0, 60, true, new Callback() { @Override public void run() { if (!result.success) { @@ -506,7 +513,7 @@ public class OverviewFragment extends Fragment implements View.OnClickListener, } else if (item.getTitle().equals(MainApp.sResources.getString(R.string.disconnectpumpfor2h))) { activeloop.disconnectTo(System.currentTimeMillis() + 2 * 60L * 60 * 1000); updateGUI("suspendmenu"); - ConfigBuilderPlugin.getCommandQueue().tempBasalAbsolute(0d, 2 * 60, true, new Callback() { + ConfigBuilderPlugin.getCommandQueue().tempBasalPercent(0, 2 * 60, true, new Callback() { @Override public void run() { if (!result.success) { @@ -519,7 +526,7 @@ public class OverviewFragment extends Fragment implements View.OnClickListener, } else if (item.getTitle().equals(MainApp.sResources.getString(R.string.disconnectpumpfor3h))) { activeloop.disconnectTo(System.currentTimeMillis() + 3 * 60L * 60 * 1000); updateGUI("suspendmenu"); - ConfigBuilderPlugin.getCommandQueue().tempBasalAbsolute(0d, 3 * 60, true, new Callback() { + ConfigBuilderPlugin.getCommandQueue().tempBasalPercent(0, 3 * 60, true, new Callback() { @Override public void run() { if (!result.success) { @@ -574,6 +581,17 @@ public class OverviewFragment extends Fragment implements View.OnClickListener, } + @Override + public boolean onLongClick(View v) { + switch (v.getId()) { + case R.id.overview_quickwizardbutton: + Intent i = new Intent(v.getContext(), QuickWizardListActivity.class); + startActivity(i); + return true; + } + return false; + } + private void onClickAcceptTemp() { if (ConfigBuilderPlugin.getActiveLoop() != null) { ConfigBuilderPlugin.getActiveLoop().invoke("Accept temp button", false); @@ -617,11 +635,10 @@ public class OverviewFragment extends Fragment implements View.OnClickListener, final Profile profile = MainApp.getConfigBuilder().getProfile(); final TempTarget tempTarget = MainApp.getConfigBuilder().getTempTargetFromHistory(); - QuickWizard.QuickWizardEntry quickWizardEntry = OverviewPlugin.getPlugin().quickWizard.getActive(); + final QuickWizardEntry quickWizardEntry = OverviewPlugin.getPlugin().quickWizard.getActive(); if (quickWizardEntry != null && actualBg != null) { quickWizardButton.setVisibility(View.VISIBLE); - BolusWizard wizard = new BolusWizard(); - wizard.doCalc(profile, tempTarget, quickWizardEntry.carbs(), 0d, actualBg.valueToUnits(profile.getUnits()), 0d, true, true, false, false); + final BolusWizard wizard = quickWizardEntry.doCalc(profile, tempTarget, actualBg); final JSONObject boluscalcJSON = new JSONObject(); try { @@ -680,6 +697,26 @@ public class OverviewFragment extends Fragment implements View.OnClickListener, } accepted = true; if (finalInsulinAfterConstraints > 0 || finalCarbsAfterConstraints > 0) { + if (wizard.superBolus) { + final LoopPlugin activeloop = ConfigBuilderPlugin.getActiveLoop(); + if (activeloop != null) { + activeloop.superBolusTo(System.currentTimeMillis() + 2 * 60L * 60 * 1000); + MainApp.bus().post(new EventRefreshOverview("WizardDialog")); + } + ConfigBuilderPlugin.getCommandQueue().tempBasalPercent(0, 120, true, new Callback() { + @Override + public void run() { + if (!result.success) { + Intent i = new Intent(MainApp.instance(), ErrorHelperActivity.class); + i.putExtra("soundid", R.raw.boluserror); + i.putExtra("status", result.comment); + i.putExtra("title", MainApp.sResources.getString(R.string.tempbasaldeliveryerror)); + i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + MainApp.instance().startActivity(i); + } + } + }); + } DetailedBolusInfo detailedBolusInfo = new DetailedBolusInfo(); detailedBolusInfo.eventType = CareportalEvent.BOLUSWIZARD; detailedBolusInfo.insulin = finalInsulinAfterConstraints; @@ -1084,12 +1121,11 @@ public class OverviewFragment extends Fragment implements View.OnClickListener, tempTargetView.setLongClickable(true); // QuickWizard button - QuickWizard.QuickWizardEntry quickWizardEntry = OverviewPlugin.getPlugin().quickWizard.getActive(); + QuickWizardEntry quickWizardEntry = OverviewPlugin.getPlugin().quickWizard.getActive(); if (quickWizardEntry != null && lastBG != null && pump.isInitialized() && !pump.isSuspended()) { quickWizardButton.setVisibility(View.VISIBLE); String text = quickWizardEntry.buttonText() + "\n" + DecimalFormatter.to0Decimal(quickWizardEntry.carbs()) + "g"; - BolusWizard wizard = new BolusWizard(); - wizard.doCalc(profile, tempTarget, quickWizardEntry.carbs(), 0d, lastBG.valueToUnits(units), 0d, true, true, false, false); + BolusWizard wizard = quickWizardEntry.doCalc(profile, tempTarget, lastBG); text += " " + DecimalFormatter.to2Decimal(wizard.calculatedTotalInsulin) + "U"; quickWizardButton.setText(text); if (wizard.calculatedTotalInsulin <= 0) @@ -1161,7 +1197,7 @@ public class OverviewFragment extends Fragment implements View.OnClickListener, // cob if (cobView != null) { // view must not exists String cobText = ""; - AutosensData autosensData = IobCobCalculatorPlugin.getAutosensData(System.currentTimeMillis()); + AutosensData autosensData = IobCobCalculatorPlugin.getLastAutosensData(); if (autosensData != null) cobText = (int) autosensData.cob + " g"; cobView.setText(cobText); diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/Overview/OverviewPlugin.java b/app/src/main/java/info/nightscout/androidaps/plugins/Overview/OverviewPlugin.java index 57aa5a8054..eb31ae66ed 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/Overview/OverviewPlugin.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/Overview/OverviewPlugin.java @@ -9,6 +9,7 @@ import org.slf4j.LoggerFactory; import info.nightscout.androidaps.MainApp; import info.nightscout.androidaps.R; +import info.nightscout.androidaps.data.QuickWizard; import info.nightscout.androidaps.events.EventRefreshOverview; import info.nightscout.androidaps.interfaces.PluginBase; import info.nightscout.androidaps.plugins.Overview.events.EventDismissNotification; diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/Overview/activities/QuickWizardListActivity.java b/app/src/main/java/info/nightscout/androidaps/plugins/Overview/activities/QuickWizardListActivity.java index 9fc731b4f5..237575c328 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/Overview/activities/QuickWizardListActivity.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/Overview/activities/QuickWizardListActivity.java @@ -1,9 +1,9 @@ package info.nightscout.androidaps.plugins.Overview.activities; import android.app.Activity; +import android.os.Bundle; import android.support.v4.app.FragmentManager; import android.support.v7.app.AppCompatActivity; -import android.os.Bundle; import android.support.v7.widget.CardView; import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; @@ -15,13 +15,11 @@ import android.widget.TextView; import com.squareup.otto.Subscribe; -import java.text.SimpleDateFormat; - import info.nightscout.androidaps.MainApp; import info.nightscout.androidaps.R; +import info.nightscout.androidaps.data.QuickWizard; import info.nightscout.androidaps.plugins.Overview.Dialogs.EditQuickWizardDialog; import info.nightscout.androidaps.plugins.Overview.OverviewPlugin; -import info.nightscout.androidaps.plugins.Overview.QuickWizard; import info.nightscout.androidaps.plugins.Overview.events.EventQuickWizardChange; import info.nightscout.utils.DateUtil; import info.nightscout.utils.DecimalFormatter; @@ -153,6 +151,7 @@ public class QuickWizardListActivity extends AppCompatActivity implements View.O break; } } + @Subscribe public void onStatusEvent(final EventQuickWizardChange ev) { updateGUI(); diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/Overview/graphData/GraphData.java b/app/src/main/java/info/nightscout/androidaps/plugins/Overview/graphData/GraphData.java index 8bead45e85..99f53ad2ef 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/Overview/graphData/GraphData.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/Overview/graphData/GraphData.java @@ -27,7 +27,7 @@ import info.nightscout.androidaps.db.Treatment; import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin; import info.nightscout.androidaps.plugins.IobCobCalculator.AutosensData; import info.nightscout.androidaps.plugins.IobCobCalculator.IobCobCalculatorPlugin; -import info.nightscout.androidaps.plugins.IobCobCalculator.events.BasalData; +import info.nightscout.androidaps.plugins.IobCobCalculator.BasalData; import info.nightscout.androidaps.plugins.OpenAPSAMA.DetermineBasalResultAMA; import info.nightscout.androidaps.plugins.Overview.graphExtensions.AreaGraphSeries; import info.nightscout.androidaps.plugins.Overview.graphExtensions.DataPointWithLabelInterface; diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/Overview/notifications/Notification.java b/app/src/main/java/info/nightscout/androidaps/plugins/Overview/notifications/Notification.java index d575c02142..d8506ad963 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/Overview/notifications/Notification.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/Overview/notifications/Notification.java @@ -57,6 +57,7 @@ public class Notification { public static final int PUMP_UNREACHABLE = 26; public static final int BG_READINGS_MISSED = 27; public static final int UNSUPPORTED_FIRMWARE = 28; + public static final int MINIMAL_BASAL_VALUE_REPLACED = 29; public int id; public Date date; diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/ProfileLocal/LocalProfileFragment.java b/app/src/main/java/info/nightscout/androidaps/plugins/ProfileLocal/LocalProfileFragment.java index 8637b863fb..ebd31e915f 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/ProfileLocal/LocalProfileFragment.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/ProfileLocal/LocalProfileFragment.java @@ -23,6 +23,7 @@ import java.text.DecimalFormat; import info.nightscout.androidaps.MainApp; import info.nightscout.androidaps.R; import info.nightscout.androidaps.events.EventInitializationChanged; +import info.nightscout.androidaps.interfaces.PumpDescription; import info.nightscout.androidaps.plugins.Careportal.CareportalFragment; import info.nightscout.androidaps.plugins.Careportal.Dialogs.NewNSTreatmentDialog; import info.nightscout.androidaps.plugins.Careportal.OptionsToShow; @@ -84,15 +85,17 @@ public class LocalProfileFragment extends SubscriberFragment { } }; + PumpDescription pumpDescription = ConfigBuilderPlugin.getActivePump().getPumpDescription(); + View layout = inflater.inflate(R.layout.localprofile_fragment, container, false); diaView = (NumberPicker) layout.findViewById(R.id.localprofile_dia); diaView.setParams(localProfilePlugin.dia, 2d, 48d, 0.1d, new DecimalFormat("0.0"), false, textWatch); mgdlView = (RadioButton) layout.findViewById(R.id.localprofile_mgdl); mmolView = (RadioButton) layout.findViewById(R.id.localprofile_mmol); - icView = new TimeListEdit(getContext(), layout, R.id.localprofile_ic, MainApp.sResources.getString(R.string.nsprofileview_ic_label) + ":", getPlugin().ic, null, 0.1d, new DecimalFormat("0.0"), save); - isfView = new TimeListEdit(getContext(), layout, R.id.localprofile_isf, MainApp.sResources.getString(R.string.nsprofileview_isf_label) + ":", getPlugin().isf, null, 0.1d, new DecimalFormat("0.0"), save); - basalView = new TimeListEdit(getContext(), layout, R.id.localprofile_basal, MainApp.sResources.getString(R.string.nsprofileview_basal_label) + ": " + getSumLabel(), getPlugin().basal, null, 0.01d, new DecimalFormat("0.00"), save); - targetView = new TimeListEdit(getContext(), layout, R.id.localprofile_target, MainApp.sResources.getString(R.string.nsprofileview_target_label) + ":", getPlugin().targetLow, getPlugin().targetHigh, 0.1d, new DecimalFormat("0.0"), save); + icView = new TimeListEdit(getContext(), layout, R.id.localprofile_ic, MainApp.sResources.getString(R.string.nsprofileview_ic_label) + ":", getPlugin().ic, null, 0.5, 50d, 0.1d, new DecimalFormat("0.0"), save); + isfView = new TimeListEdit(getContext(), layout, R.id.localprofile_isf, MainApp.sResources.getString(R.string.nsprofileview_isf_label) + ":", getPlugin().isf, null, 0.5, 500d, 0.1d, new DecimalFormat("0.0"), save); + basalView = new TimeListEdit(getContext(), layout, R.id.localprofile_basal, MainApp.sResources.getString(R.string.nsprofileview_basal_label) + ": " + getSumLabel(), getPlugin().basal, null, pumpDescription.basalMinimumRate, 10, 0.01d, new DecimalFormat("0.00"), save); + targetView = new TimeListEdit(getContext(), layout, R.id.localprofile_target, MainApp.sResources.getString(R.string.nsprofileview_target_label) + ":", getPlugin().targetLow, getPlugin().targetHigh, 3d, 200, 0.1d, new DecimalFormat("0.0"), save); profileswitchButton = (Button) layout.findViewById(R.id.localprofile_profileswitch); if (!ConfigBuilderPlugin.getActivePump().getPumpDescription().isTempBasalCapable) { diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/PumpCombo/ComboFragment.java b/app/src/main/java/info/nightscout/androidaps/plugins/PumpCombo/ComboFragment.java index 4613caf208..506bce7be5 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/PumpCombo/ComboFragment.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/PumpCombo/ComboFragment.java @@ -4,6 +4,7 @@ package info.nightscout.androidaps.plugins.PumpCombo; import android.app.Activity; import android.app.AlertDialog; import android.graphics.Color; +import android.graphics.Typeface; import android.os.Bundle; import android.text.Spanned; import android.view.LayoutInflater; @@ -137,11 +138,14 @@ public class ComboFragment extends SubscriberFragment implements View.OnClickLis if (ps.insulinState == PumpState.EMPTY || ps.batteryState == PumpState.EMPTY || ps.activeAlert != null && ps.activeAlert.errorCode != null) { stateView.setTextColor(Color.RED); + stateView.setTypeface(null, Typeface.BOLD); } else if (plugin.getPump().state.suspended || ps.activeAlert != null && ps.activeAlert.warningCode != null) { stateView.setTextColor(Color.YELLOW); + stateView.setTypeface(null, Typeface.BOLD); } else { stateView.setTextColor(Color.WHITE); + stateView.setTypeface(null, Typeface.NORMAL); } // activity @@ -171,12 +175,15 @@ public class ComboFragment extends SubscriberFragment implements View.OnClickLis if (ps.insulinState == PumpState.LOW) { reservoirView.setTextColor(Color.YELLOW); reservoirView.setText(R.string.combo_reservoir_low); + reservoirView.setTypeface(null, Typeface.BOLD); } else if (ps.insulinState == PumpState.EMPTY) { reservoirView.setTextColor(Color.RED); reservoirView.setText(R.string.combo_reservoir_empty); + reservoirView.setTypeface(null, Typeface.BOLD); } else { reservoirView.setTextColor(Color.WHITE); reservoirView.setText(R.string.combo_reservoir_normal); + reservoirView.setTypeface(null, Typeface.NORMAL); } // last connection @@ -186,7 +193,7 @@ public class ComboFragment extends SubscriberFragment implements View.OnClickLis lastConnectionView.setText(R.string.combo_pump_connected_now); lastConnectionView.setTextColor(Color.WHITE); } else if (plugin.getPump().lastSuccessfulCmdTime + 30 * 60 * 1000 < System.currentTimeMillis()) { - lastConnectionView.setText(getString(R.string.combo_no_pump_connection, min)); + lastConnectionView.setText(MainApp.sResources.getString(R.string.combo_no_pump_connection, min)); lastConnectionView.setTextColor(Color.RED); } else { lastConnectionView.setText(minAgo); @@ -199,7 +206,7 @@ public class ComboFragment extends SubscriberFragment implements View.OnClickLis long minSinceRead = (System.currentTimeMillis() - plugin.getPump().state.timestamp) / 1000 / 60; long remaining = ps.tbrRemainingDuration - minSinceRead; if (remaining >= 0) { - tbrStr = getString(R.string.combo_tbr_remaining, ps.tbrPercent, remaining); + tbrStr = MainApp.sResources.getString(R.string.combo_tbr_remaining, ps.tbrPercent, remaining); } } tempBasalText.setText(tbrStr); diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/PumpCombo/ComboPlugin.java b/app/src/main/java/info/nightscout/androidaps/plugins/PumpCombo/ComboPlugin.java index 3df159b876..bc27a3ebbc 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/PumpCombo/ComboPlugin.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/PumpCombo/ComboPlugin.java @@ -41,6 +41,7 @@ import info.nightscout.androidaps.interfaces.ConstraintsInterface; import info.nightscout.androidaps.interfaces.PluginBase; import info.nightscout.androidaps.interfaces.PumpDescription; import info.nightscout.androidaps.interfaces.PumpInterface; +import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin; import info.nightscout.androidaps.plugins.Overview.events.EventDismissNotification; import info.nightscout.androidaps.plugins.Overview.events.EventNewNotification; import info.nightscout.androidaps.plugins.Overview.events.EventOverviewBolusProgress; @@ -82,7 +83,7 @@ public class ComboPlugin implements PluginBase, PumpInterface, ConstraintsInterf pumpDescription.isSetBasalProfileCapable = true; pumpDescription.basalStep = 0.01d; - pumpDescription.basalMinimumRate = 0.0d; + pumpDescription.basalMinimumRate = 0.05d; pumpDescription.isRefillingCapable = true; } @@ -138,7 +139,9 @@ public class ComboPlugin implements PluginBase, PumpInterface, ConstraintsInterf String getStateSummary() { PumpState ps = pump.state; - if (ps.activeAlert != null) { + if (!validBasalRateProfileSelectedOnPump) { + return MainApp.sResources.getString(R.string.loopdisabled); + } else if (ps.activeAlert != null) { return ps.activeAlert.errorCode != null ? "E" + ps.activeAlert.errorCode + ": " + ps.activeAlert.message : "W" + ps.activeAlert.warningCode + ": " + ps.activeAlert.message; @@ -175,7 +178,7 @@ public class ComboPlugin implements PluginBase, PumpInterface, ConstraintsInterf @Override public boolean showInList(int type) { - return true; + return type == PUMP; } @Override @@ -190,7 +193,7 @@ public class ComboPlugin implements PluginBase, PumpInterface, ConstraintsInterf @Override public int getPreferencesId() { - return R.xml.pref_combo; + return -1; } @Override @@ -258,12 +261,17 @@ public class ComboPlugin implements PluginBase, PumpInterface, ConstraintsInterf return new PumpEnactResult().success(true).enacted(false); } + CommandResult stateResult = runCommand(null, 1, ruffyScripter::readPumpState); + if (stateResult.state.unsafeUsageDetected == PumpState.UNSUPPORTED_BASAL_RATE_PROFILE) { + return new PumpEnactResult().success(false).enacted(false).comment(MainApp.sResources.getString(R.string.combo_force_disabled_notification)); + } + CommandResult setResult = runCommand(MainApp.sResources.getString(R.string.combo_activity_setting_basal_profile), 2, () -> ruffyScripter.setBasalProfile(requestedBasalProfile)); if (!setResult.success) { Notification notification = new Notification(Notification.FAILED_UDPATE_PROFILE, MainApp.sResources.getString(R.string.failedupdatebasalprofile), Notification.URGENT); MainApp.bus().post(new EventNewNotification(notification)); - return new PumpEnactResult().success(false).enacted(false); + return new PumpEnactResult().success(false).enacted(false).comment(MainApp.sResources.getString(R.string.failedupdatebasalprofile)); } /* don't re-read basal profile to not trigger pump bug; setBasalProfile command checks the total at the end, which must suffice @@ -324,48 +332,54 @@ public class ComboPlugin implements PluginBase, PumpInterface, ConstraintsInterf return new Date(pump.lastSuccessfulCmdTime); } - /** - * Runs pump initializing if needed, checks for boluses given on the pump, updates the - * reservoir level and checks the running TBR on the pump. - */ + /** Runs pump initializing if needed and reads the pump state from the main screen. */ @Override public synchronized void getPumpStatus() { log.debug("getPumpStatus called"); if (!pump.initialized) { - long maxWait = System.currentTimeMillis() + 15 * 1000; - while (!ruffyScripter.isPumpAvailable()) { - log.debug("Waiting for ruffy service to come up ..."); - SystemClock.sleep(100); - if (System.currentTimeMillis() > maxWait) { - log.debug("ruffy service unavailable, wtf"); - return; - } + initializePump(); + } else { + runCommand(MainApp.sResources.getString(R.string.combo_pump_action_refreshing), 1, ruffyScripter::readPumpState); + } + } + + private synchronized void initializePump() { + long maxWait = System.currentTimeMillis() + 15 * 1000; + while (!ruffyScripter.isPumpAvailable()) { + log.debug("Waiting for ruffy service to come up ..."); + SystemClock.sleep(100); + if (System.currentTimeMillis() > maxWait) { + log.debug("ruffy service unavailable, wtf"); + return; } } - CommandResult stateResult = runCommand(pump.initialized ? MainApp.sResources.getString(R.string.combo_pump_action_refreshing) : MainApp.sResources.getString(R.string.combo_pump_action_initializing), - 1, ruffyScripter::readPumpState); + CommandResult stateResult = runCommand(MainApp.sResources.getString(R.string.combo_pump_action_initializing),1, ruffyScripter::readPumpState); if (!stateResult.success) { return; } - // read basal profile into cache and update pump profile if needed - if (!pump.initialized) { - CommandResult readBasalResult = runCommand("Reading basal profile", 2, ruffyScripter::readBasalProfile); - if (!readBasalResult.success) { - return; - } - pump.basalProfile = readBasalResult.basalProfile; + if (stateResult.state.unsafeUsageDetected == PumpState.UNSUPPORTED_BASAL_RATE_PROFILE) { + Notification n = new Notification(Notification.COMBO_PUMP_ALARM, + MainApp.sResources.getString(R.string.combo_force_disabled_notification), + Notification.URGENT); + n.soundId = R.raw.alarm; + MainApp.bus().post(new EventNewNotification(n)); + return; } - if (!pump.initialized) { - pump.initialized = true; - MainApp.bus().post(new EventInitializationChanged()); + // read basal profile into cache (KeepAlive will trigger a profile update if needed) + CommandResult readBasalResult = runCommand("Reading basal profile", 2, ruffyScripter::readBasalProfile); + if (!readBasalResult.success) { + return; } + pump.basalProfile = readBasalResult.basalProfile; + validBasalRateProfileSelectedOnPump = true; + pump.initialized = true; + MainApp.bus().post(new EventInitializationChanged()); - // ComboFragment updates state fully only after the pump has initialized, - // this fetches state again and updates the UI proper - runCommand(null, 0, ruffyScripter::readPumpState); + // ComboFragment updates state fully only after the pump has initialized, so run this manually here + updateLocalData(readBasalResult); } private void updateLocalData(CommandResult result) { @@ -453,7 +467,12 @@ public class ComboPlugin implements PluginBase, PumpInterface, ConstraintsInterf } lastRequestedBolus = new Bolus(System.currentTimeMillis(), detailedBolusInfo.insulin, true); - long pumpTimeWhenBolusWasRequested = runCommand(null, 1, ruffyScripter::readPumpState).state.pumpTime; + CommandResult stateResult = runCommand(null, 1, ruffyScripter::readPumpState); + long pumpTimeWhenBolusWasRequested = stateResult .state.pumpTime; + if (!stateResult.success || pumpTimeWhenBolusWasRequested == 0) { + return new PumpEnactResult().success(false).enacted(false) + .comment(MainApp.sResources.getString(R.string.combo_error_no_bolus_delivered)); + } try { pump.activity = MainApp.sResources.getString(R.string.combo_pump_action_bolusing, detailedBolusInfo.insulin); @@ -463,7 +482,7 @@ public class ComboPlugin implements PluginBase, PumpInterface, ConstraintsInterf return new PumpEnactResult().success(true).enacted(false); } - BolusProgressReporter progressReporter = detailedBolusInfo.isSMB ? nullBolusProgressReporter : ComboPlugin.bolusProgressReporter; + BolusProgressReporter progressReporter = detailedBolusInfo.isSMB ? nullBolusProgressReporter : bolusProgressReporter; // start bolus delivery bolusInProgress = true; @@ -525,6 +544,7 @@ public class ComboPlugin implements PluginBase, PumpInterface, ConstraintsInterf if (lastBolus == null // no bolus ever given || lastBolus.timestamp < pumpTimeWhenBolusWasRequested // this is not the bolus you're looking for + || lastBolus.amount - detailedBolusInfo.insulin > 0.01 // this one neither, big than requested bolus || !lastBolus.isValid) { // ext/multiwave bolus log.debug("No bolus was delivered"); return new PumpEnactResult().success(false).enacted(false) @@ -535,21 +555,21 @@ public class ComboPlugin implements PluginBase, PumpInterface, ConstraintsInterf detailedBolusInfo.insulin = lastBolus.amount; detailedBolusInfo.source = Source.USER; MainApp.getConfigBuilder().addToHistoryTreatment(detailedBolusInfo); - log.debug(String.format(Locale.getDefault(), "Added partial bolus of %.2f to treatments (requested: %.2f", lastBolus.amount, requestedBolus)); + log.debug(String.format(Locale.getDefault(), "Added partial bolus of %.2f to treatments (requested: %.2f)", lastBolus.amount, requestedBolus)); return new PumpEnactResult().success(false).enacted(true) .comment(MainApp.sResources.getString(R.string.combo_error_partial_bolus_delivered, lastBolus.amount, requestedBolus)); + } else { + // bolus was correctly and fully delivered + detailedBolusInfo.insulin = lastBolus.amount; + detailedBolusInfo.source = Source.USER; + MainApp.getConfigBuilder().addToHistoryTreatment(detailedBolusInfo); + log.debug("Added correctly delivered bolus to treatments"); + return new PumpEnactResult().success(true).enacted(true) + .bolusDelivered(lastBolus.amount) + .carbsDelivered(detailedBolusInfo.carbs); } - - // bolus was correctly and fully delivered - detailedBolusInfo.insulin = lastBolus.amount; - detailedBolusInfo.source = Source.USER; - MainApp.getConfigBuilder().addToHistoryTreatment(detailedBolusInfo); - log.debug("Added correctly delivered bolus to treatments"); - return new PumpEnactResult().success(true).enacted(true) - .bolusDelivered(lastBolus.amount) - .carbsDelivered(detailedBolusInfo.carbs); } @Override @@ -577,9 +597,18 @@ public class ComboPlugin implements PluginBase, PumpInterface, ConstraintsInterf return setTempBasalPercent(roundedPercentage, durationInMinutes); } - // Note: AAPS calls this directly only for setting a temp basal issued by the user + /** + * Note: AAPS calls this directly only for setting a temp basal issued by the user + * + * @param forceNew Driver always applies the requested TBR and simply overrides whatever TBR + * is or isn't running at the moment + */ @Override - public PumpEnactResult setTempBasalPercent(Integer percent, final Integer durationInMinutes) { + public PumpEnactResult setTempBasalPercent(Integer percent, final Integer durationInMinutes, boolean forceNew) { + return setTempBasalPercent(percent, durationInMinutes); + } + + private PumpEnactResult setTempBasalPercent(Integer percent, final Integer durationInMinutes) { log.debug("setTempBasalPercent called with " + percent + "% for " + durationInMinutes + "min"); int adjustedPercent = percent; @@ -707,9 +736,15 @@ public class ComboPlugin implements PluginBase, PumpInterface, ConstraintsInterf if (commandResult.success) { pump.lastSuccessfulCmdTime = System.currentTimeMillis(); - } - - if (commandResult.success) { + if (validBasalRateProfileSelectedOnPump && commandResult.state.unsafeUsageDetected == PumpState.UNSUPPORTED_BASAL_RATE_PROFILE) { + validBasalRateProfileSelectedOnPump = false; + Notification n = new Notification(Notification.COMBO_PUMP_ALARM, + MainApp.sResources.getString(R.string.combo_force_disabled_notification), + Notification.URGENT); + n.soundId = R.raw.alarm; + MainApp.bus().post(new EventNewNotification(n)); + ConfigBuilderPlugin.getCommandQueue().cancelTempBasal(true, null); + } updateLocalData(commandResult); } } finally { @@ -751,7 +786,7 @@ public class ComboPlugin implements PluginBase, PumpInterface, ConstraintsInterf notification.date = new Date(); notification.id = Notification.COMBO_PUMP_ALARM; notification.level = Notification.URGENT; - notification.text = MainApp.sResources.getString(R.string.combo_is_in_error_state); + notification.text = MainApp.sResources.getString(R.string.combo_is_in_error_state, activeAlert.errorCode, activeAlert.message); MainApp.bus().post(new EventNewNotification(notification)); return preCheckResult.success(false); } @@ -769,9 +804,11 @@ public class ComboPlugin implements PluginBase, PumpInterface, ConstraintsInterf if (state.pumpTime == 0) { // time couldn't be read (e.g. a warning is displayed on the menu , hiding the time field) } else if (Math.abs(state.pumpTime - System.currentTimeMillis()) >= 10 * 60 * 1000) { + log.debug("Pump clock needs update, pump time: " + state.pumpTime + " (" + new Date(state.pumpTime) + ")"); Notification notification = new Notification(Notification.COMBO_PUMP_ALARM, MainApp.sResources.getString(R.string.combo_notification_check_time_date), Notification.URGENT); MainApp.bus().post(new EventNewNotification(notification)); } else if (Math.abs(state.pumpTime - System.currentTimeMillis()) >= 3 * 60 * 1000) { + log.debug("Pump clock needs update, pump time: " + state.pumpTime + " (" + new Date(state.pumpTime) + ")"); Notification notification = new Notification(Notification.COMBO_PUMP_ALARM, MainApp.sResources.getString(R.string.combo_notification_check_time_date), Notification.NORMAL); MainApp.bus().post(new EventNewNotification(notification)); } @@ -802,7 +839,7 @@ public class ComboPlugin implements PluginBase, PumpInterface, ConstraintsInterf if (commandResult == null) return; long lastViolation = 0; - if (commandResult.state.unsafeUsageDetected) { + if (commandResult.state.unsafeUsageDetected == PumpState.UNSUPPORTED_BOLUS_TYPE) { lastViolation = System.currentTimeMillis(); } else if (commandResult.lastBolus != null && !commandResult.lastBolus.isValid) { lastViolation = commandResult.lastBolus.timestamp; @@ -814,14 +851,15 @@ public class ComboPlugin implements PluginBase, PumpInterface, ConstraintsInterf } } if (lastViolation > 0) { - lowSuspendOnlyLoopEnforcetTill = lastViolation + 6 * 60 * 60 * 1000; - if (lowSuspendOnlyLoopEnforcetTill > System.currentTimeMillis() && violationWarningRaisedFor != lowSuspendOnlyLoopEnforcetTill) { + lowSuspendOnlyLoopEnforcedUntil = lastViolation + 6 * 60 * 60 * 1000; + if (lowSuspendOnlyLoopEnforcedUntil > System.currentTimeMillis() && violationWarningRaisedForBolusAt != lowSuspendOnlyLoopEnforcedUntil) { Notification n = new Notification(Notification.COMBO_PUMP_ALARM, - MainApp.sResources.getString(R.string.combo_force_disabled_notification), + MainApp.sResources.getString(R.string.combo_low_suspend_forced_notification), Notification.URGENT); n.soundId = R.raw.alarm; MainApp.bus().post(new EventNewNotification(n)); - violationWarningRaisedFor = lowSuspendOnlyLoopEnforcetTill; + violationWarningRaisedForBolusAt = lowSuspendOnlyLoopEnforcedUntil; + ConfigBuilderPlugin.getCommandQueue().cancelTempBasal(true, null); } } } @@ -1049,12 +1087,13 @@ public class ComboPlugin implements PluginBase, PumpInterface, ConstraintsInterf } // Constraints interface - private long lowSuspendOnlyLoopEnforcetTill = 0; - private long violationWarningRaisedFor = 0; + private long lowSuspendOnlyLoopEnforcedUntil = 0; + private long violationWarningRaisedForBolusAt = 0; + private boolean validBasalRateProfileSelectedOnPump = true; @Override public boolean isLoopEnabled() { - return true; + return validBasalRateProfileSelectedOnPump; } @Override @@ -1072,6 +1111,11 @@ public class ComboPlugin implements PluginBase, PumpInterface, ConstraintsInterf return true; } + @Override + public boolean isSMBModeEnabled() { + return true; + } + @Override public Double applyBasalConstraints(Double absoluteRate) { return absoluteRate; @@ -1094,6 +1138,6 @@ public class ComboPlugin implements PluginBase, PumpInterface, ConstraintsInterf @Override public Double applyMaxIOBConstraints(Double maxIob) { - return lowSuspendOnlyLoopEnforcetTill < System.currentTimeMillis() ? maxIob : 0; + return lowSuspendOnlyLoopEnforcedUntil < System.currentTimeMillis() ? maxIob : 0; } } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaR/DanaRPlugin.java b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaR/DanaRPlugin.java index 167c430a6e..4ba660db66 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaR/DanaRPlugin.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaR/DanaRPlugin.java @@ -434,7 +434,7 @@ public class DanaRPlugin implements PluginBase, PumpInterface, DanaRInterface, C // Convert duration from minutes to hours if (Config.logPumpActions) log.debug("setTempBasalAbsolute: Setting temp basal " + percentRate + "% for " + durationInMinutes + " mins (doLowTemp || doHighTemp)"); - return setTempBasalPercent(percentRate, durationInMinutes); + return setTempBasalPercent(percentRate, durationInMinutes, false); } if (doExtendedTemp) { // Check if some temp is already in progress @@ -499,7 +499,7 @@ public class DanaRPlugin implements PluginBase, PumpInterface, DanaRInterface, C } @Override - public PumpEnactResult setTempBasalPercent(Integer percent, Integer durationInMinutes) { + public PumpEnactResult setTempBasalPercent(Integer percent, Integer durationInMinutes, boolean enforceNew) { PumpEnactResult result = new PumpEnactResult(); ConfigBuilderPlugin configBuilderPlugin = MainApp.getConfigBuilder(); percent = configBuilderPlugin.applyBasalConstraints(percent); @@ -514,7 +514,7 @@ public class DanaRPlugin implements PluginBase, PumpInterface, DanaRInterface, C if (percent > getPumpDescription().maxTempPercent) percent = getPumpDescription().maxTempPercent; TemporaryBasal runningTB = MainApp.getConfigBuilder().getRealTempBasalFromHistory(System.currentTimeMillis()); - if (runningTB != null && runningTB.percentRate == percent) { + if (runningTB != null && runningTB.percentRate == percent && !enforceNew) { result.enacted = false; result.success = true; result.isTempCancel = false; @@ -785,6 +785,11 @@ public class DanaRPlugin implements PluginBase, PumpInterface, DanaRInterface, C return true; } + @Override + public boolean isSMBModeEnabled() { + return true; + } + @SuppressWarnings("PointlessBooleanExpression") @Override public Double applyBasalConstraints(Double absoluteRate) { diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRKorean/DanaRKoreanPlugin.java b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRKorean/DanaRKoreanPlugin.java index 32c9f209ef..f269aff112 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRKorean/DanaRKoreanPlugin.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRKorean/DanaRKoreanPlugin.java @@ -436,7 +436,7 @@ public class DanaRKoreanPlugin implements PluginBase, PumpInterface, DanaRInterf // Convert duration from minutes to hours if (Config.logPumpActions) log.debug("setTempBasalAbsolute: Setting temp basal " + percentRate + "% for " + durationInMinutes + " mins (doLowTemp || doHighTemp)"); - return setTempBasalPercent(percentRate, durationInMinutes); + return setTempBasalPercent(percentRate, durationInMinutes, false); } if (doExtendedTemp) { // Check if some temp is already in progress @@ -501,7 +501,7 @@ public class DanaRKoreanPlugin implements PluginBase, PumpInterface, DanaRInterf } @Override - public PumpEnactResult setTempBasalPercent(Integer percent, Integer durationInMinutes) { + public PumpEnactResult setTempBasalPercent(Integer percent, Integer durationInMinutes, boolean enforceNew) { PumpEnactResult result = new PumpEnactResult(); ConfigBuilderPlugin configBuilderPlugin = MainApp.getConfigBuilder(); percent = configBuilderPlugin.applyBasalConstraints(percent); @@ -516,7 +516,7 @@ public class DanaRKoreanPlugin implements PluginBase, PumpInterface, DanaRInterf if (percent > getPumpDescription().maxTempPercent) percent = getPumpDescription().maxTempPercent; TemporaryBasal runningTB = MainApp.getConfigBuilder().getRealTempBasalFromHistory(System.currentTimeMillis()); - if (runningTB != null && runningTB.percentRate == percent) { + if (runningTB != null && runningTB.percentRate == percent && enforceNew) { result.enacted = false; result.success = true; result.isTempCancel = false; @@ -787,6 +787,11 @@ public class DanaRKoreanPlugin implements PluginBase, PumpInterface, DanaRInterf return true; } + @Override + public boolean isSMBModeEnabled() { + return true; + } + @SuppressWarnings("PointlessBooleanExpression") @Override public Double applyBasalConstraints(Double absoluteRate) { diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/DanaRSPlugin.java b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/DanaRSPlugin.java index 87d8ccad5d..dceb7e66bc 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/DanaRSPlugin.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/DanaRSPlugin.java @@ -289,6 +289,11 @@ public class DanaRSPlugin implements PluginBase, PumpInterface, DanaRInterface, return true; } + @Override + public boolean isSMBModeEnabled() { + return true; + } + @Override public Double applyBasalConstraints(Double absoluteRate) { double origAbsoluteRate = absoluteRate; @@ -580,7 +585,7 @@ public class DanaRSPlugin implements PluginBase, PumpInterface, DanaRInterface, } @Override - public synchronized PumpEnactResult setTempBasalPercent(Integer percent, Integer durationInMinutes) { + public synchronized PumpEnactResult setTempBasalPercent(Integer percent, Integer durationInMinutes, boolean enforceNew) { PumpEnactResult result = new PumpEnactResult(); ConfigBuilderPlugin configBuilderPlugin = MainApp.getConfigBuilder(); percent = configBuilderPlugin.applyBasalConstraints(percent); @@ -595,7 +600,7 @@ public class DanaRSPlugin implements PluginBase, PumpInterface, DanaRInterface, if (percent > getPumpDescription().maxTempPercent) percent = getPumpDescription().maxTempPercent; TemporaryBasal runningTB = MainApp.getConfigBuilder().getTempBasalFromHistory(System.currentTimeMillis()); - if (runningTB != null && runningTB.percentRate == percent) { + if (runningTB != null && runningTB.percentRate == percent && !enforceNew) { result.enacted = false; result.success = true; result.isTempCancel = false; diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/activities/BLEScanActivity.java b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/activities/BLEScanActivity.java index 2a113b3c8d..319a64f713 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/activities/BLEScanActivity.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/activities/BLEScanActivity.java @@ -162,6 +162,7 @@ public class BLEScanActivity extends AppCompatActivity { public void onClick(View v) { SP.putString(R.string.key_danars_address, item.device.getAddress()); SP.putString(R.string.key_danars_name, mName.getText().toString()); + item.device.createBond(); MainApp.bus().post(new EventDanaRSDeviceChange()); finish(); } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/activities/PairingProgressDialog.java b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/activities/PairingProgressDialog.java index 00cbdb4628..a663d14245 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/activities/PairingProgressDialog.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/activities/PairingProgressDialog.java @@ -118,7 +118,7 @@ public class PairingProgressDialog extends DialogFragment implements View.OnClic @Override public void dismiss() { - super.dismiss(); + super.dismissAllowingStateLoss(); if (helperActivity != null) { helperActivity.finish(); } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/events/EventDanaRSDeviceChange.java b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/events/EventDanaRSDeviceChange.java index 8ae02d47ff..dd9b86ebce 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/events/EventDanaRSDeviceChange.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/events/EventDanaRSDeviceChange.java @@ -1,8 +1,10 @@ package info.nightscout.androidaps.plugins.PumpDanaRS.events; +import info.nightscout.androidaps.events.Event; + /** * Created by mike on 05.09.2017. */ -public class EventDanaRSDeviceChange { +public class EventDanaRSDeviceChange extends Event { } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/events/EventDanaRSPacket.java b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/events/EventDanaRSPacket.java index 5815399194..e42b6b1440 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/events/EventDanaRSPacket.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/events/EventDanaRSPacket.java @@ -1,12 +1,13 @@ package info.nightscout.androidaps.plugins.PumpDanaRS.events; +import info.nightscout.androidaps.events.Event; import info.nightscout.androidaps.plugins.PumpDanaRS.comm.DanaRS_Packet; /** * Created by mike on 01.09.2017. */ -public class EventDanaRSPacket { +public class EventDanaRSPacket extends Event{ public EventDanaRSPacket(DanaRS_Packet data) { this.data = data; } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/events/EventDanaRSPairingSuccess.java b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/events/EventDanaRSPairingSuccess.java index d50091de55..433cdec9bf 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/events/EventDanaRSPairingSuccess.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/events/EventDanaRSPairingSuccess.java @@ -1,8 +1,10 @@ package info.nightscout.androidaps.plugins.PumpDanaRS.events; +import info.nightscout.androidaps.events.Event; + /** * Created by mike on 01.09.2017. */ -public class EventDanaRSPairingSuccess { +public class EventDanaRSPairingSuccess extends Event{ } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/services/DanaRSService.java b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/services/DanaRSService.java index a30e237672..bd6f5ca690 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/services/DanaRSService.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/services/DanaRSService.java @@ -185,7 +185,10 @@ public class DanaRSService extends Service { while (!msg.done && bleComm.isConnected()) { SystemClock.sleep(100); } - lastHistoryFetched = DanaRS_Packet_APS_History_Events.lastEventTimeLoaded - 45 * 60 * 1000L; // always load last 45 min + if (DanaRS_Packet_APS_History_Events.lastEventTimeLoaded != 0) + lastHistoryFetched = DanaRS_Packet_APS_History_Events.lastEventTimeLoaded - 45 * 60 * 1000L; // always load last 45 min + else + lastHistoryFetched = 0; log.debug("Events loaded"); return new PumpEnactResult().success(true); } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRv2/DanaRv2Plugin.java b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRv2/DanaRv2Plugin.java index 0c3ac39860..deb1594c28 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRv2/DanaRv2Plugin.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRv2/DanaRv2Plugin.java @@ -437,7 +437,7 @@ public class DanaRv2Plugin implements PluginBase, PumpInterface, DanaRInterface, } @Override - public PumpEnactResult setTempBasalPercent(Integer percent, Integer durationInMinutes) { + public PumpEnactResult setTempBasalPercent(Integer percent, Integer durationInMinutes, boolean enforceNew) { PumpEnactResult result = new PumpEnactResult(); ConfigBuilderPlugin configBuilderPlugin = MainApp.getConfigBuilder(); percent = configBuilderPlugin.applyBasalConstraints(percent); @@ -452,7 +452,7 @@ public class DanaRv2Plugin implements PluginBase, PumpInterface, DanaRInterface, if (percent > getPumpDescription().maxTempPercent) percent = getPumpDescription().maxTempPercent; TemporaryBasal runningTB = MainApp.getConfigBuilder().getRealTempBasalFromHistory(System.currentTimeMillis()); - if (runningTB != null && runningTB.percentRate == percent) { + if (runningTB != null && runningTB.percentRate == percent && !enforceNew) { result.enacted = false; result.success = true; result.isTempCancel = false; @@ -730,6 +730,11 @@ public class DanaRv2Plugin implements PluginBase, PumpInterface, DanaRInterface, return true; } + @Override + public boolean isSMBModeEnabled() { + return true; + } + @SuppressWarnings("PointlessBooleanExpression") @Override public Double applyBasalConstraints(Double absoluteRate) { diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRv2/services/DanaRv2ExecutionService.java b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRv2/services/DanaRv2ExecutionService.java index 4e5b85177a..6d6ba34838 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRv2/services/DanaRv2ExecutionService.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRv2/services/DanaRv2ExecutionService.java @@ -527,7 +527,10 @@ public class DanaRv2ExecutionService extends Service { waitMsec(100); } waitMsec(200); - lastHistoryFetched = MsgHistoryEvents_v2.lastEventTimeLoaded - 45 * 60 * 1000L; //always load last 45 min; + if (MsgHistoryEvents_v2.lastEventTimeLoaded != 0) + lastHistoryFetched = MsgHistoryEvents_v2.lastEventTimeLoaded - 45 * 60 * 1000L; //always load last 45 min; + else + lastHistoryFetched = 0; return new PumpEnactResult().success(true); } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/PumpMDI/MDIPlugin.java b/app/src/main/java/info/nightscout/androidaps/plugins/PumpMDI/MDIPlugin.java index fd5d2bd270..564d29d53b 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/PumpMDI/MDIPlugin.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/PumpMDI/MDIPlugin.java @@ -204,7 +204,7 @@ public class MDIPlugin implements PluginBase, PumpInterface { } @Override - public PumpEnactResult setTempBasalPercent(Integer percent, Integer durationInMinutes) { + public PumpEnactResult setTempBasalPercent(Integer percent, Integer durationInMinutes, boolean enforceNew) { PumpEnactResult result = new PumpEnactResult(); result.success = false; result.comment = MainApp.instance().getString(R.string.pumperror); diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/PumpVirtual/VirtualPumpPlugin.java b/app/src/main/java/info/nightscout/androidaps/plugins/PumpVirtual/VirtualPumpPlugin.java index c278f7fb16..c543fe39bd 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/PumpVirtual/VirtualPumpPlugin.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/PumpVirtual/VirtualPumpPlugin.java @@ -1,8 +1,6 @@ package info.nightscout.androidaps.plugins.PumpVirtual; -import android.content.SharedPreferences; import android.os.SystemClock; -import android.preference.PreferenceManager; import org.json.JSONException; import org.json.JSONObject; @@ -16,6 +14,7 @@ import info.nightscout.androidaps.Config; import info.nightscout.androidaps.MainApp; import info.nightscout.androidaps.R; import info.nightscout.androidaps.data.DetailedBolusInfo; +import info.nightscout.androidaps.data.Profile; import info.nightscout.androidaps.data.PumpEnactResult; import info.nightscout.androidaps.db.ExtendedBolus; import info.nightscout.androidaps.db.Source; @@ -24,7 +23,6 @@ import info.nightscout.androidaps.interfaces.PluginBase; import info.nightscout.androidaps.interfaces.PumpDescription; import info.nightscout.androidaps.interfaces.PumpInterface; import info.nightscout.androidaps.interfaces.TreatmentsInterface; -import info.nightscout.androidaps.data.Profile; import info.nightscout.androidaps.plugins.Overview.events.EventOverviewBolusProgress; import info.nightscout.androidaps.plugins.PumpVirtual.events.EventVirtualPumpUpdateGui; import info.nightscout.utils.DateUtil; @@ -65,6 +63,7 @@ public class VirtualPumpPlugin implements PluginBase, PumpInterface { } private static VirtualPumpPlugin plugin = null; + public static VirtualPumpPlugin getPlugin() { loadFakingStatus(); if (plugin == null) @@ -304,7 +303,7 @@ public class VirtualPumpPlugin implements PluginBase, PumpInterface { } @Override - public PumpEnactResult setTempBasalPercent(Integer percent, Integer durationInMinutes) { + public PumpEnactResult setTempBasalPercent(Integer percent, Integer durationInMinutes, boolean enforceNew) { TreatmentsInterface treatmentsInterface = MainApp.getConfigBuilder(); PumpEnactResult result = new PumpEnactResult(); if (MainApp.getConfigBuilder().isTempBasalInProgress()) { @@ -401,8 +400,7 @@ public class VirtualPumpPlugin implements PluginBase, PumpInterface { @Override public JSONObject getJSONStatus() { - SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(MainApp.instance().getApplicationContext()); - if (!preferences.getBoolean("virtualpump_uploadstatus", false)) { + if (!SP.getBoolean("virtualpump_uploadstatus", false)) { return null; } JSONObject pump = new JSONObject(); diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/Wear/ActionStringHandler.java b/app/src/main/java/info/nightscout/androidaps/plugins/Wear/ActionStringHandler.java index 9050fb931e..da276af3c2 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/Wear/ActionStringHandler.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/Wear/ActionStringHandler.java @@ -38,6 +38,7 @@ import info.nightscout.androidaps.plugins.PumpDanaR.DanaRPlugin; import info.nightscout.androidaps.plugins.PumpDanaR.DanaRPump; import info.nightscout.androidaps.plugins.PumpDanaR.comm.RecordTypes; import info.nightscout.androidaps.plugins.PumpDanaRKorean.DanaRKoreanPlugin; +import info.nightscout.androidaps.plugins.PumpDanaRS.DanaRSPlugin; import info.nightscout.androidaps.plugins.PumpDanaRv2.DanaRv2Plugin; import info.nightscout.androidaps.queue.Callback; import info.nightscout.utils.BolusWizard; @@ -268,13 +269,15 @@ public class ActionStringHandler { } else if ("tddstats".equals(act[0])) { Object activePump = MainApp.getConfigBuilder().getActivePump(); PumpInterface dana = MainApp.getSpecificPlugin(DanaRPlugin.class); + PumpInterface danaRS = MainApp.getSpecificPlugin(DanaRSPlugin.class); PumpInterface danaV2 = MainApp.getSpecificPlugin(DanaRv2Plugin.class); PumpInterface danaKorean = MainApp.getSpecificPlugin(DanaRKoreanPlugin.class); if ((dana == null || dana != activePump) && (danaV2 == null || danaV2 != activePump) && - (danaKorean == null || danaKorean != activePump) + (danaKorean == null || danaKorean != activePump) && + (danaRS == null || danaRS != activePump) ) { sendError("Pump does not support TDDs!"); return; diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/Wear/WearPlugin.java b/app/src/main/java/info/nightscout/androidaps/plugins/Wear/WearPlugin.java index 00f62bd2c0..3316d68d12 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/Wear/WearPlugin.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/Wear/WearPlugin.java @@ -215,6 +215,8 @@ public class WearPlugin implements PluginBase { @Subscribe public void onStatusEvent(final EventDismissBolusprogressIfRunning ev) { + if(ev.result == null) return; + String status; if(ev.result.success){ status = MainApp.sResources.getString(R.string.success); diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/Wear/wearintegration/WatchUpdaterService.java b/app/src/main/java/info/nightscout/androidaps/plugins/Wear/wearintegration/WatchUpdaterService.java index 944774baaa..73b6692904 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/Wear/wearintegration/WatchUpdaterService.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/Wear/wearintegration/WatchUpdaterService.java @@ -533,7 +533,7 @@ public class WatchUpdaterService extends WearableListenerService implements String iobSum = DecimalFormatter.to2Decimal(bolusIob.iob + basalIob.basaliob); String iobDetail = "(" + DecimalFormatter.to2Decimal(bolusIob.iob) + "|" + DecimalFormatter.to2Decimal(basalIob.basaliob) + ")"; String cobString = generateCOBString(); - String tempBasal = generateBasalString(treatmentsInterface); + String currentBasal = generateBasalString(treatmentsInterface); //bgi String bgiString = ""; @@ -543,7 +543,7 @@ public class WatchUpdaterService extends WearableListenerService implements bgiString = "" + ((bgi >= 0) ? "+" : "") + DecimalFormatter.to1Decimal(bgi); } - String status = generateStatusString(profile, tempBasal,iobSum, iobDetail, bgiString); + String status = generateStatusString(profile, currentBasal,iobSum, iobDetail, bgiString); //batteries int phoneBattery = getBatteryLevel(getApplicationContext()); @@ -567,7 +567,7 @@ public class WatchUpdaterService extends WearableListenerService implements dataMapRequest.getDataMap().putString("iobDetail", iobDetail); dataMapRequest.getDataMap().putBoolean("detailedIob", mPrefs.getBoolean("wear_detailediob", false)); dataMapRequest.getDataMap().putString("cob", cobString); - dataMapRequest.getDataMap().putString("tempBasal", tempBasal); + dataMapRequest.getDataMap().putString("currentBasal", currentBasal); dataMapRequest.getDataMap().putString("battery", "" + phoneBattery); dataMapRequest.getDataMap().putString("rigBattery", rigBattery); dataMapRequest.getDataMap().putLong("openApsStatus", openApsStatus); @@ -598,7 +598,7 @@ public class WatchUpdaterService extends WearableListenerService implements } @NonNull - private String generateStatusString(Profile profile, String tempBasal, String iobSum, String iobDetail, String bgiString) { + private String generateStatusString(Profile profile, String currentBasal, String iobSum, String iobDetail, String bgiString) { String status = ""; @@ -623,7 +623,7 @@ public class WatchUpdaterService extends WearableListenerService implements iobString = iobSum + "U"; } - status += tempBasal + " " + iobString; + status += currentBasal + " " + iobString; //add BGI if shown, otherwise return if (mPrefs.getBoolean("wear_showbgi", false)) { @@ -636,10 +636,16 @@ public class WatchUpdaterService extends WearableListenerService implements @NonNull private String generateBasalString(TreatmentsInterface treatmentsInterface) { - String basalStringResult = "-.--U/h"; + String basalStringResult; TemporaryBasal activeTemp = treatmentsInterface.getTempBasalFromHistory(System.currentTimeMillis()); if (activeTemp != null) { basalStringResult = activeTemp.toStringShort(); + } else { + if (SP.getBoolean(R.string.key_danar_visualizeextendedaspercentage, false)) { + basalStringResult = "100%"; + } else { + basalStringResult = DecimalFormatter.to2Decimal(MainApp.getConfigBuilder().getProfile().getBasal()) + "U/h"; + } } return basalStringResult; } @@ -648,7 +654,7 @@ public class WatchUpdaterService extends WearableListenerService implements private String generateCOBString() { String cobStringResult = "--"; - AutosensData autosensData = IobCobCalculatorPlugin.getAutosensData(System.currentTimeMillis()); + AutosensData autosensData = IobCobCalculatorPlugin.getLastAutosensData(); if (autosensData != null) { cobStringResult = (int) autosensData.cob + "g"; } diff --git a/app/src/main/java/info/nightscout/androidaps/queue/CommandQueue.java b/app/src/main/java/info/nightscout/androidaps/queue/CommandQueue.java index 6f5ad50235..3a981391b8 100644 --- a/app/src/main/java/info/nightscout/androidaps/queue/CommandQueue.java +++ b/app/src/main/java/info/nightscout/androidaps/queue/CommandQueue.java @@ -128,7 +128,7 @@ public class CommandQueue { // After new command added to the queue // start thread again if not already running - private void notifyAboutNewCommand() { + private synchronized void notifyAboutNewCommand() { if (thread == null || thread.getState() == Thread.State.TERMINATED) { thread = new QueueThread(this); thread.start(); @@ -203,7 +203,7 @@ public class CommandQueue { } // returns true if command is queued - public boolean tempBasalPercent(int percent, int durationInMinutes, Callback callback) { + public boolean tempBasalPercent(int percent, int durationInMinutes, boolean enforceNew, Callback callback) { if (isRunning(Command.CommandType.TEMPBASAL)) { if (callback != null) callback.result(executingNowError()).run(); @@ -216,7 +216,7 @@ public class CommandQueue { Integer percentAfterConstraints = MainApp.getConfigBuilder().applyBasalConstraints(percent); // add new command to queue - add(new CommandTempBasalPercent(percentAfterConstraints, durationInMinutes, callback)); + add(new CommandTempBasalPercent(percentAfterConstraints, durationInMinutes, enforceNew, callback)); notifyAboutNewCommand(); @@ -326,14 +326,14 @@ public class CommandQueue { // returns true if command is queued public boolean readStatus(String reason, Callback callback) { - if (isRunning(Command.CommandType.READSTATUS)) { - if (callback != null) - callback.result(executingNowError()).run(); - return false; - } + //if (isRunning(Command.CommandType.READSTATUS)) { + // if (callback != null) + // callback.result(executingNowError()).run(); + // return false; + //} // remove all unfinished - removeAll(Command.CommandType.READSTATUS); + //removeAll(Command.CommandType.READSTATUS); // add new command to queue add(new CommandReadStatus(reason, callback)); diff --git a/app/src/main/java/info/nightscout/androidaps/queue/QueueThread.java b/app/src/main/java/info/nightscout/androidaps/queue/QueueThread.java index e89af3a7db..17828645ad 100644 --- a/app/src/main/java/info/nightscout/androidaps/queue/QueueThread.java +++ b/app/src/main/java/info/nightscout/androidaps/queue/QueueThread.java @@ -59,7 +59,7 @@ public class QueueThread extends Thread { } if (!pump.isConnected() && secondsElapsed > Constants.PUMP_MAX_CONNECTION_TIME_IN_SECONDS) { - MainApp.bus().post(new EventDismissBolusprogressIfRunning(new PumpEnactResult())); + MainApp.bus().post(new EventDismissBolusprogressIfRunning(null)); MainApp.bus().post(new EventPumpStatusChanged(MainApp.sResources.getString(R.string.connectiontimedout))); log.debug("QUEUE: timed out"); pump.stopConnecting(); @@ -79,7 +79,7 @@ public class QueueThread extends Thread { mBluetoothAdapter.enable(); SystemClock.sleep(1000); //start over again once after watchdog barked - connectionStartTime = System.currentTimeMillis(); + connectionStartTime = lastCommandTime = System.currentTimeMillis(); } else { queue.clear(); return; diff --git a/app/src/main/java/info/nightscout/androidaps/queue/commands/CommandTempBasalPercent.java b/app/src/main/java/info/nightscout/androidaps/queue/commands/CommandTempBasalPercent.java index 663a20380d..e037f0b869 100644 --- a/app/src/main/java/info/nightscout/androidaps/queue/commands/CommandTempBasalPercent.java +++ b/app/src/main/java/info/nightscout/androidaps/queue/commands/CommandTempBasalPercent.java @@ -18,17 +18,19 @@ public class CommandTempBasalPercent extends Command { int durationInMinutes; int percent; + boolean enforceNew; - public CommandTempBasalPercent(int percent, int durationInMinutes, Callback callback) { + public CommandTempBasalPercent(int percent, int durationInMinutes, boolean enforceNew, Callback callback) { commandType = CommandType.TEMPBASAL; this.percent = percent; this.durationInMinutes = durationInMinutes; + this.enforceNew = enforceNew; this.callback = callback; } @Override public void execute() { - PumpEnactResult r = ConfigBuilderPlugin.getActivePump().setTempBasalPercent(percent, durationInMinutes); + PumpEnactResult r = ConfigBuilderPlugin.getActivePump().setTempBasalPercent(percent, durationInMinutes, enforceNew); if (Config.logCongigBuilderActions) log.debug("setTempBasalPercent percent: " + percent + " durationInMinutes: " + durationInMinutes + " success: " + r.success + " enacted: " + r.enacted); if (callback != null) diff --git a/app/src/main/java/info/nightscout/utils/BolusWizard.java b/app/src/main/java/info/nightscout/utils/BolusWizard.java index a97ed233ff..ac710dc51f 100644 --- a/app/src/main/java/info/nightscout/utils/BolusWizard.java +++ b/app/src/main/java/info/nightscout/utils/BolusWizard.java @@ -14,15 +14,15 @@ import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin; public class BolusWizard { // Inputs - Profile specificProfile = null; - TempTarget tempTarget; + private Profile specificProfile = null; + private TempTarget tempTarget; public Integer carbs = 0; - Double bg = 0d; - Double correction; - Boolean includeBolusIOB = true; - Boolean includeBasalIOB = true; - Boolean superBolus = false; - Boolean trend = false; + private Double bg = 0d; + private Double correction; + private Boolean includeBolusIOB = true; + private Boolean includeBasalIOB = true; + public Boolean superBolus = false; + private Boolean trend = false; // Intermediate public Double sens = 0d; @@ -71,7 +71,9 @@ public class BolusWizard { targetBGLow = Profile.fromMgdlToUnits(tempTarget.low, specificProfile.getUnits()); targetBGHigh = Profile.fromMgdlToUnits(tempTarget.high, specificProfile.getUnits()); } - if (bg <= targetBGLow) { + if (bg >= targetBGLow && bg <= targetBGHigh) { + bgDiff = 0d; + } else if (bg <= targetBGLow) { bgDiff = bg - targetBGLow; } else { bgDiff = bg - targetBGHigh; diff --git a/app/src/main/java/info/nightscout/utils/DateUtil.java b/app/src/main/java/info/nightscout/utils/DateUtil.java index c406568730..86965621d2 100644 --- a/app/src/main/java/info/nightscout/utils/DateUtil.java +++ b/app/src/main/java/info/nightscout/utils/DateUtil.java @@ -2,10 +2,12 @@ package info.nightscout.utils; import android.support.v4.util.LongSparseArray; import android.text.format.DateUtils; -import android.util.SparseIntArray; + +import org.joda.time.DateTime; +import org.joda.time.format.DateTimeFormatter; +import org.joda.time.format.ISODateTimeFormat; import java.text.DateFormat; -import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Calendar; import java.util.Date; @@ -27,9 +29,7 @@ public class DateUtil { /** * The date format in iso. */ - private static String FORMAT_DATE_ISO = "yyyy-MM-dd'T'HH:mm:ssZ"; - private static String FORMAT_DATE_ISO_MSEC = "yyyy-MM-dd'T'HH:mm:ss.SSSZ"; - private static String FORMAT_DATE_ISO_MSEC_UTC = "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"; + private static String FORMAT_DATE_ISO_OUT = "yyyy-MM-dd'T'HH:mm:ss'Z'"; /** * Takes in an ISO date string of the following format: @@ -41,33 +41,10 @@ public class DateUtil { */ public static Date fromISODateString(String isoDateString) throws Exception { - SimpleDateFormat f = new SimpleDateFormat(FORMAT_DATE_ISO, Locale.getDefault()); - Date date; - f.setTimeZone(TimeZone.getTimeZone("UTC")); - try { - date = f.parse(isoDateString); - return date; - } catch (ParseException e) { - } - - f = new SimpleDateFormat(FORMAT_DATE_ISO_MSEC, Locale.getDefault()); - f.setTimeZone(TimeZone.getTimeZone("UTC")); - try { - date = f.parse(isoDateString); - return date; - } catch (ParseException e) { - } - - f = new SimpleDateFormat(FORMAT_DATE_ISO_MSEC_UTC, Locale.getDefault()); - f.setTimeZone(TimeZone.getTimeZone("UTC")); - try { - date = f.parse(isoDateString); - return date; - } catch (ParseException e) { - } - - throw new ParseException("Unparseable date: " + isoDateString, 0); + DateTimeFormatter parser = ISODateTimeFormat.dateTimeParser(); + DateTime dateTime = DateTime.parse(isoDateString, parser); + return dateTime.toDate(); } /** @@ -79,7 +56,7 @@ public class DateUtil { * @return the iso-formatted date string */ public static String toISOString(Date date, String format, TimeZone tz) { - if (format == null) format = FORMAT_DATE_ISO; + if (format == null) format = FORMAT_DATE_ISO_OUT; if (tz == null) tz = TimeZone.getDefault(); DateFormat f = new SimpleDateFormat(format, Locale.getDefault()); f.setTimeZone(tz); @@ -87,21 +64,18 @@ public class DateUtil { } public static String toISOString(Date date) { - return toISOString(date, FORMAT_DATE_ISO, TimeZone.getTimeZone("UTC")); + return toISOString(date, FORMAT_DATE_ISO_OUT, TimeZone.getTimeZone("UTC")); } public static String toISOString(long date) { - return toISOString(new Date(date), FORMAT_DATE_ISO, TimeZone.getTimeZone("UTC")); + return toISOString(new Date(date), FORMAT_DATE_ISO_OUT, TimeZone.getTimeZone("UTC")); } public static Date toDate(Integer seconds) { Calendar calendar = new GregorianCalendar(); calendar.set(Calendar.HOUR_OF_DAY, seconds / 60 / 60); - String a = calendar.getTime().toString(); calendar.set(Calendar.MINUTE, (seconds / 60) % 60); - String b = calendar.getTime().toString(); calendar.set(Calendar.SECOND, 0); - String c = calendar.getTime().toString(); return calendar.getTime(); } diff --git a/app/src/main/java/info/nightscout/utils/PercentageSplitter.java b/app/src/main/java/info/nightscout/utils/PercentageSplitter.java new file mode 100644 index 0000000000..53e50466b5 --- /dev/null +++ b/app/src/main/java/info/nightscout/utils/PercentageSplitter.java @@ -0,0 +1,21 @@ +package info.nightscout.utils; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * Created by mike on 22.12.2017. + */ + +public class PercentageSplitter { + public static String pureName(String name) { + String newName = name; + String s = "(.*)\\((\\d+)\\%\\)"; + Pattern r = Pattern.compile(s); + Matcher m = r.matcher(name); + if (m.find()) { + newName = m.group(1); + } + return newName; + } +} diff --git a/app/src/main/java/info/nightscout/utils/SingleClickButton.java b/app/src/main/java/info/nightscout/utils/SingleClickButton.java new file mode 100644 index 0000000000..ef0d4d3aec --- /dev/null +++ b/app/src/main/java/info/nightscout/utils/SingleClickButton.java @@ -0,0 +1,67 @@ +package info.nightscout.utils; + +import android.app.Activity; +import android.content.Context; +import android.os.SystemClock; +import android.support.annotation.Nullable; +import android.util.AttributeSet; +import android.view.View; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Created by mike on 22.12.2017. + */ + +public class SingleClickButton extends android.support.v7.widget.AppCompatButton implements View.OnClickListener { + private static Logger log = LoggerFactory.getLogger(SingleClickButton.class); + + Context context; + OnClickListener listener = null; + + public SingleClickButton(Context context) { + super(context); + this.context = context; + super.setOnClickListener(this); + } + + public SingleClickButton(Context context, AttributeSet attrs) { + super(context, attrs); + this.context = context; + super.setOnClickListener(this); + } + + public SingleClickButton(Context context, AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + this.context = context; + super.setOnClickListener(this); + } + + @Override + public void setOnClickListener(@Nullable OnClickListener l) { + listener = l; + } + + @Override + public void onClick(final View v) { + setEnabled(false); + new Thread(new Runnable() { + @Override + public void run() { + SystemClock.sleep(3000); + Activity activity = (Activity) context; + if (activity != null) + activity.runOnUiThread(new Runnable() { + @Override + public void run() { + setEnabled(true); + log.debug("Button enabled"); + } + }); + } + }).start(); + if (listener != null) + listener.onClick(v); + } +} diff --git a/app/src/main/java/info/nightscout/utils/TimeListEdit.java b/app/src/main/java/info/nightscout/utils/TimeListEdit.java index af3668310a..bc41ece59d 100644 --- a/app/src/main/java/info/nightscout/utils/TimeListEdit.java +++ b/app/src/main/java/info/nightscout/utils/TimeListEdit.java @@ -52,6 +52,8 @@ public class TimeListEdit { private JSONArray data1; private JSONArray data2; private double step; + private double min; + private double max; private NumberFormat formatter; private Runnable save; private LinearLayout layout; @@ -59,7 +61,7 @@ public class TimeListEdit { private int inflatedUntil = -1; - public TimeListEdit(Context context, View view, int resLayoutId, String label, JSONArray data1, JSONArray data2, double step, NumberFormat formatter, Runnable save) { + public TimeListEdit(Context context, View view, int resLayoutId, String label, JSONArray data1, JSONArray data2, double min, double max, double step, NumberFormat formatter, Runnable save) { this.context = context; this.view = view; this.resLayoutId = resLayoutId; @@ -67,6 +69,8 @@ public class TimeListEdit { this.data1 = data1; this.data2 = data2; this.step = step; + this.min = min; + this.max = max; this.formatter = formatter; this.save = save; buildView(); @@ -239,8 +243,8 @@ public class TimeListEdit { if (i == 0) next = ONEHOURINSECONDS; fillSpinner(timeSpinner, secondFromMidnight(i), previous, next); - editText1.setParams(value1(i), 0.1d, 100d, step, formatter, false); - editText2.setParams(value2(i), 0.1d, 100d, step, formatter, false); + editText1.setParams(value1(i), min, max, step, formatter, false); + editText2.setParams(value2(i), min, max, step, formatter, false); if (data2 == null) { editText2.setVisibility(View.GONE); diff --git a/app/src/main/res/layout/actions_fragment.xml b/app/src/main/res/layout/actions_fragment.xml index bc8f416770..6673099110 100644 --- a/app/src/main/res/layout/actions_fragment.xml +++ b/app/src/main/res/layout/actions_fragment.xml @@ -13,7 +13,7 @@ android:layout_height="wrap_content" android:orientation="vertical"> -