* Read all history
* Simple viewer for TDDs, errors
* Clean up cancelling TBR (incomplete)
* Initializing pump robustness
This commit is contained in:
Johannes Mockenhaupt 2017-11-12 00:01:01 +01:00
parent 3072a42cd7
commit c11086d9ea
No known key found for this signature in database
GPG key ID: 9E1EA6AF7BBBB0D1
16 changed files with 278 additions and 104 deletions

View file

@ -73,6 +73,3 @@ Usage
have to wait till the pump's display turns off before it can reconnect to the pump).
If the pump's alarm continues, the last action might have failed, in which case the user needs to confirm the alarm
v3 TODOs
- Reading and displaying TDDs

View file

@ -8,10 +8,21 @@
- [ ] Bolus deleted in treatments (marked invalid?!) is re-added when pump reads history
- [ ] Tasks
- [ ] Main
- [ ] on command error: recover by returning to main menu
- [ ] Reading history
- [ ] Bolus
- [x] Bolus
- [x] Read
- [x] Sync DB
- [ ] TBRs
- [x] Read
- [ ] Sync DB
- [ ] Alerts
- [x] Read
- [ ] Sync DB?
- [x] Display in UI
- [ ] TDD
- [x] Read
- [ ] Sync DB?
- [ ] Display in UI
- [ ] Taking over alerts
- [ ] On connect
@ -24,6 +35,7 @@
- [ ] Run readReservoirAndBolusLevel after SetTbr too so boluses on the pump are caught sooner?
Currently the pump gets to know such a record when bolusing or when refresh() is called
after 15m of no other command taking place. IOB will then be current with next loop
- [ ] Optimize reading full history to pass timestamps of last known records to avoid reading known records
iteration.
- [ ] Cleanups
- [ ] Finish 'enacted' removal rewrite (esp. cancel tbr)
@ -39,6 +51,8 @@
- [ ] Display errors in combo tap
- [x] Option to raise overview notifications as android notification with noise (for urgent ones?)
- [ ] Low prio
- [ ] Naming is messed up: pump has warnings and errors, which cause alerts; W+E are thus alerts,
e.g. pumpErrorHistory should be renamed to alertHistory
- [ ] Enable BT if disabled? does dana does this?
- [ ] Finish and test German translation
- [ ] No clean startup/shutdown; RuffyScripter is instanciated once, idle disconnect thread never killed
@ -46,12 +60,6 @@
Android logs it as crashed and restarts it, thereby restarting the app (or just keeping it alive,
also causes errors with the DB as there were attemtps to open a closed DB instance/ref.
- [ ] v3
- [ ] Tasks (this is probably best left to the command-mode people)
- [ ] Reading TDD
- [ ] UI for TDDs
- [ ] Optimize reading full history to pass timestamps of last known records to avoid reading known records
Inbox
- [ ] Where/when to call checkTbrMisMatch?
- [ ] pairing: just start SetupFragment?

View file

@ -53,6 +53,9 @@ public class ComboFragment extends SubscriberFragment implements View.OnClickLis
Button errorHistory = (Button) view.findViewById(R.id.combo_error_history);
errorHistory.setOnClickListener(this);
Button tddHistory = (Button) view.findViewById(R.id.combo_tdd_history);
tddHistory.setOnClickListener(this);
updateGUI();
return view;
}
@ -65,8 +68,11 @@ public class ComboFragment extends SubscriberFragment implements View.OnClickLis
break;
case R.id.combo_error_history:
ComboErrorHistoryDialog ehd = new ComboErrorHistoryDialog();
FragmentManager manager = getFragmentManager();
ehd.show(manager, ComboErrorHistoryDialog.class.getSimpleName());
ehd.show(getFragmentManager(), ComboErrorHistoryDialog.class.getSimpleName());
break;
case R.id.combo_tdd_history:
ComboTddHistoryDialog thd = new ComboTddHistoryDialog();
thd.show(getFragmentManager(), ComboTddHistoryDialog.class.getSimpleName());
break;
}
}

View file

