VirtualPump

This commit is contained in:
Milos Kozak 2016-06-11 20:45:40 +02:00
parent a5088584a2
commit 68b5570d35
16 changed files with 567 additions and 25 deletions

View file

@ -37,7 +37,7 @@
<ConfirmationsSetting value="0" id="Add" />
<ConfirmationsSetting value="0" id="Remove" />
</component>
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_8" default="true" assert-keyword="true" jdk-15="true" project-jdk-name="1.8" project-jdk-type="JavaSDK">
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_7" default="true" assert-keyword="true" jdk-15="true" project-jdk-name="1.8" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/build/classes" />
</component>
<component name="ProjectType">

View file

@ -9,4 +9,5 @@ public class Config {
public static final boolean logIncommingBG = true;
public static final boolean logIncommingData = true;
public static final boolean logAPSResult = true;
public static final boolean logPumpComm = true;
}

View file

@ -16,6 +16,7 @@ import info.nightscout.androidaps.plugins.Overview.OverviewFragment;
import info.nightscout.androidaps.plugins.ProfileViewer.ProfileViewerFragment;
import info.nightscout.androidaps.plugins.TempBasals.TempBasalsFragment;
import info.nightscout.androidaps.plugins.Treatments.TreatmentsFragment;
import info.nightscout.androidaps.plugins.VirtualPump.VirtualPumpFragment;
import info.nightscout.androidaps.tabs.*;
import info.nightscout.androidaps.plugins.Objectives.ObjectivesFragment;
@ -39,6 +40,7 @@ public class MainActivity extends AppCompatActivity {
// Register all tabs in app here
mAdapter = new TabPageAdapter(getSupportFragmentManager());
mAdapter.registerNewFragment("Overview", OverviewFragment.newInstance());
mAdapter.registerNewFragment("VirtualPump", (VirtualPumpFragment) MainApp.setActivePump(VirtualPumpFragment.newInstance()));
mAdapter.registerNewFragment("LowSuspend", LowSuspendFragment.newInstance());
mAdapter.registerNewFragment("OpenAPS MA", OpenAPSMAFragment.newInstance());
mAdapter.registerNewFragment("Treatments", treatmentsFragment = TreatmentsFragment.newInstance());

View file

@ -103,8 +103,9 @@ public class MainApp extends Application {
public static Pump getActivePump() {
return activePump;
}
public static void setActivePump(Pump activepump) {
public static Pump setActivePump(Pump activepump) {
activePump = activepump;
return activepump;
}
}

View file

@ -136,7 +136,7 @@ public class DataService extends IntentService {
MainApp.instance().setActiveProfile(activeProfile);
storeNSProfile();
if (MainApp.getActivePump() != null) {
MainApp.getActivePump().setNewBasalProfile();
MainApp.getActivePump().setNewBasalProfile(MainApp.getNSProfile());
} else {
log.error("No active pump selected");
}

View file

@ -1,16 +1,34 @@
package info.nightscout.androidaps.data;
import org.json.JSONObject;
import info.nightscout.androidaps.db.Treatment;
import info.nightscout.client.data.NSProfile;
/**
* Created by mike on 04.06.2016.
*/
public abstract class Pump {
public interface Pump {
boolean tempBasalInProgress = false;
boolean isTempBasalInProgress();
boolean isExtendedBoluslInProgress();
Integer getBatteryPercent();
Integer getReservoirValue();
// Upload to pump new basal profile from MainApp.getNSProfile()
public abstract void setNewBasalProfile();
void setNewBasalProfile(NSProfile profile);
public abstract double getBaseBasalRate(); // base basal rate, not temp basal
public abstract double getTempBasalAbsoluteRate();
public abstract double getTempBasalRemainingMinutes();
double getBaseBasalRate(); // base basal rate, not temp basal
double getTempBasalAbsoluteRate();
double getTempBasalRemainingMinutes();
Result deliverTreatment(Double insulin, Double carbs);
Result setTempBasalAbsolute(Double absoluteRate, Integer durationInMinutes);
Result setTempBasalPercent(Integer percent, Integer durationInMinutes);
Result setExtendedBolus(Double insulin, Integer durationInMinutes);
Result cancelTempBasal();
Result cancelExtendedBolus();
JSONObject getJSONStatus();
}

View file

@ -0,0 +1,16 @@
package info.nightscout.androidaps.data;
public class Result extends Object {
public boolean success = false;
public boolean enacted = false;
public String comment = "";
public Integer duration = -1;
public Double absolute = -1d;
public Integer percent = -1;
public Double bolusDelivered = 0d;
public String log() {
return "Success: " + success + " Enacted: " + enacted + " Comment: " + comment + " Duration: " + duration + " Absolute: " + absolute + " Percent: " + percent;
}
}

View file

@ -47,10 +47,10 @@ public class TempBasal {
public int duration; // in minutes
@DatabaseField
public boolean isExtended; // true if set as extended bolus
public boolean isExtended = false; // true if set as extended bolus
@DatabaseField
public boolean isAbsolute; // true if if set as absolute value in U
public boolean isAbsolute = false; // true if if set as absolute value in U
public IobTotal iobCalc(Date time) {

View file

@ -9,5 +9,5 @@ public interface APSBase {
public APSResult getLastAPSResult();
public Date getLastAPSRun();
public void run();
public void invoke();
}

View file

@ -114,7 +114,7 @@ public class DetermineBasalAdapterJS {
String ret = mV8rt.executeStringScript("JSON.stringify(rT);");
if (Config.logAPSResult)
log.debug(ret);
log.debug("Result: " + ret);
V8Object v8ObjectReuslt = mV8rt.getObject("rT");
@ -170,7 +170,7 @@ public class DetermineBasalAdapterJS {
if (parameters.length() > 0) {
Object arg1 = parameters.get(0);
if (Config.logAPSResult)
log.debug("JSLOG " + arg1);
log.debug("Input params: " + arg1);
}
}
};

View file

@ -100,7 +100,7 @@ public class OpenAPSMAFragment extends Fragment implements View.OnClickListener,
public void onClick(View view) {
switch (view.getId()) {
case R.id.openapsma_run:
run();
invoke();
break;
}
@ -113,7 +113,7 @@ public class OpenAPSMAFragment extends Fragment implements View.OnClickListener,
activity.runOnUiThread(new Runnable() {
@Override
public void run() {
run();
invoke();
}
});
else
@ -135,7 +135,7 @@ public class OpenAPSMAFragment extends Fragment implements View.OnClickListener,
}
@Override
public void run() {
public void invoke() {
// private DatermineBasalResult openAps(int glucoseValue, int delta, double deltaAvg15min, StatusEvent status, LowSuspendStatus lowSuspendStatus, IobTotal iobTotal, CarbCalc.Meal mealdata) {
DetermineBasalAdapterJS determineBasalAdapterJS = null;

View file

@ -115,8 +115,12 @@ public class TempBasalsFragment extends Fragment implements PluginBase {
}
if (iobTotal != null)
iobTotal.setText(formatNumber2decimalplaces.format(total.basaliob));
lastCalculationTimestamp = new Date().getTime();
lastCalculation = total;
}
public static class RecyclerViewAdapter extends RecyclerView.Adapter<RecyclerViewAdapter.TempBasalsViewHolder> {
List<TempBasal> tempBasals;

View file

@ -0,0 +1,372 @@
package info.nightscout.androidaps.plugins.VirtualPump;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import org.json.JSONException;
import org.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.sql.SQLException;
import java.text.DateFormat;
import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import info.nightscout.androidaps.Config;
import info.nightscout.androidaps.MainActivity;
import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.R;
import info.nightscout.androidaps.data.Pump;
import info.nightscout.androidaps.data.Result;
import info.nightscout.androidaps.db.TempBasal;
import info.nightscout.androidaps.db.Treatment;
import info.nightscout.androidaps.plugins.PluginBase;
import info.nightscout.client.data.NSProfile;
import info.nightscout.utils.DateUtil;
public class VirtualPumpFragment extends Fragment implements PluginBase, Pump {
private static Logger log = LoggerFactory.getLogger(VirtualPumpFragment.class);
Double defaultBasalValue = 0.2d;
TempBasal tempBasal = null;
TempBasal extendedBolus = null;
Integer batteryPercent = 50;
Integer resevoirInUnits = 50;
TextView basaBasalRateView;
TextView tempBasalView;
TextView extendedBolusView;
TextView batteryView;
TextView reservoirView;
@Override
public int getType() {
return PluginBase.PUMP;
}
@Override
public boolean isFragmentVisible() {
return true;
}
public static VirtualPumpFragment newInstance() {
VirtualPumpFragment fragment = new VirtualPumpFragment();
return fragment;
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.vitualpump_fragment, container, false);
basaBasalRateView = (TextView) view.findViewById(R.id.virtualpump_basabasalrate);
tempBasalView = (TextView) view.findViewById(R.id.virtualpump_tempbasal);
extendedBolusView = (TextView) view.findViewById(R.id.virtualpump_extendedbolus);
batteryView = (TextView) view.findViewById(R.id.virtualpump_battery);
reservoirView = (TextView) view.findViewById(R.id.virtualpump_reservoir);
updateView();
return view;
}
public void updateView() {
DateFormat formatDateToJustTime = new SimpleDateFormat("HH:mm");
DecimalFormat formatNumber2decimalplaces = new DecimalFormat("0.00");
checkForExpiredTempsAndExtended();
basaBasalRateView.setText(getBaseBasalRate() + "U");
if (isTempBasalInProgress()) {
if (tempBasal.isAbsolute) {
tempBasalView.setText(formatNumber2decimalplaces.format(tempBasal.absolute) + "U/h @" +
formatDateToJustTime.format(tempBasal.timeStart) +
" " + tempBasal.getRemainingMinutes() + "/" + tempBasal.duration + "min");
} else { // percent
tempBasalView.setText(tempBasal.percent + "% @" +
formatDateToJustTime.format(tempBasal.timeStart) +
" " + tempBasal.getRemainingMinutes() + "/" + tempBasal.duration + "min");
}
} else {
tempBasalView.setText("");
}
if (isExtendedBoluslInProgress()) {
extendedBolusView.setText(formatNumber2decimalplaces.format(extendedBolus.absolute) + "U/h @" +
formatDateToJustTime.format(extendedBolus.timeStart) +
" " + extendedBolus.getRemainingMinutes() + "/" + extendedBolus.duration + "min");
} else {
extendedBolusView.setText("");
}
batteryView.setText(getBatteryPercent() + "%");
reservoirView.setText(getReservoirValue() + "U");
}
void checkForExpiredTempsAndExtended() {
long now = new Date().getTime();
if (isTempBasalInProgress()) {
long plannedTimeEnd = tempBasal.getPlannedTimeEnd().getTime();
if (plannedTimeEnd < now) {
tempBasal.timeEnd = new Date(plannedTimeEnd);
try {
MainApp.instance().getDbHelper().getDaoTempBasals().update(tempBasal);
} catch (SQLException e) {
e.printStackTrace();
log.error(e.getMessage());
}
if (Config.logPumpComm)
log.debug("Canceling expired temp: " + tempBasal);
tempBasal = null;
}
}
if (isExtendedBoluslInProgress()) {
long plannedTimeEnd = extendedBolus.getPlannedTimeEnd().getTime();
if (plannedTimeEnd < now) {
extendedBolus.timeEnd = new Date(plannedTimeEnd);
try {
MainApp.instance().getDbHelper().getDaoTempBasals().update(extendedBolus);
} catch (SQLException e) {
e.printStackTrace();
log.error(e.getMessage());
}
if (Config.logPumpComm)
log.debug("Canceling expired extended bolus: " + extendedBolus);
extendedBolus = null;
}
}
}
@Override
public boolean isTempBasalInProgress() {
return tempBasal != null;
}
@Override
public boolean isExtendedBoluslInProgress() {
return extendedBolus != null;
}
@Override
public Integer getBatteryPercent() {
return batteryPercent;
}
@Override
public Integer getReservoirValue() {
return resevoirInUnits;
}
@Override
public void setNewBasalProfile(NSProfile profile) {
// Do nothing here. we are using MainApp.getNSProfile();
}
@Override
public double getBaseBasalRate() {
NSProfile profile = MainApp.getNSProfile();
if (profile == null)
return defaultBasalValue;
return profile.getBasal(profile.secondsFromMidnight());
}
@Override
public double getTempBasalAbsoluteRate() {
if (!isTempBasalInProgress())
return 0;
if (tempBasal.isAbsolute) {
return tempBasal.absolute;
} else {
NSProfile profile = MainApp.getNSProfile();
if (profile == null)
return defaultBasalValue;
Double baseRate = profile.getBasal(profile.secondsFromMidnight());
Double tempRate = baseRate * (tempBasal.percent / 100d);
return baseRate + tempRate;
}
}
@Override
public double getTempBasalRemainingMinutes() {
if (!isTempBasalInProgress())
return 0;
return tempBasal.getRemainingMinutes();
}
@Override
public Result deliverTreatment(Double insulin, Double carbs) {
Result result = new Result();
result.success = true;
result.bolusDelivered = insulin;
result.comment = getString(R.string.virtualpump_resultok);
Treatment t = new Treatment();
t.insulin = insulin;
t.carbs = carbs;
t.created_at = new Date();
try {
MainApp.instance().getDbHelper().getDaoTreatments().create(t);
} catch (SQLException e) {
e.printStackTrace();
result.success = false;
result.comment = getString(R.string.virtualpump_sqlerror);
}
if (Config.logPumpComm)
log.debug("Delivering treatment: " + t + " " + result);
return result;
}
@Override
public Result setTempBasalAbsolute(Double absoluteRate, Integer durationInMinutes) {
checkForExpiredTempsAndExtended();
Result result = cancelTempBasal();
if (!result.success)
return result;
tempBasal = new TempBasal();
tempBasal.timeStart = new Date();
tempBasal.isAbsolute = true;
tempBasal.absolute = absoluteRate;
tempBasal.duration = durationInMinutes;
result.success = true;
result.comment = getString(R.string.virtualpump_resultok);
try {
MainApp.instance().getDbHelper().getDaoTempBasals().create(tempBasal);
} catch (SQLException e) {
e.printStackTrace();
result.success = false;
result.comment = getString(R.string.virtualpump_sqlerror);
}
if (Config.logPumpComm)
log.debug("Setting temp basal absolute: " + result);
return result;
}
@Override
public Result setTempBasalPercent(Integer percent, Integer durationInMinutes) {
checkForExpiredTempsAndExtended();
Result result = cancelTempBasal();
if (!result.success)
return result;
tempBasal = new TempBasal();
tempBasal.timeStart = new Date();
tempBasal.isAbsolute = false;
tempBasal.percent = percent;
tempBasal.duration = durationInMinutes;
result.success = true;
result.comment = getString(R.string.virtualpump_resultok);
try {
MainApp.instance().getDbHelper().getDaoTempBasals().create(tempBasal);
} catch (SQLException e) {
e.printStackTrace();
result.success = false;
result.comment = getString(R.string.virtualpump_sqlerror);
}
if (Config.logPumpComm)
log.debug("Settings temp basal percent: " + result);
return result;
}
@Override
public Result setExtendedBolus(Double insulin, Integer durationInMinutes) {
checkForExpiredTempsAndExtended();
Result result = cancelExtendedBolus();
if (!result.success)
return result;
extendedBolus = new TempBasal();
extendedBolus.timeStart = new Date();
extendedBolus.isExtended = true;
extendedBolus.absolute = insulin * 60d / durationInMinutes;
extendedBolus.duration = durationInMinutes;
result.success = true;
result.comment = getString(R.string.virtualpump_resultok);
try {
MainApp.instance().getDbHelper().getDaoTempBasals().create(extendedBolus);
} catch (SQLException e) {
e.printStackTrace();
result.success = false;
result.comment = getString(R.string.virtualpump_sqlerror);
}
if (Config.logPumpComm)
log.debug("Setting extended bolus: " + result);
return result;
}
@Override
public Result cancelTempBasal() {
checkForExpiredTempsAndExtended();
Result result = new Result();
if (isTempBasalInProgress()) {
tempBasal.timeEnd = new Date();
try {
MainApp.instance().getDbHelper().getDaoTempBasals().update(tempBasal);
} catch (SQLException e) {
e.printStackTrace();
result.success = false;
result.comment = getString(R.string.virtualpump_sqlerror);
}
}
result.success = true;
result.comment = getString(R.string.virtualpump_resultok);
tempBasal = null;
if (Config.logPumpComm)
log.debug("Canceling temp basal: " + result);
return result;
}
@Override
public Result cancelExtendedBolus() {
checkForExpiredTempsAndExtended();
Result result = new Result();
if (isExtendedBoluslInProgress()) {
extendedBolus.timeEnd = new Date();
try {
MainApp.instance().getDbHelper().getDaoTempBasals().update(tempBasal);
} catch (SQLException e) {
e.printStackTrace();
result.success = false;
result.comment = getString(R.string.virtualpump_sqlerror);
}
}
result.success = true;
result.comment = getString(R.string.virtualpump_resultok);
extendedBolus = null;
if (Config.logPumpComm)
log.debug("Canceling extended basal: " + result);
return result;
}
@Override
public JSONObject getJSONStatus(){
JSONObject pump = new JSONObject();
JSONObject battery = new JSONObject();
JSONObject status = new JSONObject();
try {
battery.put("percent", batteryPercent);
status.put("status", "normal");
//status.put("lastbolus", last_bolus_amount);
//status.put("lastbolustime", DateUtil.toISOString(last_bolus_time));
if (isTempBasalInProgress()) {
status.put("tempbasalpct", tempBasal.percent);
status.put("tempbasalstart", DateUtil.toISOString(tempBasal.timeStart));
status.put("tempbasalremainmin", tempBasal.getRemainingMinutes());
}
status.put("timestamp", DateUtil.toISOString(new Date()));
pump.put("battery", battery);
pump.put("status", status);
pump.put("reservoir", getReservoirValue());
pump.put("clock", DateUtil.toISOString(new Date()));
} catch (JSONException e) {
}
return pump;
}
}

View file

@ -4,10 +4,4 @@
android:layout_height="match_parent"
tools:context="info.nightscout.androidaps.plugins.LowSuspend.LowSuspendFragment">
<!-- TODO: Update blank fragment layout -->
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:text="@string/hello_blank_fragment" />
</FrameLayout>

View file

@ -0,0 +1,128 @@
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".plugins.VirtualPump.VirtualPumpFragment">
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceLarge"
android:text="@string/vitualpump_label"
android:layout_gravity="center"
android:layout_marginTop="20dp" />
<LinearLayout
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="20dp">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceMedium"
android:text="@string/virtualpump_basebasalrate_label"
android:singleLine="true"
android:textStyle="bold"
android:layout_marginRight="15dp" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/virtualpump_basabasalrate" />
</LinearLayout>
<LinearLayout
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="10dp">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceMedium"
android:text="@string/virtualpump_tempbasal_label"
android:singleLine="true"
android:textStyle="bold"
android:layout_marginRight="15dp" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/virtualpump_tempbasal" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:layout_marginTop="10dp">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:singleLine="true"
android:text="@string/virtualpump_extendedbolus_label"
android:textAppearance="?android:attr/textAppearanceMedium"
android:textStyle="bold"
android:layout_marginRight="15dp" />
<TextView
android:id="@+id/virtualpump_extendedbolus"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:layout_marginTop="10dp">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:singleLine="true"
android:text="@string/virtualpump_battery_label"
android:textAppearance="?android:attr/textAppearanceMedium"
android:textStyle="bold"
android:layout_marginRight="15dp" />
<TextView
android:id="@+id/virtualpump_battery"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:layout_marginTop="10dp">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:singleLine="true"
android:text="@string/virtualpump_reservoir_label"
android:textAppearance="?android:attr/textAppearanceMedium"
android:textStyle="bold"
android:layout_marginRight="15dp" />
<TextView
android:id="@+id/virtualpump_reservoir"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
</LinearLayout>
</FrameLayout>

View file

@ -21,8 +21,6 @@
<string name="ns_sync_use_absolute_title">Use absolute values</string>
<string name="ns_sync_use_absolute_summary">Use absolute basal values instead of percent in upload to NS</string>
<!-- TODO: Remove or change this placeholder text -->
<string name="hello_blank_fragment">Hello blank fragment</string>
<string name="objectives_objective_label_string">Objective:</string>
<string name="objectives_gate_label_string">Gate:</string>
<string name="objectives_button_start">Start</string>
@ -55,5 +53,13 @@
<string name="treatments_wizard_total_label">TOTAL</string>
<string name="profileview_units_label">Units:</string>
<string name="openapsma_run">Run now</string>
<string name="vitualpump_label">VITUAL PUMP</string>
<string name="virtualpump_basebasalrate_label">Base basal rate:</string>
<string name="virtualpump_tempbasal_label">Temp basal:</string>
<string name="virtualpump_extendedbolus_label">Extended bolus:</string>
<string name="virtualpump_battery_label">Battery:</string>
<string name="virtualpump_reservoir_label">Reservoir:</string>
<string name="virtualpump_resultok">OK</string>
<string name="virtualpump_sqlerror">SQL Error</string>
</resources>