package info.nightscout.androidaps.plugins.VirtualPump;
import android.content.Context;
import android.content.SharedPreferences;
import android.preference.PreferenceManager;
import org.json.JSONException;
import org.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.sql.SQLException;
import java.util.Date;
import info.nightscout.androidaps.BuildConfig;
import info.nightscout.androidaps.Config;
import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.R;
import info.nightscout.androidaps.data.PumpEnactResult;
import info.nightscout.androidaps.db.TempBasal;
import info.nightscout.androidaps.interfaces.PluginBase;
import info.nightscout.androidaps.interfaces.PumpDescription;
import info.nightscout.androidaps.interfaces.PumpInterface;
import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin;
import info.nightscout.androidaps.plugins.Overview.events.EventOverviewBolusProgress;
import info.nightscout.androidaps.plugins.VirtualPump.events.EventVirtualPumpUpdateGui;
import info.nightscout.androidaps.plugins.NSClientInternal.data.NSProfile;
import info.nightscout.utils.DateUtil;
/**
* Created by mike on 05.08.2016.
*/
public class VirtualPumpPlugin implements PluginBase, PumpInterface {
private static Logger log = LoggerFactory.getLogger(VirtualPumpPlugin.class);
public static Double defaultBasalValue = 0.2d;
public static Integer batteryPercent = 50;
public static Integer reservoirInUnits = 50;
Date lastDataTime = new Date(0);
boolean fragmentEnabled = true;
boolean fragmentVisible = true;
PumpDescription pumpDescription = new PumpDescription();
public VirtualPumpPlugin() {
pumpDescription.isBolusCapable = true;
pumpDescription.bolusStep = 0.1d;
pumpDescription.isExtendedBolusCapable = true;
pumpDescription.extendedBolusStep = 0.2d;
pumpDescription.isTempBasalCapable = true;
pumpDescription.lowTempBasalStyle = PumpDescription.ABSOLUTE | PumpDescription.PERCENT;
pumpDescription.highTempBasalStyle = PumpDescription.ABSOLUTE | PumpDescription.PERCENT;
pumpDescription.maxHighTempPercent = 600;
pumpDescription.maxHighTempAbsolute = 10;
pumpDescription.lowTempPercentStep = 5;
pumpDescription.lowTempAbsoluteStep = 0.1;
pumpDescription.lowTempPercentDuration = 30;
pumpDescription.lowTempAbsoluteDuration = 30;
pumpDescription.highTempPercentStep = 10;
pumpDescription.highTempAbsoluteStep = 0.05d;
pumpDescription.highTempPercentDuration = 30;
pumpDescription.highTempAbsoluteDuration = 30;
pumpDescription.isSetBasalProfileCapable = true;
pumpDescription.basalStep = 0.01d;
pumpDescription.basalMinimumRate = 0.04d;
pumpDescription.isRefillingCapable = false;
}
@Override
public String getFragmentClass() {
return VirtualPumpFragment.class.getName();
}
@Override
public String getName() {
return MainApp.instance().getString(R.string.virtualpump);
}
@Override
public String getNameShort() {
String name = MainApp.sResources.getString(R.string.virtualpump_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 == PUMP && fragmentEnabled;
}
@Override
public boolean isVisibleInTabs(int type) {
return type == PUMP && fragmentVisible;
}
@Override
public boolean canBeHidden(int type) {
return true;
}
@Override
public void setFragmentEnabled(int type, boolean fragmentEnabled) {
if (type == PUMP) this.fragmentEnabled = fragmentEnabled;
}
@Override
public void setFragmentVisible(int type, boolean fragmentVisible) {
if (type == PUMP) this.fragmentVisible = fragmentVisible;
}
@Override
public int getType() {
return PluginBase.PUMP;
}
@Override
public boolean isInitialized() {
return true;
}
@Override
public boolean isSuspended() {
return false;
}
@Override
public boolean isBusy() {
return false;
}
@Override
public boolean isTempBasalInProgress() {
return getTempBasal() != null;
}
@Override
public boolean isExtendedBoluslInProgress() {
return getExtendedBolus() != null;
}
@Override
public int setNewBasalProfile(NSProfile profile) {
// Do nothing here. we are using MainApp.getConfigBuilder().getActiveProfile().getProfile();
lastDataTime = new Date();
return SUCCESS;
}
@Override
public boolean isThisProfileSet(NSProfile profile) {
return false;
}
@Override
public Date lastDataTime() {
return lastDataTime;
}
@Override
public void refreshDataFromPump(String reason) {
MainApp.getConfigBuilder().uploadDeviceStatus();
lastDataTime = new Date();
}
@Override
public double getBaseBasalRate() {
NSProfile profile = ConfigBuilderPlugin.getActiveProfile().getProfile();
if (profile == null)
return defaultBasalValue;
return profile.getBasal(profile.secondsFromMidnight());
}
@Override
public double getTempBasalAbsoluteRate() {
if (!isTempBasalInProgress())
return 0;
if (getTempBasal().isAbsolute) {
return getTempBasal().absolute;
} else {
NSProfile profile = ConfigBuilderPlugin.getActiveProfile().getProfile();
if (profile == null)
return defaultBasalValue;
Double baseRate = profile.getBasal(profile.secondsFromMidnight());
Double tempRate = baseRate * (getTempBasal().percent / 100d);
return baseRate + tempRate;
}
}
@Override
public TempBasal getTempBasal() {
return ConfigBuilderPlugin.getActiveTempBasals().getTempBasal(new Date());
}
@Override
public TempBasal getExtendedBolus() {
return ConfigBuilderPlugin.getActiveTempBasals().getExtendedBolus(new Date());
}
@Override
public double getTempBasalRemainingMinutes() {
if (!isTempBasalInProgress())
return 0;
return getTempBasal().getPlannedRemainingMinutes();
}
@Override
public TempBasal getTempBasal(Date time) {
return ConfigBuilderPlugin.getActiveTempBasals().getTempBasal(time);
}
@Override
public PumpEnactResult deliverTreatment(Double insulin, Integer carbs, Context context) {
PumpEnactResult result = new PumpEnactResult();
result.success = true;
result.bolusDelivered = insulin;
result.carbsDelivered = carbs;
result.comment = MainApp.instance().getString(R.string.virtualpump_resultok);
Double delivering = 0d;
while (delivering < insulin) {
try {
Thread.sleep(200);
} catch (InterruptedException e) {
}
EventOverviewBolusProgress bolusingEvent = EventOverviewBolusProgress.getInstance();
bolusingEvent.status = String.format(MainApp.sResources.getString(R.string.bolusdelivering), delivering);
bolusingEvent.percent = Math.min((int) (delivering / insulin * 100), 100);
MainApp.bus().post(bolusingEvent);
delivering += 0.1d;
}
try {
Thread.sleep(200);
} catch (InterruptedException e) {
}
EventOverviewBolusProgress bolusingEvent = EventOverviewBolusProgress.getInstance();
bolusingEvent.status = String.format(MainApp.sResources.getString(R.string.bolusdelivered), insulin);
bolusingEvent.percent = 100;
MainApp.bus().post(bolusingEvent);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
}
if (Config.logPumpComm)
log.debug("Delivering treatment insulin: " + insulin + "U carbs: " + carbs + "g " + result);
MainApp.bus().post(new EventVirtualPumpUpdateGui());
lastDataTime = new Date();
return result;
}
@Override
public void stopBolusDelivering() {
}
@Override
public PumpEnactResult setTempBasalAbsolute(Double absoluteRate, Integer durationInMinutes) {
PumpEnactResult result = cancelTempBasal();
if (!result.success)
return result;
TempBasal tempBasal = new TempBasal();
tempBasal.timeStart = new Date();
tempBasal.isAbsolute = true;
tempBasal.absolute = absoluteRate;
tempBasal.duration = durationInMinutes;
result.success = true;
result.enacted = true;
result.isTempCancel = false;
result.absolute = absoluteRate;
result.duration = durationInMinutes;
result.comment = MainApp.instance().getString(R.string.virtualpump_resultok);
try {
MainApp.instance().getDbHelper().getDaoTempBasals().create(tempBasal);
} catch (SQLException e) {
e.printStackTrace();
result.success = false;
result.comment = MainApp.instance().getString(R.string.virtualpump_sqlerror);
}
if (Config.logPumpComm)
log.debug("Setting temp basal absolute: " + result);
MainApp.bus().post(new EventVirtualPumpUpdateGui());
lastDataTime = new Date();
return result;
}
@Override
public PumpEnactResult setTempBasalPercent(Integer percent, Integer durationInMinutes) {
PumpEnactResult result = new PumpEnactResult();
if (isTempBasalInProgress()) {
result = cancelTempBasal();
if (!result.success)
return result;
}
TempBasal tempBasal = new TempBasal();
tempBasal.timeStart = new Date();
tempBasal.isAbsolute = false;
tempBasal.percent = percent;
tempBasal.duration = durationInMinutes;
result.success = true;
result.enacted = true;
result.percent = percent;
result.isPercent = true;
result.isTempCancel = false;
result.duration = durationInMinutes;
result.comment = MainApp.instance().getString(R.string.virtualpump_resultok);
try {
MainApp.instance().getDbHelper().getDaoTempBasals().create(tempBasal);
} catch (SQLException e) {
e.printStackTrace();
result.success = false;
result.comment = MainApp.instance().getString(R.string.virtualpump_sqlerror);
}
if (Config.logPumpComm)
log.debug("Settings temp basal percent: " + result);
MainApp.bus().post(new EventVirtualPumpUpdateGui());
lastDataTime = new Date();
return result;
}
@Override
public PumpEnactResult setExtendedBolus(Double insulin, Integer durationInMinutes) {
PumpEnactResult result = cancelExtendedBolus();
if (!result.success)
return result;
TempBasal extendedBolus = new TempBasal();
extendedBolus.timeStart = new Date();
extendedBolus.isExtended = true;
extendedBolus.absolute = insulin * 60d / durationInMinutes;
extendedBolus.duration = durationInMinutes;
extendedBolus.isAbsolute = true;
result.success = true;
result.enacted = true;
result.bolusDelivered = insulin;
result.isTempCancel = false;
result.duration = durationInMinutes;
result.comment = MainApp.instance().getString(R.string.virtualpump_resultok);
try {
MainApp.instance().getDbHelper().getDaoTempBasals().create(extendedBolus);
} catch (SQLException e) {
e.printStackTrace();
result.success = false;
result.enacted = false;
result.comment = MainApp.instance().getString(R.string.virtualpump_sqlerror);
}
if (Config.logPumpComm)
log.debug("Setting extended bolus: " + result);
MainApp.bus().post(new EventVirtualPumpUpdateGui());
lastDataTime = new Date();
return result;
}
@Override
public PumpEnactResult cancelTempBasal() {
PumpEnactResult result = new PumpEnactResult();
result.success = true;
result.isTempCancel = true;
result.comment = MainApp.instance().getString(R.string.virtualpump_resultok);
if (isTempBasalInProgress()) {
result.enacted = true;
TempBasal tb = getTempBasal();
tb.timeEnd = new Date();
try {
MainApp.instance().getDbHelper().getDaoTempBasals().update(tb);
//tempBasal = null;
if (Config.logPumpComm)
log.debug("Canceling temp basal: " + result);
MainApp.bus().post(new EventVirtualPumpUpdateGui());
} catch (SQLException e) {
e.printStackTrace();
result.success = false;
result.enacted = false;
result.comment = MainApp.instance().getString(R.string.virtualpump_sqlerror);
}
}
lastDataTime = new Date();
return result;
}
@Override
public PumpEnactResult cancelExtendedBolus() {
PumpEnactResult result = new PumpEnactResult();
if (isExtendedBoluslInProgress()) {
TempBasal extendedBolus = getExtendedBolus();
extendedBolus.timeEnd = new Date();
try {
MainApp.instance().getDbHelper().getDaoTempBasals().update(extendedBolus);
} catch (SQLException e) {
e.printStackTrace();
result.success = false;
result.comment = MainApp.instance().getString(R.string.virtualpump_sqlerror);
}
}
result.success = true;
result.enacted = true;
result.isTempCancel = true;
result.comment = MainApp.instance().getString(R.string.virtualpump_resultok);
if (Config.logPumpComm)
log.debug("Canceling extended basal: " + result);
MainApp.bus().post(new EventVirtualPumpUpdateGui());
lastDataTime = new Date();
return result;
}
@Override
public JSONObject getJSONStatus() {
SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(MainApp.instance().getApplicationContext());
if (!preferences.getBoolean("virtualpump_uploadstatus", false)) {
return null;
}
JSONObject pump = new JSONObject();
JSONObject battery = new JSONObject();
JSONObject status = new JSONObject();
JSONObject extended = new JSONObject();
try {
battery.put("percent", batteryPercent);
status.put("status", "normal");
extended.put("Version", BuildConfig.VERSION_NAME + "-" + BuildConfig.BUILDVERSION);
try {
extended.put("ActiveProfile", MainApp.getConfigBuilder().getActiveProfile().getProfile().getActiveProfile());
} catch (Exception e) {}
TempBasal tb;
if ((tb = getTempBasal()) != null) {
status.put("tempbasalpct", tb.percent);
status.put("tempbasalstart", DateUtil.toISOString(tb.timeStart));
status.put("tempbasalremainmin", tb.getPlannedRemainingMinutes());
}
status.put("timestamp", DateUtil.toISOString(new Date()));
pump.put("battery", battery);
pump.put("status", status);
pump.put("extended", extended);
pump.put("reservoir", reservoirInUnits);
pump.put("clock", DateUtil.toISOString(new Date()));
} catch (JSONException e) {
}
return pump;
}
@Override
public String deviceID() {
return "VirtualPump";
}
@Override
public PumpDescription getPumpDescription() {
return pumpDescription;
}
@Override
public String shortStatus(boolean veryShort) {
return "Virtual Pump";
}
}