@ -17,8 +17,10 @@ import de.jotomo.ruffy.spi.CommandResult;
import de.jotomo.ruffy.spi.PumpState;
import de.jotomo.ruffy.spi.RuffyCommands;
import de.jotomo.ruffy.spi.history.Bolus;
import de.jotomo.ruffy.spi.history.PumpError;
import de.jotomo.ruffy.spi.history.PumpHistoryRequest;
import de.jotomo.ruffy.spi.history.Tbr;
import de.jotomo.ruffy.spi.history.Tdd;
import de.jotomo.ruffyscripter.RuffyCommandsV1Impl;
import info.nightscout.androidaps.BuildConfig;
import info.nightscout.androidaps.MainApp;
@ -38,6 +40,7 @@ import info.nightscout.androidaps.interfaces.PluginBase;
import info.nightscout.androidaps.interfaces.PumpDescription;
import info.nightscout.androidaps.interfaces.PumpInterface;
import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin;
import info.nightscout.androidaps.plugins.Overview.Notification;
import info.nightscout.androidaps.plugins.Overview.events.EventNewNotification;
import info.nightscout.androidaps.plugins.Overview.events.EventOverviewBolusProgress;
import info.nightscout.androidaps.plugins.PumpCombo.events.EventComboPumpUpdateGUI;
@ -243,24 +246,35 @@ public class ComboPlugin implements PluginBase, PumpInterface, ConstraintsInterf
}
}
CommandResult stateResult = runCommand("Refreshing", 3, ruffyScripter::readReservoirLevelAndLastBolus);
CommandResult stateResult = runCommand(pump.initialized ? MainApp.sResources.getString(R.string.combo_pump_action_refreshing) : MainApp.sResources.getString(R.string.combo_pump_action_initializing),
1, ruffyScripter::readReservoirLevelAndLastBolus);
if (!stateResult.success) {
return;
}
checkForTbrMismatch(stateResult.state);
int minutesOfDayNow = Calendar.getInstance().get(Calendar.HOUR) + Calendar.getInstance().get(Calendar.MINUTE) * 60;
if (!pump.initialized || (Math.abs(stateResult.state.pumpTimeMinutesOfDay - minutesOfDayNow) >= 2)) {
runCommand("Updating pump clock", 2, ruffyScripter::setDateAndTime);
if (!runCommand("Updating pump clock", 2, ruffyScripter::setDateAndTime).success) {
return;
}
}
if (!pump.initialized) {
runCommand("Reading basal profile", 2, ruffyScripter::readBasalProfile);
if (!runCommand("Reading basal profile", 2, ruffyScripter::readBasalProfile).success) {
return;
}
}
checkPumpHistory();
if (!checkPumpHistory()) {
return;
}
// if (!pump.initialized) {
// pump.initialized = clockUpdated && basalProfileRead;
// }
pump.initialized = true;
// ComboFragment updates state fully only after the pump has initialized,
// this fetches state again and updates the ui proper
runCommand(null, 0, ruffyScripter::readPumpState);
}
@ -504,11 +518,11 @@ public class ComboPlugin implements PluginBase, PumpInterface, ConstraintsInterf
PumpState state = commandResult.state;
if (state.tbrActive && state.tbrPercent == percent
&& (state.tbrRemainingDuration == durationInMinutes || state.tbrRemainingDuration == durationInMinutes - 1)) {
// TODO timestamp: can this cause problems? setting TBR while a minute flips over?
// might that be the cause if the TBR duration instantly flips from e.g. 0:30 -> 0:29 ?
TemporaryBasal tempStart = new TemporaryBasal(state.timestamp);
// 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
// TODO actually ... might setting 29 help with gaps between TBRs? w/o the hack in TemporaryBasal?
// nah, fucks up duration in treatment history
tempStart.durationInMinutes = durationInMinutes;
tempStart.percentRate = adjustedPercent;
tempStart.isAbsolute = false;
@ -529,78 +543,53 @@ public class ComboPlugin implements PluginBase, PumpInterface, ConstraintsInterf
return OPERATION_NOT_SUPPORTED;
}
// TODO clean this method up:
// check PumpState to verify TBR has been cancelled.
// enacted field.
// TODO review and test, esp. aaps/pump mismatch situations
@Override
public PumpEnactResult cancelTempBasal(boolean userRequested) {
log.debug("cancelTempBasal called");
CommandResult commandResult = null;
TemporaryBasal tempBasal = null;
PumpEnactResult pumpEnactResult = new PumpEnactResult();
final TemporaryBasal activeTemp = MainApp.getConfigBuilder().getTempBasalFromHistory(System.currentTimeMillis());
// checkForTbrMismatch();
if (activeTemp == null || userRequested) {
// TODO
/* v1 compatibility to sync DB to pump if they diverged (activeTemp == null) */
log.debug("cancelTempBasal: hard-cancelling TBR since user requested");
commandResult = runCommand(MainApp.sResources.getString(R.string.combo_pump_action_cancelling_tbr), 2, ruffyScripter::cancelTbr);
CommandResult commandResult = runCommand(MainApp.sResources.getString(R.string.combo_pump_action_cancelling_tbr), 2, ruffyScripter::cancelTbr);
if (!commandResult.state.tbrActive) {
tempBasal = new TemporaryBasal(System.currentTimeMillis());
TemporaryBasal tempBasal = new TemporaryBasal(System.currentTimeMillis());
tempBasal.durationInMinutes = 0;
tempBasal.source = Source.USER;
pumpEnactResult.isTempCancel = true;
MainApp.getConfigBuilder().addToHistoryTempBasal(tempBasal);
return new PumpEnactResult().isTempCancel(true).success(true).enacted(true);
} else {
return new PumpEnactResult().success(false).enacted(false);
}
} else if ((activeTemp.percentRate >= 90 && activeTemp.percentRate <= 110) && activeTemp.getPlannedRemainingMinutes() <= 15) {
// 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.");
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;
// looking at info/nightscout/androidaps/plugins/Loop/LoopPlugin.java:280
// both values are used as one:
// if (applyResult.enacted || applyResult.success) { ...
pumpEnactResult.enacted = true; // all fine though...
pumpEnactResult.success = true; // just roll with it...
return new PumpEnactResult().success(true).enacted(true)
.comment("cancelTempBasal skipping changing tbr since it already is at "
+ activeTemp.percentRate + "% and running for another "
+ activeTemp.getPlannedRemainingMinutes() + " mins.");
} else {
// Set a fake neutral temp to avoid TBR cancel alert. Decide 90% vs 110% based on
// on whether the TBR we're cancelling is above or below 100%.
final int percentage = (activeTemp.percentRate > 100) ? 110 : 90;
log.debug("cancelTempBasal: changing TBR to " + percentage + "% for 15 mins.");
commandResult = runCommand(MainApp.sResources.getString(R.string.combo_pump_action_cancelling_tbr), 2, () -> ruffyScripter.setTbr(percentage, 15));
CommandResult commandResult = runCommand(MainApp.sResources.getString(R.string.combo_pump_action_cancelling_tbr), 2, () -> ruffyScripter.setTbr(percentage, 15));
// TODO properly check fake neutral temp is active
// if (!commandResult.state.tbrActive) {
if (commandResult.success) {
tempBasal = new TemporaryBasal(System.currentTimeMillis());
if (commandResult.state.tbrActive && commandResult.state.tbrPercent == percentage
&& (commandResult.state.tbrRemainingDuration == 15 || commandResult.state.tbrRemainingDuration == 14)) {
TemporaryBasal tempBasal = new TemporaryBasal(System.currentTimeMillis());
tempBasal.durationInMinutes = 15;
tempBasal.source = Source.USER;
tempBasal.percentRate = percentage;
tempBasal.isAbsolute = false;
MainApp.getConfigBuilder().addToHistoryTempBasal(tempBasal);
return new PumpEnactResult().success(true).enacted(true);
} else {
return new PumpEnactResult().success(false).enacted(false);
}
}
// TODO properly check pumpstate to confirm cancellation
// PumpState state = commandResult.state;
// if (!state.tbrActive && state.tbrPercent == percent
// && (state.tbrRemainingDuration == durationInMinutes || state.tbrRemainingDuration == durationInMinutes - 1)) {
//
// }
if (tempBasal != null) {
ConfigBuilderPlugin treatmentsInterface = MainApp.getConfigBuilder();
treatmentsInterface.addToHistoryTempBasal(tempBasal);
}
if (commandResult != null) {
pumpEnactResult.success = commandResult.success;
pumpEnactResult.enacted = true;
}
return pumpEnactResult;
}
private interface CommandExecution {
@ -609,6 +598,7 @@ public class ComboPlugin implements PluginBase, PumpInterface, ConstraintsInterf
// TODO remove this method, make stuff explicit (state updates, activity updates)
// and only have a withRetries() method that simply retries a command?
/**
* Runs a command, sets an activity if provided, retries if requested and updates fields
* concerned with last connection.
@ -663,7 +653,7 @@ public class ComboPlugin implements PluginBase, PumpInterface, ConstraintsInterf
if (commandResult.state.unsafeUsageDetected) {
lastViolation = System.currentTimeMillis();
}
if (commandResult.lastBolus != null && !commandResult.lastBolus.isValid) {
if (commandResult.lastBolus != null && !commandResult.lastBolus.isValid) {
lastViolation = commandResult.lastBolus.timestamp;
} else if (commandResult.history != null) {
for (Bolus bolus : commandResult.history.bolusHistory) {
@ -687,7 +677,9 @@ public class ComboPlugin implements PluginBase, PumpInterface, ConstraintsInterf
}
}
/** Checks the main screen to determine if TBR on pump matches app state. */
/**
* Checks the main screen to determine if TBR on pump matches app state.
*/
private boolean checkForTbrMismatch(PumpState state) {
// 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;
@ -736,20 +728,18 @@ public class ComboPlugin implements PluginBase, PumpInterface, ConstraintsInterf
new PumpHistoryRequest()
.bolusHistory(PumpHistoryRequest.LAST)
.tbrHistory(PumpHistoryRequest.LAST)
.errorHistory(PumpHistoryRequest.LAST)));
.pumpErrorHistory(PumpHistoryRequest.LAST)));
if (!commandResult.success || commandResult.history == null) {
// TODO error case, command
return false;
}
// TODO opt, construct PumpHistoryRequest to requset only what needs updating
boolean syncNeeded = false;
// TODO v2.1 optimize, construct PumpHistoryRequest to requset only what needs updating
PumpHistoryRequest request = new PumpHistoryRequest();
// last bolus
List<Treatment> treatments = MainApp.getConfigBuilder().getTreatmentsFromHistory();
// Collections.reverse(treatments);
Treatment aapsBolus = null;
for (Treatment t : treatments) {
if (t.insulin != 0) {
@ -766,7 +756,6 @@ public class ComboPlugin implements PluginBase, PumpInterface, ConstraintsInterf
if ((aapsBolus == null || pumpBolus == null)
|| (Math.abs(aapsBolus.insulin - pumpBolus.amount) > 0.05 || aapsBolus.date != pumpBolus.timestamp)) {
log.debug("Last bolus on pump is unknown, refreshing full bolus history");
syncNeeded = true;
request.bolusHistory = PumpHistoryRequest.FULL;
}
@ -782,30 +771,40 @@ public class ComboPlugin implements PluginBase, PumpInterface, ConstraintsInterf
pumpTbr = tbrHistory.get(0);
}
if ((aapsTbr == null || pumpTbr == null)
|| (aapsTbr.percentRate != pumpTbr.percent || aapsTbr.durationInMinutes != pumpTbr.duration)) {
// TODO
// log.debug("Last TBR on pump is unknown, refreshing full TBR history");
// syncNeeded = true;
// request.tbrHistory = PumpHistoryRequest.FULL;
|| (aapsTbr.date != pumpTbr.timestamp || aapsTbr.percentRate != pumpTbr.percent || aapsTbr.durationInMinutes != pumpTbr.duration)) {
log.debug("Last TBR on pump is unknown, refreshing full TBR history");
request.tbrHistory = PumpHistoryRequest.FULL;
}
// last error
// 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;
PumpError aapsError = null;
if (!pump.history.pumpErrorHistory.isEmpty()) {
aapsError = pump.history.pumpErrorHistory.get(0);
}
PumpError pumpError = null;
List<PumpError> pumpErrorHistory = commandResult.history.pumpErrorHistory;
if (!pumpErrorHistory.isEmpty()){
pumpError = pumpErrorHistory.get(0);
}
if ((aapsError == null || pumpError == null)
|| aapsError.timestamp != pumpError.timestamp) {
log.debug("Last pump error is unknown, refrehing full error history");
}
// tdd
// TODO; ... just fetch them on-deamand when the user opens the fragment?
// TODO v2.1
if (syncNeeded) {
syncHistory(request);
if (request.bolusHistory != PumpHistoryRequest.SKIP
|| request.tbrHistory != PumpHistoryRequest.SKIP
|| request.pumpErrorHistory != PumpHistoryRequest.SKIP
|| request.tddHistory != PumpHistoryRequest.SKIP) {
readHistory(request);
}
return true;
}
private void syncHistory(final PumpHistoryRequest request) {
private void readHistory(final PumpHistoryRequest request) {
CommandResult result = runCommand(MainApp.sResources.getString(R.string.combo_activity_reading_pump_history), 3, () -> ruffyScripter.readHistory(request));
if (!result.success) {
// TODO
@ -833,20 +832,28 @@ public class ComboPlugin implements PluginBase, PumpInterface, ConstraintsInterf
// TODO tolerance for start/end deviations? temp start is based on pump time, but in ms; round to seconds, so we can find it here more easily?
// errors
// TODO
for (PumpError pumpError : result.history.pumpErrorHistory) {
if (!pump.history.pumpErrorHistory.contains(pumpError)) {
pump.history.pumpErrorHistory.add(pumpError);
}
}
// tdd
// TODO v3
for (Tdd tdd : result.history.tddHistory) {
if (!pump.history.tddHistory.contains(tdd)) {
pump.history.tddHistory.add(tdd);
}
}
// fetch state (updates local state as well)
runCommand(null, 3, ruffyScripter::readReservoirLevelAndLastBolus);
}
void forceSyncFullHistory() {
syncHistory(new PumpHistoryRequest()
void forceFullHistoryRead() {
// TODO v2.1: optimize to pass timestamps of last known records to avoid reading known records
readHistory(new PumpHistoryRequest()
.bolusHistory(PumpHistoryRequest.FULL)
.tbrHistory(PumpHistoryRequest.FULL)
.errorHistory(PumpHistoryRequest.FULL)
.pumpErrorHistory(PumpHistoryRequest.FULL)
.tddHistory(PumpHistoryRequest.FULL));
}

View file

@ -4,8 +4,8 @@ import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import de.jotomo.ruffy.spi.BasalProfile;
import de.jotomo.ruffy.spi.PumpState;
import de.jotomo.ruffy.spi.CommandResult;
import de.jotomo.ruffy.spi.PumpState;
import de.jotomo.ruffy.spi.history.Bolus;
import de.jotomo.ruffy.spi.history.PumpHistory;
@ -28,6 +28,8 @@ class ComboPump {
volatile BasalProfile basalProfile;
@NonNull
volatile PumpHistory history = new PumpHistory();
/** Time the active TBR was set (if any). Needed to calculate remaining time in fragment */
/**
* Time the active TBR was set (if any). Needed to calculate remaining time in fragment
*/
long tbrSetTime;
}

View file

@ -0,0 +1,48 @@
package info.nightscout.androidaps.plugins.PumpCombo;
import android.os.Bundle;
import android.support.v4.app.DialogFragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.text.SimpleDateFormat;
import java.util.List;
import de.jotomo.ruffy.spi.history.Tdd;
import info.nightscout.androidaps.R;
/**
* Created by adrian on 17/08/17.
*/
public class ComboTddHistoryDialog extends DialogFragment {
private static Logger log = LoggerFactory.getLogger(ComboTddHistoryDialog.class);
private TextView text;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View layout = inflater.inflate(R.layout.combo_tdd_history_fragment, container, false);
text = (TextView) layout.findViewById(R.id.combo_tdd_history_text);
List<Tdd> tdds = ComboPlugin.getPlugin().getPump().history.tddHistory;
StringBuilder sb = new StringBuilder();
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("dd-MM");
if (tdds.isEmpty()) {
text.setText("No TDDs. To retrieve the TDD history from the pump, long press the Refresh button.");
} else {
for (Tdd tdd : tdds) {
sb.append(simpleDateFormat.format(tdd.timestamp));
sb.append(" ");
sb.append(tdd.total);
sb.append("\n");
}
text.setText(sb.toString());
}
return layout;
}
}

View file

@ -2,7 +2,7 @@
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".plugins.ProfileNS.NSProfileFragment">
tools:context=".plugins.PumpCombo.ComboFragment">
<ScrollView
android:layout_width="match_parent"

View file

@ -3,7 +3,7 @@
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="info.nightscout.androidaps.plugins.PumpCombo.activities.PairingActivity">
tools:context=".plugins.PumpCombo.activities.PairingActivity">
<ListView
android:id="@+id/combo_pairing_listview"

View file

@ -0,0 +1,27 @@
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".plugins.PumpCombo.ComboFragment">
<ScrollView
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:id="@+id/combo_tdd_history_text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textAlignment="textStart"
android:padding="10dp"
android:gravity="start"/>
</LinearLayout>
</ScrollView>
</FrameLayout>

View file

@ -373,6 +373,17 @@
android:paddingRight="0dp"
android:text="@string/pump_errors_history" />
<Button
android:id="@+id/combo_tdd_history"
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:text="@string/combo_stats" />
</LinearLayout>
</LinearLayout>

View file

@ -1,11 +1,7 @@
package de.jotomo.ruffy.spi.history;
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). */
// public final String code;
public final Integer warningCode;
public final Integer errorCode;
/** Error message, in the language configured on the pump. */
public final String message;
@ -17,6 +13,30 @@ public class PumpError extends HistoryRecord {
this.message = message;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
PumpError pumpError = (PumpError) o;
if (timestamp != pumpError.timestamp) return false;
if (warningCode != null ? !warningCode.equals(pumpError.warningCode) : pumpError.warningCode != null)
return false;
if (errorCode != null ? !errorCode.equals(pumpError.errorCode) : pumpError.errorCode != null)
return false;
return message != null ? message.equals(pumpError.message) : pumpError.message == null;
}
@Override
public int hashCode() {
int result = (int) (timestamp ^ (timestamp >>> 32));
result = 31 * result + (warningCode != null ? warningCode.hashCode() : 0);
result = 31 * result + (errorCode != null ? errorCode.hashCode() : 0);
result = 31 * result + (message != null ? message.hashCode() : 0);
return result;
}
@Override
public String toString() {
return "PumpError{" +

View file

@ -3,6 +3,7 @@ package de.jotomo.ruffy.spi.history;
import android.support.annotation.NonNull;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
/** History data as read from the pump's My Data menu.
@ -13,7 +14,7 @@ public class PumpHistory {
@NonNull
public List<Tbr> tbrHistory = new ArrayList<>();
@NonNull
public List<PumpError> pumpErrorHistory = new ArrayList<>();
public List<PumpError> pumpErrorHistory = new LinkedList<>();
@NonNull
public List<Tdd> tddHistory = new ArrayList<>();

View file

@ -25,8 +25,8 @@ public class PumpHistoryRequest {
return this;
}
public PumpHistoryRequest errorHistory(long errorHistory) {
this.pumpErrorHistory = errorHistory;
public PumpHistoryRequest pumpErrorHistory(long pumpErrorHistory) {
this.pumpErrorHistory = pumpErrorHistory;
return this;
}

View file

@ -1,5 +1,6 @@
package de.jotomo.ruffy.spi.history;
/** Note: the timestamp is the time the TBR **ended**, not started .*/
public class Tbr extends HistoryRecord {
public final int duration;
public final int percent;
@ -10,6 +11,26 @@ public class Tbr extends HistoryRecord {
this.percent = percent;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Tbr tbr = (Tbr) o;
if (timestamp != tbr.timestamp) return false;
if (duration != tbr.duration) return false;
return percent == tbr.percent;
}
@Override
public int hashCode() {
int result = (int) (timestamp ^ (timestamp >>> 32));
result = 31 * result + duration;
result = 31 * result + percent;
return result;
}
@Override
public String toString() {
return "Tbr{" +

View file

@ -9,6 +9,27 @@ public class Tdd extends HistoryRecord {
this.total = total;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Tdd tdd = (Tdd) o;
if (timestamp != tdd.timestamp) return false;
return Double.compare(tdd.total, total) == 0;
}
@Override
public int hashCode() {
int result;
long temp;
result = (int) (timestamp ^ (timestamp >>> 32));
temp = Double.doubleToLongBits(total);
result = 31 * result + (int) (temp ^ (temp >>> 32));
return result;
}
@Override
public String toString() {
return "Tdd{" +

View file

@ -10,6 +10,7 @@ import org.monkey.d.ruffy.ruffy.driver.display.menu.MenuTime;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Calendar;
import java.util.Date;
import de.jotomo.ruffy.spi.history.Bolus;
@ -156,7 +157,11 @@ public class ReadHistoryCommand extends BaseCommand {
private Tdd readTddRecord() {
scripter.verifyMenuIsDisplayed(MenuType.DAILY_DATA);
Double dailyTotal = (Double) scripter.getCurrentMenu().getAttribute(MenuAttribute.DAILY_TOTAL);
long recordDate = readRecordDate();
MenuDate date = (MenuDate) scripter.getCurrentMenu().getAttribute(MenuAttribute.DATE);
Calendar instance = Calendar.getInstance();
int year = date.getMonth() == 12 ? Calendar.getInstance().get(Calendar.YEAR) - 1 : Calendar.getInstance().get(Calendar.YEAR);
instance.set(year, date.getMonth(), date.getDay());
long recordDate = instance.getTimeInMillis();
return new Tdd(recordDate, dailyTotal);
}