package info.nightscout.androidaps.plugins.ConfigBuilder;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.os.PowerManager;
import android.preference.PreferenceManager;
import android.support.annotation.Nullable;
import android.support.v7.app.AppCompatActivity;
import com.squareup.otto.Subscribe;
import org.json.JSONException;
import org.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.Date;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
import info.nightscout.androidaps.Config;
import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.R;
import info.nightscout.androidaps.Services.Intents;
import info.nightscout.androidaps.data.PumpEnactResult;
import info.nightscout.androidaps.db.TempBasal;
import info.nightscout.androidaps.db.Treatment;
import info.nightscout.androidaps.events.EventBolusRequested;
import info.nightscout.androidaps.events.EventNewBG;
import info.nightscout.androidaps.events.EventTempBasalChange;
import info.nightscout.androidaps.events.EventTreatmentChange;
import info.nightscout.androidaps.interfaces.APSInterface;
import info.nightscout.androidaps.interfaces.BgSourceInterface;
import info.nightscout.androidaps.interfaces.ConstraintsInterface;
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.TempBasalsInterface;
import info.nightscout.androidaps.interfaces.TreatmentsInterface;
import info.nightscout.androidaps.plugins.DanaR.comm.MsgError;
import info.nightscout.androidaps.plugins.Loop.APSResult;
import info.nightscout.androidaps.plugins.Loop.DeviceStatus;
import info.nightscout.androidaps.plugins.Loop.LoopPlugin;
import info.nightscout.androidaps.plugins.OpenAPSAMA.DetermineBasalResultAMA;
import info.nightscout.androidaps.plugins.OpenAPSMA.DetermineBasalResultMA;
import info.nightscout.androidaps.plugins.Overview.Dialogs.BolusProgressDialog;
import info.nightscout.androidaps.plugins.Overview.Dialogs.BolusProgressHelperActivity;
import info.nightscout.androidaps.plugins.Overview.Notification;
import info.nightscout.androidaps.plugins.Overview.events.EventDismissBolusprogressIfRunning;
import info.nightscout.androidaps.plugins.Overview.events.EventDismissNotification;
import info.nightscout.androidaps.plugins.Overview.events.EventNewNotification;
import info.nightscout.androidaps.plugins.NSClientInternal.data.DbLogger;
import info.nightscout.androidaps.plugins.NSClientInternal.data.NSProfile;
import info.nightscout.utils.BatteryLevel;
import info.nightscout.utils.DateUtil;
/**
* Created by mike on 05.08.2016.
*/
public class ConfigBuilderPlugin implements PluginBase, PumpInterface, ConstraintsInterface {
private static Logger log = LoggerFactory.getLogger(ConfigBuilderPlugin.class);
static BgSourceInterface activeBgSource;
static PumpInterface activePump;
static ProfileInterface activeProfile;
static TreatmentsInterface activeTreatments;
static TempBasalsInterface activeTempBasals;
static APSInterface activeAPS;
static LoopPlugin activeLoop;
static public String nightscoutVersionName = "";
static public Integer nightscoutVersionCode = 0;
static public String nsClientVersionName = "";
static public Integer nsClientVersionCode = 0;
static ArrayList<PluginBase> pluginList;
PowerManager.WakeLock mWakeLock;
public ConfigBuilderPlugin() {
MainApp.bus().register(this);
PowerManager powerManager = (PowerManager) MainApp.instance().getApplicationContext().getSystemService(Context.POWER_SERVICE);
mWakeLock = powerManager.newWakeLock(PowerManager.SCREEN_DIM_WAKE_LOCK, "ConfigBuilderPlugin");
;
}
@Override
public int getType() {
return PluginBase.GENERAL;
}
@Override
public String getFragmentClass() {
return ConfigBuilderFragment.class.getName();
}
@Override
public String getName() {
return MainApp.instance().getString(R.string.configbuilder);
}
@Override
public String getNameShort() {
String name = MainApp.sResources.getString(R.string.configbuilder_shortname);
if (!name.trim().isEmpty()) {
//only if translation exists
return name;
}
// use long name as fallback
return getName();
}
@Override
public boolean isEnabled(int type) {
return type == GENERAL && true;
}
@Override
public boolean isVisibleInTabs(int type) {
return type == GENERAL && true;
}
@Override
public boolean canBeHidden(int type) {
return false;
}
@Override
public void setFragmentEnabled(int type, boolean fragmentEnabled) {
// Always enabled
}
@Override
public void setFragmentVisible(int type, boolean fragmentVisible) {
// Always visible
}
public void initialize() {
pluginList = MainApp.getPluginsList();
loadSettings();
}
public void storeSettings() {
if (pluginList != null) {
if (Config.logPrefsChange)
log.debug("Storing settings");
SharedPreferences settings = PreferenceManager.getDefaultSharedPreferences(MainApp.instance().getApplicationContext());
SharedPreferences.Editor editor = settings.edit();
for (int type = 1; type < PluginBase.LAST; type++) {
for (PluginBase p : pluginList) {
String settingEnabled = "ConfigBuilder_" + type + "_" + p.getClass().getSimpleName() + "_Enabled";
String settingVisible = "ConfigBuilder_" + type + "_" + p.getClass().getSimpleName() + "_Visible";
editor.putBoolean(settingEnabled, p.isEnabled(type));
editor.putBoolean(settingVisible, p.isVisibleInTabs(type));
}
}
editor.apply();
verifySelectionInCategories();
}
}
private void loadSettings() {
if (Config.logPrefsChange)
log.debug("Loading stored settings");
SharedPreferences SP = PreferenceManager.getDefaultSharedPreferences(MainApp.instance().getApplicationContext());
for (int type = 1; type < PluginBase.LAST; type++) {
for (PluginBase p : pluginList) {
try {
String settingEnabled = "ConfigBuilder_" + type + "_" + p.getClass().getSimpleName() + "_Enabled";
String settingVisible = "ConfigBuilder_" + type + "_" + p.getClass().getSimpleName() + "_Visible";
if (SP.contains(settingEnabled))
p.setFragmentEnabled(type, SP.getBoolean(settingEnabled, true));
if (SP.contains(settingVisible))
p.setFragmentVisible(type, SP.getBoolean(settingVisible, true));
} catch (Exception e) {
e.printStackTrace();
}
}
}
verifySelectionInCategories();
}
public static BgSourceInterface getActiveBgSource() {
return activeBgSource;
}
@Nullable
public static ProfileInterface getActiveProfile() {
return activeProfile;
}
public static TreatmentsInterface getActiveTreatments() {
return activeTreatments;
}
public static TempBasalsInterface getActiveTempBasals() {
return activeTempBasals;
}
public static APSInterface getActiveAPS() {
return activeAPS;
}
public static LoopPlugin getActiveLoop() {
return activeLoop;
}
public void logPluginStatus() {
for (PluginBase p : pluginList) {
log.debug(p.getName() + ":" +
(p.isEnabled(1) ? " GENERAL" : "") +
(p.isEnabled(2) ? " TREATMENT" : "") +
(p.isEnabled(3) ? " TEMPBASAL" : "") +
(p.isEnabled(4) ? " PROFILE" : "") +
(p.isEnabled(5) ? " APS" : "") +
(p.isEnabled(6) ? " PUMP" : "") +
(p.isEnabled(7) ? " CONSTRAINTS" : "") +
(p.isEnabled(8) ? " LOOP" : "") +
(p.isEnabled(9) ? " BGSOURCE" : "")
);
}
}
private void verifySelectionInCategories() {
ArrayList<PluginBase> pluginsInCategory;
// PluginBase.APS
pluginsInCategory = MainApp.getSpecificPluginsListByInterface(APSInterface.class);
activeAPS = (APSInterface) getTheOneEnabledInArray(pluginsInCategory, PluginBase.APS);
if (activeAPS != null) {
if (Config.logConfigBuilder)
log.debug("Selected APS interface: " + ((PluginBase) activeAPS).getName());
for (PluginBase p : pluginsInCategory) {
if (!p.getName().equals(((PluginBase) activeAPS).getName())) {
p.setFragmentVisible(PluginBase.APS, false);
}
}
}
// PluginBase.PROFILE
pluginsInCategory = MainApp.getSpecificPluginsListByInterface(ProfileInterface.class);
activeProfile = (ProfileInterface) getTheOneEnabledInArray(pluginsInCategory, PluginBase.PROFILE);
if (Config.logConfigBuilder)
log.debug("Selected profile interface: " + ((PluginBase) activeProfile).getName());
for (PluginBase p : pluginsInCategory) {
if (!p.getName().equals(((PluginBase) activeProfile).getName())) {
p.setFragmentVisible(PluginBase.PROFILE, false);
}
}
// PluginBase.BGSOURCE
pluginsInCategory = MainApp.getSpecificPluginsListByInterface(BgSourceInterface.class);
activeBgSource = (BgSourceInterface) getTheOneEnabledInArray(pluginsInCategory, PluginBase.BGSOURCE);
if (Config.logConfigBuilder)
log.debug("Selected bgSource interface: " + ((PluginBase) activeBgSource).getName());
for (PluginBase p : pluginsInCategory) {
if (!p.getName().equals(((PluginBase) activeBgSource).getName())) {
p.setFragmentVisible(PluginBase.BGSOURCE, false);
}
}
// PluginBase.PUMP
pluginsInCategory = MainApp.getSpecificPluginsList(PluginBase.PUMP);
activePump = (PumpInterface) getTheOneEnabledInArray(pluginsInCategory, PluginBase.PUMP);
if (Config.logConfigBuilder && activePump != null)
log.debug("Selected pump interface: " + ((PluginBase) activePump).getName());
for (PluginBase p : pluginsInCategory) {
if (!p.getName().equals(((PluginBase) activePump).getName())) {
p.setFragmentVisible(PluginBase.PUMP, false);
}
}
// PluginBase.LOOP
pluginsInCategory = MainApp.getSpecificPluginsList(PluginBase.LOOP);
activeLoop = (LoopPlugin) getTheOneEnabledInArray(pluginsInCategory, PluginBase.LOOP);
if (activeLoop != null) {
if (Config.logConfigBuilder)
log.debug("Selected loop interface: " + activeLoop.getName());
for (PluginBase p : pluginsInCategory) {
if (!p.getName().equals(activeLoop.getName())) {
p.setFragmentVisible(PluginBase.LOOP, false);
}
}
}
// PluginBase.TEMPBASAL
pluginsInCategory = MainApp.getSpecificPluginsList(PluginBase.TEMPBASAL);
activeTempBasals = (TempBasalsInterface) getTheOneEnabledInArray(pluginsInCategory, PluginBase.TEMPBASAL);
if (Config.logConfigBuilder && activeTempBasals != null)
log.debug("Selected tempbasal interface: " + ((PluginBase) activeTempBasals).getName());
for (PluginBase p : pluginsInCategory) {
if (!p.getName().equals(((PluginBase) activeTempBasals).getName())) {
p.setFragmentVisible(PluginBase.TEMPBASAL, false);
}
}
// PluginBase.TREATMENT
pluginsInCategory = MainApp.getSpecificPluginsList(PluginBase.TREATMENT);
activeTreatments = (TreatmentsInterface) getTheOneEnabledInArray(pluginsInCategory, PluginBase.TREATMENT);
if (Config.logConfigBuilder)
log.debug("Selected treatment interface: " + ((PluginBase) activeTreatments).getName());
for (PluginBase p : pluginsInCategory) {
if (!p.getName().equals(((PluginBase) activeTreatments).getName())) {
p.setFragmentVisible(PluginBase.TREATMENT, false);
}
}
}
@Nullable
private PluginBase getTheOneEnabledInArray(ArrayList<PluginBase> pluginsInCategory, int type) {
PluginBase found = null;
for (PluginBase p : pluginsInCategory) {
if (p.isEnabled(type) && found == null) {
found = p;
} else if (p.isEnabled(type)) {
// set others disabled
p.setFragmentEnabled(type, false);
}
}
// If none enabled, enable first one
if (found == null && pluginsInCategory.size() > 0)
found = pluginsInCategory.get(0);
return found;
}
/*
* Pump interface
*
* Config builder return itself as a pump and check constraints before it passes command to pump driver
*/
@Override
public boolean isInitialized() {
if (activePump != null)
return activePump.isInitialized();
else return true;
}
@Override
public boolean isSuspended() {
if (activePump != null)
return activePump.isSuspended();
else return false;
}
@Override
public boolean isBusy() {
if (activePump != null)
return activePump.isBusy();
else return false;
}
@Override
public boolean isTempBasalInProgress() {
if (activePump != null)
return activePump.isTempBasalInProgress();
else return false;
}
@Override
public boolean isExtendedBoluslInProgress() {
if (activePump != null)
return activePump.isExtendedBoluslInProgress();
else return false;
}
@Override
public int setNewBasalProfile(NSProfile profile) {
// Compare with pump limits
NSProfile.BasalValue[] basalValues = profile.getBasalValues();
for (int index = 0; index < basalValues.length; index++) {
if (basalValues[index].value < getPumpDescription().basalMinimumRate) {
Notification notification = new Notification(Notification.BASAL_VALUE_BELOW_MINIMUM, MainApp.sResources.getString(R.string.basalvaluebelowminimum), Notification.URGENT);
MainApp.bus().post(new EventNewNotification(notification));
return FAILED;
}
}
MainApp.bus().post(new EventDismissNotification(Notification.BASAL_VALUE_BELOW_MINIMUM));
if (isThisProfileSet(profile)) {
log.debug("Correct profile already set");
return NOT_NEEDED;
} else if (activePump != null) {
return activePump.setNewBasalProfile(profile);
} else
return SUCCESS;
}
@Override
public boolean isThisProfileSet(NSProfile profile) {
if (activePump != null)
return activePump.isThisProfileSet(profile);
else return true;
}
@Override
public Date lastDataTime() {
if (activePump != null)
return activePump.lastDataTime();
else return new Date();
}
@Override
public void refreshDataFromPump(String reason) {
if (activePump != null)
activePump.refreshDataFromPump(reason);
}
@Override
public double getBaseBasalRate() {
if (activePump != null)
return activePump.getBaseBasalRate();
else
return 0d;
}
@Override
public double getTempBasalAbsoluteRate() {
if (activePump != null)
return activePump.getTempBasalAbsoluteRate();
else
return 0d;
}
@Override
public double getTempBasalRemainingMinutes() {
if (activePump != null)
return activePump.getTempBasalRemainingMinutes();
else
return 0d;
}
@Override
public TempBasal getTempBasal(Date time) {
if (activePump != null)
return activePump.getTempBasal(time);
else
return null;
}
@Override
public TempBasal getTempBasal() {
if (activePump != null)
return activePump.getTempBasal();
else
return null;
}
@Override
public TempBasal getExtendedBolus() {
if (activePump != null)
return activePump.getExtendedBolus();
else
return null;
}
public PumpEnactResult deliverTreatmentFromBolusWizard(Context context, Double insulin, Integer carbs, Double glucose, String glucoseType, int carbTime, JSONObject boluscalc) {
mWakeLock.acquire();
PumpEnactResult result;
if (activePump != null) {
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(insulin, carbs, context);
BolusProgressDialog.bolusEnded = true;
MainApp.bus().post(new EventDismissBolusprogressIfRunning(result));
if (result.success) {
Treatment t = new Treatment();
t.insulin = result.bolusDelivered;
if (carbTime == 0)
t.carbs = (double) result.carbsDelivered; // with different carbTime record will come back from nightscout
t.created_at = new Date();
t.mealBolus = result.carbsDelivered > 0;
MainApp.getDbHelper().create(t);
t.setTimeIndex(t.getTimeIndex());
t.carbs = (double) result.carbsDelivered;
uploadBolusWizardRecord(t, glucose, glucoseType, carbTime, boluscalc);
}
} else {
if (Config.logCongigBuilderActions)
log.debug("Creating treatment: " + insulin + " carbs: " + carbs);
Treatment t = new Treatment();
t.insulin = insulin;
t.carbs = (double) carbs;
t.created_at = new Date();
t.mealBolus = t.carbs > 0;
MainApp.getDbHelper().create(t);
t.setTimeIndex(t.getTimeIndex());
t.sendToNSClient();
result = new PumpEnactResult();
result.success = true;
result.bolusDelivered = insulin;
result.carbsDelivered = carbs;
}
mWakeLock.release();
return result;
}
@Override
public PumpEnactResult deliverTreatment(Double insulin, Integer carbs, Context context) {
return deliverTreatment(insulin, carbs, context, true);
}
public PumpEnactResult deliverTreatment(Double insulin, Integer carbs, Context context, boolean createTreatment) {
mWakeLock.acquire();
PumpEnactResult result;
if (activePump != null) {
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(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();
t.insulin = result.bolusDelivered;
t.carbs = (double) result.carbsDelivered;
t.created_at = new Date();
t.mealBolus = t.carbs > 0;
MainApp.getDbHelper().create(t);
t.setTimeIndex(t.getTimeIndex());
t.sendToNSClient();
}
} else {
if (Config.logCongigBuilderActions)
log.debug("Creating treatment: " + insulin + " carbs: " + carbs);
Treatment t = new Treatment();
t.insulin = insulin;
t.carbs = (double) carbs;
t.created_at = new Date();
t.mealBolus = t.carbs > 0;
MainApp.getDbHelper().create(t);
t.setTimeIndex(t.getTimeIndex());
t.sendToNSClient();
result = new PumpEnactResult();
result.success = true;
result.bolusDelivered = insulin;
result.carbsDelivered = carbs;
}
mWakeLock.release();
return result;
}
@Override
public void stopBolusDelivering() {
activePump.stopBolusDelivering();
}
/**
* apply constraints, set temp based on absolute valus and expecting absolute result
*
* @param absoluteRate
* @param durationInMinutes
* @return
*/
@Override
public PumpEnactResult setTempBasalAbsolute(Double absoluteRate, Integer durationInMinutes) {
Double rateAfterConstraints = applyBasalConstraints(absoluteRate);
PumpEnactResult result = activePump.setTempBasalAbsolute(rateAfterConstraints, durationInMinutes);
if (Config.logCongigBuilderActions)
log.debug("setTempBasalAbsolute rate: " + rateAfterConstraints + " durationInMinutes: " + durationInMinutes + " success: " + result.success + " enacted: " + result.enacted);
if (result.enacted && result.success) {
if (result.isPercent) {
uploadTempBasalStartPercent(result.percent, result.duration);
} else {
uploadTempBasalStartAbsolute(result.absolute, result.duration);
}
MainApp.bus().post(new EventTempBasalChange());
}
return result;
}
/**
* apply constraints, set temp based on percent and expecting result in percent
*
* @param percent 0 ... 100 ...
* @param durationInMinutes
* @return result
*/
@Override
public PumpEnactResult setTempBasalPercent(Integer percent, Integer durationInMinutes) {
Integer percentAfterConstraints = applyBasalConstraints(percent);
PumpEnactResult result = activePump.setTempBasalPercent(percentAfterConstraints, durationInMinutes);
if (Config.logCongigBuilderActions)
log.debug("setTempBasalPercent percent: " + percentAfterConstraints + " durationInMinutes: " + durationInMinutes + " success: " + result.success + " enacted: " + result.enacted);
if (result.enacted && result.success) {
uploadTempBasalStartPercent(result.percent, result.duration);
MainApp.bus().post(new EventTempBasalChange());
}
return result;
}
@Override
public PumpEnactResult setExtendedBolus(Double insulin, Integer durationInMinutes) {
Double rateAfterConstraints = applyBolusConstraints(insulin);
PumpEnactResult result = activePump.setExtendedBolus(rateAfterConstraints, durationInMinutes);
if (Config.logCongigBuilderActions)
log.debug("setExtendedBolus rate: " + rateAfterConstraints + " durationInMinutes: " + durationInMinutes + " success: " + result.success + " enacted: " + result.enacted);
if (result.enacted && result.success) {
uploadExtendedBolus(result.bolusDelivered, result.duration);
MainApp.bus().post(new EventTreatmentChange());
}
return result;
}
@Override
public PumpEnactResult cancelTempBasal() {
PumpEnactResult result = activePump.cancelTempBasal();
if (Config.logCongigBuilderActions)
log.debug("cancelTempBasal success: " + result.success + " enacted: " + result.enacted);
if (result.enacted && result.success) {
uploadTempBasalEnd();
MainApp.bus().post(new EventTempBasalChange());
}
return result;
}
@Override
public PumpEnactResult cancelExtendedBolus() {
PumpEnactResult result = activePump.cancelExtendedBolus();
if (Config.logCongigBuilderActions)
log.debug("cancelExtendedBolus success: " + result.success + " enacted: " + result.enacted);
return result;
}
/**
* expect absolute request and allow both absolute and percent response based on pump capabilities
*
* @param request
* @return
*/
public PumpEnactResult applyAPSRequest(APSResult request) {
request.rate = applyBasalConstraints(request.rate);
PumpEnactResult result;
if (!isInitialized()) {
result = new PumpEnactResult();
result.comment = MainApp.sResources.getString(R.string.pumpNotInitialized);
result.enacted = false;
result.success = false;
log.debug("applyAPSRequest: " + MainApp.sResources.getString(R.string.pumpNotInitialized));
return result;
}
if (isSuspended()) {
result = new PumpEnactResult();
result.comment = MainApp.sResources.getString(R.string.pumpsuspended);
result.enacted = false;
result.success = false;
log.debug("applyAPSRequest: " + MainApp.sResources.getString(R.string.pumpsuspended));
return result;
}
if (Config.logCongigBuilderActions)
log.debug("applyAPSRequest: " + request.toString());
if ((request.rate == 0 && request.duration == 0) || Math.abs(request.rate - getBaseBasalRate()) < 0.05) {
if (isTempBasalInProgress()) {
if (Config.logCongigBuilderActions)
log.debug("applyAPSRequest: cancelTempBasal()");
result = cancelTempBasal();
} else {
result = new PumpEnactResult();
result.absolute = request.rate;
result.duration = 0;
result.enacted = false;
result.comment = "Basal set correctly";
result.success = true;
if (Config.logCongigBuilderActions)
log.debug("applyAPSRequest: Basal set correctly");
}
} else if (isTempBasalInProgress() && Math.abs(request.rate - getTempBasalAbsoluteRate()) < 0.05) {
result = new PumpEnactResult();
result.absolute = getTempBasalAbsoluteRate();
result.duration = activePump.getTempBasal().getPlannedRemainingMinutes();
result.enacted = false;
result.comment = "Temp basal set correctly";
result.success = true;
if (Config.logCongigBuilderActions)
log.debug("applyAPSRequest: Temp basal set correctly");
} else {
if (Config.logCongigBuilderActions)
log.debug("applyAPSRequest: setTempBasalAbsolute()");
result = setTempBasalAbsolute(request.rate, request.duration);
}
return result;
}
@Nullable
@Override
public JSONObject getJSONStatus() {
if (activePump != null)
return activePump.getJSONStatus();
else return null;
}
@Override
public String deviceID() {
if (activePump != null)
return activePump.deviceID();
else return "No Pump active!";
}
@Override
public PumpDescription getPumpDescription() {
if (activePump != null)
return activePump.getPumpDescription();
else {
PumpDescription emptyDescription = new PumpDescription();
emptyDescription.isBolusCapable = false;
emptyDescription.isExtendedBolusCapable = false;
emptyDescription.isSetBasalProfileCapable = false;
emptyDescription.isTempBasalCapable = true; // needs to be true before real driver is selected
emptyDescription.isRefillingCapable = false;
return emptyDescription;
}
}
@Override
public String shortStatus(boolean veryShort) {
if (activePump != null) {
return activePump.shortStatus(veryShort);
} else {
return "No Pump active!";
}
}
/**
* Constraints interface
**/
@Override
public boolean isLoopEnabled() {
boolean result = true;
ArrayList<PluginBase> constraintsPlugins = MainApp.getSpecificPluginsListByInterface(ConstraintsInterface.class);
for (PluginBase p : constraintsPlugins) {
ConstraintsInterface constrain = (ConstraintsInterface) p;
if (!p.isEnabled(PluginBase.CONSTRAINTS)) continue;
result = result && constrain.isLoopEnabled();
}
return result;
}
@Override
public boolean isClosedModeEnabled() {
boolean result = true;
ArrayList<PluginBase> constraintsPlugins = MainApp.getSpecificPluginsListByInterface(ConstraintsInterface.class);
for (PluginBase p : constraintsPlugins) {
ConstraintsInterface constrain = (ConstraintsInterface) p;
if (!p.isEnabled(PluginBase.CONSTRAINTS)) continue;
result = result && constrain.isClosedModeEnabled();
}
return result;
}
@Override
public boolean isAutosensModeEnabled() {
boolean result = true;
ArrayList<PluginBase> constraintsPlugins = MainApp.getSpecificPluginsListByInterface(ConstraintsInterface.class);
for (PluginBase p : constraintsPlugins) {
ConstraintsInterface constrain = (ConstraintsInterface) p;
if (!p.isEnabled(PluginBase.CONSTRAINTS)) continue;
result = result && constrain.isAutosensModeEnabled();
}
return result;
}
@Override
public boolean isAMAModeEnabled() {
SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(MainApp.instance().getApplicationContext());
boolean result = preferences.getBoolean("openapsama_useautosens", false);
ArrayList<PluginBase> constraintsPlugins = MainApp.getSpecificPluginsListByInterface(ConstraintsInterface.class);
for (PluginBase p : constraintsPlugins) {
ConstraintsInterface constrain = (ConstraintsInterface) p;
if (!p.isEnabled(PluginBase.CONSTRAINTS)) continue;
result = result && constrain.isAMAModeEnabled();
}
return result;
}
@Override
public Double applyBasalConstraints(Double absoluteRate) {
Double rateAfterConstrain = absoluteRate;
ArrayList<PluginBase> constraintsPlugins = MainApp.getSpecificPluginsListByInterface(ConstraintsInterface.class);
for (PluginBase p : constraintsPlugins) {
ConstraintsInterface constrain = (ConstraintsInterface) p;
if (!p.isEnabled(PluginBase.CONSTRAINTS)) continue;
rateAfterConstrain = Math.min(constrain.applyBasalConstraints(absoluteRate), rateAfterConstrain);
}
return rateAfterConstrain;
}
@Override
public Integer applyBasalConstraints(Integer percentRate) {
Integer rateAfterConstrain = percentRate;
ArrayList<PluginBase> constraintsPlugins = MainApp.getSpecificPluginsListByInterface(ConstraintsInterface.class);
for (PluginBase p : constraintsPlugins) {
ConstraintsInterface constrain = (ConstraintsInterface) p;
if (!p.isEnabled(PluginBase.CONSTRAINTS)) continue;
rateAfterConstrain = Math.min(constrain.applyBasalConstraints(percentRate), rateAfterConstrain);
}
return rateAfterConstrain;
}
@Override
public Double applyBolusConstraints(Double insulin) {
Double insulinAfterConstrain = insulin;
ArrayList<PluginBase> constraintsPlugins = MainApp.getSpecificPluginsListByInterface(ConstraintsInterface.class);
for (PluginBase p : constraintsPlugins) {
ConstraintsInterface constrain = (ConstraintsInterface) p;
if (!p.isEnabled(PluginBase.CONSTRAINTS)) continue;
insulinAfterConstrain = Math.min(constrain.applyBolusConstraints(insulin), insulinAfterConstrain);
}
return insulinAfterConstrain;
}
@Override
public Integer applyCarbsConstraints(Integer carbs) {
Integer carbsAfterConstrain = carbs;
ArrayList<PluginBase> constraintsPlugins = MainApp.getSpecificPluginsListByInterface(ConstraintsInterface.class);
for (PluginBase p : constraintsPlugins) {
ConstraintsInterface constrain = (ConstraintsInterface) p;
if (!p.isEnabled(PluginBase.CONSTRAINTS)) continue;
carbsAfterConstrain = Math.min(constrain.applyCarbsConstraints(carbs), carbsAfterConstrain);
}
return carbsAfterConstrain;
}
@Override
public Double applyMaxIOBConstraints(Double maxIob) {
Double maxIobAfterConstrain = maxIob;
ArrayList<PluginBase> constraintsPlugins = MainApp.getSpecificPluginsListByInterface(ConstraintsInterface.class);
for (PluginBase p : constraintsPlugins) {
ConstraintsInterface constrain = (ConstraintsInterface) p;
if (!p.isEnabled(PluginBase.CONSTRAINTS)) continue;
maxIobAfterConstrain = Math.min(constrain.applyMaxIOBConstraints(maxIob), maxIobAfterConstrain);
}
return maxIobAfterConstrain;
}
public void uploadTempBasalStartAbsolute(Double absolute, double durationInMinutes) {
try {
Context context = MainApp.instance().getApplicationContext();
JSONObject data = new JSONObject();
data.put("eventType", "Temp Basal");
data.put("duration", durationInMinutes);
data.put("absolute", absolute);
data.put("created_at", DateUtil.toISOString(new Date()));
data.put("enteredBy", MainApp.instance().getString(R.string.app_name));
data.put("notes", MainApp.sResources.getString(R.string.androidaps_tempbasalstartnote) + " " + absolute + "u/h " + durationInMinutes + " min"); // ECOR
Bundle bundle = new Bundle();
bundle.putString("action", "dbAdd");
bundle.putString("collection", "treatments");
bundle.putString("data", data.toString());
Intent intent = new Intent(Intents.ACTION_DATABASE);
intent.putExtras(bundle);
intent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES);
context.sendBroadcast(intent);
DbLogger.dbAdd(intent, data.toString(), ConfigBuilderPlugin.class);
} catch (JSONException e) {
e.printStackTrace();
}
}
public void uploadTempBasalStartPercent(Integer percent, double durationInMinutes) {
try {
SharedPreferences SP = PreferenceManager.getDefaultSharedPreferences(MainApp.instance().getApplicationContext());
boolean useAbsolute = SP.getBoolean("ns_sync_use_absolute", false);
if (useAbsolute) {
double absolute = getBaseBasalRate() * percent / 100d;
uploadTempBasalStartAbsolute(absolute, durationInMinutes);
} else {
Context context = MainApp.instance().getApplicationContext();
JSONObject data = new JSONObject();
data.put("eventType", "Temp Basal");
data.put("duration", durationInMinutes);
data.put("percent", percent - 100);
data.put("created_at", DateUtil.toISOString(new Date()));
data.put("enteredBy", MainApp.instance().getString(R.string.app_name));
data.put("notes", MainApp.sResources.getString(R.string.androidaps_tempbasalstartnote) + " " + percent + "% " + durationInMinutes + " min"); // ECOR
Bundle bundle = new Bundle();
bundle.putString("action", "dbAdd");
bundle.putString("collection", "treatments");
bundle.putString("data", data.toString());
Intent intent = new Intent(Intents.ACTION_DATABASE);
intent.putExtras(bundle);
intent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES);
context.sendBroadcast(intent);
DbLogger.dbAdd(intent, data.toString(), ConfigBuilderPlugin.class);
}
} catch (JSONException e) {
e.printStackTrace();
}
}
public void uploadTempBasalEnd() {
try {
Context context = MainApp.instance().getApplicationContext();
JSONObject data = new JSONObject();
data.put("eventType", "Temp Basal");
data.put("created_at", DateUtil.toISOString(new Date()));
data.put("enteredBy", MainApp.instance().getString(R.string.app_name));
data.put("notes", MainApp.sResources.getString(R.string.androidaps_tempbasalendnote)); // ECOR
Bundle bundle = new Bundle();
bundle.putString("action", "dbAdd");
bundle.putString("collection", "treatments");
bundle.putString("data", data.toString());
Intent intent = new Intent(Intents.ACTION_DATABASE);
intent.putExtras(bundle);
intent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES);
context.sendBroadcast(intent);
DbLogger.dbAdd(intent, data.toString(), ConfigBuilderPlugin.class);
} catch (JSONException e) {
e.printStackTrace();
}
}
public void uploadExtendedBolus(Double insulin, double durationInMinutes) {
try {
Context context = MainApp.instance().getApplicationContext();
JSONObject data = new JSONObject();
data.put("eventType", "Combo Bolus");
data.put("duration", durationInMinutes);
data.put("splitNow", 0);
data.put("splitExt", 100);
data.put("enteredinsulin", insulin);
data.put("relative", insulin);
data.put("created_at", DateUtil.toISOString(new Date()));
data.put("enteredBy", MainApp.instance().getString(R.string.app_name));
Bundle bundle = new Bundle();
bundle.putString("action", "dbAdd");
bundle.putString("collection", "treatments");
bundle.putString("data", data.toString());
Intent intent = new Intent(Intents.ACTION_DATABASE);
intent.putExtras(bundle);
intent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES);
context.sendBroadcast(intent);
DbLogger.dbAdd(intent, data.toString(), ConfigBuilderPlugin.class);
} catch (JSONException e) {
e.printStackTrace();
}
}
public void uploadDeviceStatus() {
DeviceStatus deviceStatus = new DeviceStatus();
try {
LoopPlugin.LastRun lastRun = LoopPlugin.lastRun;
if (lastRun != null && lastRun.lastAPSRun.getTime() > new Date().getTime() - 300 * 1000L) {
// do not send if result is older than 1 min
APSResult apsResult = lastRun.request;
apsResult.json().put("timestamp", DateUtil.toISOString(lastRun.lastAPSRun));
deviceStatus.suggested = apsResult.json();
if (lastRun.request instanceof DetermineBasalResultMA) {
DetermineBasalResultMA result = (DetermineBasalResultMA) lastRun.request;
deviceStatus.iob = result.iob.json();
deviceStatus.iob.put("time", DateUtil.toISOString(lastRun.lastAPSRun));
}
if (lastRun.request instanceof DetermineBasalResultAMA) {
DetermineBasalResultAMA result = (DetermineBasalResultAMA) lastRun.request;
deviceStatus.iob = result.iob.json();
deviceStatus.iob.put("time", DateUtil.toISOString(lastRun.lastAPSRun));
}
if (lastRun.setByPump != null && lastRun.setByPump.enacted) { // enacted
deviceStatus.enacted = lastRun.request.json();
deviceStatus.enacted.put("rate", lastRun.setByPump.json().get("rate"));
deviceStatus.enacted.put("duration", lastRun.setByPump.json().get("duration"));
deviceStatus.enacted.put("recieved", true);
JSONObject requested = new JSONObject();
requested.put("duration", lastRun.request.duration);
requested.put("rate", lastRun.request.rate);
requested.put("temp", "absolute");
deviceStatus.enacted.put("requested", requested);
}
} else {
log.debug("OpenAPS data too old to upload");
}
if (activePump != null) {
deviceStatus.device = "openaps://" + deviceID();
JSONObject pumpstatus = getJSONStatus();
if (pumpstatus != null) {
deviceStatus.pump = pumpstatus;
}
}
int batteryLevel = BatteryLevel.getBatteryLevel();
deviceStatus.uploaderBattery = batteryLevel;
deviceStatus.created_at = DateUtil.toISOString(new Date());
deviceStatus.sendToNSClient();
} catch (JSONException e) {
e.printStackTrace();
}
}
public void uploadBolusWizardRecord(Treatment t, double glucose, String glucoseType, int carbTime, JSONObject boluscalc) {
JSONObject data = new JSONObject();
try {
data.put("eventType", "Bolus Wizard");
if (t.insulin != 0d) data.put("insulin", t.insulin);
if (t.carbs != 0d) data.put("carbs", t.carbs.intValue());
data.put("created_at", DateUtil.toISOString(t.created_at));
data.put("timeIndex", t.timeIndex);
if (glucose != 0d) data.put("glucose", glucose);
data.put("glucoseType", glucoseType);
data.put("boluscalc", boluscalc);
if (carbTime != 0) data.put("preBolus", carbTime);
} catch (JSONException e) {
e.printStackTrace();
}
uploadCareportalEntryToNS(data);
}
public static void uploadCareportalEntryToNS(JSONObject data) {
try {
if (data.has("preBolus") && data.has("carbs")) {
JSONObject prebolus = new JSONObject();
prebolus.put("carbs", data.get("carbs"));
data.remove("carbs");
prebolus.put("eventType", data.get("eventType"));
if (data.has("enteredBy")) prebolus.put("enteredBy", data.get("enteredBy"));
if (data.has("notes")) prebolus.put("notes", data.get("notes"));
long mills = DateUtil.fromISODateString(data.getString("created_at")).getTime();
Date preBolusDate = new Date(mills + data.getInt("preBolus") * 60000L);
prebolus.put("created_at", DateUtil.toISOString(preBolusDate));
uploadCareportalEntryToNS(prebolus);
}
Context context = MainApp.instance().getApplicationContext();
Bundle bundle = new Bundle();
bundle.putString("action", "dbAdd");
bundle.putString("collection", "treatments");
bundle.putString("data", data.toString());
Intent intent = new Intent(Intents.ACTION_DATABASE);
intent.putExtras(bundle);
intent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES);
context.sendBroadcast(intent);
DbLogger.dbAdd(intent, data.toString(), ConfigBuilderPlugin.class);
} catch (Exception e) {
e.printStackTrace();
}
}
public static void removeCareportalEntryFromNS(String _id) {
try {
Context context = MainApp.instance().getApplicationContext();
Bundle bundle = new Bundle();
bundle.putString("action", "dbRemove");
bundle.putString("collection", "treatments");
bundle.putString("_id", _id);
Intent intent = new Intent(Intents.ACTION_DATABASE);
intent.putExtras(bundle);
intent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES);
context.sendBroadcast(intent);
DbLogger.dbRemove(intent, _id, ConfigBuilderPlugin.class);
} catch (Exception e) {
e.printStackTrace();
}
}
public void uploadError(String error) {
Context context = MainApp.instance().getApplicationContext();
Bundle bundle = new Bundle();
bundle.putString("action", "dbAdd");
bundle.putString("collection", "treatments");
JSONObject data = new JSONObject();
try {
data.put("eventType", "Announcement");
data.put("created_at", DateUtil.toISOString(new Date()));
data.put("notes", error);
data.put("isAnnouncement", true);
} catch (JSONException e) {
e.printStackTrace();
}
bundle.putString("data", data.toString());
Intent intent = new Intent(Intents.ACTION_DATABASE);
intent.putExtras(bundle);
intent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES);
context.sendBroadcast(intent);
DbLogger.dbAdd(intent, data.toString(), MsgError.class);
}
public void uploadAppStart() {
Context context = MainApp.instance().getApplicationContext();
Bundle bundle = new Bundle();
bundle.putString("action", "dbAdd");
bundle.putString("collection", "treatments");
JSONObject data = new JSONObject();
try {
data.put("eventType", "Note");
data.put("created_at", DateUtil.toISOString(new Date()));
data.put("notes", MainApp.sResources.getString(R.string.androidaps_start));
} catch (JSONException e) {
e.printStackTrace();
}
bundle.putString("data", data.toString());
Intent intent = new Intent(Intents.ACTION_DATABASE);
intent.putExtras(bundle);
intent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES);
context.sendBroadcast(intent);
DbLogger.dbAdd(intent, data.toString(), ConfigBuilderPlugin.class);
}
}