Fix initializing ruffy service, read reservoir level on init.

This commit is contained in:
Johannes Mockenhaupt 2017-10-18 20:53:44 +02:00
parent 31a1811323
commit dca219d900
No known key found for this signature in database
GPG key ID: 9E1EA6AF7BBBB0D1
9 changed files with 222 additions and 142 deletions

View file

@ -147,6 +147,8 @@ public class ComboFragment extends Fragment implements View.OnClickListener {
insulinstateText.setTextColor(Color.RED);
break;
}
int reservoirLevel = plugin.getPump().history.reservoirLevel;
insulinstateText.setText(reservoirLevel == - 1 ? "" : "" + reservoirLevel);
}
CommandResult lastCmdResult1 = plugin.getPump().lastCmdResult;

View file

@ -15,6 +15,7 @@ import org.slf4j.LoggerFactory;
import java.util.Date;
import de.jotomo.ruffy.spi.history.PumpHistoryRequest;
import info.nightscout.androidaps.BuildConfig;
import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.R;
@ -258,6 +259,8 @@ public class ComboPlugin implements PluginBase, PumpInterface {
}
// this method is regularly called from info.nightscout.androidaps.receivers.KeepAliveReceiver
// TODO check this is eithor called regularly even with other commansd being fired; if not,
// request this periodically
@Override
public void refreshDataFromPump(String reason) {
log.debug("RefreshDataFromPump called");
@ -269,12 +272,19 @@ public class ComboPlugin implements PluginBase, PumpInterface {
}
boolean notAUserRequest = !reason.toLowerCase().contains("user");
if (notAUserRequest) SystemClock.sleep(2000);
boolean wasRunAtLeastOnce = pump.lastCmdTime.getTime() > 0;
boolean ranWithinTheLastMinute = System.currentTimeMillis() < pump.lastCmdTime.getTime() + 60 * 1000;
if (notAUserRequest && wasRunAtLeastOnce && ranWithinTheLastMinute) {
log.debug("Not fetching state from pump, since we did already within the last 60 seconds");
} else {
ruffyScripter.readPumpState();
CommandResult commandResult = ruffyScripter.readPumpState();
pump.lastCmdResult = commandResult;
pump.lastCmdTime = new Date(commandResult.completionTime);
MainApp.bus().post(new EventComboPumpUpdateGUI());
CommandResult reservoirQueryResult = ruffyScripter.readHistory(new PumpHistoryRequest().reservoirLevel(true));
pump.history = reservoirQueryResult.history;
}
}
@ -363,6 +373,10 @@ public class ComboPlugin implements PluginBase, PumpInterface {
@NonNull
private PumpEnactResult deliverBolus(DetailedBolusInfo detailedBolusInfo) {
CommandResult bolusCmdResult = ruffyScripter.deliverBolus(detailedBolusInfo.insulin, bolusProgressReporter);
pump.lastCmdResult = bolusCmdResult;
pump.lastCmdTime = new Date(bolusCmdResult.completionTime);
MainApp.bus().post(new EventComboPumpUpdateGUI());
PumpEnactResult pumpEnactResult = new PumpEnactResult();
pumpEnactResult.success = bolusCmdResult.success;
pumpEnactResult.enacted = bolusCmdResult.enacted;
@ -427,6 +441,9 @@ public class ComboPlugin implements PluginBase, PumpInterface {
}
CommandResult commandResult = ruffyScripter.setTbr(adjustedPercent, durationInMinutes);
pump.lastCmdResult = commandResult;
pump.lastCmdTime = new Date(commandResult.completionTime);
MainApp.bus().post(new EventComboPumpUpdateGUI());
if (commandResult.enacted) {
TemporaryBasal tempStart = new TemporaryBasal(commandResult.completionTime);
@ -442,8 +459,6 @@ public class ComboPlugin implements PluginBase, PumpInterface {
treatmentsInterface.addToHistoryTempBasal(tempStart);
}
MainApp.bus().post(new EventComboPumpUpdateGUI());
PumpEnactResult pumpEnactResult = new PumpEnactResult();
pumpEnactResult.success = commandResult.success;
pumpEnactResult.enacted = commandResult.enacted;
@ -476,6 +491,10 @@ public class ComboPlugin implements PluginBase, PumpInterface {
/* v1 compatibility to sync DB to pump if they diverged (activeTemp == null) */
log.debug("cancelTempBasal: hard-cancelling TBR since user requested");
commandResult = ruffyScripter.cancelTbr();
pump.lastCmdResult = commandResult;
pump.lastCmdTime = new Date(commandResult.completionTime);
MainApp.bus().post(new EventComboPumpUpdateGUI());
if (commandResult.enacted) {
tempBasal = new TemporaryBasal(commandResult.completionTime);
tempBasal.durationInMinutes = 0;
@ -498,6 +517,10 @@ public class ComboPlugin implements PluginBase, PumpInterface {
int percentage = (activeTemp.percentRate > 100) ? 110 : 90;
log.debug("cancelTempBasal: changing tbr to " + percentage + "% for 15 mins.");
commandResult = ruffyScripter.setTbr(percentage, 15);
pump.lastCmdResult = commandResult;
pump.lastCmdTime = new Date(commandResult.completionTime);
MainApp.bus().post(new EventComboPumpUpdateGUI());
if (commandResult.enacted) {
tempBasal = new TemporaryBasal(commandResult.completionTime);
tempBasal.durationInMinutes = 15;

View file

@ -7,6 +7,7 @@ import java.util.Date;
import de.jotomo.ruffy.spi.PumpState;
import de.jotomo.ruffy.spi.CommandResult;
import de.jotomo.ruffy.spi.history.PumpHistory;
class ComboPump {
@Nullable
@ -14,4 +15,5 @@ class ComboPump {
@NonNull
volatile Date lastCmdTime = new Date(0);
volatile PumpState state = new PumpState();
volatile PumpHistory history = new PumpHistory();
}

View file

@ -14,7 +14,7 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/objectives_fake_layout"
android:visibility="gone">
android:visibility="visible">
<CheckBox
android:layout_width="wrap_content"

View file

@ -2,25 +2,54 @@ package de.jotomo.ruffy.spi.history;
import android.support.annotation.NonNull;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
public class PumpHistory {
public final int reservoirLevel;
public int reservoirLevel = -1;
@NonNull
public final List<Bolus> bolusHistory;
public List<Bolus> bolusHistory = Collections.emptyList();
@NonNull
public final List<Tbr> tbrHistory;
public List<Tbr> tbrHistory = Collections.emptyList();
@NonNull
public final List<java.lang.Error> errorHistory;
public List<Error> errorHistory = Collections.emptyList();
@NonNull
public final List<Tdd> tddHistory;
public List<Tdd> tddHistory = Collections.emptyList();
public PumpHistory(int reservoirLevel, List<Bolus> bolusHistory, List<Tbr> tbrHistory, List<java.lang.Error> errorHistory, List<Tdd> tddHistory) {
this.reservoirLevel = reservoirLevel;
this.bolusHistory = Objects.requireNonNull(bolusHistory);
this.tbrHistory = Objects.requireNonNull(tbrHistory);
this.errorHistory = Objects.requireNonNull(errorHistory);
this.tddHistory = Objects.requireNonNull(tddHistory);
public PumpHistory reservoirLevel(int reservoirLevel) {
this.reservoirLevel = reservoirLevel
;
return this;
}
public PumpHistory bolusHistory(List<Bolus> bolusHistory) {
this.bolusHistory = bolusHistory;
return this;
}
public PumpHistory tbrHistory(List<Tbr> tbrHistory) {
this.tbrHistory = tbrHistory;
return this;
}
public PumpHistory errorHistory(List<Error> errorHistory) {
this.errorHistory = errorHistory;
return this;
}
@Override
public String toString() {
return "PumpHistory{" +
"reservoirLevel=" + reservoirLevel +
", bolusHistory=" + bolusHistory +
", tbrHistory=" + tbrHistory +
", errorHistory=" + errorHistory +
", tddHistory=" + tddHistory +
'}';
}
public PumpHistory tddHistory(List<Tdd> tddHistory) {
this.tddHistory = tddHistory;
return this;
}
}

View file

@ -11,9 +11,9 @@ public class PumpHistoryRequest {
public static final long SKIP = -1;
public static final long FULL = 0;
public long bolusHistory;
public long tbrHistory;
public long errorHistory;
public long bolusHistory = SKIP;
public long tbrHistory = SKIP;
public long errorHistory = SKIP;
public PumpHistoryRequest reservoirLevel(boolean reservoirLevel) {
this.reservoirLevel = reservoirLevel;

View file

@ -20,29 +20,25 @@ 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.List;
import de.jotomo.ruffy.spi.BasalProfile;
import de.jotomo.ruffy.spi.BolusProgressReporter;
import de.jotomo.ruffy.spi.CommandResult;
import de.jotomo.ruffy.spi.PumpState;
import de.jotomo.ruffy.spi.RuffyCommands;
import de.jotomo.ruffy.spi.history.PumpHistoryRequest;
import de.jotomo.ruffyscripter.commands.BolusCommand;
import de.jotomo.ruffyscripter.commands.CancelTbrCommand;
import de.jotomo.ruffyscripter.commands.Command;
import de.jotomo.ruffyscripter.commands.CommandException;
import de.jotomo.ruffyscripter.commands.GetPumpStateCommand;
import de.jotomo.ruffyscripter.commands.ReadBasalProfileCommand;
import de.jotomo.ruffyscripter.commands.ReadHistoryCommand;
import de.jotomo.ruffyscripter.commands.ReadPumpStateCommand;
import de.jotomo.ruffyscripter.commands.SetBasalProfileCommand;
import de.jotomo.ruffyscripter.commands.SetTbrCommand;
import de.jotomo.ruffy.spi.BasalProfile;
import de.jotomo.ruffy.spi.BolusProgressReporter;
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.PumpState;
import de.jotomo.ruffy.spi.RuffyCommands;
import de.jotomo.ruffy.spi.history.PumpHistoryRequest;
import de.jotomo.ruffy.spi.history.Tbr;
import de.jotomo.ruffy.spi.history.Tdd;
// 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
@ -70,91 +66,6 @@ public class RuffyScripter implements RuffyCommands {
private final Object screenlock = new Object();
private ServiceConnection mRuffyServiceConnection;
public RuffyScripter(Context context) {
boolean boundSucceeded = false;
try {
Intent intent = new Intent()
.setComponent(new ComponentName(
// this must be the base package of the app (check package attribute in
// manifest element in the manifest file of the providing app)
"org.monkey.d.ruffy.ruffy",
// full path to the driver;
// in the logs this service is mentioned as (note the slash)
// "org.monkey.d.ruffy.ruffy/.driver.Ruffy";
// org.monkey.d.ruffy.ruffy is the base package identifier
// and /.driver.Ruffy the service within the package
"org.monkey.d.ruffy.ruffy.driver.Ruffy"
));
context.startService(intent);
mRuffyServiceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
ruffyService = IRuffyService.Stub.asInterface(service);
log.debug("ruffy serivce connected");
}
@Override
public void onServiceDisconnected(ComponentName name) {
log.debug("ruffy service disconnected");
}
};
boundSucceeded = context.bindService(intent, mRuffyServiceConnection, Context.BIND_AUTO_CREATE);
} catch (Exception e) {
log.error("Binding to ruffy service failed", e);
}
if (!boundSucceeded) {
log.error("No connection to ruffy. Pump control unavailable.");
} else {
started = true;
}
}
@Override
public boolean isPumpAvailable() {
return started;
}
private volatile boolean connected = false;
private volatile long lastDisconnected = 0;
private Thread idleDisconnectMonitorThread = new Thread(new Runnable() {
@Override
public void run() {
while (unrecoverableError == null) {
try {
long now = System.currentTimeMillis();
long connectionTimeOutMs = 5000;
if (connected && activeCmd == null
&& now > lastCmdExecutionTime + connectionTimeOutMs
// don't disconnect too frequently, confuses ruffy?
&& now > lastDisconnected + 15 * 1000) {
log.debug("Disconnecting after " + (connectionTimeOutMs / 1000) + "s inactivity timeout");
lastDisconnected = now;
ruffyService.doRTDisconnect();
connected = false;
// don't attempt anything fancy in the next 10s, let the pump settle
SystemClock.sleep(10 * 1000);
}
} catch (Exception e) {
// TODO do we need to catch this exception somewhere else too? right now it's
// converted into a command failure, but it's not classified as unrecoverable;
// 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);
}
}
}, "idle-disconnect-monitor");
private IRTHandler mHandler = new IRTHandler.Stub() {
@Override
public void log(String message) throws RemoteException {
@ -221,6 +132,93 @@ public class RuffyScripter implements RuffyCommands {
}
};
public RuffyScripter(Context context) {
boolean boundSucceeded = false;
try {
Intent intent = new Intent()
.setComponent(new ComponentName(
// this must be the base package of the app (check package attribute in
// manifest element in the manifest file of the providing app)
"org.monkey.d.ruffy.ruffy",
// full path to the driver;
// in the logs this service is mentioned as (note the slash)
// "org.monkey.d.ruffy.ruffy/.driver.Ruffy";
// org.monkey.d.ruffy.ruffy is the base package identifier
// and /.driver.Ruffy the service within the package
"org.monkey.d.ruffy.ruffy.driver.Ruffy"
));
context.startService(intent);
ServiceConnection mRuffyServiceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
log.debug("ruffy service connected");
ruffyService = IRuffyService.Stub.asInterface(service);
try {
ruffyService.setHandler(mHandler);
} catch (Exception e) {
log.error("Ruffy handler has issues", e);
}
idleDisconnectMonitorThread.start();
started = true;
}
@Override
public void onServiceDisconnected(ComponentName name) {
log.debug("ruffy service disconnected");
}
};
boundSucceeded = context.bindService(intent, mRuffyServiceConnection, Context.BIND_AUTO_CREATE);
} catch (Exception e) {
log.error("Binding to ruffy service failed", e);
}
if (!boundSucceeded) {
log.error("No connection to ruffy. Pump control unavailable.");
}
}
@Override
public boolean isPumpAvailable() {
return started;
}
private volatile boolean connected = false;
private volatile long lastDisconnected = 0;
private Thread idleDisconnectMonitorThread = new Thread(new Runnable() {
@Override
public void run() {
while (unrecoverableError == null) {
try {
long now = System.currentTimeMillis();
long connectionTimeOutMs = 5000;
if (connected && activeCmd == null
&& now > lastCmdExecutionTime + connectionTimeOutMs
// don't disconnect too frequently, confuses ruffy?
&& now > lastDisconnected + 15 * 1000) {
log.debug("Disconnecting after " + (connectionTimeOutMs / 1000) + "s inactivity timeout");
lastDisconnected = now;
ruffyService.doRTDisconnect();
connected = false;
// don't attempt anything fancy in the next 10s, let the pump settle
SystemClock.sleep(10 * 1000);
}
} catch (Exception e) {
// TODO do we need to catch this exception somewhere else too? right now it's
// converted into a command failure, but it's not classified as unrecoverable;
// 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);
}
}
}, "idle-disconnect-monitor");
@Override
public boolean isPumpBusy() {
return activeCmd != null;
@ -266,14 +264,13 @@ public class RuffyScripter implements RuffyCommands {
return new CommandResult().message(Joiner.on("\n").join(violations)).state(readPumpStateInternal());
}
// synchronized (RuffyScripter.class) {
synchronized (RuffyScripter.class) {
try {
activeCmd = cmd;
long connectStart = System.currentTimeMillis();
ensureConnected();
final RuffyScripter scripter = this;
final Returnable returnable = new Returnable();
returnable.cmdResult.request = cmd.toString();
Thread cmdThread = new Thread(new Runnable() {
@Override
public void run() {
@ -370,6 +367,7 @@ public class RuffyScripter implements RuffyCommands {
long connectDurationSec = (executionStart - connectStart) / 1000;
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) {
@ -381,7 +379,7 @@ public class RuffyScripter implements RuffyCommands {
} finally {
activeCmd = null;
}
// }
}
}
/**
@ -431,8 +429,10 @@ public class RuffyScripter implements RuffyCommands {
// TODO v2 add remaining info we can extract from the main menu, low battery and low
// cartridge warnings, running extended bolus (how does that look if a TBR is active as well?)
/** This reads the state of the, which is whatever is currently displayed on the display,
* no actions are performed. */
/**
* This reads the state of the, which is whatever is currently displayed on the display,
* no actions are performed.
*/
public PumpState readPumpStateInternal() {
PumpState state = new PumpState();
Menu menu = currentMenu;
@ -541,9 +541,9 @@ public class RuffyScripter implements RuffyCommands {
// wrapNoNotTheSubwayKind(new Step() {
// @Override
// public void doStep() {
log.debug("Pressing up key");
pressKey(Key.UP, 2000);
log.debug("Releasing up key");
log.debug("Pressing up key");
pressKey(Key.UP, 2000);
log.debug("Releasing up key");
// }
// });
}
@ -611,7 +611,9 @@ public class RuffyScripter implements RuffyCommands {
// TODO confirmAlarms? and report back which were cancelled?
/** Confirms and dismisses the given alert if it's raised before the timeout */
/**
* 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;
@ -641,7 +643,9 @@ public class RuffyScripter implements RuffyCommands {
return alertProcessed;
}
/** Wait until the menu is updated */
/**
* Wait until the menu is updated
*/
public void waitForMenuUpdate() {
waitForMenuUpdate(60, "Timeout waiting for menu update");
}
@ -692,7 +696,9 @@ public class RuffyScripter implements RuffyCommands {
}
}
/** Wait till a menu changed has completed, "away" from the menu provided as argument. */
/**
* Wait till a menu changed has completed, "away" from the menu provided as argument.
*/
public void waitForMenuToBeLeft(MenuType menuType) {
long timeout = System.currentTimeMillis() + 60 * 1000;
while (getCurrentMenu().getType() == menuType) {
@ -761,12 +767,7 @@ public class RuffyScripter implements RuffyCommands {
@Override
public CommandResult readHistory(PumpHistoryRequest request) {
return new CommandResult().history(
new PumpHistory(50,
Collections.<Bolus>emptyList(),
Collections.<Tbr>emptyList(),
Collections.<Error>emptyList(),
Collections.<Tdd>emptyList()));
return runCommand(new ReadHistoryCommand(request));
}
@Override

View file

@ -1,27 +1,45 @@
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.history.PumpHistory;
import de.jotomo.ruffyscripter.RuffyScripter;
import de.jotomo.ruffy.spi.history.PumpHistoryRequest;
import de.jotomo.ruffy.spi.CommandResult;
public class ReadHistoryCommand implements Command {
public ReadHistoryCommand(PumpHistory knownHistory) {
public class ReadHistoryCommand extends BaseCommand {
private final PumpHistoryRequest request;
public ReadHistoryCommand(PumpHistoryRequest request) {
this.request = request;
}
@Override
public CommandResult execute() {
return null;
PumpHistory history = new PumpHistory();
if (request.reservoirLevel) readReservoirLevel(history);
if (request.bolusHistory != PumpHistoryRequest.SKIP) readBolusHistory(history, request.bolusHistory);
return new CommandResult().success(true).enacted(false).history(history);
}
private void readBolusHistory(PumpHistory history, long bolusHistory) {
}
private void readReservoirLevel(PumpHistory history) {
scripter.verifyMenuIsDisplayed(MenuType.MAIN_MENU);
scripter.pressCheckKey();
scripter.waitForMenuToBeLeft(MenuType.MAIN_MENU);
scripter.verifyMenuIsDisplayed(MenuType.QUICK_INFO);
int remainingInsulin = ((Double) scripter.getCurrentMenu().getAttribute(MenuAttribute.REMAINING_INSULIN)).intValue();
scripter.returnToMainMenu();
history.reservoirLevel = remainingInsulin;
}
@Override
public List<String> validateArguments() {
return null;
}
@Override
public void setScripter(RuffyScripter scripter) {
return Collections.emptyList();
}
}

View file

@ -19,4 +19,9 @@ public class ReadPumpStateCommand implements Command {
@Override
public void setScripter(RuffyScripter scripter) {}
@Override
public String toString() {
return "ReadPumpStateCommand{}";
}
}