diff --git a/app/src/main/java/info/nightscout/androidaps/MainApp.java b/app/src/main/java/info/nightscout/androidaps/MainApp.java index 1e49b03d73..b820393c33 100644 --- a/app/src/main/java/info/nightscout/androidaps/MainApp.java +++ b/app/src/main/java/info/nightscout/androidaps/MainApp.java @@ -26,10 +26,10 @@ import info.nightscout.androidaps.plugins.Careportal.CareportalFragment; import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderFragment; import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin; import info.nightscout.androidaps.plugins.ConstraintsObjectives.ObjectivesFragment; -import info.nightscout.androidaps.plugins.ConstraintsSafety.SafetyFragment; +import info.nightscout.androidaps.plugins.ConstraintsSafety.SafetyPlugin; import info.nightscout.androidaps.plugins.InsulinFastacting.InsulinFastactingFragment; import info.nightscout.androidaps.plugins.InsulinFastactingProlonged.InsulinFastactingProlongedFragment; -import info.nightscout.androidaps.plugins.IobCobCalculator.IobCobCalculatorFragment; +import info.nightscout.androidaps.plugins.IobCobCalculator.IobCobCalculatorPlugin; import info.nightscout.androidaps.plugins.Loop.LoopFragment; import info.nightscout.androidaps.plugins.NSClientInternal.NSClientInternalFragment; import info.nightscout.androidaps.plugins.OpenAPSAMA.OpenAPSAMAFragment; @@ -46,17 +46,18 @@ import info.nightscout.androidaps.plugins.PumpDanaRKorean.DanaRKoreanFragment; import info.nightscout.androidaps.plugins.PumpDanaRKorean.services.DanaRKoreanExecutionService; import info.nightscout.androidaps.plugins.PumpDanaRv2.DanaRv2Fragment; import info.nightscout.androidaps.plugins.PumpDanaRv2.services.DanaRv2ExecutionService; -import info.nightscout.androidaps.plugins.PumpMDI.MDIFragment; -import info.nightscout.androidaps.plugins.PumpVirtual.VirtualPumpFragment; +import info.nightscout.androidaps.plugins.PumpMDI.MDIPlugin; import info.nightscout.androidaps.plugins.PumpVirtual.VirtualPumpPlugin; +import info.nightscout.androidaps.plugins.SensitivityMK.SensitivityMKPlugin; +import info.nightscout.androidaps.plugins.SensitivityOref0.SensitivityOref0Plugin; import info.nightscout.androidaps.plugins.SmsCommunicator.SmsCommunicatorFragment; -import info.nightscout.androidaps.plugins.SourceGlimp.SourceGlimpFragment; -import info.nightscout.androidaps.plugins.SourceMM640g.SourceMM640gFragment; -import info.nightscout.androidaps.plugins.SourceNSClient.SourceNSClientFragment; -import info.nightscout.androidaps.plugins.SourceXdrip.SourceXdripFragment; +import info.nightscout.androidaps.plugins.SourceGlimp.SourceGlimpPlugin; +import info.nightscout.androidaps.plugins.SourceMM640g.SourceMM640gPlugin; +import info.nightscout.androidaps.plugins.SourceNSClient.SourceNSClientPlugin; +import info.nightscout.androidaps.plugins.SourceXdrip.SourceXdripPlugin; import info.nightscout.androidaps.plugins.Treatments.TreatmentsFragment; import info.nightscout.androidaps.plugins.Wear.WearFragment; -import info.nightscout.androidaps.plugins.XDripStatusline.StatuslineFragment; +import info.nightscout.androidaps.plugins.XDripStatusline.StatuslinePlugin; import info.nightscout.androidaps.receivers.KeepAliveReceiver; import info.nightscout.utils.NSUpload; import io.fabric.sdk.android.Fabric; @@ -94,15 +95,17 @@ public class MainApp extends Application { pluginsList = new ArrayList<>(); // Register all tabs in app here pluginsList.add(OverviewFragment.getPlugin()); - pluginsList.add(IobCobCalculatorFragment.getPlugin()); + pluginsList.add(IobCobCalculatorPlugin.getPlugin()); if (Config.ACTION) pluginsList.add(ActionsFragment.getPlugin()); pluginsList.add(InsulinFastactingFragment.getPlugin()); pluginsList.add(InsulinFastactingProlongedFragment.getPlugin()); + pluginsList.add(SensitivityOref0Plugin.getPlugin()); + pluginsList.add(SensitivityMKPlugin.getPlugin()); if (Config.DANAR) pluginsList.add(DanaRFragment.getPlugin()); if (Config.DANAR) pluginsList.add(DanaRKoreanFragment.getPlugin()); if (Config.DANARv2) pluginsList.add(DanaRv2Fragment.getPlugin()); pluginsList.add(CareportalFragment.getPlugin()); - if (Config.MDI) pluginsList.add(MDIFragment.getPlugin()); + if (Config.MDI) pluginsList.add(MDIPlugin.getPlugin()); if (Config.VIRTUALPUMP) pluginsList.add(VirtualPumpPlugin.getInstance()); if (Config.LOOPENABLED) pluginsList.add(LoopFragment.getPlugin()); if (Config.OPENAPSENABLED) pluginsList.add(OpenAPSMAFragment.getPlugin()); @@ -113,19 +116,19 @@ public class MainApp extends Application { if (Config.OTHERPROFILES) pluginsList.add(CircadianPercentageProfileFragment.getPlugin()); pluginsList.add(TreatmentsFragment.getPlugin()); - if (Config.SAFETY) pluginsList.add(SafetyFragment.getPlugin()); + if (Config.SAFETY) pluginsList.add(SafetyPlugin.getPlugin()); if (Config.APS) pluginsList.add(ObjectivesFragment.getPlugin()); if (!Config.NSCLIENT) - pluginsList.add(SourceXdripFragment.getPlugin()); - pluginsList.add(SourceNSClientFragment.getPlugin()); + pluginsList.add(SourceXdripPlugin.getPlugin()); + pluginsList.add(SourceNSClientPlugin.getPlugin()); if (!Config.NSCLIENT) - pluginsList.add(SourceMM640gFragment.getPlugin()); + pluginsList.add(SourceMM640gPlugin.getPlugin()); if (!Config.NSCLIENT) - pluginsList.add(SourceGlimpFragment.getPlugin()); + pluginsList.add(SourceGlimpPlugin.getPlugin()); if (Config.SMSCOMMUNICATORENABLED) pluginsList.add(SmsCommunicatorFragment.getPlugin()); if (Config.WEAR) pluginsList.add(WearFragment.getPlugin(this)); - pluginsList.add(StatuslineFragment.getPlugin(this)); + pluginsList.add(StatuslinePlugin.getPlugin(this)); pluginsList.add(new PersistentNotificationPlugin(this)); pluginsList.add(NSClientInternalFragment.getPlugin()); diff --git a/app/src/main/java/info/nightscout/androidaps/PreferencesActivity.java b/app/src/main/java/info/nightscout/androidaps/PreferencesActivity.java index 43bfb53c79..71c3a3981e 100644 --- a/app/src/main/java/info/nightscout/androidaps/PreferencesActivity.java +++ b/app/src/main/java/info/nightscout/androidaps/PreferencesActivity.java @@ -21,6 +21,7 @@ import info.nightscout.androidaps.plugins.NSClientInternal.NSClientInternalPlugi import info.nightscout.androidaps.plugins.OpenAPSAMA.OpenAPSAMAPlugin; import info.nightscout.androidaps.plugins.PumpDanaRv2.DanaRv2Plugin; import info.nightscout.androidaps.plugins.PumpVirtual.VirtualPumpPlugin; +import info.nightscout.androidaps.plugins.SensitivityMK.SensitivityMKPlugin; import info.nightscout.androidaps.plugins.Wear.WearPlugin; import info.nightscout.androidaps.plugins.XDripStatusline.StatuslinePlugin; import info.nightscout.utils.LocaleHelper; @@ -105,6 +106,8 @@ public class PreferencesActivity extends PreferenceActivity implements SharedPre if (MainApp.getSpecificPlugin(OpenAPSAMAPlugin.class) != null && MainApp.getSpecificPlugin(OpenAPSAMAPlugin.class).isEnabled(PluginBase.APS)) addPreferencesFromResource(R.xml.pref_openapsama); } + if (MainApp.getSpecificPlugin(SensitivityMKPlugin.class) != null && MainApp.getSpecificPlugin(SensitivityMKPlugin.class).isEnabled(PluginBase.SENSITIVITY)) + addPreferencesFromResource(R.xml.pref_absorption); if (Config.ALLPREFERENCES) { addPreferencesFromResource(R.xml.pref_profile); } diff --git a/app/src/main/java/info/nightscout/androidaps/interfaces/PluginBase.java b/app/src/main/java/info/nightscout/androidaps/interfaces/PluginBase.java index ba4faf4ba6..bf5e66f2a1 100644 --- a/app/src/main/java/info/nightscout/androidaps/interfaces/PluginBase.java +++ b/app/src/main/java/info/nightscout/androidaps/interfaces/PluginBase.java @@ -8,7 +8,7 @@ import java.util.Date; public interface PluginBase { int GENERAL = 1; int TREATMENT = 2; - //int TEMPBASAL = 3; + int SENSITIVITY = 3; int PROFILE = 4; int APS = 5; int PUMP = 6; diff --git a/app/src/main/java/info/nightscout/androidaps/interfaces/SensitivityInterface.java b/app/src/main/java/info/nightscout/androidaps/interfaces/SensitivityInterface.java new file mode 100644 index 0000000000..deb649c21f --- /dev/null +++ b/app/src/main/java/info/nightscout/androidaps/interfaces/SensitivityInterface.java @@ -0,0 +1,11 @@ +package info.nightscout.androidaps.interfaces; + +import info.nightscout.androidaps.plugins.IobCobCalculator.AutosensResult; + +/** + * Created by mike on 24.06.2017. + */ + +public interface SensitivityInterface { + AutosensResult detectSensitivity(long fromTime, long toTime); +} diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/ConfigBuilder/ConfigBuilderFragment.java b/app/src/main/java/info/nightscout/androidaps/plugins/ConfigBuilder/ConfigBuilderFragment.java index 8aa43831f5..bd269e7c66 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/ConfigBuilder/ConfigBuilderFragment.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/ConfigBuilder/ConfigBuilderFragment.java @@ -34,9 +34,11 @@ import info.nightscout.androidaps.interfaces.InsulinInterface; import info.nightscout.androidaps.interfaces.PluginBase; import info.nightscout.androidaps.interfaces.ProfileInterface; import info.nightscout.androidaps.interfaces.PumpInterface; +import info.nightscout.androidaps.interfaces.SensitivityInterface; import info.nightscout.androidaps.plugins.InsulinFastacting.InsulinFastactingPlugin; import info.nightscout.androidaps.plugins.ProfileNS.NSProfilePlugin; import info.nightscout.androidaps.plugins.PumpVirtual.VirtualPumpPlugin; +import info.nightscout.androidaps.plugins.SensitivityOref0.SensitivityOref0Plugin; import info.nightscout.utils.PasswordProtection; @@ -49,6 +51,7 @@ public class ConfigBuilderFragment extends Fragment { } ListView insulinListView; + ListView sensitivityListView; ListView bgsourceListView; TextView bgsourceLabel; ListView pumpListView; @@ -71,6 +74,7 @@ public class ConfigBuilderFragment extends Fragment { Button unlock; PluginCustomAdapter insulinDataAdapter = null; + PluginCustomAdapter sensivityDataAdapter = null; PluginCustomAdapter bgsourceDataAdapter = null; PluginCustomAdapter pumpDataAdapter = null; PluginCustomAdapter loopDataAdapter = null; @@ -96,6 +100,7 @@ public class ConfigBuilderFragment extends Fragment { smallWidth = screen_width < Constants.SMALL_WIDTH; insulinListView = (ListView) view.findViewById(R.id.configbuilder_insulinlistview); + sensitivityListView = (ListView) view.findViewById(R.id.configbuilder_sensitivitylistview); bgsourceListView = (ListView) view.findViewById(R.id.configbuilder_bgsourcelistview); bgsourceLabel = (TextView) view.findViewById(R.id.configbuilder_bgsourcelabel); pumpListView = (ListView) view.findViewById(R.id.configbuilder_pumplistview); @@ -178,6 +183,9 @@ public class ConfigBuilderFragment extends Fragment { setListViewHeightBasedOnChildren(apsListView); if (MainApp.getSpecificPluginsVisibleInList(PluginBase.APS).size() == 0) apsLabel.setVisibility(View.GONE); + sensivityDataAdapter = new PluginCustomAdapter(getContext(), smallWidth?R.layout.configbuilder_smallitem :R.layout.configbuilder_simpleitem, MainApp.getSpecificPluginsVisibleInListByInterface(SensitivityInterface.class, PluginBase.SENSITIVITY), PluginBase.SENSITIVITY); + sensitivityListView.setAdapter(sensivityDataAdapter); + setListViewHeightBasedOnChildren(sensitivityListView); constraintsDataAdapter = new PluginCustomAdapter(getContext(), smallWidth?R.layout.configbuilder_smallitem :R.layout.configbuilder_simpleitem, MainApp.getSpecificPluginsVisibleInListByInterface(ConstraintsInterface.class, PluginBase.BGSOURCE), PluginBase.CONSTRAINTS); constraintsListView.setAdapter(constraintsDataAdapter); setListViewHeightBasedOnChildren(constraintsListView); @@ -277,7 +285,7 @@ public class ConfigBuilderFragment extends Fragment { } // Hide enabled control and force enabled plugin if there is only one plugin available - if (type == PluginBase.INSULIN || type == PluginBase.PUMP || type == PluginBase.TREATMENT || type == PluginBase.PROFILE) + if (type == PluginBase.INSULIN || type == PluginBase.PUMP || type == PluginBase.TREATMENT || type == PluginBase.PROFILE || type == PluginBase.SENSITIVITY) if (pluginList.size() < 2) { holder.checkboxEnabled.setEnabled(false); plugin.setFragmentEnabled(type, true); @@ -326,6 +334,9 @@ public class ConfigBuilderFragment extends Fragment { case PluginBase.INSULIN: pluginsInCategory = MainApp.getSpecificPluginsListByInterface(InsulinInterface.class); break; + case PluginBase.SENSITIVITY: + pluginsInCategory = MainApp.getSpecificPluginsListByInterface(SensitivityInterface.class); + break; case PluginBase.APS: pluginsInCategory = MainApp.getSpecificPluginsListByInterface(APSInterface.class); break; @@ -356,6 +367,8 @@ public class ConfigBuilderFragment extends Fragment { MainApp.getSpecificPlugin(VirtualPumpPlugin.class).setFragmentEnabled(type, true); else if (type == PluginBase.INSULIN) MainApp.getSpecificPlugin(InsulinFastactingPlugin.class).setFragmentEnabled(type, true); + else if (type == PluginBase.SENSITIVITY) + MainApp.getSpecificPlugin(SensitivityOref0Plugin.class).setFragmentEnabled(type, true); else if (type == PluginBase.PROFILE) MainApp.getSpecificPlugin(NSProfilePlugin.class).setFragmentEnabled(type, true); else 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 9b849ea5d4..4c53cfa6d8 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 @@ -40,6 +40,7 @@ import info.nightscout.androidaps.interfaces.PluginBase; import info.nightscout.androidaps.interfaces.ProfileInterface; import info.nightscout.androidaps.interfaces.PumpDescription; import info.nightscout.androidaps.interfaces.PumpInterface; +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; @@ -65,6 +66,7 @@ public class ConfigBuilderPlugin implements PluginBase, PumpInterface, Constrain private static APSInterface activeAPS; private static LoopPlugin activeLoop; private static InsulinInterface activeInsulin; + private static SensitivityInterface activeSensitivity; static public String nightscoutVersionName = ""; static public Integer nightscoutVersionCode = 0; @@ -213,11 +215,16 @@ public class ConfigBuilderPlugin implements PluginBase, PumpInterface, Constrain return activePump; } + public static SensitivityInterface getActiveSensitivity() { + return activeSensitivity; + } + void logPluginStatus() { for (PluginBase p : pluginList) { log.debug(p.getName() + ":" + (p.isEnabled(1) ? " GENERAL" : "") + (p.isEnabled(2) ? " TREATMENT" : "") + + (p.isEnabled(3) ? " SENSITIVITY" : "") + (p.isEnabled(4) ? " PROFILE" : "") + (p.isEnabled(5) ? " APS" : "") + (p.isEnabled(6) ? " PUMP" : "") + @@ -256,6 +263,17 @@ public class ConfigBuilderPlugin implements PluginBase, PumpInterface, Constrain } } + // PluginBase.SENSITIVITY + pluginsInCategory = MainApp.getSpecificPluginsListByInterface(SensitivityInterface.class); + activeSensitivity = (SensitivityInterface) getTheOneEnabledInArray(pluginsInCategory, PluginBase.SENSITIVITY); + if (Config.logConfigBuilder) + log.debug("Selected sensitivity interface: " + ((PluginBase) activeSensitivity).getName()); + for (PluginBase p : pluginsInCategory) { + if (!p.getName().equals(((PluginBase) activeSensitivity).getName())) { + p.setFragmentVisible(PluginBase.SENSITIVITY, false); + } + } + // PluginBase.PROFILE pluginsInCategory = MainApp.getSpecificPluginsListByInterface(ProfileInterface.class); activeProfile = (ProfileInterface) getTheOneEnabledInArray(pluginsInCategory, PluginBase.PROFILE); @@ -411,43 +429,6 @@ public class ConfigBuilderPlugin implements PluginBase, PumpInterface, Constrain return 0d; } - /* - public PumpEnactResult deliverTreatmentFromBolusWizard(InsulinInterface insulinType, Context context, Double insulin, Integer carbs, Double glucose, String glucoseType, int carbTime, JSONObject boluscalc) { - mWakeLock.acquire(); - PumpEnactResult result; - insulin = applyBolusConstraints(insulin); - carbs = applyCarbsConstraints(carbs); - - BolusProgressDialog bolusProgressDialog = null; - if (context != null) { - bolusProgressDialog = new BolusProgressDialog(); - bolusProgressDialog.setInsulin(insulin); - bolusProgressDialog.show(((AppCompatActivity) context).getSupportFragmentManager(), "BolusProgress"); - } - - MainApp.bus().post(new EventBolusRequested(insulin)); - - result = activePump.deliverTreatment(insulinType, insulin, carbs, context); - - BolusProgressDialog.bolusEnded = true; - - MainApp.bus().post(new EventDismissBolusprogressIfRunning(result)); - - if (result.success) { - Treatment t = new Treatment(insulinType); - t.insulin = result.bolusDelivered; - if (carbTime == 0) - t.carbs = (double) result.carbsDelivered; // with different carbTime record will come back from nightscout - t.date = System.currentTimeMillis(); - t.mealBolus = result.carbsDelivered > 0; - addToHistoryTreatment(t); - t.carbs = (double) result.carbsDelivered; - NSUpload.uploadBolusWizardRecord(t, glucose, glucoseType, carbTime, boluscalc); - } - mWakeLock.release(); - return result; - } - */ @Override public PumpEnactResult deliverTreatment(DetailedBolusInfo detailedBolusInfo) { mWakeLock.acquire(); @@ -473,56 +454,6 @@ public class ConfigBuilderPlugin implements PluginBase, PumpInterface, Constrain return result; } - /* - @Override - public PumpEnactResult deliverTreatment(InsulinInterface insulinType, Double insulin, Integer carbs, Context context) { - return deliverTreatment(insulinType, insulin, carbs, context, true); - } - - public PumpEnactResult deliverTreatment(InsulinInterface insulinType, Double insulin, Integer carbs, Context context, boolean createTreatment) { - mWakeLock.acquire(); - PumpEnactResult result; - insulin = applyBolusConstraints(insulin); - carbs = applyCarbsConstraints(carbs); - - BolusProgressDialog bolusProgressDialog = null; - if (context != null) { - bolusProgressDialog = new BolusProgressDialog(); - bolusProgressDialog.setInsulin(insulin); - bolusProgressDialog.show(((AppCompatActivity) context).getSupportFragmentManager(), "BolusProgress"); - } else { - Intent i = new Intent(); - i.putExtra("insulin", insulin.doubleValue()); - i.setClass(MainApp.instance(), BolusProgressHelperActivity.class); - i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - MainApp.instance().startActivity(i); - } - - MainApp.bus().post(new EventBolusRequested(insulin)); - - result = activePump.deliverTreatment(insulinType, insulin, carbs, context); - - BolusProgressDialog.bolusEnded = true; - - MainApp.bus().post(new EventDismissBolusprogressIfRunning(result)); - - if (Config.logCongigBuilderActions) - log.debug("deliverTreatment insulin: " + insulin + " carbs: " + carbs + " success: " + result.success + " enacted: " + result.enacted + " bolusDelivered: " + result.bolusDelivered); - - if (result.success && createTreatment) { - Treatment t = new Treatment(insulinType); - t.insulin = result.bolusDelivered; - t.carbs = (double) result.carbsDelivered; - t.date = System.currentTimeMillis(); - t.mealBolus = t.carbs > 0; - addToHistoryTreatment(t); - NSUpload.uploadTreatment(t); - } - mWakeLock.release(); - return result; - } - - */ @Override public void stopBolusDelivering() { activePump.stopBolusDelivering(); diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/ConstraintsSafety/SafetyFragment.java b/app/src/main/java/info/nightscout/androidaps/plugins/ConstraintsSafety/SafetyFragment.java deleted file mode 100644 index 07583e7622..0000000000 --- a/app/src/main/java/info/nightscout/androidaps/plugins/ConstraintsSafety/SafetyFragment.java +++ /dev/null @@ -1,17 +0,0 @@ -package info.nightscout.androidaps.plugins.ConstraintsSafety; - - -import android.support.v4.app.Fragment; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class SafetyFragment extends Fragment { - private static Logger log = LoggerFactory.getLogger(SafetyFragment.class); - - private static SafetyPlugin safetyPlugin = new SafetyPlugin(); - - public static SafetyPlugin getPlugin() { - return safetyPlugin; - } -} 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 213bba47fa..c685cd472d 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 @@ -21,9 +21,17 @@ import info.nightscout.utils.SP; public class SafetyPlugin implements PluginBase, ConstraintsInterface { private static Logger log = LoggerFactory.getLogger(SafetyPlugin.class); + static SafetyPlugin plugin = null; + + public static SafetyPlugin getPlugin() { + if (plugin == null) + plugin = new SafetyPlugin(); + return plugin; + } + @Override public String getFragmentClass() { - return SafetyFragment.class.getName(); + return null; } @Override diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/IobCobCalculator/AutosensData.java b/app/src/main/java/info/nightscout/androidaps/plugins/IobCobCalculator/AutosensData.java index 8f15653135..7efcf083b4 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/IobCobCalculator/AutosensData.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/IobCobCalculator/AutosensData.java @@ -1,17 +1,56 @@ package info.nightscout.androidaps.plugins.IobCobCalculator; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.ArrayList; import java.util.Date; +import java.util.List; + +import info.nightscout.androidaps.MainApp; +import info.nightscout.androidaps.R; +import info.nightscout.androidaps.data.Profile; +import info.nightscout.androidaps.db.Treatment; +import info.nightscout.androidaps.interfaces.PluginBase; +import info.nightscout.androidaps.plugins.SensitivityMK.SensitivityMKPlugin; +import info.nightscout.utils.SP; /** * Created by mike on 25.04.2017. */ public class AutosensData { - long time = 0L; + private static Logger log = LoggerFactory.getLogger(AutosensData.class); + + static class CarbsInPast { + long time = 0L; + double carbs = 0d; + double min5minCarbImpact = 0d; + double remaining = 0d; + + public CarbsInPast(Treatment t) { + time = t.date; + carbs = t.carbs; + remaining = t.carbs; + if (MainApp.getSpecificPlugin(SensitivityMKPlugin.class) != null && MainApp.getSpecificPlugin(SensitivityMKPlugin.class).isEnabled(PluginBase.SENSITIVITY)) { + double maxAbsorptionHours = SP.getDouble(R.string.key_absorption_maxtime, 4d); + Profile profile = MainApp.getConfigBuilder().getProfile(t.date); + double sens = Profile.toMgdl(profile.getIsf(t.date), profile.getUnits()); + double ic = profile.getIc(t.date); + min5minCarbImpact = t.carbs / (maxAbsorptionHours * 60 / 5) * sens / ic; + log.debug("Min 5m carbs impact for " + carbs + "g @" + new Date(t.date).toLocaleString() + " for " + maxAbsorptionHours + "h calculated to " + min5minCarbImpact + " ISF: " + sens + " IC: " + ic); + } else { + min5minCarbImpact = SP.getDouble("openapsama_min_5m_carbimpact", 3.0); + } + } + } + + public long time = 0L; public String pastSensitivity = ""; public double deviation = 0d; boolean nonCarbsDeviation = false; - boolean nonEqualDeviation = false; + public boolean nonEqualDeviation = false; + List activeCarbsList = new ArrayList<>(); double absorbed = 0d; public double carbsFromBolus = 0d; public double cob = 0; @@ -28,4 +67,29 @@ public class AutosensData { return (int) ((System.currentTimeMillis() - time) / 1000 / 60); } + // remove carbs older than 4h + public void removeOldCarbs(long toTime) { + for (int i = 0; i < activeCarbsList.size(); i++) { + CarbsInPast c = activeCarbsList.get(i); + if (c.time + 4 * 60 * 60 * 1000L < toTime) { + activeCarbsList.remove(i--); + if (c.remaining > 0) + cob -= c.remaining; + log.debug("Removing carbs at "+ new Date(toTime).toLocaleString() + " + after 4h :" + new Date(c.time).toLocaleString()); + } + } + } + + public void substractAbosorbedCarbs() { + double ac = absorbed; + for (int i = 0; i < activeCarbsList.size() && ac > 0; i++) { + CarbsInPast c = activeCarbsList.get(i); + if (c.remaining > 0) { + double sub = Math.min(ac, c.remaining); + c.remaining -= sub; + ac -= sub; + } + } + } + } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/IobCobCalculator/IobCobCalculatorFragment.java b/app/src/main/java/info/nightscout/androidaps/plugins/IobCobCalculator/IobCobCalculatorFragment.java deleted file mode 100644 index db1db95998..0000000000 --- a/app/src/main/java/info/nightscout/androidaps/plugins/IobCobCalculator/IobCobCalculatorFragment.java +++ /dev/null @@ -1,16 +0,0 @@ -package info.nightscout.androidaps.plugins.IobCobCalculator; - -import android.support.v4.app.Fragment; - -/** - * Created by adrian on 17/11/16. - */ - -public class IobCobCalculatorFragment extends Fragment { - - private static IobCobCalculatorPlugin iobCobCalculatorPlugin = new IobCobCalculatorPlugin(); - - public static IobCobCalculatorPlugin getPlugin() { - return iobCobCalculatorPlugin; - } -} 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 b8a28c671f..60779e85aa 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 @@ -25,10 +25,12 @@ import info.nightscout.androidaps.data.Profile; import info.nightscout.androidaps.db.BgReading; import info.nightscout.androidaps.db.TemporaryBasal; import info.nightscout.androidaps.db.Treatment; +import info.nightscout.androidaps.events.EventConfigBuilderChange; import info.nightscout.androidaps.events.EventNewBG; 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; @@ -55,7 +57,23 @@ public class IobCobCalculatorPlugin implements PluginBase { private static Handler sHandler = null; private static HandlerThread sHandlerThread = null; - private static Object dataLock = new Object(); + private static final Object dataLock = new Object(); + + private static IobCobCalculatorPlugin plugin = null; + + public static IobCobCalculatorPlugin getPlugin() { + if (plugin == null) + plugin = new IobCobCalculatorPlugin(); + return plugin; + } + + public static LongSparseArray getAutosensDataTable() { + return autosensDataTable; + } + + public static List getBucketedData() { + return bucketed_data; + } @Override public int getType() { @@ -64,7 +82,7 @@ public class IobCobCalculatorPlugin implements PluginBase { @Override public String getFragmentClass() { - return IobCobCalculatorFragment.class.getName(); + return null; } @Override @@ -112,7 +130,7 @@ public class IobCobCalculatorPlugin implements PluginBase { } - public IobCobCalculatorPlugin() { + IobCobCalculatorPlugin() { MainApp.bus().register(this); if (sHandlerThread == null) { sHandlerThread = new HandlerThread(IobCobCalculatorPlugin.class.getSimpleName()); @@ -190,14 +208,14 @@ public class IobCobCalculatorPlugin implements PluginBase { } } - public void createBucketedData() { + private void createBucketedData() { if (isAbout5minData()) createBucketedData5min(); else createBucketedDataRecalculated(); } - public void createBucketedDataRecalculated() { + private void createBucketedDataRecalculated() { synchronized (dataLock) { if (bgReadings == null || bgReadings.size() < 3) { bucketed_data = null; @@ -302,7 +320,7 @@ public class IobCobCalculatorPlugin implements PluginBase { //log.debug("Releasing createBucketedData"); } - public void calculateSensitivityData() { + private void calculateSensitivityData() { if (MainApp.getConfigBuilder() == null) return; // app still initializing if (MainApp.getConfigBuilder().getProfile() == null) @@ -337,6 +355,10 @@ public class IobCobCalculatorPlugin implements PluginBase { AutosensData autosensData = new AutosensData(); autosensData.time = bgTime; + if (previous != null) + autosensData.activeCarbsList = new ArrayList<>(previous.activeCarbsList); + else + autosensData.activeCarbsList = new ArrayList<>(); //console.error(bgTime , bucketed_data[i].glucose); double bg; @@ -357,17 +379,28 @@ public class IobCobCalculatorPlugin implements PluginBase { List recentTreatments = MainApp.getConfigBuilder().getTreatments5MinBackFromHistory(bgTime); for (int ir = 0; ir < recentTreatments.size(); ir++) { autosensData.carbsFromBolus += recentTreatments.get(ir).carbs; + autosensData.activeCarbsList.add(new AutosensData.CarbsInPast(recentTreatments.get(ir))); } + // if we are absorbing carbs if (previous != null && previous.cob > 0) { + // calculate sum of min carb impact from all active treatments + double totalMinCarbsImpact = 0d; + for (int ii = 0; ii < autosensData.activeCarbsList.size(); ++ii) { + AutosensData.CarbsInPast c = autosensData.activeCarbsList.get(ii); + totalMinCarbsImpact += c.min5minCarbImpact; + } + // figure out how many carbs that represents - // but always assume at least 3mg/dL/5m (default) absorption - double ci = Math.max(deviation, SP.getDouble("openapsama_min_5m_carbimpact", 3.0)); + // but always assume at least 3mg/dL/5m (default) absorption per active treatment + double ci = Math.max(deviation, totalMinCarbsImpact); autosensData.absorbed = ci * profile.getIc(bgTime) / sens; // and add that to the running total carbsAbsorbed autosensData.cob = Math.max(previous.cob - autosensData.absorbed, 0d); + autosensData.substractAbosorbedCarbs(); } + autosensData.removeOldCarbs(bgTime); autosensData.cob += autosensData.carbsFromBolus; autosensData.deviation = deviation; autosensData.bgi = bgi; @@ -465,6 +498,7 @@ public class IobCobCalculatorPlugin implements PluginBase { return retval; } + @Nullable public static AutosensData getAutosensData(long time) { long now = System.currentTimeMillis(); if (time > now) @@ -483,6 +517,7 @@ public class IobCobCalculatorPlugin implements PluginBase { } } + @Nullable public static AutosensData getLastAutosensData() { if (autosensDataTable.size() < 1) return null; @@ -517,106 +552,10 @@ public class IobCobCalculatorPlugin implements PluginBase { } } - public static AutosensResult detectSensitivity(long fromTime, long toTime) { - String age = SP.getString(R.string.key_age, ""); - int defaultHours = 24; - if (age.equals(MainApp.sResources.getString(R.string.key_adult))) defaultHours = 24; - if (age.equals(MainApp.sResources.getString(R.string.key_teenage))) defaultHours = 4; - if (age.equals(MainApp.sResources.getString(R.string.key_child))) defaultHours = 4; - int hoursForDetection = SP.getInt(R.string.key_openapsama_autosens_period, defaultHours); - - long now = System.currentTimeMillis(); - - if (autosensDataTable == null || autosensDataTable.size() < 4) { - log.debug("No autosens data available"); - return new AutosensResult(); - } - - AutosensData current = getAutosensData(toTime); - if (current == null) { - log.debug("No autosens data available"); - return new AutosensResult(); - } - - - List deviationsArray = new ArrayList<>(); - String pastSensitivity = ""; - int index = 0; - while (index < autosensDataTable.size()) { - AutosensData autosensData = autosensDataTable.valueAt(index); - - if (autosensData.time < fromTime) { - index++; - continue; - } - - if (autosensData.time > toTime) { - index++; - continue; - } - - if (autosensData.time > now - hoursForDetection * 60 * 60 * 1000L) - deviationsArray.add(autosensData.nonEqualDeviation ? autosensData.deviation : 0d); - if (deviationsArray.size() > hoursForDetection * 60 / 5) - deviationsArray.remove(0); - - - pastSensitivity += autosensData.pastSensitivity; - int secondsFromMidnight = Profile.secondsFromMidnight(autosensData.time); - if (secondsFromMidnight % 3600 < 2.5 * 60 || secondsFromMidnight % 3600 > 57.5 * 60) { - pastSensitivity += "(" + Math.round(secondsFromMidnight / 3600d) + ")"; - } - index++; - } - - Double[] deviations = new Double[deviationsArray.size()]; - deviations = deviationsArray.toArray(deviations); - - Profile profile = MainApp.getConfigBuilder().getProfile(); - - double sens = profile.getIsf(); - - String ratioLimit = ""; - String sensResult = ""; - - log.debug("Records: " + index + " " + pastSensitivity); - Arrays.sort(deviations); - - double percentile = percentile(deviations, 0.50); - double basalOff = percentile * (60 / 5) / Profile.toMgdl(sens, profile.getUnits()); - double ratio = 1 + (basalOff / profile.getMaxDailyBasal()); - - if (percentile < 0) { // sensitive - sensResult = "Excess insulin sensitivity detected"; - } else if (percentile > 0) { // resistant - sensResult = "Excess insulin resistance detected"; - } else { - sensResult = "Sensitivity normal"; - } - - log.debug(sensResult); - - double rawRatio = ratio; - ratio = Math.max(ratio, SafeParse.stringToDouble(SP.getString("openapsama_autosens_min", "0.7"))); - ratio = Math.min(ratio, SafeParse.stringToDouble(SP.getString("openapsama_autosens_max", "1.2"))); - - if (ratio != rawRatio) { - ratioLimit = "Ratio limited from " + rawRatio + " to " + ratio; - log.debug(ratioLimit); - } - - log.error("Sensitivity to: " + new Date(toTime).toLocaleString() + " percentile: " + percentile); - - AutosensResult output = new AutosensResult(); - output.ratio = Round.roundTo(ratio, 0.01); - output.carbsAbsorbed = Round.roundTo(current.cob, 0.01); - output.pastSensitivity = pastSensitivity; - output.ratioLimit = ratioLimit; - output.sensResult = sensResult; - return output; + private static AutosensResult detectSensitivity(long fromTime, long toTime) { + return ConfigBuilderPlugin.getActiveSensitivity().detectSensitivity(fromTime, toTime); } - public static JSONArray convertToJSONArray(IobTotal[] iobArray) { JSONArray array = new JSONArray(); for (int i = 0; i < iobArray.length; i++) { @@ -664,7 +603,8 @@ public class IobCobCalculatorPlugin implements PluginBase { @Subscribe public void onStatusEvent(EventPreferenceChange ev) { if (ev.isChanged(R.string.key_openapsama_autosens_period) || - ev.isChanged(R.string.key_age) + ev.isChanged(R.string.key_age) || + ev.isChanged(R.string.key_absorption_maxtime) ) { synchronized (dataLock) { log.debug("Invalidating cached data because of preference change. IOB: " + iobTable.size() + " Autosens: " + autosensDataTable.size() + " records"); @@ -680,6 +620,21 @@ public class IobCobCalculatorPlugin implements PluginBase { } } + @Subscribe + public void onStatusEvent(EventConfigBuilderChange ev) { + synchronized (dataLock) { + log.debug("Invalidating cached data because of configuration change. IOB: " + iobTable.size() + " Autosens: " + autosensDataTable.size() + " records"); + iobTable = new LongSparseArray<>(); + autosensDataTable = new LongSparseArray<>(); + } + sHandler.post(new Runnable() { + @Override + public void run() { + calculateSensitivityData(); + } + }); + } + // When historical data is changed (comming from NS etc) finished calculations after this date must be invalidated @Subscribe public void onNewHistoryData(EventNewHistoryData ev) { 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 cb127da990..c282b9a625 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 @@ -313,11 +313,14 @@ public class OverviewFragment extends Fragment implements View.OnClickListener, iobGraph.getGridLabelRenderer().setLabelVerticalWidth(50); iobGraph.getGridLabelRenderer().setNumVerticalLabels(5); + rangeToDisplay = SP.getInt(R.string.key_rangetodisplay, 6); + bgGraph.setOnLongClickListener(new View.OnLongClickListener() { @Override public boolean onLongClick(View v) { rangeToDisplay += 6; rangeToDisplay = rangeToDisplay > 24 ? 6 : rangeToDisplay; + SP.putInt(R.string.key_rangetodisplay, rangeToDisplay); updateGUI("rangeChange"); return false; } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/Persistentnotification/PersistentNotificationFragment.java b/app/src/main/java/info/nightscout/androidaps/plugins/Persistentnotification/PersistentNotificationFragment.java deleted file mode 100644 index 78e7791c2d..0000000000 --- a/app/src/main/java/info/nightscout/androidaps/plugins/Persistentnotification/PersistentNotificationFragment.java +++ /dev/null @@ -1,12 +0,0 @@ -package info.nightscout.androidaps.plugins.Persistentnotification; - -import android.support.v4.app.Fragment; - -/** - * Created by adrian on 23/12/16. - */ - -public class PersistentNotificationFragment extends Fragment { - - -} diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/Persistentnotification/PersistentNotificationPlugin.java b/app/src/main/java/info/nightscout/androidaps/plugins/Persistentnotification/PersistentNotificationPlugin.java index e64e3375e2..68d1ed487a 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/Persistentnotification/PersistentNotificationPlugin.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/Persistentnotification/PersistentNotificationPlugin.java @@ -54,7 +54,7 @@ public class PersistentNotificationPlugin implements PluginBase { @Override public String getFragmentClass() { - return PersistentNotificationFragment.class.getName(); + return null; } @Override diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/PumpMDI/MDIFragment.java b/app/src/main/java/info/nightscout/androidaps/plugins/PumpMDI/MDIFragment.java deleted file mode 100644 index f6221d627e..0000000000 --- a/app/src/main/java/info/nightscout/androidaps/plugins/PumpMDI/MDIFragment.java +++ /dev/null @@ -1,12 +0,0 @@ -package info.nightscout.androidaps.plugins.PumpMDI; - - -import android.support.v4.app.Fragment; - -public class MDIFragment extends Fragment { - private static MDIPlugin mdiPlugin = new MDIPlugin(); - - public static MDIPlugin getPlugin() { - return mdiPlugin; - } -} 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 b0c55ba036..b51a0bb66e 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 @@ -12,11 +12,11 @@ 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.interfaces.PluginBase; import info.nightscout.androidaps.interfaces.PumpDescription; import info.nightscout.androidaps.interfaces.PumpInterface; -import info.nightscout.androidaps.data.Profile; import info.nightscout.utils.DateUtil; /** @@ -30,6 +30,14 @@ public class MDIPlugin implements PluginBase, PumpInterface { PumpDescription pumpDescription = new PumpDescription(); + static MDIPlugin plugin = null; + + public static MDIPlugin getPlugin() { + if (plugin == null) + plugin = new MDIPlugin(); + return plugin; + } + public MDIPlugin() { pumpDescription.isBolusCapable = true; pumpDescription.bolusStep = 0.5d; @@ -42,7 +50,7 @@ public class MDIPlugin implements PluginBase, PumpInterface { @Override public String getFragmentClass() { - return MDIFragment.class.getName(); + return null; } @Override diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/SensitivityMK/SensitivityMKPlugin.java b/app/src/main/java/info/nightscout/androidaps/plugins/SensitivityMK/SensitivityMKPlugin.java new file mode 100644 index 0000000000..ac7f8ccb86 --- /dev/null +++ b/app/src/main/java/info/nightscout/androidaps/plugins/SensitivityMK/SensitivityMKPlugin.java @@ -0,0 +1,200 @@ +package info.nightscout.androidaps.plugins.SensitivityMK; + +import android.support.v4.util.LongSparseArray; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Date; +import java.util.List; + +import info.nightscout.androidaps.MainApp; +import info.nightscout.androidaps.R; +import info.nightscout.androidaps.data.Profile; +import info.nightscout.androidaps.interfaces.PluginBase; +import info.nightscout.androidaps.interfaces.SensitivityInterface; +import info.nightscout.androidaps.plugins.IobCobCalculator.AutosensData; +import info.nightscout.androidaps.plugins.IobCobCalculator.AutosensResult; +import info.nightscout.androidaps.plugins.IobCobCalculator.IobCobCalculatorPlugin; +import info.nightscout.utils.Round; +import info.nightscout.utils.SP; +import info.nightscout.utils.SafeParse; + +/** + * Created by mike on 24.06.2017. + */ + +public class SensitivityMKPlugin implements PluginBase, SensitivityInterface{ + private static Logger log = LoggerFactory.getLogger(SensitivityMKPlugin.class); + + private static boolean fragmentEnabled = true; + private static boolean fragmentVisible = false; + + static SensitivityMKPlugin plugin = null; + + public static SensitivityMKPlugin getPlugin() { + if (plugin == null) + plugin = new SensitivityMKPlugin(); + return plugin; + } + + @Override + public int getType() { + return INSULIN; + } + + @Override + public String getFragmentClass() { + return null; + } + + @Override + public String getName() { + return MainApp.sResources.getString(R.string.sensitivitymk); + } + + @Override + public String getNameShort() { + return MainApp.sResources.getString(R.string.sensitivity_shortname); + } + + @Override + public boolean isEnabled(int type) { + return type == SENSITIVITY && fragmentEnabled; + } + + @Override + public boolean isVisibleInTabs(int type) { + return type == SENSITIVITY && fragmentVisible; + } + + @Override + public boolean canBeHidden(int type) { + return true; + } + + @Override + public boolean hasFragment() { + return false; + } + + @Override + public boolean showInList(int type) { + return true; + } + + @Override + public void setFragmentEnabled(int type, boolean fragmentEnabled) { + if (type == SENSITIVITY) this.fragmentEnabled = fragmentEnabled; + } + + @Override + public void setFragmentVisible(int type, boolean fragmentVisible) { + if (type == SENSITIVITY) this.fragmentVisible = fragmentVisible; + } + + + @Override + public AutosensResult detectSensitivity(long fromTime, long toTime) { + LongSparseArray autosensDataTable = IobCobCalculatorPlugin.getAutosensDataTable(); + + String age = SP.getString(R.string.key_age, ""); + int defaultHours = 24; + if (age.equals(MainApp.sResources.getString(R.string.key_adult))) defaultHours = 24; + if (age.equals(MainApp.sResources.getString(R.string.key_teenage))) defaultHours = 4; + if (age.equals(MainApp.sResources.getString(R.string.key_child))) defaultHours = 4; + int hoursForDetection = SP.getInt(R.string.key_openapsama_autosens_period, defaultHours); + + long now = System.currentTimeMillis(); + + if (autosensDataTable == null || autosensDataTable.size() < 4) { + log.debug("No autosens data available"); + return new AutosensResult(); + } + + AutosensData current = IobCobCalculatorPlugin.getAutosensData(toTime); + if (current == null) { + log.debug("No autosens data available"); + return new AutosensResult(); + } + + + List deviationsArray = new ArrayList<>(); + String pastSensitivity = ""; + int index = 0; + while (index < autosensDataTable.size()) { + AutosensData autosensData = autosensDataTable.valueAt(index); + + if (autosensData.time < fromTime) { + index++; + continue; + } + + if (autosensData.time > toTime) { + index++; + continue; + } + + if (autosensData.time > now - hoursForDetection * 60 * 60 * 1000L) + deviationsArray.add(autosensData.nonEqualDeviation ? autosensData.deviation : 0d); + if (deviationsArray.size() > hoursForDetection * 60 / 5) + deviationsArray.remove(0); + + + pastSensitivity += autosensData.pastSensitivity; + int secondsFromMidnight = Profile.secondsFromMidnight(autosensData.time); + if (secondsFromMidnight % 3600 < 2.5 * 60 || secondsFromMidnight % 3600 > 57.5 * 60) { + pastSensitivity += "(" + Math.round(secondsFromMidnight / 3600d) + ")"; + } + index++; + } + + Double[] deviations = new Double[deviationsArray.size()]; + deviations = deviationsArray.toArray(deviations); + + Profile profile = MainApp.getConfigBuilder().getProfile(); + + double sens = profile.getIsf(); + + String ratioLimit = ""; + String sensResult = ""; + + log.debug("Records: " + index + " " + pastSensitivity); + Arrays.sort(deviations); + + double percentile = IobCobCalculatorPlugin.percentile(deviations, 0.50); + double basalOff = percentile * (60 / 5) / Profile.toMgdl(sens, profile.getUnits()); + double ratio = 1 + (basalOff / profile.getMaxDailyBasal()); + + if (percentile < 0) { // sensitive + sensResult = "Excess insulin sensitivity detected"; + } else if (percentile > 0) { // resistant + sensResult = "Excess insulin resistance detected"; + } else { + sensResult = "Sensitivity normal"; + } + + log.debug(sensResult); + + double rawRatio = ratio; + ratio = Math.max(ratio, SafeParse.stringToDouble(SP.getString("openapsama_autosens_min", "0.7"))); + ratio = Math.min(ratio, SafeParse.stringToDouble(SP.getString("openapsama_autosens_max", "1.2"))); + + if (ratio != rawRatio) { + ratioLimit = "Ratio limited from " + rawRatio + " to " + ratio; + log.debug(ratioLimit); + } + + log.error("Sensitivity to: " + new Date(toTime).toLocaleString() + " percentile: " + percentile); + + AutosensResult output = new AutosensResult(); + output.ratio = Round.roundTo(ratio, 0.01); + output.carbsAbsorbed = Round.roundTo(current.cob, 0.01); + output.pastSensitivity = pastSensitivity; + output.ratioLimit = ratioLimit; + output.sensResult = sensResult; + return output; + } +} diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/SensitivityOref0/SensitivityOref0Plugin.java b/app/src/main/java/info/nightscout/androidaps/plugins/SensitivityOref0/SensitivityOref0Plugin.java new file mode 100644 index 0000000000..5cf74be25d --- /dev/null +++ b/app/src/main/java/info/nightscout/androidaps/plugins/SensitivityOref0/SensitivityOref0Plugin.java @@ -0,0 +1,210 @@ +package info.nightscout.androidaps.plugins.SensitivityOref0; + +import android.support.v4.util.LongSparseArray; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import info.nightscout.androidaps.MainApp; +import info.nightscout.androidaps.R; +import info.nightscout.androidaps.data.Profile; +import info.nightscout.androidaps.interfaces.PluginBase; +import info.nightscout.androidaps.interfaces.SensitivityInterface; +import info.nightscout.androidaps.plugins.IobCobCalculator.AutosensData; +import info.nightscout.androidaps.plugins.IobCobCalculator.AutosensResult; +import info.nightscout.androidaps.plugins.IobCobCalculator.IobCobCalculatorPlugin; +import info.nightscout.utils.Round; +import info.nightscout.utils.SP; +import info.nightscout.utils.SafeParse; + +/** + * Created by mike on 24.06.2017. + */ + +public class SensitivityOref0Plugin implements PluginBase, SensitivityInterface { + private static Logger log = LoggerFactory.getLogger(IobCobCalculatorPlugin.class); + + private static boolean fragmentEnabled = true; + private static boolean fragmentVisible = false; + + static SensitivityOref0Plugin plugin = null; + + public static SensitivityOref0Plugin getPlugin() { + if (plugin == null) + plugin = new SensitivityOref0Plugin(); + return plugin; + } + + @Override + public int getType() { + return INSULIN; + } + + @Override + public String getFragmentClass() { + return null; + } + + @Override + public String getName() { + return MainApp.sResources.getString(R.string.sensitivityoref0); + } + + @Override + public String getNameShort() { + return MainApp.sResources.getString(R.string.sensitivity_shortname); + } + + @Override + public boolean isEnabled(int type) { + return type == SENSITIVITY && fragmentEnabled; + } + + @Override + public boolean isVisibleInTabs(int type) { + return type == SENSITIVITY && fragmentVisible; + } + + @Override + public boolean canBeHidden(int type) { + return true; + } + + @Override + public boolean hasFragment() { + return false; + } + + @Override + public boolean showInList(int type) { + return true; + } + + @Override + public void setFragmentEnabled(int type, boolean fragmentEnabled) { + if (type == SENSITIVITY) this.fragmentEnabled = fragmentEnabled; + } + + @Override + public void setFragmentVisible(int type, boolean fragmentVisible) { + if (type == SENSITIVITY) this.fragmentVisible = fragmentVisible; + } + + + @Override + public AutosensResult detectSensitivity(long fromTime, long toTime) { + LongSparseArray autosensDataTable = IobCobCalculatorPlugin.getAutosensDataTable(); + + String age = SP.getString(R.string.key_age, ""); + int defaultHours = 24; + if (age.equals(MainApp.sResources.getString(R.string.key_adult))) defaultHours = 24; + if (age.equals(MainApp.sResources.getString(R.string.key_teenage))) defaultHours = 24; + if (age.equals(MainApp.sResources.getString(R.string.key_child))) defaultHours = 24; + int hoursForDetection = SP.getInt(R.string.key_openapsama_autosens_period, defaultHours); + + long now = System.currentTimeMillis(); + + if (autosensDataTable == null || autosensDataTable.size() < 4) { + log.debug("No autosens data available"); + return new AutosensResult(); + } + + AutosensData current = IobCobCalculatorPlugin.getLastAutosensData(); + if (current == null) { + log.debug("No current autosens data available"); + return new AutosensResult(); + } + + + List deviationsArray = new ArrayList<>(); + String pastSensitivity = ""; + int index = 0; + while (index < autosensDataTable.size()) { + AutosensData autosensData = autosensDataTable.valueAt(index); + + if (autosensData.time < fromTime) { + index++; + continue; + } + + if (autosensData.time > toTime) { + index++; + continue; + } + + if (autosensData.time > now - hoursForDetection * 60 * 60 * 1000L) + deviationsArray.add(autosensData.nonEqualDeviation ? autosensData.deviation : 0d); + if (deviationsArray.size() > hoursForDetection * 60 / 5) + deviationsArray.remove(0); + + pastSensitivity += autosensData.pastSensitivity; + int secondsFromMidnight = Profile.secondsFromMidnight(autosensData.time); + if (secondsFromMidnight % 3600 < 2.5 * 60 || secondsFromMidnight % 3600 > 57.5 * 60) { + pastSensitivity += "(" + Math.round(secondsFromMidnight / 3600d) + ")"; + } + index++; + } + + Double[] deviations = new Double[deviationsArray.size()]; + deviations = deviationsArray.toArray(deviations); + + Profile profile = MainApp.getConfigBuilder().getProfile(); + + double sens = profile.getIsf(); + + double ratio = 1; + String ratioLimit = ""; + String sensResult = ""; + + log.debug("Records: " + index + " " + pastSensitivity); + Arrays.sort(deviations); + + for (double i = 0.9; i > 0.1; i = i - 0.02) { + if (IobCobCalculatorPlugin.percentile(deviations, (i + 0.02)) >= 0 && IobCobCalculatorPlugin.percentile(deviations, i) < 0) { + log.debug(Math.round(100 * i) + "% of non-meal deviations negative (target 45%-50%)"); + } + } + double pSensitive = IobCobCalculatorPlugin.percentile(deviations, 0.50); + double pResistant = IobCobCalculatorPlugin.percentile(deviations, 0.45); + + double basalOff = 0; + + if (pSensitive < 0) { // sensitive + basalOff = pSensitive * (60 / 5) / Profile.toMgdl(sens, profile.getUnits()); + sensResult = "Excess insulin sensitivity detected"; + } else if (pResistant > 0) { // resistant + basalOff = pResistant * (60 / 5) / Profile.toMgdl(sens, profile.getUnits()); + sensResult = "Excess insulin resistance detected"; + } else { + sensResult = "Sensitivity normal"; + } + log.debug(sensResult); + ratio = 1 + (basalOff / profile.getMaxDailyBasal()); + + double rawRatio = ratio; + ratio = Math.max(ratio, SafeParse.stringToDouble(SP.getString("openapsama_autosens_min", "0.7"))); + ratio = Math.min(ratio, SafeParse.stringToDouble(SP.getString("openapsama_autosens_max", "1.2"))); + + if (ratio != rawRatio) { + ratioLimit = "Ratio limited from " + rawRatio + " to " + ratio; + log.debug(ratioLimit); + } + + double newisf = Math.round(Profile.toMgdl(sens, profile.getUnits()) / ratio); + if (ratio != 1) { + log.debug("ISF adjusted from " + Profile.toMgdl(sens, profile.getUnits()) + " to " + newisf); + } + + AutosensResult output = new AutosensResult(); + output.ratio = Round.roundTo(ratio, 0.01); + output.carbsAbsorbed = Round.roundTo(current.cob, 0.01); + output.pastSensitivity = pastSensitivity; + output.ratioLimit = ratioLimit; + output.sensResult = sensResult; + return output; + } +} diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/SourceGlimp/SourceGlimpFragment.java b/app/src/main/java/info/nightscout/androidaps/plugins/SourceGlimp/SourceGlimpFragment.java deleted file mode 100644 index 63ab27deee..0000000000 --- a/app/src/main/java/info/nightscout/androidaps/plugins/SourceGlimp/SourceGlimpFragment.java +++ /dev/null @@ -1,14 +0,0 @@ -package info.nightscout.androidaps.plugins.SourceGlimp; - - -import android.support.v4.app.Fragment; - -public class SourceGlimpFragment extends Fragment { - - private static SourceGlimpPlugin sourceGlimpPlugin = new SourceGlimpPlugin(); - - public static SourceGlimpPlugin getPlugin() { - return sourceGlimpPlugin; - } - -} diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/SourceGlimp/SourceGlimpPlugin.java b/app/src/main/java/info/nightscout/androidaps/plugins/SourceGlimp/SourceGlimpPlugin.java index 3c1248c4de..0f914feddc 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/SourceGlimp/SourceGlimpPlugin.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/SourceGlimp/SourceGlimpPlugin.java @@ -4,7 +4,6 @@ import info.nightscout.androidaps.MainApp; import info.nightscout.androidaps.R; import info.nightscout.androidaps.interfaces.BgSourceInterface; import info.nightscout.androidaps.interfaces.PluginBase; -import info.nightscout.androidaps.plugins.SourceMM640g.SourceMM640gFragment; /** * Created by mike on 05.08.2016. @@ -12,9 +11,17 @@ import info.nightscout.androidaps.plugins.SourceMM640g.SourceMM640gFragment; public class SourceGlimpPlugin implements PluginBase, BgSourceInterface { boolean fragmentEnabled = false; + static SourceGlimpPlugin plugin = null; + + public static SourceGlimpPlugin getPlugin() { + if (plugin == null) + plugin = new SourceGlimpPlugin(); + return plugin; + } + @Override public String getFragmentClass() { - return SourceGlimpFragment.class.getName(); + return null; } @Override diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/SourceMM640g/SourceMM640gFragment.java b/app/src/main/java/info/nightscout/androidaps/plugins/SourceMM640g/SourceMM640gFragment.java deleted file mode 100644 index 28bfabf813..0000000000 --- a/app/src/main/java/info/nightscout/androidaps/plugins/SourceMM640g/SourceMM640gFragment.java +++ /dev/null @@ -1,14 +0,0 @@ -package info.nightscout.androidaps.plugins.SourceMM640g; - - -import android.support.v4.app.Fragment; - -public class SourceMM640gFragment extends Fragment { - - private static SourceMM640gPlugin sourceMM640gPlugin = new SourceMM640gPlugin(); - - public static SourceMM640gPlugin getPlugin() { - return sourceMM640gPlugin; - } - -} diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/SourceMM640g/SourceMM640gPlugin.java b/app/src/main/java/info/nightscout/androidaps/plugins/SourceMM640g/SourceMM640gPlugin.java index df8111b5cd..fcef6a565b 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/SourceMM640g/SourceMM640gPlugin.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/SourceMM640g/SourceMM640gPlugin.java @@ -4,7 +4,7 @@ import info.nightscout.androidaps.MainApp; import info.nightscout.androidaps.R; import info.nightscout.androidaps.interfaces.BgSourceInterface; import info.nightscout.androidaps.interfaces.PluginBase; -import info.nightscout.androidaps.plugins.SourceNSClient.SourceNSClientFragment; +import info.nightscout.androidaps.plugins.SourceGlimp.SourceGlimpPlugin; /** * Created by mike on 05.08.2016. @@ -12,9 +12,17 @@ import info.nightscout.androidaps.plugins.SourceNSClient.SourceNSClientFragment; public class SourceMM640gPlugin implements PluginBase, BgSourceInterface { boolean fragmentEnabled = false; + static SourceGlimpPlugin plugin = null; + + public static SourceGlimpPlugin getPlugin() { + if (plugin == null) + plugin = new SourceGlimpPlugin(); + return plugin; + } + @Override public String getFragmentClass() { - return SourceMM640gFragment.class.getName(); + return null; } @Override diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/SourceNSClient/SourceNSClientFragment.java b/app/src/main/java/info/nightscout/androidaps/plugins/SourceNSClient/SourceNSClientFragment.java deleted file mode 100644 index b2eddc09fc..0000000000 --- a/app/src/main/java/info/nightscout/androidaps/plugins/SourceNSClient/SourceNSClientFragment.java +++ /dev/null @@ -1,14 +0,0 @@ -package info.nightscout.androidaps.plugins.SourceNSClient; - - -import android.support.v4.app.Fragment; - -public class SourceNSClientFragment extends Fragment { - - private static SourceNSClientPlugin sourceNSClientPlugin = new SourceNSClientPlugin(); - - public static SourceNSClientPlugin getPlugin() { - return sourceNSClientPlugin; - } - -} diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/SourceNSClient/SourceNSClientPlugin.java b/app/src/main/java/info/nightscout/androidaps/plugins/SourceNSClient/SourceNSClientPlugin.java index 62ae6b93da..a10d0d1d1e 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/SourceNSClient/SourceNSClientPlugin.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/SourceNSClient/SourceNSClientPlugin.java @@ -12,9 +12,17 @@ import info.nightscout.androidaps.interfaces.PluginBase; public class SourceNSClientPlugin implements PluginBase, BgSourceInterface { boolean fragmentEnabled = true; + static SourceNSClientPlugin plugin = null; + + public static SourceNSClientPlugin getPlugin() { + if (plugin == null) + plugin = new SourceNSClientPlugin(); + return plugin; + } + @Override public String getFragmentClass() { - return SourceNSClientFragment.class.getName(); + return null; } @Override diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/SourceXdrip/SourceXdripFragment.java b/app/src/main/java/info/nightscout/androidaps/plugins/SourceXdrip/SourceXdripFragment.java deleted file mode 100644 index c9be1298d2..0000000000 --- a/app/src/main/java/info/nightscout/androidaps/plugins/SourceXdrip/SourceXdripFragment.java +++ /dev/null @@ -1,13 +0,0 @@ -package info.nightscout.androidaps.plugins.SourceXdrip; - - -import android.support.v4.app.Fragment; - -public class SourceXdripFragment extends Fragment { - - private static SourceXdripPlugin sourceXdripPlugin = new SourceXdripPlugin(); - - public static SourceXdripPlugin getPlugin() { - return sourceXdripPlugin; - } -} diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/SourceXdrip/SourceXdripPlugin.java b/app/src/main/java/info/nightscout/androidaps/plugins/SourceXdrip/SourceXdripPlugin.java index b32040a2e8..6d214dc028 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/SourceXdrip/SourceXdripPlugin.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/SourceXdrip/SourceXdripPlugin.java @@ -4,16 +4,23 @@ import info.nightscout.androidaps.MainApp; import info.nightscout.androidaps.R; import info.nightscout.androidaps.interfaces.BgSourceInterface; import info.nightscout.androidaps.interfaces.PluginBase; -import info.nightscout.androidaps.plugins.SourceNSClient.SourceNSClientFragment; /** * Created by mike on 05.08.2016. */ public class SourceXdripPlugin implements PluginBase, BgSourceInterface { + static SourceXdripPlugin plugin = null; + + public static SourceXdripPlugin getPlugin() { + if (plugin == null) + plugin = new SourceXdripPlugin(); + return plugin; + } + @Override public String getFragmentClass() { - return SourceNSClientFragment.class.getName(); + return null; } private static boolean fragmentEnabled = false; diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/XDripStatusline/StatuslineFragment.java b/app/src/main/java/info/nightscout/androidaps/plugins/XDripStatusline/StatuslineFragment.java deleted file mode 100644 index ba2cbc0783..0000000000 --- a/app/src/main/java/info/nightscout/androidaps/plugins/XDripStatusline/StatuslineFragment.java +++ /dev/null @@ -1,29 +0,0 @@ -package info.nightscout.androidaps.plugins.XDripStatusline; - -import android.content.Context; -import android.os.Bundle; -import android.support.v4.app.Fragment; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; - -import info.nightscout.androidaps.R; - -/** - * Created by adrian on 17/11/16. - */ - -public class StatuslineFragment extends Fragment { - - private static StatuslinePlugin statuslinePlugin; - - public static StatuslinePlugin getPlugin(Context ctx) { - - if (statuslinePlugin == null) { - statuslinePlugin = new StatuslinePlugin(ctx); - } - - return statuslinePlugin; - } - -} diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/XDripStatusline/StatuslinePlugin.java b/app/src/main/java/info/nightscout/androidaps/plugins/XDripStatusline/StatuslinePlugin.java index 1d3e427f1b..3f35d2af42 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/XDripStatusline/StatuslinePlugin.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/XDripStatusline/StatuslinePlugin.java @@ -44,6 +44,17 @@ public class StatuslinePlugin implements PluginBase { private final Context ctx; SharedPreferences mPrefs; + private static StatuslinePlugin statuslinePlugin; + + public static StatuslinePlugin getPlugin(Context ctx) { + + if (statuslinePlugin == null) { + statuslinePlugin = new StatuslinePlugin(ctx); + } + + return statuslinePlugin; + } + StatuslinePlugin(Context ctx) { this.ctx = ctx; this.mPrefs = PreferenceManager.getDefaultSharedPreferences(ctx); @@ -56,7 +67,7 @@ public class StatuslinePlugin implements PluginBase { @Override public String getFragmentClass() { - return StatuslineFragment.class.getName(); + return null; } @Override diff --git a/app/src/main/java/info/nightscout/utils/SP.java b/app/src/main/java/info/nightscout/utils/SP.java index 4733c42d04..acb727d864 100644 --- a/app/src/main/java/info/nightscout/utils/SP.java +++ b/app/src/main/java/info/nightscout/utils/SP.java @@ -49,11 +49,19 @@ public class SP { } static public int getInt(int resourceID, Integer defaultValue) { - return SafeParse.stringToInt(sharedPreferences.getString(MainApp.sResources.getString(resourceID), defaultValue.toString())); + try { + return sharedPreferences.getInt(MainApp.sResources.getString(resourceID), defaultValue); + } catch (Exception e) { + return SafeParse.stringToInt(sharedPreferences.getString(MainApp.sResources.getString(resourceID), defaultValue.toString())); + } } static public int getInt(String key, Integer defaultValue) { - return SafeParse.stringToInt(sharedPreferences.getString(key, defaultValue.toString())); + try { + return sharedPreferences.getInt(key, defaultValue); + } catch (Exception e) { + return SafeParse.stringToInt(sharedPreferences.getString(key, defaultValue.toString())); + } } static public long getLong(int resourceID, Long defaultValue) { @@ -92,6 +100,24 @@ public class SP { editor.apply(); } + static public void putLong(int resourceID, long value) { + SharedPreferences.Editor editor = sharedPreferences.edit(); + editor.putLong(MainApp.sResources.getString(resourceID), value); + editor.apply(); + } + + static public void putInt(String key, int value) { + SharedPreferences.Editor editor = sharedPreferences.edit(); + editor.putInt(key, value); + editor.apply(); + } + + static public void putInt(int resourceID, int value) { + SharedPreferences.Editor editor = sharedPreferences.edit(); + editor.putInt(MainApp.sResources.getString(resourceID), value); + editor.apply(); + } + static public void putString(int resourceID, String value) { SharedPreferences.Editor editor = sharedPreferences.edit(); editor.putString(MainApp.sResources.getString(resourceID), value); diff --git a/app/src/main/res/layout/configbuilder_fragment.xml b/app/src/main/res/layout/configbuilder_fragment.xml index 64841fe593..e4de98b02e 100644 --- a/app/src/main/res/layout/configbuilder_fragment.xml +++ b/app/src/main/res/layout/configbuilder_fragment.xml @@ -41,7 +41,6 @@ android:layout_marginRight="10dp" android:background="@color/cardColorBackground" /> - + + + OpenAPS Device Uploader + Sensitivity detection + SENS + Sensitivity Oref0 + Sensitivity MK + Absorption settings + absorption_maxtime + Meal max absorption time + Time in hours where is expected all carbs from meal will be absorbed + rangetodisplay diff --git a/app/src/main/res/xml/pref_absorption.xml b/app/src/main/res/xml/pref_absorption.xml new file mode 100644 index 0000000000..f86a21ec88 --- /dev/null +++ b/app/src/main/res/xml/pref_absorption.xml @@ -0,0 +1,35 @@ + + + + + + + + + diff --git a/app/src/main/res/xml/pref_openapsama.xml b/app/src/main/res/xml/pref_openapsama.xml index b9576242dc..c861cac8be 100644 --- a/app/src/main/res/xml/pref_openapsama.xml +++ b/app/src/main/res/xml/pref_openapsama.xml @@ -10,21 +10,6 @@ android:key="openapsama_useautosens" android:title="@string/openapsama_useautosens" /> - - \ No newline at end of file