Day 1
* Some UI rework * Start removing (retry) logic from ruffyscripter to ComboPlugin * Cleanups all over * Remove TDD stuff, this can be done independently of a pump * New SPI/API methods confirmAlert, readReservoirLevelAndLastBolus * Add warning and error codes from Combo manual * Rework commands to just execute an action (verification will be in ComboPlugin eventually, together with retry logic) * Rework commands to update state in field as command progresses rather than returnin/throwing. * Initial version reading bolus and error history (no DB sync yet).
This commit is contained in:
parent
14307cb77b
commit
6b6d252173
34 changed files with 909 additions and 1121 deletions
|
@ -15,8 +15,6 @@ import com.squareup.otto.Subscribe;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import de.jotomo.ruffy.spi.CommandResult;
|
import de.jotomo.ruffy.spi.CommandResult;
|
||||||
import de.jotomo.ruffy.spi.PumpState;
|
import de.jotomo.ruffy.spi.PumpState;
|
||||||
import de.jotomo.ruffy.spi.history.Bolus;
|
import de.jotomo.ruffy.spi.history.Bolus;
|
||||||
|
@ -62,20 +60,17 @@ public class ComboFragment extends SubscriberFragment implements View.OnClickLis
|
||||||
public void onClick(View view) {
|
public void onClick(View view) {
|
||||||
switch (view.getId()) {
|
switch (view.getId()) {
|
||||||
case R.id.combo_refresh:
|
case R.id.combo_refresh:
|
||||||
Thread thread = new Thread(new Runnable() {
|
Thread thread = new Thread(() -> ComboPlugin.getPlugin().refreshDataFromPump("User request"));
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
ComboPlugin.getPlugin().refreshDataFromPump("User request");
|
|
||||||
}
|
|
||||||
});
|
|
||||||
thread.start();
|
thread.start();
|
||||||
break;
|
break;
|
||||||
case R.id.combo_error_history:
|
case R.id.combo_error_history:
|
||||||
// TODO show popup with pump errors and comm problems
|
// TODO show popup with pump errors and comm problems
|
||||||
break;
|
break;
|
||||||
case R.id.combo_stats:
|
// case R.id.combo_stats:
|
||||||
// TODO show TDD stats from the pump (later)
|
// TODO show TDD stats from the pump (later)
|
||||||
break;
|
// how about rather making this a pump agnostic thing, it's all in the DB,
|
||||||
|
// add a TDD tab to Treatments?
|
||||||
|
// break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -85,99 +80,97 @@ public class ComboFragment extends SubscriberFragment implements View.OnClickLis
|
||||||
}
|
}
|
||||||
|
|
||||||
public void updateGUI() {
|
public void updateGUI() {
|
||||||
Activity activity = getActivity();
|
Activity fragmentActivity = getActivity();
|
||||||
if (activity != null)
|
if (fragmentActivity != null)
|
||||||
activity.runOnUiThread(new Runnable() {
|
fragmentActivity.runOnUiThread(() -> {
|
||||||
@Override
|
ComboPlugin plugin = ComboPlugin.getPlugin();
|
||||||
public void run() {
|
|
||||||
ComboPlugin plugin = ComboPlugin.getPlugin();
|
|
||||||
|
|
||||||
// activity
|
// state
|
||||||
String activity = plugin.getPump().activity;
|
stateView.setText(plugin.getStateSummary());
|
||||||
activityView.setText(activity != null ? activity : getString(R.string.combo_action_idle));
|
PumpState ps = plugin.getPump().state;
|
||||||
|
if (plugin.getPump().state.errorMsg != null
|
||||||
|
|| ps.insulinState == PumpState.EMPTY
|
||||||
|
|| ps.batteryState == PumpState.EMPTY) {
|
||||||
|
stateView.setTextColor(Color.RED);
|
||||||
|
} else if (plugin.getPump().state.suspended) {
|
||||||
|
stateView.setTextColor(Color.YELLOW);
|
||||||
|
} else {
|
||||||
|
stateView.setTextColor(Color.WHITE);
|
||||||
|
}
|
||||||
|
|
||||||
if (plugin.isInitialized()) {
|
// activity
|
||||||
// state
|
String activity = plugin.getPump().activity;
|
||||||
stateView.setText(plugin.getStateSummary());
|
activityView.setText(activity != null ? activity : getString(R.string.combo_action_idle));
|
||||||
|
|
||||||
PumpState ps = plugin.getPump().state;
|
if (plugin.isInitialized()) {
|
||||||
if (plugin.getPump().state.errorMsg != null
|
// battery
|
||||||
|| ps.insulinState == PumpState.EMPTY
|
if (ps.batteryState == PumpState.EMPTY) {
|
||||||
|| ps.batteryState == PumpState.EMPTY) {
|
batteryView.setText("{fa-battery-empty}");
|
||||||
stateView.setTextColor(Color.RED);
|
batteryView.setTextColor(Color.RED);
|
||||||
} else if (plugin.getPump().state.suspended) {
|
} else if (ps.batteryState == PumpState.LOW) {
|
||||||
stateView.setTextColor(Color.YELLOW);
|
batteryView.setText("{fa-battery-quarter}");
|
||||||
|
batteryView.setTextColor(Color.YELLOW);
|
||||||
|
} else if (ps.batteryState == PumpState.UNKNOWN) {
|
||||||
|
batteryView.setText("");
|
||||||
|
batteryView.setTextColor(Color.YELLOW);
|
||||||
|
} else {
|
||||||
|
batteryView.setText("{fa-battery-full}");
|
||||||
|
batteryView.setTextColor(Color.WHITE);
|
||||||
|
}
|
||||||
|
|
||||||
|
// reservoir
|
||||||
|
int reservoirLevel = plugin.getPump().reservoirLevel;
|
||||||
|
reservoirView.setText(reservoirLevel == -1 ? "" : "" + reservoirLevel + " U");
|
||||||
|
if (ps.insulinState == PumpState.LOW) {
|
||||||
|
reservoirView.setTextColor(Color.YELLOW);
|
||||||
|
} else if (ps.insulinState == PumpState.EMPTY) {
|
||||||
|
reservoirView.setTextColor(Color.RED);
|
||||||
|
} else {
|
||||||
|
reservoirView.setTextColor(Color.WHITE);
|
||||||
|
}
|
||||||
|
|
||||||
|
// last connection
|
||||||
|
CommandResult lastCmdResult = plugin.getPump().lastCmdResult;
|
||||||
|
if (lastCmdResult != null) {
|
||||||
|
String minAgo = DateUtil.minAgo(plugin.getPump().lastSuccessfulConnection);
|
||||||
|
String time = DateUtil.timeString(plugin.getPump().lastSuccessfulConnection);
|
||||||
|
if (plugin.getPump().lastSuccessfulConnection < System.currentTimeMillis() + 30 * 60 * 1000) {
|
||||||
|
lastConnectionView.setText(getString(R.string.combo_no_pump_connection, minAgo));
|
||||||
|
lastConnectionView.setTextColor(Color.RED);
|
||||||
|
}
|
||||||
|
if (plugin.getPump().lastConnectionAttempt > plugin.getPump().lastSuccessfulConnection) {
|
||||||
|
lastConnectionView.setText(R.string.combo_connect_attempt_failed);
|
||||||
|
lastConnectionView.setTextColor(Color.YELLOW);
|
||||||
} else {
|
} else {
|
||||||
stateView.setTextColor(Color.WHITE);
|
lastConnectionView.setText(getString(R.string.combo_last_connection_time, minAgo, time));
|
||||||
|
lastConnectionView.setTextColor(Color.WHITE);
|
||||||
}
|
}
|
||||||
|
|
||||||
// battery
|
// last bolus
|
||||||
if (ps.batteryState == PumpState.EMPTY) {
|
Bolus bolus = plugin.getPump().lastBolus;
|
||||||
batteryView.setText("{fa-battery-empty}");
|
if (bolus != null && bolus.timestamp + 6 * 60 * 60 * 1000 >= System.currentTimeMillis()) {
|
||||||
batteryView.setTextColor(Color.RED);
|
long agoMsc = System.currentTimeMillis() - bolus.timestamp;
|
||||||
} else if (ps.batteryState == PumpState.LOW) {
|
double agoHours = agoMsc / 60d / 60d / 1000d;
|
||||||
batteryView.setText("{fa-battery-quarter}");
|
lastBolusView.setText(getString(R.string.combo_last_bolus,
|
||||||
batteryView.setTextColor(Color.YELLOW);
|
bolus.amount,
|
||||||
|
agoHours,
|
||||||
|
getString(R.string.hoursago),
|
||||||
|
DateUtil.timeString(bolus.timestamp)));
|
||||||
} else {
|
} else {
|
||||||
batteryView.setText("{fa-battery-full}");
|
lastBolusView.setText("");
|
||||||
batteryView.setTextColor(Color.WHITE);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// reservoir
|
// TBR
|
||||||
int reservoirLevel = plugin.getPump().reservoirLevel;
|
boolean tbrActive = ps.tbrPercent != -1 && ps.tbrPercent != 100;
|
||||||
reservoirView.setText(reservoirLevel == -1 ? "" : "" + reservoirLevel + " U");
|
String tbrStr = "";
|
||||||
if (ps.insulinState == PumpState.LOW) {
|
if (tbrActive) {
|
||||||
reservoirView.setTextColor(Color.YELLOW);
|
long minSinceRead = (System.currentTimeMillis() - plugin.getPump().state.timestamp) / 1000 / 60;
|
||||||
} else if (ps.insulinState == PumpState.EMPTY) {
|
long remaining = ps.tbrRemainingDuration - minSinceRead;
|
||||||
reservoirView.setTextColor(Color.RED);
|
if (remaining >= 0) {
|
||||||
} else {
|
tbrStr = getString(R.string.combo_tbr_remaining, ps.tbrPercent, remaining);
|
||||||
reservoirView.setTextColor(Color.WHITE);
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// last connection
|
|
||||||
CommandResult lastCmdResult = plugin.getPump().lastCmdResult;
|
|
||||||
if (lastCmdResult != null) {
|
|
||||||
String minAgo = DateUtil.minAgo(lastCmdResult.completionTime);
|
|
||||||
String time = DateUtil.timeString(lastCmdResult.completionTime);
|
|
||||||
if (plugin.getPump().lastSuccessfulConnection < System.currentTimeMillis() + 30 * 60 * 1000) {
|
|
||||||
lastConnectionView.setText(getString(R.string.combo_no_pump_connection, minAgo));
|
|
||||||
lastConnectionView.setTextColor(Color.RED);
|
|
||||||
}
|
|
||||||
if (plugin.getPump().lastConnectionAttempt > plugin.getPump().lastSuccessfulConnection) {
|
|
||||||
lastConnectionView.setText(R.string.combo_connect_attempt_failed);
|
|
||||||
lastConnectionView.setTextColor(Color.YELLOW);
|
|
||||||
} else {
|
|
||||||
lastConnectionView.setText(getString(R.string.combo_last_connection_time, minAgo, time));
|
|
||||||
lastConnectionView.setTextColor(Color.WHITE);
|
|
||||||
}
|
|
||||||
|
|
||||||
// last bolus
|
|
||||||
List<Bolus> history = plugin.getPump().history.bolusHistory;
|
|
||||||
if (!history.isEmpty() && history.get(0).timestamp + 6 * 60 * 60 * 1000 >= System.currentTimeMillis()) {
|
|
||||||
Bolus bolus = history.get(0);
|
|
||||||
long agoMsc = System.currentTimeMillis() - bolus.timestamp;
|
|
||||||
double agoHours = agoMsc / 60d / 60d / 1000d;
|
|
||||||
lastBolusView.setText(getString(R.string.combo_last_bolus,
|
|
||||||
bolus.amount,
|
|
||||||
agoHours,
|
|
||||||
getString(R.string.hoursago),
|
|
||||||
DateUtil.timeString(bolus.timestamp)));
|
|
||||||
} else {
|
|
||||||
lastBolusView.setText("");
|
|
||||||
}
|
|
||||||
|
|
||||||
// TBR
|
|
||||||
boolean tbrActive = ps.tbrPercent != -1 && ps.tbrPercent != 100;
|
|
||||||
String tbrStr = "";
|
|
||||||
if (tbrActive) {
|
|
||||||
long minSinceRead = (System.currentTimeMillis() - lastCmdResult.completionTime) / 1000 / 60;
|
|
||||||
long remaining = ps.tbrRemainingDuration - minSinceRead;
|
|
||||||
if (remaining >= 0) {
|
|
||||||
tbrStr = getString(R.string.combo_tbr_remaining, ps.tbrPercent, remaining);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
tempBasalText.setText(tbrStr);
|
|
||||||
}
|
}
|
||||||
|
tempBasalText.setText(tbrStr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -35,6 +35,7 @@ import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin;
|
||||||
import info.nightscout.androidaps.plugins.Overview.events.EventOverviewBolusProgress;
|
import info.nightscout.androidaps.plugins.Overview.events.EventOverviewBolusProgress;
|
||||||
import info.nightscout.androidaps.plugins.PumpCombo.events.EventComboPumpUpdateGUI;
|
import info.nightscout.androidaps.plugins.PumpCombo.events.EventComboPumpUpdateGUI;
|
||||||
import info.nightscout.utils.DateUtil;
|
import info.nightscout.utils.DateUtil;
|
||||||
|
import info.nightscout.utils.DecimalFormatter;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Created by mike on 05.08.2016.
|
* Created by mike on 05.08.2016.
|
||||||
|
@ -51,7 +52,7 @@ public class ComboPlugin implements PluginBase, PumpInterface {
|
||||||
private final RuffyCommands ruffyScripter;
|
private final RuffyCommands ruffyScripter;
|
||||||
|
|
||||||
// TODO access to pump (and its members) is chaotic and needs an update
|
// TODO access to pump (and its members) is chaotic and needs an update
|
||||||
private ComboPump pump = new ComboPump();
|
private static ComboPump pump = new ComboPump();
|
||||||
|
|
||||||
private static ComboPlugin plugin = null;
|
private static ComboPlugin plugin = null;
|
||||||
|
|
||||||
|
@ -128,12 +129,12 @@ public class ComboPlugin implements PluginBase, PumpInterface {
|
||||||
String getStateSummary() {
|
String getStateSummary() {
|
||||||
PumpState ps = pump.state;
|
PumpState ps = pump.state;
|
||||||
if (ps.menu == null)
|
if (ps.menu == null)
|
||||||
return MainApp.sResources.getString(R.string.combo_pump_state_unreachable);
|
return MainApp.sResources.getString(R.string.combo_pump_state_disconnected);
|
||||||
else if (ps.suspended && (ps.batteryState == PumpState.EMPTY || ps.insulinState == PumpState.EMPTY))
|
else if (ps.suspended && (ps.batteryState == PumpState.EMPTY || ps.insulinState == PumpState.EMPTY))
|
||||||
return MainApp.sResources.getString(R.string.combo_pump_state_suspended_due_to_error);
|
return MainApp.sResources.getString(R.string.combo_pump_state_suspended_due_to_error);
|
||||||
else if (ps.suspended)
|
else if (ps.suspended)
|
||||||
return MainApp.sResources.getString(R.string.combo_pump_state_suspended_by_user);
|
return MainApp.sResources.getString(R.string.combo_pump_state_suspended_by_user);
|
||||||
return MainApp.sResources.getString(R.string.combo_pump_state_running);
|
return MainApp.sResources.getString(R.string.combo_pump_state_normal);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -207,41 +208,46 @@ public class ComboPlugin implements PluginBase, PumpInterface {
|
||||||
return new Date(pump.lastSuccessfulConnection);
|
return new Date(pump.lastSuccessfulConnection);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Runs pump initializing if needed, checks for boluses given on the pump, updates the
|
||||||
|
* reservoir level and checks the running TBR on the pump.
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public synchronized void refreshDataFromPump(String reason) {
|
public synchronized void refreshDataFromPump(String reason) {
|
||||||
log.debug("RefreshDataFromPump called");
|
log.debug("RefreshDataFromPump called");
|
||||||
|
|
||||||
if (!pump.initialized) {
|
if (!pump.initialized) {
|
||||||
runCommand(MainApp.sResources.getString(R.string.connecting), new CommandExecution() {
|
// TODO reading profile
|
||||||
@Override
|
long maxWait = System.currentTimeMillis() + 15 * 1000;
|
||||||
public CommandResult execute() {
|
while (!ruffyScripter.isPumpAvailable()) {
|
||||||
return ruffyScripter.readPumpState();
|
log.debug("Waiting for ruffy service to be connected ...");
|
||||||
|
SystemClock.sleep(100);
|
||||||
|
if (System.currentTimeMillis() > maxWait) {
|
||||||
|
log.debug("ruffy service unavailable, wtf");
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
checkPumpHistory();
|
runCommand("Initializing", () -> ruffyScripter.readHistory(new PumpHistoryRequest()));
|
||||||
pump.initialized = true;
|
pump.initialized = true;
|
||||||
} else {
|
|
||||||
runCommand(MainApp.sResources.getString(R.string.combo_action_refreshing), new CommandExecution() {
|
|
||||||
@Override
|
|
||||||
public CommandResult execute() {
|
|
||||||
return ruffyScripter.readHistory(new PumpHistoryRequest().reservoirLevel(true).bolusHistory(PumpHistoryRequest.LAST));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
runCommand("Refreshing", ruffyScripter::readReservoirLevelAndLastBolus);
|
||||||
|
|
||||||
|
// TODO fuse the below into 'sync'? or make checkForTbrMismatch jut a trigger to issue a sync if needed; don't run sync twice as is nice
|
||||||
|
// checkForTbrMismatch();
|
||||||
|
checkPumpHistory();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if there are any changes on the pump AAPS isn't aware of yet and if so, read the
|
||||||
|
* full pump history and update AAPS' DB.
|
||||||
|
*/
|
||||||
private void checkPumpHistory() {
|
private void checkPumpHistory() {
|
||||||
CommandResult commandResult = runCommand("Checking pump history", false, new CommandExecution() {
|
CommandResult commandResult = runCommand(MainApp.sResources.getString(R.string.combo_pump_action_checking_history), () ->
|
||||||
@Override
|
ruffyScripter.readHistory(
|
||||||
public CommandResult execute() {
|
|
||||||
return ruffyScripter.readHistory(
|
|
||||||
new PumpHistoryRequest()
|
new PumpHistoryRequest()
|
||||||
.reservoirLevel(true)
|
|
||||||
.bolusHistory(PumpHistoryRequest.LAST)
|
.bolusHistory(PumpHistoryRequest.LAST)
|
||||||
.tbrHistory(PumpHistoryRequest.LAST)
|
.tbrHistory(PumpHistoryRequest.LAST)
|
||||||
.errorHistory(PumpHistoryRequest.LAST));
|
.errorHistory(PumpHistoryRequest.LAST)));
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!commandResult.success || commandResult.history == null) {
|
if (!commandResult.success || commandResult.history == null) {
|
||||||
// TODO error case, command
|
// TODO error case, command
|
||||||
|
@ -250,6 +256,7 @@ public class ComboPlugin implements PluginBase, PumpInterface {
|
||||||
|
|
||||||
// TODO opt, construct PumpHistoryRequest to requset only what needs updating
|
// TODO opt, construct PumpHistoryRequest to requset only what needs updating
|
||||||
boolean syncNeeded = false;
|
boolean syncNeeded = false;
|
||||||
|
PumpHistoryRequest request = new PumpHistoryRequest();
|
||||||
|
|
||||||
// last bolus
|
// last bolus
|
||||||
List<Treatment> treatments = MainApp.getConfigBuilder().getTreatmentsFromHistory();
|
List<Treatment> treatments = MainApp.getConfigBuilder().getTreatmentsFromHistory();
|
||||||
|
@ -267,11 +274,10 @@ public class ComboPlugin implements PluginBase, PumpInterface {
|
||||||
pumpBolus = bolusHistory.get(0);
|
pumpBolus = bolusHistory.get(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (aapsBolus == null || pumpBolus == null) {
|
if ((aapsBolus == null || pumpBolus == null)
|
||||||
syncNeeded = true;
|
|| (Math.abs(aapsBolus.insulin - pumpBolus.amount) > 0.05 || aapsBolus.date != pumpBolus.timestamp)) {
|
||||||
} else if (Math.abs(aapsBolus.insulin - pumpBolus.amount) > 0.05
|
|
||||||
|| aapsBolus.date != pumpBolus.timestamp) {
|
|
||||||
syncNeeded = true;
|
syncNeeded = true;
|
||||||
|
request.bolusHistory = PumpHistoryRequest.FULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
// last tbr
|
// last tbr
|
||||||
|
@ -282,106 +288,89 @@ public class ComboPlugin implements PluginBase, PumpInterface {
|
||||||
}
|
}
|
||||||
Tbr pumpTbr = null;
|
Tbr pumpTbr = null;
|
||||||
List<Tbr> tbrHistory = commandResult.history.tbrHistory;
|
List<Tbr> tbrHistory = commandResult.history.tbrHistory;
|
||||||
if(!tbrHistory.isEmpty()) {
|
if (!tbrHistory.isEmpty()) {
|
||||||
pumpTbr = tbrHistory.get(0);
|
pumpTbr = tbrHistory.get(0);
|
||||||
}
|
}
|
||||||
if (aapsTbr == null || pumpTbr == null) {
|
if ((aapsTbr == null || pumpTbr == null)
|
||||||
syncNeeded = true;
|
|| (aapsTbr.percentRate != pumpTbr.percent || aapsTbr.durationInMinutes != pumpTbr.duration)) {
|
||||||
} else if (aapsTbr.percentRate != pumpTbr.percent || aapsTbr.durationInMinutes != pumpTbr.duration) {
|
|
||||||
syncNeeded = true;
|
syncNeeded = true;
|
||||||
|
request.tbrHistory = PumpHistoryRequest.FULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
// last error
|
// last error
|
||||||
// TODO add DB table
|
// TODO add DB table ... or just keep in memory? does android allow that (fragment kill frenzy) without workarounds?
|
||||||
|
// is comboplugin a service or a class with statics?
|
||||||
|
request.pumpErrorHistory = PumpHistoryRequest.FULL;
|
||||||
|
|
||||||
|
// tdd
|
||||||
|
// TODO; ... just fetch them on-deamand when the user opens the fragment?
|
||||||
|
|
||||||
|
|
||||||
if (syncNeeded) {
|
if (syncNeeded) {
|
||||||
runFullSync();
|
runFullSync(request);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO
|
|
||||||
// detectStateMismatch(): expensive sync, checking everything (detectTbrMisMatch us called for every command)
|
|
||||||
// check 'lasts' of pump against treatment db, request full sync if needed
|
|
||||||
// and also remove treatments the pump doesn't have.
|
|
||||||
// warn about this with a notification? show what was removed on combo tab?
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO uses profile values for the time being
|
// TODO uses profile values for the time being
|
||||||
// this get's called multiple times a minute, must absolutely be cached
|
|
||||||
@Override
|
@Override
|
||||||
public double getBaseBasalRate() {
|
public double getBaseBasalRate() {
|
||||||
|
/* if (pump.basalProfile == null) {
|
||||||
|
// TODO when to force refresh this?
|
||||||
|
CommandResult result = runCommand("Reading basal profile", new CommandExecution() {
|
||||||
|
@Override
|
||||||
|
public CommandResult execute() {
|
||||||
|
return ruffyScripter.readBasalProfile(1);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
pump.basalProfile = result.basalProfile;
|
||||||
|
// TODO error handling ...
|
||||||
|
}
|
||||||
|
return pump.basalProfile.hourlyRates[Calendar.getInstance().get(Calendar.HOUR_OF_DAY)];
|
||||||
|
*/
|
||||||
|
|
||||||
Profile profile = MainApp.getConfigBuilder().getProfile();
|
Profile profile = MainApp.getConfigBuilder().getProfile();
|
||||||
Double basal = profile.getBasal();
|
Double basal = profile.getBasal();
|
||||||
log.trace("getBaseBasalrate returning " + basal);
|
log.trace("getBaseBasalrate returning " + basal);
|
||||||
return basal;
|
return basal;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static BolusProgressReporter nullBolusProgressReporter = new BolusProgressReporter() {
|
private static BolusProgressReporter nullBolusProgressReporter = (state, percent, delivered) -> {
|
||||||
@Override
|
|
||||||
public void report(State state, int percent, double delivered) {}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
private static BolusProgressReporter bolusProgressReporter =
|
private static BolusProgressReporter bolusProgressReporter = (state, percent, delivered) -> {
|
||||||
new BolusProgressReporter() {
|
EventOverviewBolusProgress event = EventOverviewBolusProgress.getInstance();
|
||||||
@Override
|
switch (state) {
|
||||||
public void report(BolusProgressReporter.State state, int percent, double delivered) {
|
case PROGRAMMING:
|
||||||
EventOverviewBolusProgress event = EventOverviewBolusProgress.getInstance();
|
event.status = MainApp.sResources.getString(R.string.combo_programming_bolus);
|
||||||
switch (state) {
|
break;
|
||||||
case PROGRAMMING:
|
case DELIVERING:
|
||||||
event.status = MainApp.sResources.getString(R.string.combo_programming_bolus);
|
event.status = String.format(MainApp.sResources.getString(R.string.bolusdelivering), delivered);
|
||||||
break;
|
break;
|
||||||
case DELIVERING:
|
case DELIVERED:
|
||||||
event.status = String.format(MainApp.sResources.getString(R.string.bolusdelivering), delivered);
|
event.status = String.format(MainApp.sResources.getString(R.string.bolusdelivered), delivered);
|
||||||
break;
|
break;
|
||||||
case DELIVERED:
|
case STOPPING:
|
||||||
event.status = String.format(MainApp.sResources.getString(R.string.bolusdelivered), delivered);
|
event.status = MainApp.sResources.getString(R.string.bolusstopping);
|
||||||
break;
|
break;
|
||||||
case STOPPING:
|
case STOPPED:
|
||||||
event.status = MainApp.sResources.getString(R.string.bolusstopping);
|
event.status = MainApp.sResources.getString(R.string.bolusstopped);
|
||||||
break;
|
break;
|
||||||
case STOPPED:
|
case FINISHED:
|
||||||
event.status = MainApp.sResources.getString(R.string.bolusstopped);
|
// no state, just percent below to close bolus progress dialog
|
||||||
break;
|
break;
|
||||||
case FINISHED:
|
}
|
||||||
// no state, just percent below to close bolus progress dialog
|
event.percent = percent;
|
||||||
break;
|
MainApp.bus().post(event);
|
||||||
}
|
};
|
||||||
event.percent = percent;
|
|
||||||
MainApp.bus().post(event);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Updates Treatment records with carbs and boluses and delivers a bolus if needed
|
* Updates Treatment records with carbs and boluses and delivers a bolus if needed
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public PumpEnactResult deliverTreatment(DetailedBolusInfo detailedBolusInfo) {
|
public PumpEnactResult deliverTreatment(DetailedBolusInfo detailedBolusInfo) {
|
||||||
|
// TODO for non-SMB: read resorvoir level first to make sure there's enough insulin left
|
||||||
try {
|
try {
|
||||||
if (detailedBolusInfo.insulin > 0 || detailedBolusInfo.carbs > 0) {
|
if (detailedBolusInfo.insulin == 0 && detailedBolusInfo.carbs == 0) {
|
||||||
if (detailedBolusInfo.insulin > 0) {
|
|
||||||
// bolus needed, ask pump to deliver it
|
|
||||||
return deliverBolus(detailedBolusInfo);
|
|
||||||
} else {
|
|
||||||
// no bolus required, carb only treatment
|
|
||||||
|
|
||||||
// TODO the ui freezes when the calculator issues a carb-only treatment
|
|
||||||
// so just wait, yeah, this is dumb. for now; proper fix via GL#10
|
|
||||||
// info.nightscout.androidaps.plugins.Overview.Dialogs.BolusProgressDialog.scheduleDismiss()
|
|
||||||
SystemClock.sleep(6000);
|
|
||||||
PumpEnactResult pumpEnactResult = new PumpEnactResult();
|
|
||||||
pumpEnactResult.success = true;
|
|
||||||
pumpEnactResult.enacted = true;
|
|
||||||
pumpEnactResult.bolusDelivered = 0d;
|
|
||||||
pumpEnactResult.carbsDelivered = detailedBolusInfo.carbs;
|
|
||||||
pumpEnactResult.comment = MainApp.instance().getString(R.string.virtualpump_resultok);
|
|
||||||
MainApp.getConfigBuilder().addToHistoryTreatment(detailedBolusInfo);
|
|
||||||
|
|
||||||
EventOverviewBolusProgress bolusingEvent = EventOverviewBolusProgress.getInstance();
|
|
||||||
bolusingEvent.percent = 100;
|
|
||||||
MainApp.bus().post(bolusingEvent);
|
|
||||||
return pumpEnactResult;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// neither carbs nor bolus requested
|
// neither carbs nor bolus requested
|
||||||
PumpEnactResult pumpEnactResult = new PumpEnactResult();
|
PumpEnactResult pumpEnactResult = new PumpEnactResult();
|
||||||
pumpEnactResult.success = false;
|
pumpEnactResult.success = false;
|
||||||
|
@ -391,6 +380,24 @@ public class ComboPlugin implements PluginBase, PumpInterface {
|
||||||
pumpEnactResult.comment = MainApp.instance().getString(R.string.danar_invalidinput);
|
pumpEnactResult.comment = MainApp.instance().getString(R.string.danar_invalidinput);
|
||||||
log.error("deliverTreatment: Invalid input");
|
log.error("deliverTreatment: Invalid input");
|
||||||
return pumpEnactResult;
|
return pumpEnactResult;
|
||||||
|
} else if (detailedBolusInfo.insulin > 0) {
|
||||||
|
// bolus needed, ask pump to deliver it
|
||||||
|
return deliverBolus(detailedBolusInfo);
|
||||||
|
} else {
|
||||||
|
// no bolus required, carb only treatment
|
||||||
|
SystemClock.sleep(6000);
|
||||||
|
PumpEnactResult pumpEnactResult = new PumpEnactResult();
|
||||||
|
pumpEnactResult.success = true;
|
||||||
|
pumpEnactResult.enacted = true;
|
||||||
|
pumpEnactResult.bolusDelivered = 0d;
|
||||||
|
pumpEnactResult.carbsDelivered = detailedBolusInfo.carbs;
|
||||||
|
pumpEnactResult.comment = MainApp.instance().getString(R.string.virtualpump_resultok);
|
||||||
|
MainApp.getConfigBuilder().addToHistoryTreatment(detailedBolusInfo);
|
||||||
|
|
||||||
|
EventOverviewBolusProgress bolusingEvent = EventOverviewBolusProgress.getInstance();
|
||||||
|
bolusingEvent.percent = 100;
|
||||||
|
MainApp.bus().post(bolusingEvent);
|
||||||
|
return pumpEnactResult;
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
MainApp.bus().post(new EventComboPumpUpdateGUI());
|
MainApp.bus().post(new EventComboPumpUpdateGUI());
|
||||||
|
@ -399,18 +406,18 @@ public class ComboPlugin implements PluginBase, PumpInterface {
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
private PumpEnactResult deliverBolus(final DetailedBolusInfo detailedBolusInfo) {
|
private PumpEnactResult deliverBolus(final DetailedBolusInfo detailedBolusInfo) {
|
||||||
CommandResult bolusCmdResult = runCommand(MainApp.sResources.getString(R.string.combo_action_bolusing), new CommandExecution() {
|
// TODO
|
||||||
@Override
|
// before non-SMB: check enough insulin is available, check we're up to date on boluses
|
||||||
public CommandResult execute() {
|
// after bolus: update reservoir level and check the bolus we just did is actually there
|
||||||
return ruffyScripter.deliverBolus(detailedBolusInfo.insulin,
|
|
||||||
detailedBolusInfo.isSMB ? nullBolusProgressReporter : bolusProgressReporter);
|
// retry flag: reconnect, kill warning, check if command can be restarted, restart
|
||||||
}
|
CommandResult bolusCmdResult = runCommand(MainApp.sResources.getString(R.string.combo_action_bolusing), () -> ruffyScripter.deliverBolus(detailedBolusInfo.insulin,
|
||||||
});
|
detailedBolusInfo.isSMB ? nullBolusProgressReporter : bolusProgressReporter));
|
||||||
|
|
||||||
PumpEnactResult pumpEnactResult = new PumpEnactResult();
|
PumpEnactResult pumpEnactResult = new PumpEnactResult();
|
||||||
pumpEnactResult.success = bolusCmdResult.success;
|
pumpEnactResult.success = bolusCmdResult.success;
|
||||||
pumpEnactResult.enacted = bolusCmdResult.enacted;
|
pumpEnactResult.enacted = bolusCmdResult.enacted;
|
||||||
pumpEnactResult.comment = bolusCmdResult.message;
|
// pumpEnactResult.comment = bolusCmdResult.message;
|
||||||
|
|
||||||
// if enacted, add bolus and carbs to treatment history
|
// if enacted, add bolus and carbs to treatment history
|
||||||
if (pumpEnactResult.enacted) {
|
if (pumpEnactResult.enacted) {
|
||||||
|
@ -421,7 +428,7 @@ public class ComboPlugin implements PluginBase, PumpInterface {
|
||||||
pumpEnactResult.bolusDelivered = detailedBolusInfo.insulin;
|
pumpEnactResult.bolusDelivered = detailedBolusInfo.insulin;
|
||||||
pumpEnactResult.carbsDelivered = detailedBolusInfo.carbs;
|
pumpEnactResult.carbsDelivered = detailedBolusInfo.carbs;
|
||||||
|
|
||||||
detailedBolusInfo.date = bolusCmdResult.completionTime;
|
detailedBolusInfo.date = System.currentTimeMillis();
|
||||||
MainApp.getConfigBuilder().addToHistoryTreatment(detailedBolusInfo);
|
MainApp.getConfigBuilder().addToHistoryTreatment(detailedBolusInfo);
|
||||||
} else {
|
} else {
|
||||||
pumpEnactResult.bolusDelivered = 0d;
|
pumpEnactResult.bolusDelivered = 0d;
|
||||||
|
@ -432,6 +439,8 @@ public class ComboPlugin implements PluginBase, PumpInterface {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void stopBolusDelivering() {
|
public void stopBolusDelivering() {
|
||||||
|
// TODO note that we requested this, so we can thandle this proper in runCommand;
|
||||||
|
// or is it fine if the command returns success with noting enacted and history checks as well/**/
|
||||||
ruffyScripter.cancelBolus();
|
ruffyScripter.cancelBolus();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -471,16 +480,11 @@ public class ComboPlugin implements PluginBase, PumpInterface {
|
||||||
}
|
}
|
||||||
|
|
||||||
final int finalAdjustedPercent = adjustedPercent;
|
final int finalAdjustedPercent = adjustedPercent;
|
||||||
CommandResult commandResult = runCommand(MainApp.sResources.getString(R.string.combo_action_setting_tbr), new CommandExecution() {
|
CommandResult commandResult = runCommand(MainApp.sResources.getString(R.string.combo_action_setting_tbr), () -> ruffyScripter.setTbr(finalAdjustedPercent, durationInMinutes));
|
||||||
@Override
|
|
||||||
public CommandResult execute() {
|
|
||||||
return ruffyScripter.setTbr(finalAdjustedPercent, durationInMinutes);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
if (commandResult.enacted) {
|
if (commandResult.enacted) {
|
||||||
TemporaryBasal tempStart = new TemporaryBasal(commandResult.completionTime);
|
pump.tbrSetTime = System.currentTimeMillis();
|
||||||
|
TemporaryBasal tempStart = new TemporaryBasal(pump.tbrSetTime);
|
||||||
// TODO commandResult.state.tbrRemainingDuration might already display 29 if 30 was set, since 29:59 is shown as 29 ...
|
// TODO commandResult.state.tbrRemainingDuration might already display 29 if 30 was set, since 29:59 is shown as 29 ...
|
||||||
// we should check this, but really ... something must be really screwed up if that number was anything different
|
// we should check this, but really ... something must be really screwed up if that number was anything different
|
||||||
// TODO actually ... might setting 29 help with gaps between TBRs? w/o the hack in TemporaryBasal?
|
// TODO actually ... might setting 29 help with gaps between TBRs? w/o the hack in TemporaryBasal?
|
||||||
|
@ -496,7 +500,7 @@ public class ComboPlugin implements PluginBase, PumpInterface {
|
||||||
PumpEnactResult pumpEnactResult = new PumpEnactResult();
|
PumpEnactResult pumpEnactResult = new PumpEnactResult();
|
||||||
pumpEnactResult.success = commandResult.success;
|
pumpEnactResult.success = commandResult.success;
|
||||||
pumpEnactResult.enacted = commandResult.enacted;
|
pumpEnactResult.enacted = commandResult.enacted;
|
||||||
pumpEnactResult.comment = commandResult.message;
|
// pumpEnactResult.comment = commandResult.message;
|
||||||
pumpEnactResult.isPercent = true;
|
pumpEnactResult.isPercent = true;
|
||||||
// Combo would have bailed if this wasn't set properly. Maybe we should
|
// Combo would have bailed if this wasn't set properly. Maybe we should
|
||||||
// have the command return this anyways ...
|
// have the command return this anyways ...
|
||||||
|
@ -524,21 +528,16 @@ public class ComboPlugin implements PluginBase, PumpInterface {
|
||||||
if (activeTemp == null || userRequested) {
|
if (activeTemp == null || userRequested) {
|
||||||
/* v1 compatibility to sync DB to pump if they diverged (activeTemp == null) */
|
/* v1 compatibility to sync DB to pump if they diverged (activeTemp == null) */
|
||||||
log.debug("cancelTempBasal: hard-cancelling TBR since user requested");
|
log.debug("cancelTempBasal: hard-cancelling TBR since user requested");
|
||||||
commandResult = runCommand(MainApp.sResources.getString(R.string.combo_action_cancelling_tbr), new CommandExecution() {
|
commandResult = runCommand(MainApp.sResources.getString(R.string.combo_action_cancelling_tbr), ruffyScripter::cancelTbr);
|
||||||
@Override
|
|
||||||
public CommandResult execute() {
|
|
||||||
return ruffyScripter.cancelTbr();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
if (commandResult.enacted) {
|
if (commandResult.enacted) {
|
||||||
tempBasal = new TemporaryBasal(commandResult.completionTime);
|
tempBasal = new TemporaryBasal(System.currentTimeMillis());
|
||||||
tempBasal.durationInMinutes = 0;
|
tempBasal.durationInMinutes = 0;
|
||||||
tempBasal.source = Source.USER;
|
tempBasal.source = Source.USER;
|
||||||
pumpEnactResult.isTempCancel = true;
|
pumpEnactResult.isTempCancel = true;
|
||||||
}
|
}
|
||||||
} else if ((activeTemp.percentRate >= 90 && activeTemp.percentRate <= 110) && activeTemp.getPlannedRemainingMinutes() <= 15) {
|
} else if ((activeTemp.percentRate >= 90 && activeTemp.percentRate <= 110) && activeTemp.getPlannedRemainingMinutes() <= 15) {
|
||||||
// Let fake neutral temp keep running (see below)
|
// Let fake neutral temp keep run (see below)
|
||||||
log.debug("cancelTempBasal: skipping changing tbr since it already is at " + activeTemp.percentRate + "% and running for another " + activeTemp.getPlannedRemainingMinutes() + " mins.");
|
log.debug("cancelTempBasal: skipping changing tbr since it already is at " + activeTemp.percentRate + "% and running for another " + activeTemp.getPlannedRemainingMinutes() + " mins.");
|
||||||
pumpEnactResult.comment = "cancelTempBasal skipping changing tbr since it already is at " + activeTemp.percentRate + "% and running for another " + activeTemp.getPlannedRemainingMinutes() + " mins.";
|
pumpEnactResult.comment = "cancelTempBasal skipping changing tbr since it already is at " + activeTemp.percentRate + "% and running for another " + activeTemp.getPlannedRemainingMinutes() + " mins.";
|
||||||
// TODO check what AAPS does with this; no DB update is required;
|
// TODO check what AAPS does with this; no DB update is required;
|
||||||
|
@ -552,15 +551,10 @@ public class ComboPlugin implements PluginBase, PumpInterface {
|
||||||
// on whether the TBR we're cancelling is above or below 100%.
|
// on whether the TBR we're cancelling is above or below 100%.
|
||||||
final int percentage = (activeTemp.percentRate > 100) ? 110 : 90;
|
final int percentage = (activeTemp.percentRate > 100) ? 110 : 90;
|
||||||
log.debug("cancelTempBasal: changing TBR to " + percentage + "% for 15 mins.");
|
log.debug("cancelTempBasal: changing TBR to " + percentage + "% for 15 mins.");
|
||||||
commandResult = runCommand(MainApp.sResources.getString(R.string.combo_action_setting_tbr), new CommandExecution() {
|
commandResult = runCommand(MainApp.sResources.getString(R.string.combo_action_setting_tbr), () -> ruffyScripter.setTbr(percentage, 15));
|
||||||
@Override
|
|
||||||
public CommandResult execute() {
|
|
||||||
return ruffyScripter.setTbr(percentage, 15);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
if (commandResult.enacted) {
|
if (commandResult.enacted) {
|
||||||
tempBasal = new TemporaryBasal(commandResult.completionTime);
|
tempBasal = new TemporaryBasal(System.currentTimeMillis());
|
||||||
tempBasal.durationInMinutes = 15;
|
tempBasal.durationInMinutes = 15;
|
||||||
tempBasal.source = Source.USER;
|
tempBasal.source = Source.USER;
|
||||||
tempBasal.percentRate = percentage;
|
tempBasal.percentRate = percentage;
|
||||||
|
@ -576,7 +570,7 @@ public class ComboPlugin implements PluginBase, PumpInterface {
|
||||||
if (commandResult != null) {
|
if (commandResult != null) {
|
||||||
pumpEnactResult.success = commandResult.success;
|
pumpEnactResult.success = commandResult.success;
|
||||||
pumpEnactResult.enacted = commandResult.enacted;
|
pumpEnactResult.enacted = commandResult.enacted;
|
||||||
pumpEnactResult.comment = commandResult.message;
|
// pumpEnactResult.comment = commandResult.message;
|
||||||
}
|
}
|
||||||
return pumpEnactResult;
|
return pumpEnactResult;
|
||||||
}
|
}
|
||||||
|
@ -585,23 +579,47 @@ public class ComboPlugin implements PluginBase, PumpInterface {
|
||||||
CommandResult execute();
|
CommandResult execute();
|
||||||
}
|
}
|
||||||
|
|
||||||
private CommandResult runCommand(String status, CommandExecution commandExecution) {
|
// TODO if there was an error (or the pump was suspended) force a resync before a bolus;
|
||||||
return runCommand(status, true, commandExecution);
|
// transport a message, e.g. 'new bolus found on pump, synced, check and issue bolus again'
|
||||||
|
// back to the user?b
|
||||||
|
|
||||||
}
|
private synchronized CommandResult runCommand(String activity, CommandExecution commandExecution) {
|
||||||
|
if (activity != null) {
|
||||||
|
pump.activity = activity;
|
||||||
|
MainApp.bus().post(new EventComboPumpUpdateGUI());
|
||||||
|
}
|
||||||
|
|
||||||
private CommandResult runCommand(String activity, boolean checkTbrMisMatch, CommandExecution commandExecution) {
|
// CommandResult precheck = ruffyScripter.readPumpState();
|
||||||
pump.activity = activity;
|
// tbrcheck?
|
||||||
MainApp.bus().post(new EventComboPumpUpdateGUI());
|
// check for active alert; if warning confirm; on warning confirm, read history (bolus, errors), which shall raise alerts if appropriate
|
||||||
|
//
|
||||||
|
// precheck.
|
||||||
|
|
||||||
CommandResult commandResult = commandExecution.execute();
|
CommandResult commandResult = commandExecution.execute();
|
||||||
|
pump.lastCmdResult = commandResult;
|
||||||
|
pump.lastConnectionAttempt = System.currentTimeMillis();
|
||||||
if (commandResult.success) {
|
if (commandResult.success) {
|
||||||
pump.lastSuccessfulConnection = System.currentTimeMillis();
|
pump.lastSuccessfulConnection = System.currentTimeMillis();
|
||||||
} else {
|
|
||||||
pump.lastConnectionAttempt = System.currentTimeMillis();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// copy over state (as supplied) so it will still be available when another command runs that doesn't return that data
|
||||||
|
pump.state = commandResult.state;
|
||||||
|
if (commandResult.reservoirLevel != -1) {
|
||||||
|
pump.reservoirLevel = commandResult.reservoirLevel;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (commandResult.lastBolus != null) {
|
||||||
|
pump.lastBolus = commandResult.lastBolus;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (commandResult.history != null) {
|
||||||
|
if (!commandResult.history.bolusHistory.isEmpty()) {
|
||||||
|
pump.lastBolus = commandResult.history.bolusHistory.get(0);
|
||||||
|
}
|
||||||
|
pump.history = commandResult.history;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// TODO hm... automatically confirm messages and return them and handle them here proper?
|
// TODO hm... automatically confirm messages and return them and handle them here proper?
|
||||||
// with an option to corfirm all messages, non-critical (letting occlusion alert ring on phone and pump)
|
// with an option to corfirm all messages, non-critical (letting occlusion alert ring on phone and pump)
|
||||||
// or let all alarms ring and don't try to control the pump in any way
|
// or let all alarms ring and don't try to control the pump in any way
|
||||||
|
@ -627,105 +645,76 @@ public class ComboPlugin implements PluginBase, PumpInterface {
|
||||||
commandResult.state = takeOverAlarmResult.state;
|
commandResult.state = takeOverAlarmResult.state;
|
||||||
}*/
|
}*/
|
||||||
|
|
||||||
pump.lastCmdResult = commandResult;
|
|
||||||
pump.state = commandResult.state;
|
|
||||||
|
|
||||||
// TODO call this explicitely when needed after/before calling this?
|
// TODO call this explicitely when needed after/before calling this?
|
||||||
if (checkTbrMisMatch) {
|
// if (checkTbrMisMatch) {
|
||||||
checkForTbrMismatch();
|
// checkForTbrMismatch();
|
||||||
}
|
// }
|
||||||
|
|
||||||
|
|
||||||
// TODO not propely set all the time ...
|
|
||||||
if (pump.lastCmdResult == null) {
|
|
||||||
log.error("JOE: no!");
|
|
||||||
} else {
|
|
||||||
// still crashable ...
|
|
||||||
// TODO only update if command was successful? -> KeepAliveReceiver, triggering alarm on unavaiblae pump
|
|
||||||
pump.lastCmdResult.completionTime = System.currentTimeMillis();
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO merge all new history here?
|
|
||||||
if (commandResult.history != null) {
|
|
||||||
if (commandResult.history.reservoirLevel != -1) {
|
|
||||||
pump.reservoirLevel = commandResult.history.reservoirLevel;
|
|
||||||
}
|
|
||||||
pump.history = commandResult.history;
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO in the event of an error schedule a resync
|
// TODO in the event of an error schedule a resync
|
||||||
|
|
||||||
pump.activity = null;
|
if (activity != null) {
|
||||||
MainApp.bus().post(new EventComboPumpUpdateGUI());
|
pump.activity = null;
|
||||||
|
MainApp.bus().post(new EventComboPumpUpdateGUI());
|
||||||
|
}
|
||||||
return commandResult;
|
return commandResult;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO rename to checkState or so and also check time (& date) of pump
|
||||||
private void checkForTbrMismatch() {
|
private void checkForTbrMismatch() {
|
||||||
// detectTbrMismatch(): 'quick' check with not overhead on the pump side
|
// detectTbrMismatch(): 'quick' check with no overhead on the pump side
|
||||||
// TODO check if this works with pump suspend, esp. around pump suspend there'll be syncing to do;
|
// TODO check if this works with pump suspend, esp. around pump suspend there'll be syncing to do;
|
||||||
|
|
||||||
|
// TODO we need to tolerate differences of 1-2 minutes due to the time it takes to programm a tbr
|
||||||
|
// mismatching a 5m interval etc
|
||||||
|
|
||||||
TemporaryBasal aapsTbr = MainApp.getConfigBuilder().getTempBasalFromHistory(System.currentTimeMillis());
|
TemporaryBasal aapsTbr = MainApp.getConfigBuilder().getTempBasalFromHistory(System.currentTimeMillis());
|
||||||
// if (true) {
|
boolean sync = false;
|
||||||
//
|
|
||||||
// // not yet
|
|
||||||
// } else
|
|
||||||
if (aapsTbr == null && pump.state.tbrActive) {
|
if (aapsTbr == null && pump.state.tbrActive) {
|
||||||
// pump runs TBR AAPS is unaware off
|
// pump runs TBR AAPS is unaware off
|
||||||
// => fetch full history so the full TBR is added to treatments
|
log.debug("Pump runs TBR AAPS is unaware of, reading last 3h of pump TBR history");
|
||||||
log.debug("JOE: sync required 1");
|
sync = true;
|
||||||
runFullSync();
|
|
||||||
} else if (aapsTbr != null && !pump.state.tbrActive) {
|
} else if (aapsTbr != null && !pump.state.tbrActive) {
|
||||||
// AAPS has a TBR but the pump isn't running a TBR
|
// AAPS has a TBR but the pump isn't running a TBR
|
||||||
// => remove the TBR from treatments
|
log.debug("AAPS shows TBR but pump isn't running a TBR; deleting TBR in AAPS and reading last 3h of pump TBR history");
|
||||||
// => fetch full history, so that if the TBR was cancelled but ran some time we get the IOB from that partial TBR
|
|
||||||
log.debug("JOE: sync required 2");
|
|
||||||
MainApp.getDbHelper().delete(aapsTbr);
|
MainApp.getDbHelper().delete(aapsTbr);
|
||||||
runFullSync();
|
sync = true;
|
||||||
} else if (aapsTbr != null && pump.state.tbrActive) {
|
} else if (aapsTbr != null && pump.state.tbrActive) {
|
||||||
// both AAPS and pump have a TBR ...
|
// both AAPS and pump have a TBR ...
|
||||||
if (aapsTbr.percentRate != pump.state.tbrPercent) {
|
if (aapsTbr.percentRate != pump.state.tbrPercent) {
|
||||||
// ... but they have different percentages
|
// ... but they have different percentages
|
||||||
// => remove TBR from treatments
|
log.debug("TBR percentage differs between AAPS and pump; deleting TBR in AAPS and reading last 3h of pump TBR history");
|
||||||
// => full history sync so we get up to date on actual IOB
|
|
||||||
log.debug("JOE: sync required 3");
|
|
||||||
MainApp.getDbHelper().delete(aapsTbr);
|
MainApp.getDbHelper().delete(aapsTbr);
|
||||||
runFullSync();
|
sync = true;
|
||||||
}
|
}
|
||||||
int durationDiff = Math.abs(aapsTbr.getPlannedRemainingMinutes() - pump.state.tbrRemainingDuration);
|
int durationDiff = Math.abs(aapsTbr.getPlannedRemainingMinutes() - pump.state.tbrRemainingDuration);
|
||||||
if (durationDiff > 2) {
|
if (durationDiff > 2) {
|
||||||
// ... but they have different runtimes
|
// ... but they have different runtimes
|
||||||
// ^ same as above, merge branches
|
log.debug("TBR duration differs between AAPS and pump; deleting TBR in AAPS and reading last 3h of pump TBR history");
|
||||||
log.debug("JOE: sync required 4");
|
|
||||||
MainApp.getDbHelper().delete(aapsTbr);
|
MainApp.getDbHelper().delete(aapsTbr);
|
||||||
runFullSync();
|
sync = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (sync) {
|
||||||
|
runFullSync(new PumpHistoryRequest().tbrHistory(System.currentTimeMillis() - 3 * 60 * 60 * 1000));
|
||||||
|
}
|
||||||
|
|
||||||
// TODO request a loop run to (re)apply a TBR/SMB given this new information? or just wait till next iteration?
|
// TODO request a loop run to (re)apply a TBR/SMB given this new information? or just wait till next iteration?
|
||||||
// could take 15m or so if there are missed SGVs ...
|
// could take 15m or so if there are missed SGVs ...
|
||||||
|
// new sensitivity calc required, no?
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void runFullSync() {
|
private void runFullSync(final PumpHistoryRequest request) {
|
||||||
// TODO separate fetching and comparing
|
CommandResult result = runCommand("Syncing full pump history", () -> ruffyScripter.readHistory(request));
|
||||||
if (1 == 1 ) {
|
|
||||||
log.error("Skipping full sync - not implemented yet");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
CommandResult commandResult = runCommand("Syncing full pump history", false, new CommandExecution() {
|
|
||||||
@Override
|
|
||||||
public CommandResult execute() {
|
|
||||||
return ruffyScripter.readHistory(
|
|
||||||
new PumpHistoryRequest()
|
|
||||||
.reservoirLevel(true)
|
|
||||||
.bolusHistory(PumpHistoryRequest.FULL)
|
|
||||||
.tbrHistory(PumpHistoryRequest.FULL)
|
|
||||||
.errorHistory(PumpHistoryRequest.FULL)
|
|
||||||
.tddHistory(PumpHistoryRequest.FULL)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
|
// boluses
|
||||||
|
|
||||||
|
// TBRs
|
||||||
|
|
||||||
|
// errors
|
||||||
|
// TODO
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -734,44 +723,55 @@ public class ComboPlugin implements PluginBase, PumpInterface {
|
||||||
return OPERATION_NOT_SUPPORTED;
|
return OPERATION_NOT_SUPPORTED;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns the state of the pump as it was received during last pump comms.
|
|
||||||
// TODO v2 add battery, reservoir info when we start reading that and clean up the code
|
|
||||||
@Override
|
@Override
|
||||||
public JSONObject getJSONStatus() {
|
public JSONObject getJSONStatus() {
|
||||||
CommandResult lastCmdResult = pump.lastCmdResult;
|
if (!pump.initialized) {
|
||||||
if (lastCmdResult == null || lastCmdResult.completionTime + 5 * 60 * 1000L < System.currentTimeMillis()) {
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
JSONObject pumpJson = new JSONObject();
|
JSONObject pumpJson = new JSONObject();
|
||||||
|
pumpJson.put("clock", DateUtil.toISOString(pump.lastSuccessfulConnection));
|
||||||
|
pumpJson.put("reservoir", pump.reservoirLevel);
|
||||||
|
|
||||||
JSONObject statusJson = new JSONObject();
|
JSONObject statusJson = new JSONObject();
|
||||||
JSONObject extendedJson = new JSONObject();
|
|
||||||
statusJson.put("status", getStateSummary());
|
statusJson.put("status", getStateSummary());
|
||||||
extendedJson.put("Version", BuildConfig.VERSION_NAME + "-" + BuildConfig.BUILDVERSION);
|
statusJson.put("timestamp", pump.lastSuccessfulConnection);
|
||||||
try {
|
|
||||||
extendedJson.put("ActiveProfile", MainApp.getConfigBuilder().getProfileName());
|
|
||||||
} catch (Exception e) {
|
|
||||||
}
|
|
||||||
statusJson.put("timestamp", lastCmdResult.completionTime);
|
|
||||||
|
|
||||||
PumpState ps = pump.state;
|
|
||||||
if (ps != null) {
|
|
||||||
if (ps.tbrActive) {
|
|
||||||
extendedJson.put("TempBasalAbsoluteRate", ps.tbrRate);
|
|
||||||
extendedJson.put("TempBasalPercent", ps.tbrPercent);
|
|
||||||
extendedJson.put("TempBasalRemaining", ps.tbrRemainingDuration);
|
|
||||||
}
|
|
||||||
if (ps.errorMsg != null) {
|
|
||||||
extendedJson.put("ErrorMessage", ps.errorMsg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// more info here .... look at dana plugin
|
|
||||||
|
|
||||||
pumpJson.put("status", statusJson);
|
pumpJson.put("status", statusJson);
|
||||||
|
|
||||||
|
JSONObject extendedJson = new JSONObject();
|
||||||
|
extendedJson.put("Version", BuildConfig.VERSION_NAME + "-" + BuildConfig.BUILDVERSION);
|
||||||
|
extendedJson.put("ActiveProfile", MainApp.getConfigBuilder().getProfileName());
|
||||||
|
if (pump.lastBolus != null) {
|
||||||
|
extendedJson.put("LastBolus", new Date(pump.lastBolus.timestamp).toLocaleString());
|
||||||
|
extendedJson.put("LastBolusAmount", DecimalFormatter.to1Decimal(pump.lastBolus.amount));
|
||||||
|
}
|
||||||
|
PumpState ps = pump.state;
|
||||||
|
if (ps.tbrActive) {
|
||||||
|
extendedJson.put("TempBasalAbsoluteRate", ps.tbrRate);
|
||||||
|
extendedJson.put("TempBasalPercent", ps.tbrPercent);
|
||||||
|
extendedJson.put("TempBasalRemaining", ps.tbrRemainingDuration);
|
||||||
|
}
|
||||||
|
if (ps.errorMsg != null) {
|
||||||
|
extendedJson.put("ErrorMessage", ps.errorMsg);
|
||||||
|
}
|
||||||
pumpJson.put("extended", extendedJson);
|
pumpJson.put("extended", extendedJson);
|
||||||
pumpJson.put("clock", DateUtil.toISOString(lastCmdResult.completionTime));
|
|
||||||
|
JSONObject batteryJson = new JSONObject();
|
||||||
|
int battery;
|
||||||
|
switch (ps.batteryState) {
|
||||||
|
case PumpState.EMPTY:
|
||||||
|
battery = 0;
|
||||||
|
break;
|
||||||
|
case PumpState.LOW:
|
||||||
|
battery = 25;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
battery = 75;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
batteryJson.put("percent", battery);
|
||||||
|
pumpJson.put("battery", batteryJson);
|
||||||
|
|
||||||
return pumpJson;
|
return pumpJson;
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
|
@ -781,10 +781,8 @@ public class ComboPlugin implements PluginBase, PumpInterface {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO
|
|
||||||
@Override
|
@Override
|
||||||
public String deviceID() {
|
public String deviceID() {
|
||||||
// Serial number here
|
|
||||||
return "Combo";
|
return "Combo";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -795,7 +793,6 @@ public class ComboPlugin implements PluginBase, PumpInterface {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String shortStatus(boolean veryShort) {
|
public String shortStatus(boolean veryShort) {
|
||||||
// TODO trim for wear if veryShort==true
|
|
||||||
return getStateSummary();
|
return getStateSummary();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,24 +3,31 @@ package info.nightscout.androidaps.plugins.PumpCombo;
|
||||||
import android.support.annotation.NonNull;
|
import android.support.annotation.NonNull;
|
||||||
import android.support.annotation.Nullable;
|
import android.support.annotation.Nullable;
|
||||||
|
|
||||||
|
import de.jotomo.ruffy.spi.BasalProfile;
|
||||||
import de.jotomo.ruffy.spi.PumpState;
|
import de.jotomo.ruffy.spi.PumpState;
|
||||||
import de.jotomo.ruffy.spi.CommandResult;
|
import de.jotomo.ruffy.spi.CommandResult;
|
||||||
|
import de.jotomo.ruffy.spi.history.Bolus;
|
||||||
import de.jotomo.ruffy.spi.history.PumpHistory;
|
import de.jotomo.ruffy.spi.history.PumpHistory;
|
||||||
|
|
||||||
class ComboPump {
|
class ComboPump {
|
||||||
// TODO actually ... this isn't about successful command execution, but whether we could connect to the pump at all
|
// TODO all non-state (==main screen) data is overriden by commands, no? put them seperately
|
||||||
|
// at least skim over how dana does it!
|
||||||
boolean initialized = false;
|
boolean initialized = false;
|
||||||
|
// TODO actually ... this isn't about successful command execution, but whether we could connect to the pump at all
|
||||||
volatile long lastSuccessfulConnection;
|
volatile long lastSuccessfulConnection;
|
||||||
volatile long lastConnectionAttempt;
|
volatile long lastConnectionAttempt;
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
volatile CommandResult lastCmdResult;
|
volatile CommandResult lastCmdResult;
|
||||||
|
|
||||||
public volatile String activity;
|
public volatile String activity;
|
||||||
@NonNull
|
@NonNull
|
||||||
volatile PumpState state = new PumpState();
|
volatile PumpState state = new PumpState();
|
||||||
volatile int reservoirLevel = -1;
|
volatile int reservoirLevel = -1;
|
||||||
|
volatile Bolus lastBolus = null;
|
||||||
|
@Nullable
|
||||||
|
volatile BasalProfile basalProfile;
|
||||||
@NonNull
|
@NonNull
|
||||||
|
|
||||||
volatile PumpHistory history = new PumpHistory();
|
volatile PumpHistory history = new PumpHistory();
|
||||||
|
/** Time the active TBR was set (if any) */
|
||||||
|
long tbrSetTime;
|
||||||
}
|
}
|
||||||
|
|
|
@ -56,7 +56,9 @@ public class KeepAliveReceiver extends BroadcastReceiver {
|
||||||
private void checkPump() {
|
private void checkPump() {
|
||||||
final PumpInterface pump = MainApp.getConfigBuilder();
|
final PumpInterface pump = MainApp.getConfigBuilder();
|
||||||
final Profile profile = MainApp.getConfigBuilder().getProfile();
|
final Profile profile = MainApp.getConfigBuilder().getProfile();
|
||||||
if (pump != null && pump.isInitialized() && profile != null && profile.getBasal() != null) {
|
if (pump != null && /* TODO does this prevent the error in case the pump is never initialized because it was never reachable? */
|
||||||
|
// pump.isInitialized() &&
|
||||||
|
profile != null && profile.getBasal() != null) {
|
||||||
Date lastConnection = pump.lastDataTime();
|
Date lastConnection = pump.lastDataTime();
|
||||||
|
|
||||||
boolean isStatusOutdated = lastConnection.getTime() + 15 * 60 * 1000L < System.currentTimeMillis();
|
boolean isStatusOutdated = lastConnection.getTime() + 15 * 60 * 1000L < System.currentTimeMillis();
|
||||||
|
@ -71,7 +73,7 @@ public class KeepAliveReceiver extends BroadcastReceiver {
|
||||||
// The alarm sound is played back as regular media, that means it might be muted if sound level is at 0
|
// The alarm sound is played back as regular media, that means it might be muted if sound level is at 0
|
||||||
// a simple 'Enable/disable alarms' button on the actions tab?
|
// a simple 'Enable/disable alarms' button on the actions tab?
|
||||||
Notification n = new Notification(Notification.PUMP_UNREACHABLE,
|
Notification n = new Notification(Notification.PUMP_UNREACHABLE,
|
||||||
MainApp.sResources.getString(R.string.combo_pump_state_unreachable), Notification.URGENT);
|
MainApp.sResources.getString(R.string.combo_pump_state_disconnected), Notification.URGENT);
|
||||||
n.soundId = R.raw.alarm;
|
n.soundId = R.raw.alarm;
|
||||||
MainApp.bus().post(new EventNewNotification(n));
|
MainApp.bus().post(new EventNewNotification(n));
|
||||||
} else if (SP.getBoolean("syncprofiletopump", false) && !pump.isThisProfileSet(profile)) {
|
} else if (SP.getBoolean("syncprofiletopump", false) && !pump.isThisProfileSet(profile)) {
|
||||||
|
|
|
@ -95,7 +95,7 @@
|
||||||
android:gravity="start"
|
android:gravity="start"
|
||||||
android:paddingLeft="5dp"
|
android:paddingLeft="5dp"
|
||||||
android:textColor="@android:color/white"
|
android:textColor="@android:color/white"
|
||||||
android:textSize="20dp" />
|
android:textSize="20sp" />
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
|
@ -360,19 +360,6 @@
|
||||||
android:paddingRight="0dp"
|
android:paddingRight="0dp"
|
||||||
android:text="@string/combo_refresh" />
|
android:text="@string/combo_refresh" />
|
||||||
|
|
||||||
<!-- TODO v3-->
|
|
||||||
<Button
|
|
||||||
android:id="@+id/combo_stats"
|
|
||||||
style="@style/ButtonSmallFontStyle"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_weight="1"
|
|
||||||
android:drawableTop="@drawable/icon_danarstats"
|
|
||||||
android:paddingLeft="0dp"
|
|
||||||
android:paddingRight="0dp"
|
|
||||||
android:visibility="gone"
|
|
||||||
android:text="@string/combo_stats" />
|
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
android:id="@+id/combo_error_history"
|
android:id="@+id/combo_error_history"
|
||||||
style="@style/ButtonSmallFontStyle"
|
style="@style/ButtonSmallFontStyle"
|
||||||
|
|
|
@ -684,13 +684,12 @@
|
||||||
<string name="pump_errors_history">Fehlerprotokol</string>
|
<string name="pump_errors_history">Fehlerprotokol</string>
|
||||||
<string name="treatments_wizard_tt_label">TZ</string>
|
<string name="treatments_wizard_tt_label">TZ</string>
|
||||||
<string name="combo_pump_state_label">Status</string>
|
<string name="combo_pump_state_label">Status</string>
|
||||||
<string name="combo_pump_state_unreachable">Keine Verbindung zur Pumpe</string>
|
<string name="combo_pump_state_disconnected">Keine Verbindung zur Pumpe</string>
|
||||||
<string name="combo_pump_state_suspended_by_user">Durch Benuzter gestoppt</string>
|
<string name="combo_pump_state_suspended_by_user">Durch Benuzter gestoppt</string>
|
||||||
<string name="combo_pump_state_suspended_due_to_error">Wegen Fehler gestoppt</string>
|
<string name="combo_pump_state_suspended_due_to_error">Wegen Fehler gestoppt</string>
|
||||||
<string name="combo_pump_state_running">Normaler Betrieb</string>
|
<string name="combo_pump_state_normal">Normaler Betrieb</string>
|
||||||
<string name="combo_stats">Statistiken</string>
|
<string name="combo_stats">Statistiken</string>
|
||||||
<string name="combo_programming_bolus">Bolusabgabe wird vorbereitet</string>
|
<string name="combo_programming_bolus">Bolusabgabe wird vorbereitet</string>
|
||||||
<string name="combo_action_refreshing">Aktualisierung</string>
|
|
||||||
<string name="combo_action_cancelling_tbr">TBR wird abgebrochen</string>
|
<string name="combo_action_cancelling_tbr">TBR wird abgebrochen</string>
|
||||||
<string name="combo_action_setting_tbr">TBR wird gesetzt</string>
|
<string name="combo_action_setting_tbr">TBR wird gesetzt</string>
|
||||||
<string name="combo_action_bolusing">Bolus wird abgegeben</string>
|
<string name="combo_action_bolusing">Bolus wird abgegeben</string>
|
||||||
|
|
|
@ -748,7 +748,6 @@
|
||||||
<string name="reuse">reuse</string>
|
<string name="reuse">reuse</string>
|
||||||
<string name="wearcontrol_title">Controls from Watch</string>
|
<string name="wearcontrol_title">Controls from Watch</string>
|
||||||
<string name="wearcontrol_summary">Set Temp-Targets and enter Treatments from the watch.</string>
|
<string name="wearcontrol_summary">Set Temp-Targets and enter Treatments from the watch.</string>
|
||||||
<!-- TODO combo: still needed? -->
|
|
||||||
<string name="connectiontimedout">Connection timed out</string>
|
<string name="connectiontimedout">Connection timed out</string>
|
||||||
<string name="active"><![CDATA[<Active>]]></string>
|
<string name="active"><![CDATA[<Active>]]></string>
|
||||||
<string name="waitingforestimatedbolusend" formatted="false">Waiting for estimated bolus end. Remaining %d sec.</string>
|
<string name="waitingforestimatedbolusend" formatted="false">Waiting for estimated bolus end. Remaining %d sec.</string>
|
||||||
|
@ -766,12 +765,12 @@
|
||||||
<string name="combo_connect_attempt_failed">Last connect attempt failed</string>
|
<string name="combo_connect_attempt_failed">Last connect attempt failed</string>
|
||||||
<string name="combo_last_connection_time">%s (%s)</string>
|
<string name="combo_last_connection_time">%s (%s)</string>
|
||||||
<string name="combo_tbr_remaining">%d%% (%d remaining)</string>
|
<string name="combo_tbr_remaining">%d%% (%d remaining)</string>
|
||||||
<string name="combo_last_bolus">%.2f U (%.1f %s, %s)</string>
|
<string name="combo_last_bolus">%.1f U (%.1f %s, %s)</string>
|
||||||
<string name="combo_pump_state_unreachable">Pump unreachable</string>
|
<string name="combo_pump_state_disconnected">Pump disconnected</string>
|
||||||
<string name="combo_pump_state_suspended_due_to_error">Suspended due to error</string>
|
<string name="combo_pump_state_suspended_due_to_error">Suspended due to error</string>
|
||||||
<string name="combo_pump_state_suspended_by_user">Suspended by user</string>
|
<string name="combo_pump_state_suspended_by_user">Suspended by user</string>
|
||||||
<string name="combo_pump_state_running">Running</string>
|
<string name="combo_pump_state_normal">Normal</string>
|
||||||
<string name="combo_action_refreshing">Refreshing</string>
|
<string name="combo_pump_action_checking_history">Checking pump history</string>
|
||||||
<string name="combo_action_cancelling_tbr">Cancelling TBR</string>
|
<string name="combo_action_cancelling_tbr">Cancelling TBR</string>
|
||||||
<string name="combo_action_setting_tbr">Setting TBR</string>
|
<string name="combo_action_setting_tbr">Setting TBR</string>
|
||||||
<string name="combo_action_bolusing">Bolusing</string>
|
<string name="combo_action_bolusing">Bolusing</string>
|
||||||
|
|
|
@ -1,38 +1,43 @@
|
||||||
package de.jotomo.ruffy.spi;
|
package de.jotomo.ruffy.spi;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.Date;
|
||||||
|
|
||||||
|
import de.jotomo.ruffy.spi.history.Bolus;
|
||||||
import de.jotomo.ruffy.spi.history.PumpHistory;
|
import de.jotomo.ruffy.spi.history.PumpHistory;
|
||||||
|
|
||||||
public class CommandResult {
|
public class CommandResult {
|
||||||
/** The request made made to the pump, like setting a TBR. */
|
|
||||||
public String request;
|
|
||||||
/** Whether the command was executed successfully. */
|
/** Whether the command was executed successfully. */
|
||||||
public boolean success;
|
public boolean success;
|
||||||
/** Whether any changes were made, e.g. if a the request was to cancel a running TBR,
|
/** Whether any changes were made, e.g. if a the request was to cancel a running TBR,
|
||||||
* but not TBR was active, this will be false. */
|
* but not TBR was active, this will be false. */
|
||||||
public boolean enacted;
|
public boolean enacted;
|
||||||
/** Time the command completed. */
|
|
||||||
public long completionTime;
|
|
||||||
/** Null unless an unhandled exception was raised. */
|
/** Null unless an unhandled exception was raised. */
|
||||||
public Exception exception;
|
public Exception exception;
|
||||||
/** (Error)message describing the result of the command. */
|
/** (Error)message describing the result of the command. */
|
||||||
public String message;
|
// TODO work outh this message
|
||||||
|
// public String message;
|
||||||
/** State of the pump *after* command execution. */
|
/** State of the pump *after* command execution. */
|
||||||
public PumpState state;
|
public PumpState state;
|
||||||
/** History if requested by the command. */
|
/** History if requested by the command. */
|
||||||
public PumpHistory history;
|
public PumpHistory history;
|
||||||
/** Basal rate profile if requested. */
|
/** Basal rate profile if requested. */
|
||||||
public List<BasalProfile> basalProfiles;
|
public BasalProfile basalProfile;
|
||||||
/** Total duration the command took. */
|
/** Total duration the command took. */
|
||||||
public String duration;
|
public String duration;
|
||||||
|
|
||||||
public CommandResult() {
|
/** Whether an alert (warning only) was confirmed. This can happen during boluses.
|
||||||
}
|
* Request error history to see which errors occured. */
|
||||||
|
public boolean alertConfirmed;
|
||||||
|
/** BolusCommand: if a cancel request was successful */
|
||||||
|
public boolean wasSuccessfullyCancelled;
|
||||||
|
|
||||||
public CommandResult request(String request) {
|
public int reservoirLevel = -1;
|
||||||
this.request = request;
|
|
||||||
return this;
|
public Bolus lastBolus;
|
||||||
|
|
||||||
|
public long pumpTime;
|
||||||
|
|
||||||
|
public CommandResult() {
|
||||||
}
|
}
|
||||||
|
|
||||||
public CommandResult success(boolean success) {
|
public CommandResult success(boolean success) {
|
||||||
|
@ -45,11 +50,6 @@ public class CommandResult {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public CommandResult completionTime(long completionTime) {
|
|
||||||
this.completionTime = completionTime;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public CommandResult duration(String duration) {
|
public CommandResult duration(String duration) {
|
||||||
this.duration = duration;
|
this.duration = duration;
|
||||||
return this;
|
return this;
|
||||||
|
@ -60,10 +60,10 @@ public class CommandResult {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public CommandResult message(String message) {
|
// public CommandResult message(String message) {
|
||||||
this.message = message;
|
// this.message = message;
|
||||||
return this;
|
// return this;
|
||||||
}
|
// }
|
||||||
|
|
||||||
public CommandResult state(PumpState state) {
|
public CommandResult state(PumpState state) {
|
||||||
this.state = state;
|
this.state = state;
|
||||||
|
@ -75,24 +75,24 @@ public class CommandResult {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public CommandResult basalProfile(List<BasalProfile> basalProfiles) {
|
public CommandResult basalProfile(BasalProfile basalProfile) {
|
||||||
this.basalProfiles = basalProfiles;
|
this.basalProfile = basalProfile;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "CommandResult{" +
|
return "CommandResult{" +
|
||||||
"request='" + request + '\'' +
|
|
||||||
", success=" + success +
|
", success=" + success +
|
||||||
", enacted=" + enacted +
|
", enacted=" + enacted +
|
||||||
", completionTime=" + completionTime +
|
|
||||||
", exception=" + exception +
|
", exception=" + exception +
|
||||||
", message='" + message + '\'' +
|
// ", message='" + message + '\'' +
|
||||||
", state=" + state +
|
", state=" + state +
|
||||||
", history=" + history +
|
", history=" + history +
|
||||||
", basalProfiles=" + basalProfiles +
|
", basalProfile=" + basalProfile +
|
||||||
", duration='" + duration + '\'' +
|
", duration='" + duration + '\'' +
|
||||||
|
", alertConfirmed='" + alertConfirmed + '\'' +
|
||||||
|
", wasSuccessfullyCancelled='" + wasSuccessfullyCancelled + '\'' +
|
||||||
'}';
|
'}';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,17 @@
|
||||||
|
package de.jotomo.ruffy.spi;
|
||||||
|
|
||||||
|
public class PumpErrorCodes {
|
||||||
|
public static final int CARTRIDGE_EMPTY = 1;
|
||||||
|
public static final int BATTERY_EMPTY = 2;
|
||||||
|
public static final int AUTOMATIC_OFF = 3;
|
||||||
|
public static final int OCCLUSION = 4;
|
||||||
|
public static final int END_OF_OPERATION_BACKUP_PUMP = 5;
|
||||||
|
public static final int MECHANICAL_ERROR = 6;
|
||||||
|
public static final int ELECTRONIC_ERROR = 7;
|
||||||
|
public static final int POWER_INTERRUPT = 8;
|
||||||
|
public static final int END_OF_OPERATION_LOAN_PUMP = 9;
|
||||||
|
public static final int CARTRIDGE_ERROR = 10;
|
||||||
|
public static final int SET_NOT_PRIMED = 11;
|
||||||
|
public static final int DATA_INTERRUPTED = 12;
|
||||||
|
public static final int LANGUAGE_ERROR = 13;
|
||||||
|
}
|
|
@ -2,6 +2,7 @@ package de.jotomo.ruffy.spi;
|
||||||
|
|
||||||
/** State displayed on the main screen of the pump. */
|
/** State displayed on the main screen of the pump. */
|
||||||
public class PumpState {
|
public class PumpState {
|
||||||
|
public long timestamp;
|
||||||
public String menu = null;
|
public String menu = null;
|
||||||
public boolean tbrActive = false;
|
public boolean tbrActive = false;
|
||||||
/** TBR percentage. 100% means no TBR active, just the normal basal rate running. */
|
/** TBR percentage. 100% means no TBR active, just the normal basal rate running. */
|
||||||
|
@ -22,10 +23,11 @@ public class PumpState {
|
||||||
public String errorMsg;
|
public String errorMsg;
|
||||||
public boolean suspended;
|
public boolean suspended;
|
||||||
|
|
||||||
|
public static final int UNKNOWN = -1;
|
||||||
public static final int LOW = 1;
|
public static final int LOW = 1;
|
||||||
public static final int EMPTY = 2;
|
public static final int EMPTY = 2;
|
||||||
public int batteryState = - 1;
|
public int batteryState = UNKNOWN;
|
||||||
public int insulinState = -1;
|
public int insulinState = UNKNOWN;
|
||||||
|
|
||||||
public int activeBasalProfileNumber;
|
public int activeBasalProfileNumber;
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,14 @@
|
||||||
|
package de.jotomo.ruffy.spi;
|
||||||
|
|
||||||
|
public class PumpWarningCodes {
|
||||||
|
public static final int CARTRIDGE_LOW = 1;
|
||||||
|
public static final int BATTERY_LOW = 2;
|
||||||
|
public static final int REVIEW_TIME = 3;
|
||||||
|
public static final int CALL_FOR_UPDATE = 4;
|
||||||
|
public static final int PUMP_TIMER = 5;
|
||||||
|
public static final int TBR_CANCELLED = 6;
|
||||||
|
public static final int TBR_OVER = 7;
|
||||||
|
public static final int BOLUS_CANCELLED = 8;
|
||||||
|
public static final int LOANTIME_WARNING = 9;
|
||||||
|
public static final int BLUETOOTH_FAULT = 10;
|
||||||
|
}
|
|
@ -13,81 +13,24 @@ public interface RuffyCommands {
|
||||||
|
|
||||||
CommandResult cancelTbr();
|
CommandResult cancelTbr();
|
||||||
|
|
||||||
// TODO read Dana code wrt to syncing and such
|
CommandResult confirmAlert(int warningCode);
|
||||||
|
|
||||||
/** Confirms an active alarm on the pump. The state returned is the state after the alarm
|
|
||||||
* has been confirmed. Confirmed alerts are returned in history.pumpErrorHistory. */
|
|
||||||
@Deprecated
|
|
||||||
// TODO rename to confirmActiveAlarm (single)
|
|
||||||
// add a field activeAlarm to PumpState and put logic in ComboPlugin.
|
|
||||||
CommandResult takeOverAlarms();
|
|
||||||
// let this be an actual command in RS? or extend readPumpState wit ha flag to return confirmed errors?
|
|
||||||
|
|
||||||
/* plan:
|
|
||||||
|
|
||||||
let errors ring on the pump (all require interacting with the pump anyways and they
|
|
||||||
should not be subject to errors in AAPS/ruffy.
|
|
||||||
|
|
||||||
When connecting to the pump, read the current state. If a warning(s) is ongoing
|
|
||||||
confirm it and forward it and let AAPS display it.
|
|
||||||
Check if a previous command failed (tbr/bolus) and if so, DON'T report a warning
|
|
||||||
caused by an interrupted command.
|
|
||||||
Put the logic in AAPS: don't have readPumpState automatically confirm anything,
|
|
||||||
but read state, call takeOverAlarm(alarm)
|
|
||||||
|
|
||||||
concrete warnings???
|
|
||||||
tbr cancelled => we can almost always just confirm this, we sync aaps if neded
|
|
||||||
bolus => basically the same with SMBs, for user-initiated boluses and error should be reported
|
|
||||||
properly, but that should work since it's interactive and PumpEneact result is
|
|
||||||
or should be checked (verify it is)
|
|
||||||
deliwerTreatment knows if it's SMB or not, whether it's okay to dismiss bolus cancelled alarm.
|
|
||||||
|
|
||||||
battery low => always forward (not configurable, whole point is to make AAPS master)
|
|
||||||
cartridge low => always forward
|
|
||||||
|
|
||||||
when sync detects a significant mismatch it should alert?
|
|
||||||
big bolus on pump aaps didn't knew about???
|
|
||||||
removing a big bolus in aaps db since it's not in pump history? warn? aaps bug.
|
|
||||||
|
|
||||||
==> think this whole comm errors thing through (incl. auto/reconnect, auto-confirm
|
|
||||||
), on LoD - 1 and go back to coding after that
|
|
||||||
|
|
||||||
open: dealing with low cartridge/battery during bolus.
|
|
||||||
also: dealing with empty cartridge/battery alarms we let ring (force resync
|
|
||||||
when 'next possible'. force resync when coming from a suspended state, or any
|
|
||||||
error state in general.
|
|
||||||
if cartridge is low, check reservoir before each bolus and don't attempt
|
|
||||||
to bolus if not enough in reservoir for bolus?
|
|
||||||
(testers: bolus with cartridge very low to run in such scenarios - forget the
|
|
||||||
cartridge is low).
|
|
||||||
|
|
||||||
so: * confirm pump warnings; for tbr/bolus cancelled caused by connection loss don't
|
|
||||||
report them to the user (on disconnect set a flag 'error caused by us' or use.
|
|
||||||
also note connection lose and force history resync if appropriate(?) (LAST).
|
|
||||||
* stuff low warnings: confirm, show in combo tab and give overview notification
|
|
||||||
* keepaliver receiver raises an urgent error if there have been no pump comms in
|
|
||||||
> 25m
|
|
||||||
* errors always ring on the pump, are critical and require the pump to be interacted
|
|
||||||
with, so they're not confirmed. if encountered, they're read and also reported as
|
|
||||||
urgent on the phone. cancel again if we see the user has confirmed them on the pump?
|
|
||||||
(parent monitoring, needing to see an error).
|
|
||||||
make Combo->Status red and "Occlusion" for errors?
|
|
||||||
*/
|
|
||||||
|
|
||||||
boolean isPumpAvailable();
|
boolean isPumpAvailable();
|
||||||
|
|
||||||
boolean isPumpBusy();
|
boolean isPumpBusy();
|
||||||
|
|
||||||
// start everything with this: read pump state.
|
|
||||||
// see if there's an error active.
|
|
||||||
CommandResult readPumpState();
|
CommandResult readPumpState();
|
||||||
|
|
||||||
|
CommandResult readReservoirLevelAndLastBolus();
|
||||||
|
|
||||||
CommandResult readHistory(PumpHistoryRequest request);
|
CommandResult readHistory(PumpHistoryRequest request);
|
||||||
|
|
||||||
CommandResult readBasalProfile(int number);
|
CommandResult readBasalProfile(int number);
|
||||||
|
|
||||||
CommandResult setBasalProfile(BasalProfile basalProfile);
|
CommandResult setBasalProfile(BasalProfile basalProfile);
|
||||||
|
|
||||||
|
CommandResult getDateAndTime();
|
||||||
|
|
||||||
CommandResult setDateAndTime(Date date);
|
CommandResult setDateAndTime(Date date);
|
||||||
|
|
||||||
void requestPairing();
|
void requestPairing();
|
||||||
|
|
|
@ -7,4 +7,12 @@ public class Bolus extends HistoryRecord {
|
||||||
super(timestamp);
|
super(timestamp);
|
||||||
this.amount = amount;
|
this.amount = amount;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "Bolus{" +
|
||||||
|
"timestamp=" + timestamp +
|
||||||
|
", amount=" + amount +
|
||||||
|
'}';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,13 +2,28 @@ package de.jotomo.ruffy.spi.history;
|
||||||
|
|
||||||
public class PumpError extends HistoryRecord {
|
public class PumpError extends HistoryRecord {
|
||||||
/** Code is an E for error or W for warning, followed by a single digit, e.g. W7 (TBR cancelled). */
|
/** Code is an E for error or W for warning, followed by a single digit, e.g. W7 (TBR cancelled). */
|
||||||
public final String code;
|
// public final String code;
|
||||||
|
public final Integer warningCode;
|
||||||
|
|
||||||
|
|
||||||
|
public final Integer errorCode;
|
||||||
/** Error message, in the language configured on the pump. */
|
/** Error message, in the language configured on the pump. */
|
||||||
public final String message;
|
public final String message;
|
||||||
|
|
||||||
public PumpError(long timestamp, String code, String message) {
|
public PumpError(long timestamp, Integer warningCode, Integer errorCode, String message) {
|
||||||
super(timestamp);
|
super(timestamp);
|
||||||
this.code = code;
|
this.warningCode = warningCode;
|
||||||
|
this.errorCode = errorCode;
|
||||||
this.message = message;
|
this.message = message;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "PumpError{" +
|
||||||
|
"timestamp=" + timestamp +
|
||||||
|
", warningCode=" + warningCode +
|
||||||
|
", errorCode=" + errorCode +
|
||||||
|
", message='" + message + '\'' +
|
||||||
|
'}';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,10 +3,10 @@ package de.jotomo.ruffy.spi.history;
|
||||||
import android.support.annotation.NonNull;
|
import android.support.annotation.NonNull;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.LinkedList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
public class PumpHistory {
|
public class PumpHistory {
|
||||||
public int reservoirLevel = -1;
|
|
||||||
@NonNull
|
@NonNull
|
||||||
public List<Bolus> bolusHistory = new ArrayList<>();
|
public List<Bolus> bolusHistory = new ArrayList<>();
|
||||||
@NonNull
|
@NonNull
|
||||||
|
@ -16,12 +16,6 @@ public class PumpHistory {
|
||||||
@NonNull
|
@NonNull
|
||||||
public List<Tdd> tddHistory = new ArrayList<>();
|
public List<Tdd> tddHistory = new ArrayList<>();
|
||||||
|
|
||||||
public PumpHistory reservoirLevel(int reservoirLevel) {
|
|
||||||
this.reservoirLevel = reservoirLevel
|
|
||||||
;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public PumpHistory bolusHistory(List<Bolus> bolusHistory) {
|
public PumpHistory bolusHistory(List<Bolus> bolusHistory) {
|
||||||
this.bolusHistory = bolusHistory;
|
this.bolusHistory = bolusHistory;
|
||||||
return this;
|
return this;
|
||||||
|
@ -32,7 +26,7 @@ public class PumpHistory {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public PumpHistory errorHistory(List<PumpError> pumpErrorHistory) {
|
public PumpHistory pumpErrorHistory(List<PumpError> pumpErrorHistory) {
|
||||||
this.pumpErrorHistory = pumpErrorHistory;
|
this.pumpErrorHistory = pumpErrorHistory;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
@ -45,7 +39,6 @@ public class PumpHistory {
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "PumpHistory{" +
|
return "PumpHistory{" +
|
||||||
"reservoirLevel=" + reservoirLevel +
|
|
||||||
", bolusHistory=" + bolusHistory.size() +
|
", bolusHistory=" + bolusHistory.size() +
|
||||||
", tbrHistory=" + tbrHistory.size() +
|
", tbrHistory=" + tbrHistory.size() +
|
||||||
", pumpErrorHistory=" + pumpErrorHistory.size() +
|
", pumpErrorHistory=" + pumpErrorHistory.size() +
|
||||||
|
|
|
@ -2,8 +2,6 @@ package de.jotomo.ruffy.spi.history;
|
||||||
|
|
||||||
/** What data a 'read history' request should return. */
|
/** What data a 'read history' request should return. */
|
||||||
public class PumpHistoryRequest {
|
public class PumpHistoryRequest {
|
||||||
public boolean reservoirLevel;
|
|
||||||
|
|
||||||
/* History to read:
|
/* History to read:
|
||||||
Either the timestamp of the last known record to fetch all newer records,
|
Either the timestamp of the last known record to fetch all newer records,
|
||||||
or one of the constants to read no history or all of it.
|
or one of the constants to read no history or all of it.
|
||||||
|
@ -15,12 +13,6 @@ public class PumpHistoryRequest {
|
||||||
public long bolusHistory = SKIP;
|
public long bolusHistory = SKIP;
|
||||||
public long tbrHistory = SKIP;
|
public long tbrHistory = SKIP;
|
||||||
public long pumpErrorHistory = SKIP;
|
public long pumpErrorHistory = SKIP;
|
||||||
public long tddHistory = SKIP;
|
|
||||||
|
|
||||||
public PumpHistoryRequest reservoirLevel(boolean reservoirLevel) {
|
|
||||||
this.reservoirLevel = reservoirLevel;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public PumpHistoryRequest bolusHistory(long bolusHistory) {
|
public PumpHistoryRequest bolusHistory(long bolusHistory) {
|
||||||
this.bolusHistory = bolusHistory;
|
this.bolusHistory = bolusHistory;
|
||||||
|
@ -37,19 +29,12 @@ public class PumpHistoryRequest {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public PumpHistoryRequest tddHistory(long tddHistory) {
|
|
||||||
this.tddHistory = tddHistory;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "PumpHistoryRequest{" +
|
return "PumpHistoryRequest{" +
|
||||||
"reservoirLevel=" + reservoirLevel +
|
|
||||||
", bolusHistory=" + bolusHistory +
|
", bolusHistory=" + bolusHistory +
|
||||||
", tbrHistory=" + tbrHistory +
|
", tbrHistory=" + tbrHistory +
|
||||||
", pumpErrorHistory=" + pumpErrorHistory +
|
", pumpErrorHistory=" + pumpErrorHistory +
|
||||||
", tddHistory=" + tddHistory +
|
|
||||||
'}';
|
'}';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,4 +9,13 @@ public class Tbr extends HistoryRecord {
|
||||||
this.duration = duration;
|
this.duration = duration;
|
||||||
this.percent = percent;
|
this.percent = percent;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "Tbr{" +
|
||||||
|
"timestamp=" + timestamp +
|
||||||
|
", duration=" + duration +
|
||||||
|
", percent=" + percent +
|
||||||
|
'}';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,4 +8,12 @@ public class Tdd extends HistoryRecord {
|
||||||
super(timestamp);
|
super(timestamp);
|
||||||
this.total = total;
|
this.total = total;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "Tdd{" +
|
||||||
|
"timestamp=" + timestamp +
|
||||||
|
", total=" + total +
|
||||||
|
'}';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,12 +21,21 @@ public class RuffyCommandsV1Impl implements RuffyCommands {
|
||||||
return delegate;
|
return delegate;
|
||||||
}
|
}
|
||||||
|
|
||||||
private RuffyCommandsV1Impl() {
|
private RuffyCommandsV1Impl() {}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CommandResult getDateAndTime() {
|
||||||
|
return delegate.getDateAndTime();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CommandResult takeOverAlarms() {
|
public CommandResult readReservoirLevelAndLastBolus() {
|
||||||
return delegate.takeOverAlarms();
|
return delegate.readReservoirLevelAndLastBolus();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CommandResult confirmAlert(int warningCode) {
|
||||||
|
return delegate.confirmAlert(warningCode);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -34,12 +34,13 @@ import de.jotomo.ruffyscripter.commands.BolusCommand;
|
||||||
import de.jotomo.ruffyscripter.commands.CancelTbrCommand;
|
import de.jotomo.ruffyscripter.commands.CancelTbrCommand;
|
||||||
import de.jotomo.ruffyscripter.commands.Command;
|
import de.jotomo.ruffyscripter.commands.Command;
|
||||||
import de.jotomo.ruffyscripter.commands.CommandException;
|
import de.jotomo.ruffyscripter.commands.CommandException;
|
||||||
|
import de.jotomo.ruffyscripter.commands.ConfirmAlertCommand;
|
||||||
import de.jotomo.ruffyscripter.commands.ReadBasalProfileCommand;
|
import de.jotomo.ruffyscripter.commands.ReadBasalProfileCommand;
|
||||||
import de.jotomo.ruffyscripter.commands.ReadHistoryCommand;
|
import de.jotomo.ruffyscripter.commands.ReadHistoryCommand;
|
||||||
import de.jotomo.ruffyscripter.commands.ReadPumpStateCommand;
|
import de.jotomo.ruffyscripter.commands.ReadPumpStateCommand;
|
||||||
|
import de.jotomo.ruffyscripter.commands.ReadReservoirLevelAndLastBolus;
|
||||||
import de.jotomo.ruffyscripter.commands.SetBasalProfileCommand;
|
import de.jotomo.ruffyscripter.commands.SetBasalProfileCommand;
|
||||||
import de.jotomo.ruffyscripter.commands.SetTbrCommand;
|
import de.jotomo.ruffyscripter.commands.SetTbrCommand;
|
||||||
import de.jotomo.ruffyscripter.commands.TakeOverAlarmsCommand;
|
|
||||||
|
|
||||||
// TODO regularly read "My data" history (boluses, TBR) to double check all commands ran successfully.
|
// TODO regularly read "My data" history (boluses, TBR) to double check all commands ran successfully.
|
||||||
// Automatically compare against AAPS db, or log all requests in the PumpInterface (maybe Milos
|
// Automatically compare against AAPS db, or log all requests in the PumpInterface (maybe Milos
|
||||||
|
@ -54,6 +55,7 @@ public class RuffyScripter implements RuffyCommands {
|
||||||
private static final Logger log = LoggerFactory.getLogger(RuffyScripter.class);
|
private static final Logger log = LoggerFactory.getLogger(RuffyScripter.class);
|
||||||
|
|
||||||
private IRuffyService ruffyService;
|
private IRuffyService ruffyService;
|
||||||
|
// TODO never written
|
||||||
private String unrecoverableError = null;
|
private String unrecoverableError = null;
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
|
@ -75,6 +77,8 @@ public class RuffyScripter implements RuffyCommands {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void fail(String message) throws RemoteException {
|
public void fail(String message) throws RemoteException {
|
||||||
|
// 10-28 19:50:54.059 1426 1826 W RuffyScripter: [Thread-268] WARN [de.jotomo.ruffyscripter.RuffyScripter$1:78]: Ruffy warns: no connection possible
|
||||||
|
|
||||||
log.warn("Ruffy warns: " + message);
|
log.warn("Ruffy warns: " + message);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -87,13 +91,11 @@ public class RuffyScripter implements RuffyCommands {
|
||||||
public void rtStopped() throws RemoteException {
|
public void rtStopped() throws RemoteException {
|
||||||
log.debug("rtStopped callback invoked");
|
log.debug("rtStopped callback invoked");
|
||||||
currentMenu = null;
|
currentMenu = null;
|
||||||
connected = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void rtStarted() throws RemoteException {
|
public void rtStarted() throws RemoteException {
|
||||||
log.debug("rtStarted callback invoked");
|
log.debug("rtStarted callback invoked");
|
||||||
connected = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -115,16 +117,6 @@ public class RuffyScripter implements RuffyCommands {
|
||||||
synchronized (screenlock) {
|
synchronized (screenlock) {
|
||||||
screenlock.notifyAll();
|
screenlock.notifyAll();
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO v2 switch to using IRuffyService.isConnected, rather than guessing connectivity state
|
|
||||||
// passed on screen updates
|
|
||||||
connected = true;
|
|
||||||
|
|
||||||
// note that a WARNING_OR_ERROR menu can be a valid temporary state (cancelling TBR)
|
|
||||||
// of a running command
|
|
||||||
if (activeCmd == null && currentMenu.getType() == MenuType.WARNING_OR_ERROR) {
|
|
||||||
log.warn("Warning/error menu encountered without a command running");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -174,9 +166,6 @@ public class RuffyScripter implements RuffyCommands {
|
||||||
return started;
|
return started;
|
||||||
}
|
}
|
||||||
|
|
||||||
private volatile boolean connected = false;
|
|
||||||
private volatile long lastDisconnected = 0;
|
|
||||||
|
|
||||||
private Thread idleDisconnectMonitorThread = new Thread(new Runnable() {
|
private Thread idleDisconnectMonitorThread = new Thread(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
|
@ -184,25 +173,16 @@ public class RuffyScripter implements RuffyCommands {
|
||||||
try {
|
try {
|
||||||
long now = System.currentTimeMillis();
|
long now = System.currentTimeMillis();
|
||||||
long connectionTimeOutMs = 5000;
|
long connectionTimeOutMs = 5000;
|
||||||
if (connected && activeCmd == null
|
if (ruffyService.isConnected() && activeCmd == null
|
||||||
&& now > lastCmdExecutionTime + connectionTimeOutMs
|
&& now > lastCmdExecutionTime + connectionTimeOutMs) {
|
||||||
// don't disconnect too frequently, confuses ruffy?
|
|
||||||
&& now > lastDisconnected + 15 * 1000) {
|
|
||||||
log.debug("Disconnecting after " + (connectionTimeOutMs / 1000) + "s inactivity timeout");
|
log.debug("Disconnecting after " + (connectionTimeOutMs / 1000) + "s inactivity timeout");
|
||||||
lastDisconnected = now;
|
|
||||||
ruffyService.doRTDisconnect();
|
ruffyService.doRTDisconnect();
|
||||||
connected = false;
|
|
||||||
// don't attempt anything fancy in the next 10s, let the pump settle
|
// don't attempt anything fancy in the next 10s, let the pump settle
|
||||||
SystemClock.sleep(10 * 1000);
|
SystemClock.sleep(10 * 1000);
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
// TODO do we need to catch this exception somewhere else too? right now it's
|
log.debug("Exception in idle disconnect monitor thread, taking a break and then carrying on", e);
|
||||||
// converted into a command failure, but it's not classified as unrecoverable;
|
SystemClock.sleep(10 * 1000);
|
||||||
// eventually we might try to recover ... check docs, there's also another
|
|
||||||
// execption we should watch interacting with a remote service.
|
|
||||||
// SecurityException was the other, when there's an AIDL mismatch;
|
|
||||||
//unrecoverableError = "Ruffy service went away";
|
|
||||||
log.debug("Exception in idle disconnect monitor thread, carrying on", e);
|
|
||||||
}
|
}
|
||||||
SystemClock.sleep(1000);
|
SystemClock.sleep(1000);
|
||||||
}
|
}
|
||||||
|
@ -219,18 +199,15 @@ public class RuffyScripter implements RuffyCommands {
|
||||||
return runCommand(new ReadPumpStateCommand());
|
return runCommand(new ReadPumpStateCommand());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CommandResult readReservoirLevelAndLastBolus() {
|
||||||
|
return runCommand(new ReadReservoirLevelAndLastBolus());
|
||||||
|
}
|
||||||
|
|
||||||
public void returnToRootMenu() {
|
public void returnToRootMenu() {
|
||||||
// returning to main menu using the 'back' key does not cause a vibration
|
// returning to main menu using the 'back' key does not cause a vibration
|
||||||
MenuType menuType = getCurrentMenu().getType();
|
MenuType menuType = getCurrentMenu().getType();
|
||||||
while (menuType != MenuType.MAIN_MENU && menuType != MenuType.STOP && menuType != MenuType.WARNING_OR_ERROR) {
|
while (menuType != MenuType.MAIN_MENU && menuType != MenuType.STOP && menuType != MenuType.WARNING_OR_ERROR) {
|
||||||
// if (getCurrentMenu().getType() == MenuType.WARNING_OR_ERROR) {
|
|
||||||
// String errorMsg = (String) getCurrentMenu().getAttribute(MenuAttribute.MESSAGE);
|
|
||||||
// confirmAlert(errorMsg, 1000);
|
|
||||||
// // TODO this isn't gonna work out ... this method can't know if something was enacted ...
|
|
||||||
// // gotta keep that state in the command instance
|
|
||||||
// throw new CommandException().success(false).enacted(false)
|
|
||||||
// .message("Warning/error " + errorMsg + " raised while returning to main menu");
|
|
||||||
// }
|
|
||||||
log.debug("Going back to main menu, currently at " + menuType);
|
log.debug("Going back to main menu, currently at " + menuType);
|
||||||
pressBackKey();
|
pressBackKey();
|
||||||
waitForMenuUpdate();
|
waitForMenuUpdate();
|
||||||
|
@ -238,17 +215,11 @@ public class RuffyScripter implements RuffyCommands {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class Returnable {
|
/** Always returns a CommandResult, never throws */
|
||||||
CommandResult cmdResult;
|
private CommandResult runCommand(final Command cmd) {
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Always returns a CommandResult, never throws
|
|
||||||
*/
|
|
||||||
public CommandResult runCommand(final Command cmd) {
|
|
||||||
log.debug("Attempting to run cmd: " + cmd);
|
log.debug("Attempting to run cmd: " + cmd);
|
||||||
if (unrecoverableError != null) {
|
if (unrecoverableError != null) {
|
||||||
return new CommandResult().success(false).enacted(false).message(unrecoverableError);
|
return new CommandResult().success(false).enacted(false).message(unrecoverableError).state(readPumpStateInternal());
|
||||||
}
|
}
|
||||||
|
|
||||||
List<String> violations = cmd.validateArguments();
|
List<String> violations = cmd.validateArguments();
|
||||||
|
@ -262,59 +233,36 @@ public class RuffyScripter implements RuffyCommands {
|
||||||
activeCmd = cmd;
|
activeCmd = cmd;
|
||||||
long connectStart = System.currentTimeMillis();
|
long connectStart = System.currentTimeMillis();
|
||||||
ensureConnected();
|
ensureConnected();
|
||||||
final Returnable returnable = new Returnable();
|
log.debug("Connection ready to execute cmd " + cmd);
|
||||||
class CommandRunner {
|
Thread cmdThread = new Thread(() -> {
|
||||||
public void run() {
|
try {
|
||||||
try {
|
// TODO fail if currentMenu is not available?
|
||||||
|
Menu localCurrentMenu = currentMenu;
|
||||||
// Except for GetPumpStateCommand: fail on all requests if the pump is suspended.
|
if (localCurrentMenu == null || localCurrentMenu.getType() == MenuType.STOP) {
|
||||||
// All trickery of not executing but returning success, so that AAPS can non-sensically TBR away when suspended
|
if (cmd.needsRunMode()) {
|
||||||
// are dangerous in the current model where commands are dispatched without checking state beforehand, so
|
activeCmd.getResult().success(false).message("Pump is suspended but operations requires to the pump to be running");
|
||||||
// the above tactic would result in boluses not being applied and no warning being raised.
|
return;
|
||||||
// (Doing this check on the ComboPlugin level would require the plugin to fetch state from the pump,
|
|
||||||
// deal with states changes (running/stopped), propagating that to AAPS and so on, adding more state,
|
|
||||||
// which adds complexity I don't want in v1 and which requires more up-front design to do well,
|
|
||||||
// esp. with AAPS).
|
|
||||||
|
|
||||||
// So, for v1, just check the pump is not suspended before executing commands and raising an error for all
|
|
||||||
// but the GetPumpStateCommand. For v2, we'll have to come up with a better idea how to deal with the pump's
|
|
||||||
// state. Maybe having read-only commands and write/treatment commands treated differently, or maybe
|
|
||||||
// build an abstraction on top of the commands, so that e.g. a method on RuffyScripter encapsulates checking
|
|
||||||
// pre-condititions, running one or several commands, checking-post conditions and what not.
|
|
||||||
// Or maybe stick with commands, have them specify if they can run in stop mode. Think properly at which
|
|
||||||
// level to handle state and logic.
|
|
||||||
// For now, when changing cartridges and such: tell AAPS to stop the loop, change cartridge and resume the loop.
|
|
||||||
if (currentMenu == null || currentMenu.getType() == MenuType.STOP) {
|
|
||||||
if (cmd.needsRunMode()) {
|
|
||||||
returnable.cmdResult = new CommandResult().success(false).enacted(false).message("Pump is suspended");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
log.debug("Connection ready to execute cmd " + cmd);
|
|
||||||
PumpState pumpState = readPumpStateInternal();
|
|
||||||
log.debug("Pump state before running command: " + pumpState);
|
|
||||||
long cmdStartTime = System.currentTimeMillis();
|
|
||||||
cmd.setScripter(RuffyScripter.this);
|
|
||||||
returnable.cmdResult = cmd.execute();
|
|
||||||
long cmdEndTime = System.currentTimeMillis();
|
|
||||||
returnable.cmdResult.completionTime = cmdEndTime;
|
|
||||||
log.debug("Executing " + cmd + " took " + (cmdEndTime - cmdStartTime) + "ms");
|
|
||||||
} catch (CommandException e) {
|
|
||||||
returnable.cmdResult = e.toCommandResult();
|
|
||||||
} catch (Exception e) {
|
|
||||||
log.error("Unexpected exception running cmd", e);
|
|
||||||
returnable.cmdResult = new CommandResult().exception(e).message("Unexpected exception running cmd");
|
|
||||||
} finally {
|
|
||||||
lastCmdExecutionTime = System.currentTimeMillis();
|
|
||||||
}
|
}
|
||||||
|
if (localCurrentMenu != null && localCurrentMenu.getType() == MenuType.WARNING_OR_ERROR) {
|
||||||
|
// TODO unless confirmALert command fail here and return message
|
||||||
|
}
|
||||||
|
PumpState pumpState = readPumpStateInternal();
|
||||||
|
log.debug("Pump state before running command: " + pumpState);
|
||||||
|
cmd.setScripter(RuffyScripter.this);
|
||||||
|
long cmdStartTime = System.currentTimeMillis();
|
||||||
|
cmd.execute();
|
||||||
|
long cmdEndTime = System.currentTimeMillis();
|
||||||
|
log.debug("Executing " + cmd + " took " + (cmdEndTime - cmdStartTime) + "ms");
|
||||||
|
} catch (CommandException e) {
|
||||||
|
activeCmd.getResult().message(e.getMessage());
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("Unexpected exception running cmd", e);
|
||||||
|
activeCmd.getResult().message("Unexpected exception running cmd");
|
||||||
|
} finally {
|
||||||
|
lastCmdExecutionTime = System.currentTimeMillis();
|
||||||
}
|
}
|
||||||
}
|
}, cmd.getClass().getSimpleName());
|
||||||
Thread cmdThread = new Thread(new Runnable() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
new CommandRunner().run();
|
|
||||||
}
|
|
||||||
}, cmd.toString());
|
|
||||||
long executionStart = System.currentTimeMillis();
|
long executionStart = System.currentTimeMillis();
|
||||||
cmdThread.start();
|
cmdThread.start();
|
||||||
|
|
||||||
|
@ -331,23 +279,6 @@ public class RuffyScripter implements RuffyCommands {
|
||||||
maxReconnectAttempts--;
|
maxReconnectAttempts--;
|
||||||
cmdThread.interrupt();
|
cmdThread.interrupt();
|
||||||
reconnect();
|
reconnect();
|
||||||
// TODO at least for bigger boluses we should check history after reconnect to make sure
|
|
||||||
// we haven't issued that bolus within the last 1-2m? in case there's a bug in the code ...
|
|
||||||
|
|
||||||
// TODO: only do the reconnect to confirm the alert, then return and let the ComboPlugin decide what to do next;
|
|
||||||
// for bolus: how ... run 'step 2': checking/reading history?! step1 being bolus delivery, so have different resume points? ggrrrmpf
|
|
||||||
// less logic in scripter; just reconnect to confirm alert if needed, then return with error;
|
|
||||||
// let CP read history.LAST to see what actually happened and then resume appropriately.
|
|
||||||
cmdThread = new Thread(new Runnable() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
new CommandRunner().run();
|
|
||||||
}
|
|
||||||
}, cmd.toString());
|
|
||||||
cmdThread.start();
|
|
||||||
// reset timeouts after reconnect
|
|
||||||
dynamicTimeout = calculateCmdInactivityTimeout();
|
|
||||||
overallTimeout = calculateOverallCmdTimeout();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -363,42 +294,33 @@ public class RuffyScripter implements RuffyCommands {
|
||||||
cmdThread.interrupt();
|
cmdThread.interrupt();
|
||||||
SystemClock.sleep(5000);
|
SystemClock.sleep(5000);
|
||||||
log.error("Timed out thread dead yet? " + cmdThread.isAlive());
|
log.error("Timed out thread dead yet? " + cmdThread.isAlive());
|
||||||
return new CommandResult().success(false).enacted(false).message("Command stalled, check pump!");
|
activeCmd.getResult().success(false).message("Command stalled, check pump!");
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (now > overallTimeout) {
|
if (now > overallTimeout) {
|
||||||
String msg = "Command " + cmd + " timed out after 4 min, check pump!";
|
String msg = "Command " + cmd + " timed out after 4 min, check pump!";
|
||||||
log.error(msg);
|
log.error(msg);
|
||||||
return new CommandResult().success(false).enacted(false).message(msg);
|
activeCmd.getResult().success(false).message(msg);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (returnable.cmdResult.state == null) {
|
activeCmd.getResult().state = readPumpStateInternal();
|
||||||
returnable.cmdResult.state = readPumpStateInternal();
|
CommandResult result = activeCmd.getResult();
|
||||||
|
if (log.isDebugEnabled()) {
|
||||||
|
long connectDurationSec = (executionStart - connectStart) / 1000;
|
||||||
|
long executionDurationSec = (System.currentTimeMillis() - executionStart) / 1000;
|
||||||
|
log.debug("Command result: " + result);
|
||||||
|
log.debug("Connect: " + connectDurationSec + "s, execution: " + executionDurationSec + "s");
|
||||||
}
|
}
|
||||||
long connectDurationSec = (executionStart - connectStart) / 1000;
|
return result;
|
||||||
long executionDurationSec = (System.currentTimeMillis() - executionStart) / 1000;
|
|
||||||
returnable.cmdResult.duration = "Connect: " + connectDurationSec + "s, execution: " + executionDurationSec + "s";
|
|
||||||
returnable.cmdResult.request = cmd.toString();
|
|
||||||
log.debug("Command result: " + returnable.cmdResult);
|
|
||||||
return returnable.cmdResult;
|
|
||||||
} catch (CommandException e) {
|
} catch (CommandException e) {
|
||||||
CommandResult commandResult = e.toCommandResult();
|
return activeCmd.getResult().success(false).message(e.getMessage()).state(readPumpStateInternal());
|
||||||
if (commandResult.state == null) commandResult.state = readPumpStateInternal();
|
|
||||||
return commandResult;
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
// TODO catching E here AND in CommandRunner?
|
log.error("Unexpected exception communication with ruffy", e);
|
||||||
// TODO detect and report pump warnings/errors differently?
|
return activeCmd.getResult().success(false).exception(e)
|
||||||
log.error("Error in ruffyscripter/ruffy", e);
|
.message("Unexpected exception communication with ruffy: " + e.getMessage()).state(readPumpStateInternal());
|
||||||
try {
|
|
||||||
return new CommandResult()
|
|
||||||
.exception(e)
|
|
||||||
.message("Unexpected exception communication with ruffy: " + e.getMessage())
|
|
||||||
.state(readPumpStateInternal());
|
|
||||||
} catch (Exception e1) {
|
|
||||||
// nothing more we can try
|
|
||||||
}
|
|
||||||
return new CommandResult().exception(e).message("Unexpected exception communication with ruffy: " + e.getMessage());
|
|
||||||
} finally {
|
} finally {
|
||||||
activeCmd = null;
|
activeCmd = null;
|
||||||
}
|
}
|
||||||
|
@ -420,6 +342,17 @@ public class RuffyScripter implements RuffyCommands {
|
||||||
*
|
*
|
||||||
* @return whether the reconnect and return to main menu was successful
|
* @return whether the reconnect and return to main menu was successful
|
||||||
*/
|
*/
|
||||||
|
// TODO only reconnect, confirm the warning the disconnect caused ond then return to ComboPlugin, which shall decide whether/how to restart
|
||||||
|
// requires turning CommandResult from a return type into a command field
|
||||||
|
|
||||||
|
// TODO at least for bigger boluses we should check history after reconnect to make sure
|
||||||
|
// we haven't issued that bolus within the last 1-2m? in case there's a bug in the code ...
|
||||||
|
|
||||||
|
// TODO: only do the reconnect to confirm the alert, then return and let the ComboPlugin decide what to do next;
|
||||||
|
// for bolus: how ... run 'step 2': checking/reading history?! step1 being bolus delivery, so have different resume points? ggrrrmpf
|
||||||
|
// less logic in scripter; just reconnect to confirm alert if needed, then return with error;
|
||||||
|
// let CP read history.LAST to see what actually happened and then resume appropriately.
|
||||||
|
|
||||||
private boolean reconnect() {
|
private boolean reconnect() {
|
||||||
try {
|
try {
|
||||||
log.debug("Connection was lost, trying to reconnect");
|
log.debug("Connection was lost, trying to reconnect");
|
||||||
|
@ -475,58 +408,37 @@ public class RuffyScripter implements RuffyCommands {
|
||||||
*/
|
*/
|
||||||
private void ensureConnected() {
|
private void ensureConnected() {
|
||||||
try {
|
try {
|
||||||
boolean menuUpdateRecentlyReceived = currentMenu != null && menuLastUpdated + 1000 > System.currentTimeMillis();
|
if (ruffyService.isConnected()) {
|
||||||
log.debug("ensureConnect, connected: " + connected + ", receiving menu updates: " + menuUpdateRecentlyReceived);
|
log.debug("Already connected");
|
||||||
if (menuUpdateRecentlyReceived) {
|
|
||||||
log.debug("Pump is sending us menu updates, so we're connected");
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Occasionally the rtConnect is called a few seconds after the rtDisconnected
|
|
||||||
// callback was called, in response to your disconnect request via doRtDisconnect.
|
|
||||||
// When connecting again shortly after disconnecting, the pump sometimes fails
|
|
||||||
// to come up. So for v1, just wait. This happens rarely, so no overly fancy logic needed.
|
|
||||||
// TODO v2 see if we can do this cleaner, use isDisconnected as well maybe. GL#34.
|
|
||||||
// TODO remove this, will be in the way of quickly reconnecting after an exception and dealing
|
|
||||||
// with an alarm; we'll then see if the pump can deal with this
|
|
||||||
/* if (System.currentTimeMillis() < lastDisconnected + 10 * 1000) {
|
|
||||||
log.debug("Waiting 10s to let pump settle after recent disconnect");
|
|
||||||
SystemClock.sleep(10 * 1000);
|
|
||||||
}*/
|
|
||||||
|
|
||||||
boolean connectInitSuccessful = ruffyService.doRTConnect() == 0;
|
boolean connectInitSuccessful = ruffyService.doRTConnect() == 0;
|
||||||
log.debug("Connect init successful: " + connectInitSuccessful);
|
log.debug("Connect init successful: " + connectInitSuccessful);
|
||||||
log.debug("Waiting for first menu update to be sent");
|
log.debug("Waiting for first menu update to be sent");
|
||||||
// Note: there was an 'if(currentMenu == null)' around the next call, since
|
|
||||||
// the rtDisconnected callback sets currentMenu = null. However, there were
|
|
||||||
// race conditions, so it was removed. And really, waiting for an update
|
|
||||||
// to come in is a much safer bet.
|
|
||||||
|
|
||||||
// waitForMenuUpdate times out after 60s and throws a CommandException.
|
|
||||||
// if the user just pressed a button on the combo, the screen needs to time first
|
|
||||||
// before a connection is possible. In that case, it takes 45s before the
|
|
||||||
// connection comes up.
|
|
||||||
// waitForMenuUpdate(90, "Timeout connecting to pump");
|
|
||||||
long timeoutExpired = System.currentTimeMillis() + 90 * 1000;
|
long timeoutExpired = System.currentTimeMillis() + 90 * 1000;
|
||||||
long initialUpdateTime = menuLastUpdated;
|
long initialUpdateTime = menuLastUpdated;
|
||||||
long again = System.currentTimeMillis() + 30 * 1000;
|
long again = System.currentTimeMillis() + 30 * 1000;
|
||||||
while (initialUpdateTime == menuLastUpdated) {
|
while (initialUpdateTime == menuLastUpdated) {
|
||||||
if (System.currentTimeMillis() > timeoutExpired) {
|
if (System.currentTimeMillis() > timeoutExpired) {
|
||||||
throw new CommandException().message("Timeout connecting to pump");
|
throw new CommandException("Timeout connecting to pump");
|
||||||
}
|
}
|
||||||
SystemClock.sleep(50);
|
SystemClock.sleep(50);
|
||||||
if (again < System.currentTimeMillis()) {
|
if (again < System.currentTimeMillis()) {
|
||||||
// TODO test
|
// TODO test
|
||||||
|
log.debug("Connecting taking long, forcing disconnect first");
|
||||||
ruffyService.doRTDisconnect();
|
ruffyService.doRTDisconnect();
|
||||||
SystemClock.sleep(2000);
|
SystemClock.sleep(2000);
|
||||||
|
log.debug("Connecting again");
|
||||||
ruffyService.doRTConnect();
|
ruffyService.doRTConnect();
|
||||||
|
SystemClock.sleep(1000);
|
||||||
again = System.currentTimeMillis() + 30 * 1000;
|
again = System.currentTimeMillis() + 30 * 1000;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (CommandException e) {
|
} catch (CommandException e) {
|
||||||
throw e;
|
throw e;
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
throw new CommandException().exception(e).message("Unexpected exception while initiating/restoring pump connection");
|
throw new CommandException("Unexpected exception while initiating/restoring pump connection", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -539,6 +451,7 @@ public class RuffyScripter implements RuffyCommands {
|
||||||
*/
|
*/
|
||||||
public PumpState readPumpStateInternal() {
|
public PumpState readPumpStateInternal() {
|
||||||
PumpState state = new PumpState();
|
PumpState state = new PumpState();
|
||||||
|
state.timestamp = System.currentTimeMillis();
|
||||||
Menu menu = currentMenu;
|
Menu menu = currentMenu;
|
||||||
if (menu == null) {
|
if (menu == null) {
|
||||||
return state;
|
return state;
|
||||||
|
@ -571,6 +484,16 @@ public class RuffyScripter implements RuffyCommands {
|
||||||
return state;
|
return state;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int readWarningCode() {
|
||||||
|
verifyMenuIsDisplayed(MenuType.WARNING_OR_ERROR);
|
||||||
|
Integer warningCode = (Integer) getCurrentMenu().getAttribute(MenuAttribute.WARNING);
|
||||||
|
while (warningCode == null) {
|
||||||
|
waitForScreenUpdate();
|
||||||
|
warningCode = (Integer) getCurrentMenu().getAttribute(MenuAttribute.WARNING);
|
||||||
|
}
|
||||||
|
return warningCode;
|
||||||
|
}
|
||||||
|
|
||||||
// below: methods to be used by commands
|
// below: methods to be used by commands
|
||||||
// TODO move into a new Operations(scripter) class commands can delegate to,
|
// TODO move into a new Operations(scripter) class commands can delegate to,
|
||||||
// so this class can focus on providing a connection to run commands
|
// so this class can focus on providing a connection to run commands
|
||||||
|
@ -625,7 +548,7 @@ public class RuffyScripter implements RuffyCommands {
|
||||||
// TODO force reconnect? and retry?
|
// TODO force reconnect? and retry?
|
||||||
while (currentMenu == null) {
|
while (currentMenu == null) {
|
||||||
if (System.currentTimeMillis() > timeout) {
|
if (System.currentTimeMillis() > timeout) {
|
||||||
throw new CommandException().message("Unable to read current menu");
|
throw new CommandException("Unable to read current menu");
|
||||||
}
|
}
|
||||||
log.debug("currentMenu == null, waiting");
|
log.debug("currentMenu == null, waiting");
|
||||||
waitForMenuUpdate();
|
waitForMenuUpdate();
|
||||||
|
@ -678,21 +601,20 @@ public class RuffyScripter implements RuffyCommands {
|
||||||
ruffyService.rtSendKey(Key.NO_KEY, true);
|
ruffyService.rtSendKey(Key.NO_KEY, true);
|
||||||
log.debug("Releasing key");
|
log.debug("Releasing key");
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
throw new CommandException().exception(e).message("Error while pressing buttons");
|
throw new CommandException("Error while pressing buttons");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO sort out usages of this method and waitForMenu update, which have the same intent,
|
// TODO sort out usages of this method and waitForMenu update, which have the same intent,
|
||||||
// but approach things differently;
|
// but approach things differently;
|
||||||
public boolean waitForScreenUpdate(long timeout) {
|
private void waitForScreenUpdate() {
|
||||||
synchronized (screenlock) {
|
synchronized (screenlock) {
|
||||||
try {
|
try {
|
||||||
screenlock.wait(timeout);
|
screenlock.wait((long) 2000); // usually ~500, occassionally up to 1100ms
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
return false;
|
log.debug("Ignoring exception in wait for screenlock", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO v2, rework these two methods: waitForMenuUpdate shoud only be used by commands
|
// TODO v2, rework these two methods: waitForMenuUpdate shoud only be used by commands
|
||||||
|
@ -702,54 +624,19 @@ public class RuffyScripter implements RuffyCommands {
|
||||||
|
|
||||||
// TODO confirmAlarms? and report back which were cancelled?
|
// TODO confirmAlarms? and report back which were cancelled?
|
||||||
|
|
||||||
/**
|
|
||||||
* Confirms and dismisses the given alert if it's raised before the timeout
|
|
||||||
*/
|
|
||||||
public boolean confirmAlert(String alertMessage, int maxWaitMs) {
|
|
||||||
long inFiveSeconds = System.currentTimeMillis() + maxWaitMs;
|
|
||||||
boolean alertProcessed = false;
|
|
||||||
while (System.currentTimeMillis() < inFiveSeconds && !alertProcessed) {
|
|
||||||
if (getCurrentMenu().getType() == MenuType.WARNING_OR_ERROR) {
|
|
||||||
// Note that the message is permanently displayed, while the error code is blinking.
|
|
||||||
// A wait till the error code can be read results in the code hanging, despite
|
|
||||||
// menu updates coming in, so just check the message.
|
|
||||||
// TODO quick try if the can't make reading the error code work ..
|
|
||||||
String errorMsg = (String) getCurrentMenu().getAttribute(MenuAttribute.MESSAGE);
|
|
||||||
if (!errorMsg.equals(alertMessage)) {
|
|
||||||
throw new CommandException().success(false).enacted(false)
|
|
||||||
.message("An alert other than the expected " + alertMessage + " was raised by the pump: "
|
|
||||||
+ errorMsg + ". Please check the pump.");
|
|
||||||
}
|
|
||||||
// confirm alert
|
|
||||||
verifyMenuIsDisplayed(MenuType.WARNING_OR_ERROR);
|
|
||||||
pressCheckKey();
|
|
||||||
// dismiss alert
|
|
||||||
verifyMenuIsDisplayed(MenuType.WARNING_OR_ERROR);
|
|
||||||
pressCheckKey();
|
|
||||||
waitForMenuToBeLeft(MenuType.WARNING_OR_ERROR);
|
|
||||||
alertProcessed = true;
|
|
||||||
}
|
|
||||||
SystemClock.sleep(10);
|
|
||||||
}
|
|
||||||
return alertProcessed;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Wait until the menu is updated
|
* Wait until the menu is updated
|
||||||
*/
|
*/
|
||||||
public void waitForMenuUpdate() {
|
public void waitForMenuUpdate() {
|
||||||
waitForMenuUpdate(60, "Timeout waiting for menu update");
|
waitForScreenUpdate();
|
||||||
}
|
// long timeoutExpired = System.currentTimeMillis() + 60 * 1000;
|
||||||
|
// long initialUpdateTime = menuLastUpdated;
|
||||||
private void waitForMenuUpdate(long timeoutInSeconds, String errorMessage) {
|
// while (initialUpdateTime == menuLastUpdated) {
|
||||||
long timeoutExpired = System.currentTimeMillis() + timeoutInSeconds * 1000;
|
// if (System.currentTimeMillis() > timeoutExpired) {
|
||||||
long initialUpdateTime = menuLastUpdated;
|
// throw new CommandException("Timeout waiting for menu update");
|
||||||
while (initialUpdateTime == menuLastUpdated) {
|
// }
|
||||||
if (System.currentTimeMillis() > timeoutExpired) {
|
// SystemClock.sleep(10);
|
||||||
throw new CommandException().message(errorMessage);
|
// }
|
||||||
}
|
|
||||||
SystemClock.sleep(50);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void pressKey(final byte key) {
|
private void pressKey(final byte key) {
|
||||||
|
@ -758,7 +645,7 @@ public class RuffyScripter implements RuffyCommands {
|
||||||
SystemClock.sleep(150);
|
SystemClock.sleep(150);
|
||||||
ruffyService.rtSendKey(Key.NO_KEY, true);
|
ruffyService.rtSendKey(Key.NO_KEY, true);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
throw new CommandException().exception(e).message("Error while pressing buttons");
|
throw new CommandException("Error while pressing buttons");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -775,7 +662,7 @@ public class RuffyScripter implements RuffyCommands {
|
||||||
// + ". Check menu settings on your pump to ensure it's not hidden.");
|
// + ". Check menu settings on your pump to ensure it's not hidden.");
|
||||||
// }
|
// }
|
||||||
if (retries == 0) {
|
if (retries == 0) {
|
||||||
throw new CommandException().message("Menu not found searching for " + desiredMenu
|
throw new CommandException("Menu not found searching for " + desiredMenu
|
||||||
+ ". Check menu settings on your pump to ensure it's not hidden.");
|
+ ". Check menu settings on your pump to ensure it's not hidden.");
|
||||||
}
|
}
|
||||||
pressMenuKey();
|
pressMenuKey();
|
||||||
|
@ -792,7 +679,7 @@ public class RuffyScripter implements RuffyCommands {
|
||||||
long timeout = System.currentTimeMillis() + 60 * 1000;
|
long timeout = System.currentTimeMillis() + 60 * 1000;
|
||||||
while (getCurrentMenu().getType() == menuType) {
|
while (getCurrentMenu().getType() == menuType) {
|
||||||
if (System.currentTimeMillis() > timeout) {
|
if (System.currentTimeMillis() > timeout) {
|
||||||
throw new CommandException().message("Timeout waiting for menu " + menuType + " to be left");
|
throw new CommandException("Timeout waiting for menu " + menuType + " to be left");
|
||||||
}
|
}
|
||||||
SystemClock.sleep(10);
|
SystemClock.sleep(10);
|
||||||
}
|
}
|
||||||
|
@ -812,7 +699,7 @@ public class RuffyScripter implements RuffyCommands {
|
||||||
if (failureMessage == null) {
|
if (failureMessage == null) {
|
||||||
failureMessage = "Invalid pump state, expected to be in menu " + expectedMenu + ", but current menu is " + currentMenu.getType();
|
failureMessage = "Invalid pump state, expected to be in menu " + expectedMenu + ", but current menu is " + currentMenu.getType();
|
||||||
}
|
}
|
||||||
throw new CommandException().message(failureMessage);
|
throw new CommandException(failureMessage);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -824,7 +711,7 @@ public class RuffyScripter implements RuffyCommands {
|
||||||
SystemClock.sleep(100);
|
SystemClock.sleep(100);
|
||||||
retries = retries - 1;
|
retries = retries - 1;
|
||||||
} else {
|
} else {
|
||||||
throw new CommandException().message("Invalid pump state, expected to be in menu MAIN or STOP but current menu is " + currentMenu.getType());
|
throw new CommandException("Invalid pump state, expected to be in menu MAIN or STOP but current menu is " + currentMenu.getType());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -835,10 +722,10 @@ public class RuffyScripter implements RuffyCommands {
|
||||||
Object value = getCurrentMenu().getAttribute(attribute);
|
Object value = getCurrentMenu().getAttribute(attribute);
|
||||||
while (!expectedType.isInstance(value)) {
|
while (!expectedType.isInstance(value)) {
|
||||||
value = getCurrentMenu().getAttribute(attribute);
|
value = getCurrentMenu().getAttribute(attribute);
|
||||||
waitForScreenUpdate(1000);
|
waitForScreenUpdate();
|
||||||
retries--;
|
retries--;
|
||||||
if (retries == 0) {
|
if (retries == 0) {
|
||||||
throw new CommandException().message("Failed to read blinkng value: " + attribute + "=" + value + " type=" + value);
|
throw new CommandException("Failed to read blinkng value: " + attribute + "=" + value + " type=" + value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return (T) value;
|
return (T) value;
|
||||||
|
@ -867,8 +754,8 @@ public class RuffyScripter implements RuffyCommands {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CommandResult takeOverAlarms() {
|
public CommandResult confirmAlert(int warningCode) {
|
||||||
return runCommand(new TakeOverAlarmsCommand());
|
return runCommand(new ConfirmAlertCommand(warningCode));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -886,10 +773,15 @@ public class RuffyScripter implements RuffyCommands {
|
||||||
return runCommand(new SetBasalProfileCommand(basalProfile));
|
return runCommand(new SetBasalProfileCommand(basalProfile));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CommandResult getDateAndTime() {
|
||||||
|
return new CommandResult().success(false).enacted(false);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CommandResult setDateAndTime(Date date) {
|
public CommandResult setDateAndTime(Date date) {
|
||||||
// TODO I'm a faker!
|
// TODO
|
||||||
return new CommandResult().success(true).enacted(false);
|
return new CommandResult().success(false).enacted(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -906,4 +798,36 @@ public class RuffyScripter implements RuffyCommands {
|
||||||
public void unpair() {
|
public void unpair() {
|
||||||
throw new UnsupportedOperationException();
|
throw new UnsupportedOperationException();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Confirms and dismisses the given alert if it's raised before the timeout
|
||||||
|
*/
|
||||||
|
public boolean confirmAlert(int warningCode, int maxWaitMs) {
|
||||||
|
long timeout = System.currentTimeMillis() + maxWaitMs;
|
||||||
|
while (System.currentTimeMillis() < timeout) {
|
||||||
|
if (getCurrentMenu().getType() == MenuType.WARNING_OR_ERROR) {
|
||||||
|
// Note that the message is permanently displayed, while the error code is blinking.
|
||||||
|
// A wait till the error code can be read results in the code hanging, despite
|
||||||
|
// menu updates coming in, so just check the message.
|
||||||
|
|
||||||
|
int displayedWarningCode = readWarningCode();
|
||||||
|
String errorMsg = (String) getCurrentMenu().getAttribute(MenuAttribute.MESSAGE);
|
||||||
|
if (displayedWarningCode != warningCode) {
|
||||||
|
throw new CommandException("An alert other than the expected warning " + warningCode+ " was raised by the pump: "
|
||||||
|
+ displayedWarningCode + "(" + errorMsg + "). Please check the pump.");
|
||||||
|
}
|
||||||
|
// confirm alert
|
||||||
|
verifyMenuIsDisplayed(MenuType.WARNING_OR_ERROR);
|
||||||
|
pressCheckKey();
|
||||||
|
// dismiss alert
|
||||||
|
verifyMenuIsDisplayed(MenuType.WARNING_OR_ERROR);
|
||||||
|
pressCheckKey();
|
||||||
|
/* // TODO multiple alerts in a row ... can this occur in non-freak circumstances?
|
||||||
|
waitForMenuToBeLeft(MenuType.WARNING_OR_ERROR);*/
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
SystemClock.sleep(10);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +1,17 @@
|
||||||
package de.jotomo.ruffyscripter.commands;
|
package de.jotomo.ruffyscripter.commands;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import de.jotomo.ruffy.spi.CommandResult;
|
||||||
import de.jotomo.ruffyscripter.RuffyScripter;
|
import de.jotomo.ruffyscripter.RuffyScripter;
|
||||||
|
|
||||||
public abstract class BaseCommand implements Command {
|
public abstract class BaseCommand implements Command {
|
||||||
// RS will inject itself here
|
// RS will inject itself here
|
||||||
protected RuffyScripter scripter;
|
protected RuffyScripter scripter;
|
||||||
|
|
||||||
|
protected CommandResult result = new CommandResult();
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setScripter(RuffyScripter scripter) {
|
public void setScripter(RuffyScripter scripter) {
|
||||||
this.scripter = scripter;
|
this.scripter = scripter;
|
||||||
|
@ -18,8 +24,23 @@ public abstract class BaseCommand implements Command {
|
||||||
|
|
||||||
// TODO i18n; can we work with error codes instead of messages? Like W07? that way we're language agnostic
|
// TODO i18n; can we work with error codes instead of messages? Like W07? that way we're language agnostic
|
||||||
// error message ist still needed to cancel TBR though, let next-gen ruffy take care of that?
|
// error message ist still needed to cancel TBR though, let next-gen ruffy take care of that?
|
||||||
/** An alarm (or null) caused by a disconnect we can safely confirm on reconnect,
|
|
||||||
* knowing it's not severe as it was caused by this command. */
|
/**
|
||||||
|
* An alarm (or null) caused by a disconnect we can safely confirm on reconnect,
|
||||||
|
* knowing it's not severe as it was caused by this command.
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public String getReconnectAlarm() { return null; }
|
public String getReconnectAlarm() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<String> validateArguments() {
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CommandResult getResult() {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,15 +9,18 @@ import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Locale;
|
|
||||||
|
|
||||||
import de.jotomo.ruffy.spi.history.Bolus;
|
|
||||||
import de.jotomo.ruffy.spi.history.PumpHistory;
|
|
||||||
import de.jotomo.ruffyscripter.RuffyScripter;
|
|
||||||
import de.jotomo.ruffy.spi.BolusProgressReporter;
|
import de.jotomo.ruffy.spi.BolusProgressReporter;
|
||||||
import de.jotomo.ruffy.spi.CommandResult;
|
import de.jotomo.ruffy.spi.CommandResult;
|
||||||
|
import de.jotomo.ruffy.spi.PumpWarningCodes;
|
||||||
|
import de.jotomo.ruffyscripter.RuffyScripter;
|
||||||
|
|
||||||
import static de.jotomo.ruffy.spi.BolusProgressReporter.State.*;
|
import static de.jotomo.ruffy.spi.BolusProgressReporter.State.DELIVERED;
|
||||||
|
import static de.jotomo.ruffy.spi.BolusProgressReporter.State.DELIVERING;
|
||||||
|
import static de.jotomo.ruffy.spi.BolusProgressReporter.State.FINISHED;
|
||||||
|
import static de.jotomo.ruffy.spi.BolusProgressReporter.State.PROGRAMMING;
|
||||||
|
import static de.jotomo.ruffy.spi.BolusProgressReporter.State.STOPPED;
|
||||||
|
import static de.jotomo.ruffy.spi.BolusProgressReporter.State.STOPPING;
|
||||||
|
|
||||||
public class BolusCommand extends BaseCommand {
|
public class BolusCommand extends BaseCommand {
|
||||||
private static final Logger log = LoggerFactory.getLogger(BolusCommand.class);
|
private static final Logger log = LoggerFactory.getLogger(BolusCommand.class);
|
||||||
|
@ -26,14 +29,10 @@ public class BolusCommand extends BaseCommand {
|
||||||
private final BolusProgressReporter bolusProgressReporter;
|
private final BolusProgressReporter bolusProgressReporter;
|
||||||
private volatile boolean cancelRequested;
|
private volatile boolean cancelRequested;
|
||||||
|
|
||||||
// TODO make CommandResult a field that is updated as the command progress so that we can
|
|
||||||
// (also) see via cmdResult.enacted if something has been enacted and how safe it is to
|
|
||||||
// restart the command (also checking history of course, but lets double check this cruical
|
|
||||||
// part)
|
|
||||||
|
|
||||||
public BolusCommand(double bolus, BolusProgressReporter bolusProgressReporter) {
|
public BolusCommand(double bolus, BolusProgressReporter bolusProgressReporter) {
|
||||||
this.bolus = bolus;
|
this.bolus = bolus;
|
||||||
this.bolusProgressReporter = bolusProgressReporter;
|
this.bolusProgressReporter = bolusProgressReporter;
|
||||||
|
this.result = new CommandResult();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -53,28 +52,26 @@ public class BolusCommand extends BaseCommand {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CommandResult execute() {
|
public void execute() {
|
||||||
try {
|
try {
|
||||||
// TODO read reservoir level and reject request if reservoir < bolus
|
|
||||||
// TODO also check if there's a bolus in history we're not aware of
|
|
||||||
// press check twice to get reservoir level and last bolus quickly
|
|
||||||
|
|
||||||
bolusProgressReporter.report(PROGRAMMING, 0, 0);
|
bolusProgressReporter.report(PROGRAMMING, 0, 0);
|
||||||
enterBolusMenu();
|
enterBolusMenu();
|
||||||
inputBolusAmount();
|
inputBolusAmount();
|
||||||
verifyDisplayedBolusAmount();
|
verifyDisplayedBolusAmount();
|
||||||
|
|
||||||
|
// last chance to abort before confirm the bolus
|
||||||
if (cancelRequested) {
|
if (cancelRequested) {
|
||||||
bolusProgressReporter.report(STOPPING, 0, 0);
|
bolusProgressReporter.report(STOPPING, 0, 0);
|
||||||
scripter.returnToRootMenu();
|
scripter.returnToRootMenu();
|
||||||
bolusProgressReporter.report(STOPPED, 0, 0);
|
bolusProgressReporter.report(STOPPED, 0, 0);
|
||||||
return new CommandResult().success(true).enacted(false)
|
result.success = true;
|
||||||
.message("Bolus cancelled as per user request with no insulin delivered");
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// confirm bolus
|
// confirm bolus
|
||||||
scripter.verifyMenuIsDisplayed(MenuType.BOLUS_ENTER);
|
scripter.verifyMenuIsDisplayed(MenuType.BOLUS_ENTER);
|
||||||
scripter.pressCheckKey();
|
scripter.pressCheckKey();
|
||||||
|
result.enacted = true;
|
||||||
|
|
||||||
// the pump displays the entered bolus and waits a few seconds to let user check and cancel
|
// the pump displays the entered bolus and waits a few seconds to let user check and cancel
|
||||||
while (scripter.getCurrentMenu().getType() == MenuType.BOLUS_ENTER) {
|
while (scripter.getCurrentMenu().getType() == MenuType.BOLUS_ENTER) {
|
||||||
|
@ -83,47 +80,47 @@ public class BolusCommand extends BaseCommand {
|
||||||
scripter.pressUpKey();
|
scripter.pressUpKey();
|
||||||
// wait up to 1s for a BOLUS_CANCELLED alert, if it doesn't happen we missed
|
// wait up to 1s for a BOLUS_CANCELLED alert, if it doesn't happen we missed
|
||||||
// the window, simply continue and let the next cancel attempt try its luck
|
// the window, simply continue and let the next cancel attempt try its luck
|
||||||
boolean alertWasCancelled = scripter.confirmAlert("BOLUS CANCELLED", 1000);
|
boolean alertWasCancelled = scripter.confirmAlert(PumpWarningCodes.BOLUS_CANCELLED, 1000);
|
||||||
if (alertWasCancelled) {
|
if (alertWasCancelled) {
|
||||||
bolusProgressReporter.report(STOPPED, 0, 0);
|
bolusProgressReporter.report(STOPPED, 0, 0);
|
||||||
return new CommandResult().success(true).enacted(false)
|
result.success = true;
|
||||||
.message("Bolus cancelled as per user request with no insulin delivered");
|
return;
|
||||||
}
|
}
|
||||||
|
SystemClock.sleep(10);
|
||||||
}
|
}
|
||||||
SystemClock.sleep(10);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// the bolus progress is displayed on the main menu
|
||||||
scripter.verifyMenuIsDisplayed(MenuType.MAIN_MENU,
|
scripter.verifyMenuIsDisplayed(MenuType.MAIN_MENU,
|
||||||
"Pump did not return to MAIN_MEU from BOLUS_ENTER to deliver bolus. "
|
"Pump did not return to MAIN_MEU from BOLUS_ENTER to deliver bolus. "
|
||||||
+ "Check pump manually, the bolus might not have been delivered.");
|
+ "Check pump manually, the bolus might not have been delivered.");
|
||||||
|
|
||||||
bolusProgressReporter.report(DELIVERING, 0, 0);
|
bolusProgressReporter.report(DELIVERING, 0, 0);
|
||||||
Double bolusRemaining = (Double) scripter.getCurrentMenu().getAttribute(MenuAttribute.BOLUS_REMAINING);
|
|
||||||
double lastBolusReported = 0;
|
|
||||||
boolean lowCartdrigeAlarmTriggered = false;
|
|
||||||
// wait for bolus delivery to complete; the remaining units to deliver are counted
|
|
||||||
// down and are displayed on the main menu.
|
|
||||||
// TODO extract into method
|
|
||||||
|
|
||||||
// TODO 'low cartrdige' alarm must be handled inside, since the bolus continues regardless;
|
// wait for bolus delivery to complete; the remaining units to deliver are counted down
|
||||||
// it must be cleared so we can see the remaining bolus again;
|
boolean cancelInProgress = false;
|
||||||
|
double lastBolusReported = 0;
|
||||||
|
Double bolusRemaining = (Double) scripter.getCurrentMenu().getAttribute(MenuAttribute.BOLUS_REMAINING);
|
||||||
while (bolusRemaining != null) {
|
while (bolusRemaining != null) {
|
||||||
if (cancelRequested) {
|
if (cancelRequested && !cancelInProgress) {
|
||||||
// cancel running bolus by pressing up for 3s, while raise a BOLUS CANCELLED
|
|
||||||
// alert, unless the bolus finished within those 3s.
|
|
||||||
bolusProgressReporter.report(STOPPING, 0, 0);
|
bolusProgressReporter.report(STOPPING, 0, 0);
|
||||||
scripter.pressKeyMs(RuffyScripter.Key.UP, 3000);
|
cancelInProgress = true;
|
||||||
bolusProgressReporter.report(STOPPED, 0, 0);
|
new Thread(() -> scripter.pressKeyMs(RuffyScripter.Key.UP, 3000), "bolus-canceller").start();
|
||||||
// if the bolus finished while we attempted to cancel it, there'll be no alarm
|
}
|
||||||
long timeout = System.currentTimeMillis() + 2000;
|
if (scripter.getCurrentMenu().getType() == MenuType.WARNING_OR_ERROR) {
|
||||||
while (scripter.getCurrentMenu().getType() != MenuType.WARNING_OR_ERROR && System.currentTimeMillis() < timeout) {
|
// confirm warning alerts and update the result to indicate alerts occurred
|
||||||
SystemClock.sleep(10);
|
int warningCode = scripter.readWarningCode();
|
||||||
|
if (warningCode == PumpWarningCodes.BOLUS_CANCELLED) {
|
||||||
|
scripter.confirmAlert(PumpWarningCodes.BOLUS_CANCELLED, 2000);
|
||||||
|
bolusProgressReporter.report(STOPPED, 0, 0);
|
||||||
|
result.wasSuccessfullyCancelled = true;
|
||||||
|
result.alertConfirmed = true;
|
||||||
|
} else if (warningCode == PumpWarningCodes.CARTRIDGE_LOW) {
|
||||||
|
scripter.confirmAlert(PumpWarningCodes.CARTRIDGE_LOW, 2000);
|
||||||
|
result.alertConfirmed = true;
|
||||||
|
} else if (warningCode == PumpWarningCodes.BATTERY_LOW) {
|
||||||
|
scripter.confirmAlert(PumpWarningCodes.BATTERY_LOW, 2000);
|
||||||
|
result.alertConfirmed = true;
|
||||||
}
|
}
|
||||||
while (scripter.getCurrentMenu().getType() == MenuType.WARNING_OR_ERROR) {
|
|
||||||
// TODO make this cleaner, extract method, needed below too
|
|
||||||
scripter.pressCheckKey();
|
|
||||||
SystemClock.sleep(200);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
if (lastBolusReported != bolusRemaining) {
|
if (lastBolusReported != bolusRemaining) {
|
||||||
log.debug("Delivering bolus, remaining: " + bolusRemaining);
|
log.debug("Delivering bolus, remaining: " + bolusRemaining);
|
||||||
|
@ -132,94 +129,13 @@ public class BolusCommand extends BaseCommand {
|
||||||
lastBolusReported = bolusRemaining;
|
lastBolusReported = bolusRemaining;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
// TODO think through situatiotns where an alarm can be raised, not just when pressing a button,
|
|
||||||
// but a 'low battery' alarm can trigger at any time ...
|
|
||||||
if (scripter.getCurrentMenu().getType() == MenuType.WARNING_OR_ERROR) {
|
|
||||||
String message = (String) scripter.getCurrentMenu().getAttribute(MenuAttribute.MESSAGE);
|
|
||||||
if (message.equals("LOW CARTRIDGE")) {
|
|
||||||
lowCartdrigeAlarmTriggered = true;
|
|
||||||
scripter.confirmAlert("LOW CARTRIDGE", 2000);
|
|
||||||
} else {
|
|
||||||
// any other alert
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
SystemClock.sleep(50);
|
SystemClock.sleep(50);
|
||||||
bolusRemaining = (Double) scripter.getCurrentMenu().getAttribute(MenuAttribute.BOLUS_REMAINING);
|
bolusRemaining = (Double) scripter.getCurrentMenu().getAttribute(MenuAttribute.BOLUS_REMAINING);
|
||||||
}
|
}
|
||||||
bolusProgressReporter.report(DELIVERED, 100, bolus);
|
bolusProgressReporter.report(DELIVERED, 100, bolus);
|
||||||
|
result.success = true;
|
||||||
/*
|
|
||||||
// wait up to 2s for any possible warning to be raised, if not raised already
|
|
||||||
// TODO what could be raised here, other than those alarms than can ring at any time anyways?
|
|
||||||
long timeout = System.currentTimeMillis() + 2 * 1000;
|
|
||||||
while (scripter.getCurrentMenu().getType() != MenuType.WARNING_OR_ERROR && System.currentTimeMillis() < timeout) {
|
|
||||||
SystemClock.sleep(50);
|
|
||||||
}
|
|
||||||
|
|
||||||
// process warnings (confirm them, report back to AAPS about them)
|
|
||||||
// while (scripter.getCurrentMenu().getType() == MenuType.WARNING_OR_ERROR || System.currentTimeMillis() < timeout) {
|
|
||||||
if (scripter.getCurrentMenu().getType() == MenuType.WARNING_OR_ERROR) {
|
|
||||||
scripter.confirmAlert(((String) scripter.getCurrentMenu().getAttribute(MenuAttribute.MESSAGE)), 1000);
|
|
||||||
}
|
|
||||||
// SystemClock.sleep(50);
|
|
||||||
// }
|
|
||||||
*/
|
|
||||||
|
|
||||||
// TODO what if we hit 'cartridge low' alert here? is it immediately displayed or after the bolus?
|
|
||||||
// TODO how are error states reported back to the caller that occur outside of calls in genal? Low battery, low cartridge?
|
|
||||||
|
|
||||||
// make sure no alert (occlusion, cartridge empty) has occurred.
|
|
||||||
scripter.verifyMenuIsDisplayed(MenuType.MAIN_MENU,
|
|
||||||
"Bolus delivery did not complete as expected. "
|
|
||||||
+ "Check pump manually, the bolus might not have been delivered.");
|
|
||||||
|
|
||||||
// TODO report back what was read from history
|
|
||||||
|
|
||||||
// read last bolus record; those menus display static data and therefore
|
|
||||||
// only a single menu update is sent
|
|
||||||
scripter.navigateToMenu(MenuType.MY_DATA_MENU);
|
|
||||||
scripter.verifyMenuIsDisplayed(MenuType.MY_DATA_MENU);
|
|
||||||
scripter.pressCheckKey();
|
|
||||||
if (scripter.getCurrentMenu().getType() != MenuType.BOLUS_DATA) {
|
|
||||||
scripter.waitForMenuUpdate();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!scripter.getCurrentMenu().attributes().contains(MenuAttribute.BOLUS)) {
|
|
||||||
throw new CommandException().success(false).enacted(true)
|
|
||||||
.message("Bolus was delivered, but unable to confirm it with history record");
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO check date so we don't pick a false record if the previous bolus had the same amount;
|
|
||||||
// also, report back partial bolus. Just call ReadHistory(timestamp, boluses=true) cmd ...
|
|
||||||
double lastBolusInHistory = (double) scripter.getCurrentMenu().getAttribute(MenuAttribute.BOLUS);
|
|
||||||
if (Math.abs(bolus - lastBolusInHistory) > 0.05) {
|
|
||||||
throw new CommandException().success(false).enacted(true)
|
|
||||||
.message("Last bolus shows " + lastBolusInHistory
|
|
||||||
+ " U delievered, but " + bolus + " U were requested");
|
|
||||||
}
|
|
||||||
log.debug("Bolus record in history confirms delivered bolus");
|
|
||||||
|
|
||||||
// TODO how would this call fail? more generally ......
|
|
||||||
scripter.returnToRootMenu();
|
|
||||||
if (scripter.getCurrentMenu().getType() != MenuType.MAIN_MENU) {
|
|
||||||
throw new CommandException().success(false).enacted(true)
|
|
||||||
.message("Bolus was correctly delivered and checked against history, but we "
|
|
||||||
+ "did not return the main menu successfully.");
|
|
||||||
}
|
|
||||||
|
|
||||||
ArrayList<Bolus> boluses = new ArrayList<>();
|
|
||||||
boluses.add(new Bolus(System.currentTimeMillis(), bolus));
|
|
||||||
return new CommandResult().success(true).enacted(true)
|
|
||||||
.message(String.format(Locale.US, "Delivered %02.1f U", bolus))
|
|
||||||
.history(new PumpHistory().bolusHistory(boluses));
|
|
||||||
} catch (CommandException e) {
|
|
||||||
return e.toCommandResult();
|
|
||||||
} finally {
|
} finally {
|
||||||
bolusProgressReporter.report(null, 100, 0);
|
bolusProgressReporter.report(FINISHED, 100, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -257,7 +173,7 @@ public class BolusCommand extends BaseCommand {
|
||||||
|
|
||||||
log.debug("Final bolus: " + displayedBolus);
|
log.debug("Final bolus: " + displayedBolus);
|
||||||
if (Math.abs(displayedBolus - bolus) > 0.05) {
|
if (Math.abs(displayedBolus - bolus) > 0.05) {
|
||||||
throw new CommandException().message("Failed to set correct bolus. Expected: " + bolus + ", actual: " + displayedBolus);
|
throw new CommandException("Failed to set correct bolus. Expected: " + bolus + ", actual: " + displayedBolus);
|
||||||
}
|
}
|
||||||
|
|
||||||
// check again to ensure the displayed value hasn't change due to due scrolling taking extremely long
|
// check again to ensure the displayed value hasn't change due to due scrolling taking extremely long
|
||||||
|
@ -265,7 +181,7 @@ public class BolusCommand extends BaseCommand {
|
||||||
scripter.verifyMenuIsDisplayed(MenuType.BOLUS_ENTER);
|
scripter.verifyMenuIsDisplayed(MenuType.BOLUS_ENTER);
|
||||||
double refreshedDisplayedBolus = scripter.readBlinkingValue(Double.class, MenuAttribute.BOLUS);
|
double refreshedDisplayedBolus = scripter.readBlinkingValue(Double.class, MenuAttribute.BOLUS);
|
||||||
if (Math.abs(displayedBolus - refreshedDisplayedBolus) > 0.05) {
|
if (Math.abs(displayedBolus - refreshedDisplayedBolus) > 0.05) {
|
||||||
throw new CommandException().message("Failed to set bolus: bolus changed after input stopped from "
|
throw new CommandException("Failed to set bolus: bolus changed after input stopped from "
|
||||||
+ displayedBolus + " -> " + refreshedDisplayedBolus);
|
+ displayedBolus + " -> " + refreshedDisplayedBolus);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,11 +4,7 @@ import org.monkey.d.ruffy.ruffy.driver.display.MenuType;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import de.jotomo.ruffy.spi.PumpState;
|
import de.jotomo.ruffy.spi.PumpState;
|
||||||
import de.jotomo.ruffy.spi.CommandResult;
|
|
||||||
|
|
||||||
// TODO robustness: can a TBR run out, whilst we're trying to cancel it?
|
// TODO robustness: can a TBR run out, whilst we're trying to cancel it?
|
||||||
// Hm, we could just ignore TBRs that run out within the next 60s (0:01 or even 0:02
|
// Hm, we could just ignore TBRs that run out within the next 60s (0:01 or even 0:02
|
||||||
|
@ -16,41 +12,21 @@ import de.jotomo.ruffy.spi.CommandResult;
|
||||||
public class CancelTbrCommand extends BaseCommand {
|
public class CancelTbrCommand extends BaseCommand {
|
||||||
private static final Logger log = LoggerFactory.getLogger(CancelTbrCommand.class);
|
private static final Logger log = LoggerFactory.getLogger(CancelTbrCommand.class);
|
||||||
|
|
||||||
@Override
|
|
||||||
public List<String> validateArguments() {
|
|
||||||
return Collections.emptyList();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getReconnectAlarm() {
|
public String getReconnectAlarm() {
|
||||||
return "TBR CANCELLED";
|
return "TBR CANCELLED";
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CommandResult execute() {
|
public void execute() {
|
||||||
try {
|
scripter.verifyMenuIsDisplayed(MenuType.MAIN_MENU);
|
||||||
scripter.verifyMenuIsDisplayed(MenuType.MAIN_MENU);
|
PumpState pumpState = scripter.readPumpStateInternal();
|
||||||
PumpState pumpState = scripter.readPumpStateInternal();
|
log.debug("Cancelling active TBR of " + pumpState.tbrPercent
|
||||||
if (!pumpState.tbrActive) {
|
+ "% with " + pumpState.tbrRemainingDuration + " min remaining");
|
||||||
log.debug("No TBR active to cancel");
|
SetTbrCommand setTbrCommand = new SetTbrCommand(100, 0);
|
||||||
return new CommandResult()
|
setTbrCommand.setScripter(scripter);
|
||||||
.success(true)
|
setTbrCommand.execute();
|
||||||
// Technically, nothing was enacted, but AAPS needs this to recover
|
result = setTbrCommand.result;
|
||||||
// when there was an issue and AAPS thinks a TBR is still active,
|
|
||||||
// so the ComboPlugin can create a TempporaryBasel to mark the TBR
|
|
||||||
// as finished to get in sync with the pump state.
|
|
||||||
.enacted(true)
|
|
||||||
.message("No TBR active");
|
|
||||||
}
|
|
||||||
|
|
||||||
log.debug("Cancelling active TBR of " + pumpState.tbrPercent
|
|
||||||
+ "% with " + pumpState.tbrRemainingDuration + " min remaining");
|
|
||||||
SetTbrCommand setTbrCommand = new SetTbrCommand(100, 0);
|
|
||||||
setTbrCommand.setScripter(scripter);
|
|
||||||
return setTbrCommand.execute();
|
|
||||||
} catch (CommandException e) {
|
|
||||||
return e.toCommandResult();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -13,9 +13,10 @@ import de.jotomo.ruffy.spi.CommandResult;
|
||||||
* sequence, letting the methods take care of waits.
|
* sequence, letting the methods take care of waits.
|
||||||
*/
|
*/
|
||||||
public interface Command {
|
public interface Command {
|
||||||
CommandResult execute();
|
|
||||||
List<String> validateArguments();
|
|
||||||
void setScripter(RuffyScripter scripter);
|
void setScripter(RuffyScripter scripter);
|
||||||
|
List<String> validateArguments();
|
||||||
boolean needsRunMode();
|
boolean needsRunMode();
|
||||||
|
void execute();
|
||||||
|
CommandResult getResult();
|
||||||
String getReconnectAlarm();
|
String getReconnectAlarm();
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,52 +1,11 @@
|
||||||
package de.jotomo.ruffyscripter.commands;
|
package de.jotomo.ruffyscripter.commands;
|
||||||
|
|
||||||
import de.jotomo.ruffy.spi.CommandResult;
|
|
||||||
|
|
||||||
public class CommandException extends RuntimeException {
|
public class CommandException extends RuntimeException {
|
||||||
public boolean success = false;
|
public CommandException(String message) {
|
||||||
public boolean enacted = false;
|
super(message);
|
||||||
public Exception exception = null;
|
|
||||||
public String message = null;
|
|
||||||
|
|
||||||
public CommandException() {
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public CommandException success(boolean success) {
|
public CommandException(String message, Exception exception) {
|
||||||
this.success = success;
|
super(message, exception);
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public CommandException enacted(boolean enacted) {
|
|
||||||
this.enacted = enacted;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public CommandException exception(Exception exception) {
|
|
||||||
this.exception = exception;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getMessage() {
|
|
||||||
return message;
|
|
||||||
}
|
|
||||||
|
|
||||||
public CommandException message(String message) {
|
|
||||||
this.message = message;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public CommandResult toCommandResult() {
|
|
||||||
return new CommandResult().success(success).enacted(enacted).exception(exception).message(message);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return "CommandException{" +
|
|
||||||
"success=" + success +
|
|
||||||
", enacted=" + enacted +
|
|
||||||
", exception=" + exception +
|
|
||||||
", message='" + message + '\'' +
|
|
||||||
'}';
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,14 @@
|
||||||
|
package de.jotomo.ruffyscripter.commands;
|
||||||
|
|
||||||
|
public class ConfirmAlertCommand extends BaseCommand {
|
||||||
|
private final int warningCode;
|
||||||
|
|
||||||
|
public ConfirmAlertCommand(int warningCode) {
|
||||||
|
this.warningCode = warningCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void execute() {
|
||||||
|
result.success(scripter.confirmAlert(warningCode, 5000));
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,11 +1,5 @@
|
||||||
package de.jotomo.ruffyscripter.commands;
|
package de.jotomo.ruffyscripter.commands;
|
||||||
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import de.jotomo.ruffyscripter.RuffyScripter;
|
|
||||||
import de.jotomo.ruffy.spi.CommandResult;
|
|
||||||
|
|
||||||
public class ReadBasalProfileCommand extends BaseCommand {
|
public class ReadBasalProfileCommand extends BaseCommand {
|
||||||
private final int number;
|
private final int number;
|
||||||
|
|
||||||
|
@ -14,17 +8,7 @@ public class ReadBasalProfileCommand extends BaseCommand {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CommandResult execute() {
|
public void execute() {
|
||||||
return new CommandResult().success(false).enacted(false);
|
// TODO
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public List<String> validateArguments() {
|
|
||||||
return Collections.emptyList();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setScripter(RuffyScripter scripter) {
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,17 +7,19 @@ import org.monkey.d.ruffy.ruffy.driver.display.MenuType;
|
||||||
import org.monkey.d.ruffy.ruffy.driver.display.menu.BolusType;
|
import org.monkey.d.ruffy.ruffy.driver.display.menu.BolusType;
|
||||||
import org.monkey.d.ruffy.ruffy.driver.display.menu.MenuDate;
|
import org.monkey.d.ruffy.ruffy.driver.display.menu.MenuDate;
|
||||||
import org.monkey.d.ruffy.ruffy.driver.display.menu.MenuTime;
|
import org.monkey.d.ruffy.ruffy.driver.display.menu.MenuTime;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import de.jotomo.ruffy.spi.CommandResult;
|
|
||||||
import de.jotomo.ruffy.spi.history.Bolus;
|
import de.jotomo.ruffy.spi.history.Bolus;
|
||||||
|
import de.jotomo.ruffy.spi.history.PumpError;
|
||||||
import de.jotomo.ruffy.spi.history.PumpHistory;
|
import de.jotomo.ruffy.spi.history.PumpHistory;
|
||||||
import de.jotomo.ruffy.spi.history.PumpHistoryRequest;
|
import de.jotomo.ruffy.spi.history.PumpHistoryRequest;
|
||||||
|
|
||||||
public class ReadHistoryCommand extends BaseCommand {
|
public class ReadHistoryCommand extends BaseCommand {
|
||||||
|
private static Logger log = LoggerFactory.getLogger(ReadHistoryCommand.class);
|
||||||
|
|
||||||
private final PumpHistoryRequest request;
|
private final PumpHistoryRequest request;
|
||||||
private final PumpHistory history = new PumpHistory();
|
private final PumpHistory history = new PumpHistory();
|
||||||
|
|
||||||
|
@ -26,24 +28,22 @@ public class ReadHistoryCommand extends BaseCommand {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CommandResult execute() {
|
public void execute() {
|
||||||
if (request.reservoirLevel) {
|
|
||||||
readReservoirLevel();
|
|
||||||
}
|
|
||||||
if (request.bolusHistory != PumpHistoryRequest.SKIP
|
if (request.bolusHistory != PumpHistoryRequest.SKIP
|
||||||
|| request.tbrHistory != PumpHistoryRequest.SKIP
|
|| request.tbrHistory != PumpHistoryRequest.SKIP
|
||||||
|| request.pumpErrorHistory != PumpHistoryRequest.SKIP
|
|| request.pumpErrorHistory != PumpHistoryRequest.SKIP) {
|
||||||
|| request.tddHistory != PumpHistoryRequest.SKIP) {
|
|
||||||
scripter.navigateToMenu(MenuType.MY_DATA_MENU);
|
scripter.navigateToMenu(MenuType.MY_DATA_MENU);
|
||||||
scripter.verifyMenuIsDisplayed(MenuType.MY_DATA_MENU);
|
scripter.verifyMenuIsDisplayed(MenuType.MY_DATA_MENU);
|
||||||
scripter.pressCheckKey();
|
scripter.pressCheckKey();
|
||||||
|
|
||||||
|
// TODO see how dana does time mangling for timezones
|
||||||
|
|
||||||
// bolus history
|
// bolus history
|
||||||
scripter.verifyMenuIsDisplayed(MenuType.BOLUS_DATA);
|
scripter.verifyMenuIsDisplayed(MenuType.BOLUS_DATA);
|
||||||
if (request.bolusHistory != PumpHistoryRequest.SKIP) {
|
if (request.bolusHistory != PumpHistoryRequest.SKIP) {
|
||||||
int totalRecords = (int) scripter.getCurrentMenu().getAttribute(MenuAttribute.TOTAL_RECORD);
|
int totalRecords = (int) scripter.getCurrentMenu().getAttribute(MenuAttribute.TOTAL_RECORD);
|
||||||
if (totalRecords > 0) {
|
if (totalRecords > 0) {
|
||||||
if (request.bolusHistory == PumpHistoryRequest.LAST) {
|
if (true || request.bolusHistory == PumpHistoryRequest.LAST) {
|
||||||
Bolus bolus = readBolusRecord();
|
Bolus bolus = readBolusRecord();
|
||||||
history.bolusHistory.add(bolus);
|
history.bolusHistory.add(bolus);
|
||||||
} else {
|
} else {
|
||||||
|
@ -56,22 +56,21 @@ public class ReadHistoryCommand extends BaseCommand {
|
||||||
scripter.pressMenuKey();
|
scripter.pressMenuKey();
|
||||||
scripter.verifyMenuIsDisplayed(MenuType.ERROR_DATA);
|
scripter.verifyMenuIsDisplayed(MenuType.ERROR_DATA);
|
||||||
if (request.pumpErrorHistory != PumpHistoryRequest.SKIP) {
|
if (request.pumpErrorHistory != PumpHistoryRequest.SKIP) {
|
||||||
int code = (int) scripter.getCurrentMenu().getAttribute(MenuAttribute.WARNING);
|
int totalRecords = (int) scripter.getCurrentMenu().getAttribute(MenuAttribute.TOTAL_RECORD);
|
||||||
String message = (String) scripter.getCurrentMenu().getAttribute(MenuAttribute.MESSAGE);
|
if (totalRecords > 0) {
|
||||||
MenuDate date = (MenuDate) scripter.getCurrentMenu().getAttribute(MenuAttribute.DATE);
|
if (true || request.pumpErrorHistory == PumpHistoryRequest.LAST) {
|
||||||
MenuTime time = (MenuTime) scripter.getCurrentMenu().getAttribute(MenuAttribute.TIME);
|
PumpError error = readErrorRecord();
|
||||||
|
history.pumpErrorHistory.add(error);
|
||||||
|
} else {
|
||||||
|
readErrorRecords(request.pumpErrorHistory);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// tdd history
|
// tdd history
|
||||||
scripter.pressMenuKey();
|
scripter.pressMenuKey();
|
||||||
scripter.verifyMenuIsDisplayed(MenuType.DAILY_DATA);
|
scripter.verifyMenuIsDisplayed(MenuType.DAILY_DATA);
|
||||||
if (request.tddHistory != PumpHistoryRequest.SKIP) {
|
/*
|
||||||
Double total = (Double) scripter.getCurrentMenu().getAttribute(MenuAttribute.DAILY_TOTAL);
|
|
||||||
MenuDate date = (MenuDate) scripter.getCurrentMenu().getAttribute(MenuAttribute.DATE);
|
|
||||||
MenuTime time = (MenuTime) scripter.getCurrentMenu().getAttribute(MenuAttribute.TIME);
|
|
||||||
}
|
|
||||||
|
|
||||||
// tbr history
|
// tbr history
|
||||||
scripter.pressMenuKey();
|
scripter.pressMenuKey();
|
||||||
scripter.verifyMenuIsDisplayed(MenuType.TBR_DATA);
|
scripter.verifyMenuIsDisplayed(MenuType.TBR_DATA);
|
||||||
|
@ -82,64 +81,102 @@ public class ReadHistoryCommand extends BaseCommand {
|
||||||
// TODO start or end time?
|
// TODO start or end time?
|
||||||
MenuTime time = (MenuTime) scripter.getCurrentMenu().getAttribute(MenuAttribute.TIME);
|
MenuTime time = (MenuTime) scripter.getCurrentMenu().getAttribute(MenuAttribute.TIME);
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
scripter.pressBackKey();
|
scripter.pressBackKey();
|
||||||
scripter.returnToRootMenu();
|
scripter.returnToRootMenu();
|
||||||
scripter.verifyRootMenuIsDisplayed();
|
scripter.verifyRootMenuIsDisplayed();
|
||||||
}
|
}
|
||||||
|
|
||||||
return new CommandResult().success(true).enacted(false).history(history);
|
if (log.isDebugEnabled()) {
|
||||||
|
if (!history.bolusHistory.isEmpty()) {
|
||||||
|
log.debug("Read bolus history:");
|
||||||
|
for (Bolus bolus : history.bolusHistory) {
|
||||||
|
log.debug(new Date(bolus.timestamp) + ": " + bolus.toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!history.pumpErrorHistory.isEmpty()) {
|
||||||
|
log.debug("Read error history:");
|
||||||
|
for (PumpError pumpError : history.pumpErrorHistory) {
|
||||||
|
log.debug(new Date(pumpError.timestamp) + ": " + pumpError.toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
result.success(true).history(history);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void readBolusRecords(long requestedTime) {
|
private void readBolusRecords(long requestedTime) {
|
||||||
int record = (int) scripter.getCurrentMenu().getAttribute(MenuAttribute.CURRENT_RECORD);
|
int record = (int) scripter.getCurrentMenu().getAttribute(MenuAttribute.CURRENT_RECORD);
|
||||||
int totalRecords = (int) scripter.getCurrentMenu().getAttribute(MenuAttribute.TOTAL_RECORD);
|
int totalRecords = (int) scripter.getCurrentMenu().getAttribute(MenuAttribute.TOTAL_RECORD);
|
||||||
while (record <= totalRecords) {
|
while (true) {
|
||||||
|
log.debug("Reading bolus record #" + record + "/" + totalRecords);
|
||||||
Bolus bolus = readBolusRecord();
|
Bolus bolus = readBolusRecord();
|
||||||
if (requestedTime != PumpHistoryRequest.FULL && bolus.timestamp < requestedTime) {
|
if (requestedTime != PumpHistoryRequest.FULL && bolus.timestamp <= requestedTime) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
history.bolusHistory.add(bolus);
|
history.bolusHistory.add(bolus);
|
||||||
|
scripter.pressDownKey();
|
||||||
|
scripter.waitForMenuUpdate();
|
||||||
record = (int) scripter.getCurrentMenu().getAttribute(MenuAttribute.CURRENT_RECORD);
|
record = (int) scripter.getCurrentMenu().getAttribute(MenuAttribute.CURRENT_RECORD);
|
||||||
|
if (record == totalRecords) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
private Bolus readBolusRecord() {
|
private Bolus readBolusRecord() {
|
||||||
|
scripter.verifyMenuIsDisplayed(MenuType.BOLUS_DATA);
|
||||||
// Could also be extended, multiwave
|
// Could also be extended, multiwave
|
||||||
BolusType bolusType = (BolusType) scripter.getCurrentMenu().getAttribute(MenuAttribute.BOLUS_TYPE);
|
BolusType bolusType = (BolusType) scripter.getCurrentMenu().getAttribute(MenuAttribute.BOLUS_TYPE);
|
||||||
if (!bolusType.equals(BolusType.NORMAL)) {
|
if (!bolusType.equals(BolusType.NORMAL)) {
|
||||||
throw new CommandException().success(false).enacted(false).message("Unsupported bolus type encountered: " + bolusType);
|
throw new CommandException("Unsupported bolus type encountered: " + bolusType);
|
||||||
}
|
}
|
||||||
// TODO no bolus etc yet? How would that ever look?
|
|
||||||
Double bolus = (Double) scripter.getCurrentMenu().getAttribute(MenuAttribute.BOLUS);
|
Double bolus = (Double) scripter.getCurrentMenu().getAttribute(MenuAttribute.BOLUS);
|
||||||
|
long recordDate = readRecordDate();
|
||||||
|
return new Bolus(recordDate, bolus);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void readErrorRecords(long requestedTime) {
|
||||||
|
int record = (int) scripter.getCurrentMenu().getAttribute(MenuAttribute.CURRENT_RECORD);
|
||||||
|
int totalRecords = (int) scripter.getCurrentMenu().getAttribute(MenuAttribute.TOTAL_RECORD);
|
||||||
|
while (true) {
|
||||||
|
log.debug("Reading error record #" + record + "/" + totalRecords);
|
||||||
|
PumpError error = readErrorRecord();
|
||||||
|
if (requestedTime != PumpHistoryRequest.FULL && error.timestamp <= requestedTime) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
history.pumpErrorHistory.add(error);
|
||||||
|
scripter.pressDownKey();
|
||||||
|
scripter.waitForMenuUpdate();
|
||||||
|
record = (int) scripter.getCurrentMenu().getAttribute(MenuAttribute.CURRENT_RECORD);
|
||||||
|
if (record == totalRecords) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
private PumpError readErrorRecord() {
|
||||||
|
scripter.verifyMenuIsDisplayed(MenuType.ERROR_DATA);
|
||||||
|
|
||||||
|
Integer warningCode = (Integer) scripter.getCurrentMenu().getAttribute(MenuAttribute.WARNING);
|
||||||
|
Integer errorCode = (Integer) scripter.getCurrentMenu().getAttribute(MenuAttribute.ERROR);
|
||||||
|
String message = (String) scripter.getCurrentMenu().getAttribute(MenuAttribute.MESSAGE);
|
||||||
|
long recordDate = readRecordDate();
|
||||||
|
return new PumpError(recordDate, warningCode, errorCode, message);
|
||||||
|
}
|
||||||
|
|
||||||
|
private long readRecordDate() {
|
||||||
MenuDate date = (MenuDate) scripter.getCurrentMenu().getAttribute(MenuAttribute.DATE);
|
MenuDate date = (MenuDate) scripter.getCurrentMenu().getAttribute(MenuAttribute.DATE);
|
||||||
MenuTime time = (MenuTime) scripter.getCurrentMenu().getAttribute(MenuAttribute.TIME);
|
MenuTime time = (MenuTime) scripter.getCurrentMenu().getAttribute(MenuAttribute.TIME);
|
||||||
|
|
||||||
// TODO handle year changes; if current month == 1 and record date == 12, use $YEAR-1
|
|
||||||
int currentMonth = new Date().getMonth() + 1;
|
int currentMonth = new Date().getMonth() + 1;
|
||||||
int currentYear = new Date().getYear() + 1900;
|
int currentYear = new Date().getYear() + 1900;
|
||||||
if (currentMonth == 1 && date.getMonth() == 12) {
|
if (currentMonth == 1 && date.getMonth() == 12) {
|
||||||
currentYear -= 1;
|
currentYear -= 1;
|
||||||
}
|
}
|
||||||
long recordDate = new Date(currentYear - 1900, date.getMonth() - 1, date.getDay(), time.getHour(), time.getMinute()).getTime();
|
return new Date(currentYear - 1900, date.getMonth() - 1, date.getDay(), time.getHour(), time.getMinute()).getTime();
|
||||||
return new Bolus(recordDate, bolus);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void readReservoirLevel() {
|
|
||||||
scripter.verifyRootMenuIsDisplayed();
|
|
||||||
scripter.pressCheckKey();
|
|
||||||
scripter.waitForMenuToBeLeft(MenuType.MAIN_MENU);
|
|
||||||
scripter.waitForMenuToBeLeft(MenuType.STOP);
|
|
||||||
scripter.verifyMenuIsDisplayed(MenuType.QUICK_INFO);
|
|
||||||
int remainingInsulin = ((Double) scripter.getCurrentMenu().getAttribute(MenuAttribute.REMAINING_INSULIN)).intValue();
|
|
||||||
scripter.returnToRootMenu();
|
|
||||||
history.reservoirLevel = remainingInsulin;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public List<String> validateArguments() {
|
|
||||||
return Collections.emptyList();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -149,5 +186,4 @@ public class ReadHistoryCommand extends BaseCommand {
|
||||||
", history=" + history +
|
", history=" + history +
|
||||||
'}';
|
'}';
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,25 +1,12 @@
|
||||||
package de.jotomo.ruffyscripter.commands;
|
package de.jotomo.ruffyscripter.commands;
|
||||||
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import de.jotomo.ruffy.spi.CommandResult;
|
|
||||||
import de.jotomo.ruffyscripter.RuffyScripter;
|
|
||||||
|
|
||||||
public class ReadPumpStateCommand extends BaseCommand {
|
public class ReadPumpStateCommand extends BaseCommand {
|
||||||
@Override
|
@Override
|
||||||
public CommandResult execute() {
|
public void execute() {
|
||||||
return new CommandResult().success(true).enacted(false).state(scripter.readPumpStateInternal());
|
// nothing to do, scripter adds state to all command results
|
||||||
|
result.success = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public List<String> validateArguments() {
|
|
||||||
return Collections.emptyList();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setScripter(RuffyScripter scripter) {}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "ReadPumpStateCommand{}";
|
return "ReadPumpStateCommand{}";
|
||||||
|
|
|
@ -0,0 +1,56 @@
|
||||||
|
package de.jotomo.ruffyscripter.commands;
|
||||||
|
|
||||||
|
import android.support.annotation.NonNull;
|
||||||
|
|
||||||
|
import org.monkey.d.ruffy.ruffy.driver.display.MenuAttribute;
|
||||||
|
import org.monkey.d.ruffy.ruffy.driver.display.MenuType;
|
||||||
|
import org.monkey.d.ruffy.ruffy.driver.display.menu.BolusType;
|
||||||
|
import org.monkey.d.ruffy.ruffy.driver.display.menu.MenuDate;
|
||||||
|
import org.monkey.d.ruffy.ruffy.driver.display.menu.MenuTime;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
import de.jotomo.ruffy.spi.history.Bolus;
|
||||||
|
|
||||||
|
public class ReadReservoirLevelAndLastBolus extends BaseCommand {
|
||||||
|
@Override
|
||||||
|
public void execute() {
|
||||||
|
scripter.verifyRootMenuIsDisplayed();
|
||||||
|
scripter.pressCheckKey();
|
||||||
|
scripter.waitForMenuToBeLeft(MenuType.MAIN_MENU);
|
||||||
|
scripter.waitForMenuToBeLeft(MenuType.STOP);
|
||||||
|
scripter.verifyMenuIsDisplayed(MenuType.QUICK_INFO);
|
||||||
|
result.reservoirLevel = ((Double) scripter.getCurrentMenu().getAttribute(MenuAttribute.REMAINING_INSULIN)).intValue();
|
||||||
|
scripter.pressCheckKey();
|
||||||
|
result.lastBolus = readBolusRecord();
|
||||||
|
scripter.returnToRootMenu();
|
||||||
|
result.success = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO deduplicate -> ReadHistoryCommand
|
||||||
|
@NonNull
|
||||||
|
private Bolus readBolusRecord() {
|
||||||
|
scripter.verifyMenuIsDisplayed(MenuType.BOLUS_DATA);
|
||||||
|
// Could also be extended, multiwave
|
||||||
|
BolusType bolusType = (BolusType) scripter.getCurrentMenu().getAttribute(MenuAttribute.BOLUS_TYPE);
|
||||||
|
if (!bolusType.equals(BolusType.NORMAL)) {
|
||||||
|
throw new CommandException("Unsupported bolus type encountered: " + bolusType);
|
||||||
|
}
|
||||||
|
Double bolus = (Double) scripter.getCurrentMenu().getAttribute(MenuAttribute.BOLUS);
|
||||||
|
long recordDate = readRecordDate();
|
||||||
|
return new Bolus(recordDate, bolus);
|
||||||
|
}
|
||||||
|
|
||||||
|
private long readRecordDate() {
|
||||||
|
MenuDate date = (MenuDate) scripter.getCurrentMenu().getAttribute(MenuAttribute.DATE);
|
||||||
|
MenuTime time = (MenuTime) scripter.getCurrentMenu().getAttribute(MenuAttribute.TIME);
|
||||||
|
|
||||||
|
int currentMonth = new Date().getMonth() + 1;
|
||||||
|
int currentYear = new Date().getYear() + 1900;
|
||||||
|
if (currentMonth == 1 && date.getMonth() == 12) {
|
||||||
|
currentYear -= 1;
|
||||||
|
}
|
||||||
|
return new Date(currentYear - 1900, date.getMonth() - 1, date.getDay(), time.getHour(), time.getMinute()).getTime();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -1,28 +1,29 @@
|
||||||
package de.jotomo.ruffyscripter.commands;
|
package de.jotomo.ruffyscripter.commands;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import de.jotomo.ruffy.spi.BasalProfile;
|
import de.jotomo.ruffy.spi.BasalProfile;
|
||||||
import de.jotomo.ruffyscripter.RuffyScripter;
|
|
||||||
import de.jotomo.ruffy.spi.CommandResult;
|
|
||||||
|
|
||||||
public class SetBasalProfileCommand extends BaseCommand {
|
public class SetBasalProfileCommand extends BaseCommand {
|
||||||
public SetBasalProfileCommand(BasalProfile basalProfile) {
|
private final BasalProfile basalProfile;
|
||||||
|
|
||||||
|
public SetBasalProfileCommand(BasalProfile basalProfile) {
|
||||||
|
this.basalProfile = basalProfile;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CommandResult execute() {
|
public void execute() {
|
||||||
return null;
|
// TODO
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<String> validateArguments() {
|
public List<String> validateArguments() {
|
||||||
return null;
|
ArrayList<String> violations = new ArrayList<>();
|
||||||
}
|
if (basalProfile == null) {
|
||||||
|
violations.add("No basal profile supplied");
|
||||||
@Override
|
}
|
||||||
public void setScripter(RuffyScripter scripter) {
|
|
||||||
|
|
||||||
|
return violations;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,19 +0,0 @@
|
||||||
package de.jotomo.ruffyscripter.commands;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import de.jotomo.ruffy.spi.CommandResult;
|
|
||||||
|
|
||||||
public class SetBasalRateProfileCommand extends BaseCommand {
|
|
||||||
@Override
|
|
||||||
public CommandResult execute() {
|
|
||||||
// TODO stub
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public List<String> validateArguments() {
|
|
||||||
// TODO stub
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -12,7 +12,7 @@ import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
|
|
||||||
import de.jotomo.ruffy.spi.CommandResult;
|
import de.jotomo.ruffy.spi.PumpWarningCodes;
|
||||||
|
|
||||||
public class SetTbrCommand extends BaseCommand {
|
public class SetTbrCommand extends BaseCommand {
|
||||||
private static final Logger log = LoggerFactory.getLogger(SetTbrCommand.class);
|
private static final Logger log = LoggerFactory.getLogger(SetTbrCommand.class);
|
||||||
|
@ -58,47 +58,42 @@ public class SetTbrCommand extends BaseCommand {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CommandResult execute() {
|
public void execute() {
|
||||||
try {
|
boolean cancellingTbr = percentage == 100;
|
||||||
boolean cancellingTbr = percentage == 100;
|
|
||||||
|
|
||||||
enterTbrMenu();
|
enterTbrMenu();
|
||||||
boolean increasingPercentage = inputTbrPercentage();
|
boolean increasingPercentage = inputTbrPercentage();
|
||||||
verifyDisplayedTbrPercentage(increasingPercentage);
|
verifyDisplayedTbrPercentage(increasingPercentage);
|
||||||
|
|
||||||
if (cancellingTbr) {
|
if (cancellingTbr) {
|
||||||
cancelTbrAndConfirmCancellationWarning();
|
cancelTbrAndConfirmCancellationWarning();
|
||||||
} else {
|
} else {
|
||||||
// switch to TBR_DURATION menu by pressing menu key
|
// switch to TBR_DURATION menu by pressing menu key
|
||||||
scripter.verifyMenuIsDisplayed(MenuType.TBR_SET);
|
scripter.verifyMenuIsDisplayed(MenuType.TBR_SET);
|
||||||
scripter.pressMenuKey();
|
scripter.pressMenuKey();
|
||||||
scripter.waitForMenuUpdate();
|
scripter.waitForMenuUpdate();
|
||||||
scripter.verifyMenuIsDisplayed(MenuType.TBR_DURATION);
|
scripter.verifyMenuIsDisplayed(MenuType.TBR_DURATION);
|
||||||
|
|
||||||
boolean increasingDuration = inputTbrDuration();
|
boolean increasingDuration = inputTbrDuration();
|
||||||
verifyDisplayedTbrDuration(increasingDuration);
|
verifyDisplayedTbrDuration(increasingDuration);
|
||||||
|
|
||||||
// confirm TBR
|
// confirm TBR
|
||||||
scripter.pressCheckKey();
|
scripter.pressCheckKey();
|
||||||
scripter.waitForMenuToBeLeft(MenuType.TBR_DURATION);
|
scripter.waitForMenuToBeLeft(MenuType.TBR_DURATION);
|
||||||
}
|
}
|
||||||
|
|
||||||
scripter.verifyMenuIsDisplayed(MenuType.MAIN_MENU,
|
scripter.verifyMenuIsDisplayed(MenuType.MAIN_MENU,
|
||||||
"Pump did not return to MAIN_MEU after setting TBR. " +
|
"Pump did not return to MAIN_MEU after setting TBR. " +
|
||||||
"Check pump manually, the TBR might not have been set/cancelled.");
|
"Check pump manually, the TBR might not have been set/cancelled.");
|
||||||
|
|
||||||
// check main menu shows the same values we just set
|
// check main menu shows the same values we just set
|
||||||
if (cancellingTbr) {
|
if (cancellingTbr) {
|
||||||
verifyMainMenuShowsNoActiveTbr();
|
verifyMainMenuShowsNoActiveTbr();
|
||||||
return new CommandResult().success(true).enacted(true).message("TBR was cancelled");
|
result.success(true).enacted(true).message("TBR was cancelled");
|
||||||
} else {
|
} else {
|
||||||
verifyMainMenuShowsExpectedTbrActive();
|
verifyMainMenuShowsExpectedTbrActive();
|
||||||
return new CommandResult().success(true).enacted(true).message(
|
result.success(true).enacted(true)
|
||||||
String.format(Locale.US, "TBR set to %d%% for %d min", percentage, duration));
|
.message(String.format(Locale.US, "TBR set to %d%% for %d min", percentage, duration));
|
||||||
}
|
|
||||||
|
|
||||||
} catch (CommandException e) {
|
|
||||||
return e.toCommandResult();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -146,7 +141,7 @@ public class SetTbrCommand extends BaseCommand {
|
||||||
}
|
}
|
||||||
log.debug("Final displayed TBR percentage: " + displayedPercentage);
|
log.debug("Final displayed TBR percentage: " + displayedPercentage);
|
||||||
if (displayedPercentage != percentage) {
|
if (displayedPercentage != percentage) {
|
||||||
throw new CommandException().message("Failed to set TBR percentage, requested: "
|
throw new CommandException("Failed to set TBR percentage, requested: "
|
||||||
+ percentage + ", actual: " + displayedPercentage);
|
+ percentage + ", actual: " + displayedPercentage);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -156,7 +151,7 @@ public class SetTbrCommand extends BaseCommand {
|
||||||
scripter.verifyMenuIsDisplayed(MenuType.TBR_SET);
|
scripter.verifyMenuIsDisplayed(MenuType.TBR_SET);
|
||||||
long refreshedDisplayedTbrPecentage = readDisplayedPercentage();
|
long refreshedDisplayedTbrPecentage = readDisplayedPercentage();
|
||||||
if (displayedPercentage != refreshedDisplayedTbrPecentage) {
|
if (displayedPercentage != refreshedDisplayedTbrPecentage) {
|
||||||
throw new CommandException().message("Failed to set TBR percentage: " +
|
throw new CommandException("Failed to set TBR percentage: " +
|
||||||
"percentage changed after input stopped from "
|
"percentage changed after input stopped from "
|
||||||
+ displayedPercentage + " -> " + refreshedDisplayedTbrPecentage);
|
+ displayedPercentage + " -> " + refreshedDisplayedTbrPecentage);
|
||||||
}
|
}
|
||||||
|
@ -208,7 +203,7 @@ public class SetTbrCommand extends BaseCommand {
|
||||||
|
|
||||||
log.debug("Final displayed TBR duration: " + displayedDuration);
|
log.debug("Final displayed TBR duration: " + displayedDuration);
|
||||||
if (displayedDuration != duration) {
|
if (displayedDuration != duration) {
|
||||||
throw new CommandException().message("Failed to set TBR duration, requested: "
|
throw new CommandException("Failed to set TBR duration, requested: "
|
||||||
+ duration + ", actual: " + displayedDuration);
|
+ duration + ", actual: " + displayedDuration);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -218,7 +213,7 @@ public class SetTbrCommand extends BaseCommand {
|
||||||
scripter.verifyMenuIsDisplayed(MenuType.TBR_DURATION);
|
scripter.verifyMenuIsDisplayed(MenuType.TBR_DURATION);
|
||||||
long refreshedDisplayedTbrDuration = readDisplayedDuration();
|
long refreshedDisplayedTbrDuration = readDisplayedDuration();
|
||||||
if (displayedDuration != refreshedDisplayedTbrDuration) {
|
if (displayedDuration != refreshedDisplayedTbrDuration) {
|
||||||
throw new CommandException().message("Failed to set TBR duration: " +
|
throw new CommandException("Failed to set TBR duration: " +
|
||||||
"duration changed after input stopped from "
|
"duration changed after input stopped from "
|
||||||
+ displayedDuration + " -> " + refreshedDisplayedTbrDuration);
|
+ displayedDuration + " -> " + refreshedDisplayedTbrDuration);
|
||||||
}
|
}
|
||||||
|
@ -234,7 +229,7 @@ public class SetTbrCommand extends BaseCommand {
|
||||||
// We could read the remaining duration from MAIN_MENU, but by the time we're here,
|
// We could read the remaining duration from MAIN_MENU, but by the time we're here,
|
||||||
// the pump could have moved from 0:02 to 0:01, so instead, check if a "TBR CANCELLED" alert
|
// the pump could have moved from 0:02 to 0:01, so instead, check if a "TBR CANCELLED" alert
|
||||||
// is raised and if so dismiss it
|
// is raised and if so dismiss it
|
||||||
scripter.confirmAlert("TBR CANCELLED", 5000);
|
scripter.confirmAlert(PumpWarningCodes.TBR_CANCELLED, 2000);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void verifyMainMenuShowsNoActiveTbr() {
|
private void verifyMainMenuShowsNoActiveTbr() {
|
||||||
|
@ -242,7 +237,7 @@ public class SetTbrCommand extends BaseCommand {
|
||||||
Double tbrPercentage = (Double) scripter.getCurrentMenu().getAttribute(MenuAttribute.TBR);
|
Double tbrPercentage = (Double) scripter.getCurrentMenu().getAttribute(MenuAttribute.TBR);
|
||||||
boolean runtimeDisplayed = scripter.getCurrentMenu().attributes().contains(MenuAttribute.RUNTIME);
|
boolean runtimeDisplayed = scripter.getCurrentMenu().attributes().contains(MenuAttribute.RUNTIME);
|
||||||
if (tbrPercentage != 100 || runtimeDisplayed) {
|
if (tbrPercentage != 100 || runtimeDisplayed) {
|
||||||
throw new CommandException().message("Cancelling TBR failed, TBR is still set according to MAIN_MENU");
|
throw new CommandException("Cancelling TBR failed, TBR is still set according to MAIN_MENU");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -251,7 +246,7 @@ public class SetTbrCommand extends BaseCommand {
|
||||||
// new TBR set; percentage and duration must be displayed ...
|
// new TBR set; percentage and duration must be displayed ...
|
||||||
if (!scripter.getCurrentMenu().attributes().contains(MenuAttribute.TBR) ||
|
if (!scripter.getCurrentMenu().attributes().contains(MenuAttribute.TBR) ||
|
||||||
!scripter.getCurrentMenu().attributes().contains(MenuAttribute.RUNTIME)) {
|
!scripter.getCurrentMenu().attributes().contains(MenuAttribute.RUNTIME)) {
|
||||||
throw new CommandException().message("Setting TBR failed, according to MAIN_MENU no TBR is active");
|
throw new CommandException("Setting TBR failed, according to MAIN_MENU no TBR is active");
|
||||||
}
|
}
|
||||||
Double mmTbrPercentage = (Double) scripter.getCurrentMenu().getAttribute(MenuAttribute.TBR);
|
Double mmTbrPercentage = (Double) scripter.getCurrentMenu().getAttribute(MenuAttribute.TBR);
|
||||||
MenuTime mmTbrDuration = (MenuTime) scripter.getCurrentMenu().getAttribute(MenuAttribute.RUNTIME);
|
MenuTime mmTbrDuration = (MenuTime) scripter.getCurrentMenu().getAttribute(MenuAttribute.RUNTIME);
|
||||||
|
@ -260,7 +255,7 @@ public class SetTbrCommand extends BaseCommand {
|
||||||
// 29 minutes and 59 seconds, so that 29 minutes are displayed
|
// 29 minutes and 59 seconds, so that 29 minutes are displayed
|
||||||
int mmTbrDurationInMinutes = mmTbrDuration.getHour() * 60 + mmTbrDuration.getMinute();
|
int mmTbrDurationInMinutes = mmTbrDuration.getHour() * 60 + mmTbrDuration.getMinute();
|
||||||
if (mmTbrPercentage != percentage || (mmTbrDurationInMinutes != duration && mmTbrDurationInMinutes + 1 != duration)) {
|
if (mmTbrPercentage != percentage || (mmTbrDurationInMinutes != duration && mmTbrDurationInMinutes + 1 != duration)) {
|
||||||
throw new CommandException().message("Setting TBR failed, TBR in MAIN_MENU differs from expected");
|
throw new CommandException("Setting TBR failed, TBR in MAIN_MENU differs from expected");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,50 +0,0 @@
|
||||||
package de.jotomo.ruffyscripter.commands;
|
|
||||||
|
|
||||||
import org.monkey.d.ruffy.ruffy.driver.display.MenuAttribute;
|
|
||||||
import org.monkey.d.ruffy.ruffy.driver.display.MenuType;
|
|
||||||
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import de.jotomo.ruffy.spi.CommandResult;
|
|
||||||
import de.jotomo.ruffy.spi.PumpState;
|
|
||||||
import de.jotomo.ruffy.spi.history.PumpError;
|
|
||||||
|
|
||||||
// TODO rename to ConfirmALarm(alarm) => logic in CP, just report back alarm, then explicitely confirm that one alarm.
|
|
||||||
// multiple alarms oncy occur for errors (battery/cartdige low/occlusion) => let ring.
|
|
||||||
public class TakeOverAlarmsCommand extends BaseCommand {
|
|
||||||
@Override
|
|
||||||
public CommandResult execute() {
|
|
||||||
if (scripter.getCurrentMenu().getType() != MenuType.WARNING_OR_ERROR) {
|
|
||||||
return new CommandResult().success(false).enacted(false).message("No alarm active on the pump");
|
|
||||||
}
|
|
||||||
while (scripter.getCurrentMenu().getType() == MenuType.WARNING_OR_ERROR) {
|
|
||||||
new PumpError(System.currentTimeMillis(),
|
|
||||||
"",
|
|
||||||
// TODO
|
|
||||||
// codes unqiue across W/E?
|
|
||||||
// (int) currentMenu.getAttribute(MenuAttribute.WARNING),
|
|
||||||
// (int) currentMenu.getAttribute(MenuAttribute.ERROR),
|
|
||||||
(String) scripter.getCurrentMenu().getAttribute(MenuAttribute.MESSAGE));
|
|
||||||
}
|
|
||||||
// confirm alert
|
|
||||||
scripter.verifyMenuIsDisplayed(MenuType.WARNING_OR_ERROR);
|
|
||||||
scripter.pressCheckKey();
|
|
||||||
// dismiss alert
|
|
||||||
scripter.verifyMenuIsDisplayed(MenuType.WARNING_OR_ERROR);
|
|
||||||
scripter.pressCheckKey();
|
|
||||||
scripter.waitForMenuToBeLeft(MenuType.WARNING_OR_ERROR);
|
|
||||||
|
|
||||||
PumpState pumpState = scripter.readPumpStateInternal();
|
|
||||||
return new CommandResult()
|
|
||||||
.success(true)
|
|
||||||
.enacted(false /* well, no treatments were enacted ... */)
|
|
||||||
// .message(pumpState.errorMsg) // todo yikes?
|
|
||||||
.state(pumpState);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public List<String> validateArguments() {
|
|
||||||
return Collections.emptyList();
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Reference in a new issue