- done some fixes according to Crashalytics (most common problem from last month)
- extended custom actions, to have enabled flag, and if entry is enabled=false button is not added. Added EventCustomActionsChanged event that can refresh custom actions
- #111 - do not put multiple statuses into queue
- #110 - set driver busy if wake up and tune is running
- #104 - when bolus is delivering driver is set to busy, and custom action was added to remove this block
This commit is contained in:
Andy Rozman 2019-03-30 18:36:50 +00:00
parent 0c27b8c6e3
commit afcedc83d1
22 changed files with 564 additions and 104 deletions

View file

@ -64,7 +64,7 @@ android {
multiDexEnabled true
versionCode 1500
// dev_version: 2.1
version "medtronic-0.8.1-SNAPSHOT"
version "medtronic-0.8.2-SNAPSHOT"
buildConfigField "String", "VERSION", '"' + version + '"'
buildConfigField "String", "BUILDVERSION", '"' + generateGitBuild() + '-' + generateDate() + '"'
buildConfigField "String", "HEAD", '"' + generateGitBuild() + '"'

View file

@ -0,0 +1,4 @@
package info.nightscout.androidaps.events;
public class EventCustomActionsChanged extends Event {
}

View file

@ -26,6 +26,7 @@ import info.nightscout.androidaps.activities.HistoryBrowseActivity;
import info.nightscout.androidaps.activities.TDDStatsActivity;
import info.nightscout.androidaps.db.ExtendedBolus;
import info.nightscout.androidaps.db.TemporaryBasal;
import info.nightscout.androidaps.events.EventCustomActionsChanged;
import info.nightscout.androidaps.events.EventExtendedBolusChange;
import info.nightscout.androidaps.events.EventInitializationChanged;
import info.nightscout.androidaps.events.EventRefreshOverview;
@ -135,6 +136,12 @@ public class ActionsFragment extends SubscriberFragment implements View.OnClickL
}
@Subscribe
public void onStatusEvent(final EventCustomActionsChanged ev) {
updateGUI();
}
@Override
protected void updateGUI() {
Activity activity = getActivity();
@ -257,6 +264,9 @@ public class ActionsFragment extends SubscriberFragment implements View.OnClickL
for (CustomAction customAction : customActions) {
if (!customAction.isEnabled())
continue;
SingleClickButton btn = new SingleClickButton(getContext(), null, android.R.attr.buttonStyle);
btn.setText(MainApp.gs(customAction.getName()));

View file

@ -9,11 +9,18 @@ public class CustomAction {
private int name;
private String iconName;
private CustomActionType customActionType;
private boolean enabled = true;
public CustomAction(int nameResourceId, CustomActionType actionType) {
this(nameResourceId, actionType, true);
}
public CustomAction(int nameResourceId, CustomActionType actionType, boolean enabled) {
this.name = nameResourceId;
this.customActionType = actionType;
this.enabled = enabled;
}
@ -45,4 +52,14 @@ public class CustomAction {
this.customActionType = customActionType;
}
public boolean isEnabled() {
return enabled;
}
public void setEnabled(boolean enabled) {
this.enabled = enabled;
}
}

View file

@ -283,6 +283,9 @@ public class RileyLinkBLEScanActivity extends AppCompatActivity {
private void scanLeDevice(final boolean enable) {
if (mLEScanner == null)
return;
if (enable) {
mLeDeviceListAdapter.clear();

View file

@ -130,10 +130,9 @@ public class RileyLinkUtil {
return null;
} else {
return RileyLinkUtil.rileyLinkServiceData.serviceState == null ? RileyLinkServiceState.NotStarted
return (RileyLinkUtil.rileyLinkServiceData == null || RileyLinkUtil.rileyLinkServiceData.serviceState == null) ? //
RileyLinkServiceState.NotStarted
: RileyLinkUtil.rileyLinkServiceData.serviceState;
}
}

View file

@ -18,7 +18,6 @@ import android.bluetooth.BluetoothGattService;
import android.bluetooth.BluetoothProfile;
import android.content.Context;
import android.os.SystemClock;
import android.widget.Toast;
import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.RileyLinkConst;
import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.RileyLinkUtil;
@ -330,6 +329,12 @@ public class RileyLinkBLE {
public boolean discoverServices() {
if (bluetoothConnectionGatt == null) {
// shouldn't happen, but if it does we exit
return false;
}
if (bluetoothConnectionGatt.discoverServices()) {
LOG.warn("Starting to discover GATT Services.");
return true;
@ -367,7 +372,7 @@ public class RileyLinkBLE {
// , BluetoothDevice.TRANSPORT_LE
if (bluetoothConnectionGatt == null) {
LOG.error("Failed to connect to Bluetooth Low Energy device at " + bluetoothAdapter.getAddress());
Toast.makeText(context, "No Rileylink at " + bluetoothAdapter.getAddress(), Toast.LENGTH_SHORT).show();
// Toast.makeText(context, "No Rileylink at " + bluetoothAdapter.getAddress(), Toast.LENGTH_SHORT).show();
} else {
if (gattDebugEnabled) {
LOG.debug("Gatt Connected?");

View file

@ -2,6 +2,7 @@ package info.nightscout.androidaps.plugins.pump.common.hw.rileylink.service.task
import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.service.data.ServiceTransport;
import info.nightscout.androidaps.plugins.pump.medtronic.MedtronicFragment;
import info.nightscout.androidaps.plugins.pump.medtronic.MedtronicPumpPlugin;
import info.nightscout.androidaps.plugins.pump.medtronic.service.RileyLinkMedtronicService;
/**
@ -24,7 +25,9 @@ public class WakeAndTuneTask extends PumpTask {
@Override
public void run() {
MedtronicFragment.refreshButtonEnabled(false);
MedtronicPumpPlugin.isBusy = true;
RileyLinkMedtronicService.getInstance().doTuneUpDevice();
MedtronicPumpPlugin.isBusy = false;
MedtronicFragment.refreshButtonEnabled(true);
}

View file

@ -1,6 +1,7 @@
package info.nightscout.androidaps.plugins.pump.medtronic;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
@ -31,6 +32,7 @@ import info.nightscout.androidaps.data.Profile;
import info.nightscout.androidaps.data.PumpEnactResult;
import info.nightscout.androidaps.db.Source;
import info.nightscout.androidaps.db.TemporaryBasal;
import info.nightscout.androidaps.events.EventCustomActionsChanged;
import info.nightscout.androidaps.events.EventRefreshOverview;
import info.nightscout.androidaps.interfaces.PluginDescription;
import info.nightscout.androidaps.interfaces.PluginType;
@ -73,6 +75,8 @@ import info.nightscout.androidaps.utils.SP;
/**
* Created by andy on 23.04.18.
*
* @author Andy Rozman (andy.rozman@gmail.com)
*/
public class MedtronicPumpPlugin extends PumpPluginAbstract implements PumpInterface {
@ -98,6 +102,9 @@ public class MedtronicPumpPlugin extends PumpPluginAbstract implements PumpInter
public static Gson gsonInstancePretty = new GsonBuilder().excludeFieldsWithoutExposeAnnotation()
.setPrettyPrinting().create();
public static boolean isBusy = false;
private List<Long> busyTimestamps = new ArrayList<>();
private MedtronicPumpPlugin() {
@ -198,7 +205,6 @@ public class MedtronicPumpPlugin extends PumpPluginAbstract implements PumpInter
}
// TODO remove
private void migrateSettings() {
if ("US (916 MHz)".equals(SP.getString(MedtronicConst.Prefs.PumpFrequency, null))) {
@ -222,7 +228,10 @@ public class MedtronicPumpPlugin extends PumpPluginAbstract implements PumpInter
StatusRefreshAction.GetData, null, null);
if (doWeHaveAnyStatusNeededRefereshing(statusRefresh)) {
ConfigBuilderPlugin.getPlugin().getCommandQueue().readStatus("Scheduled Status Refresh", null);
if (!ConfigBuilderPlugin.getPlugin().getCommandQueue().statusInQueue()) {
ConfigBuilderPlugin.getPlugin().getCommandQueue()
.readStatus("Scheduled Status Refresh", null);
}
}
}
@ -274,10 +283,49 @@ public class MedtronicPumpPlugin extends PumpPluginAbstract implements PumpInter
@Override
public boolean isBusy() {
// TODO remove
if (isLoggingEnabled())
if (isLoggingEnabled() && displayConnectionMessages)
LOG.debug("MedtronicPumpPlugin::isBusy");
return isServiceSet() && medtronicService.isBusy();
if (isServiceSet()) {
if (isBusy)
return true;
if (busyTimestamps.size() > 0) {
clearBusyQueue();
if (busyTimestamps.size() > 0) {
return true;
}
}
}
return false;
}
private void clearBusyQueue() {
Set<Long> deleteFromQueue = new HashSet<>();
for (Long busyTimestamp : busyTimestamps) {
if (System.currentTimeMillis() > busyTimestamp) {
deleteFromQueue.add(busyTimestamp);
}
}
if (deleteFromQueue.size() == busyTimestamps.size()) {
busyTimestamps.clear();
this.customActionClearBolusBlock.setEnabled(false);
refreshCustomActionsList();
}
if (deleteFromQueue.size() > 0) {
busyTimestamps.removeAll(deleteFromQueue);
}
}
@ -691,7 +739,6 @@ public class MedtronicPumpPlugin extends PumpPluginAbstract implements PumpInter
}).start();
}
// FIXME this needs to be fixed to read info from history
boolean treatmentCreated = TreatmentsPlugin.getPlugin().addToHistoryTreatment(detailedBolusInfo, true);
// we subtract insulin, exact amount will be visible with next remainingInsulin update.
@ -700,6 +747,15 @@ public class MedtronicPumpPlugin extends PumpPluginAbstract implements PumpInter
incrementStatistics(detailedBolusInfo.isSMB ? MedtronicConst.Statistics.SMBBoluses
: MedtronicConst.Statistics.StandardBoluses);
if (response) {
int bolusTime = (int)(detailedBolusInfo.insulin * 42.0d);
long time = System.currentTimeMillis() + (bolusTime * 1000);
this.busyTimestamps.add(time);
this.customActionClearBolusBlock.setEnabled(true);
refreshCustomActionsList();
}
return new PumpEnactResult().success(response) //
.enacted(response) //
.bolusDelivered(detailedBolusInfo.insulin) //
@ -912,13 +968,11 @@ public class MedtronicPumpPlugin extends PumpPluginAbstract implements PumpInter
if (this.getMDTPumpStatus().basalProfileStatus != BasalProfileStatus.NotInitialized
&& medtronicHistoryData.hasBasalProfileChanged()) {
medtronicHistoryData.processLastBasalProfileChange(getMDTPumpStatus());
// this.basalProfileChanged = true;
}
PumpDriverState previousState = this.pumpState;
if (medtronicHistoryData.isPumpSuspended(this.pumpState == PumpDriverState.Suspended)) {
// scheduleNextRefresh(MedtronicStatusRefreshType.PumpTime, -1);
if (medtronicHistoryData.isPumpSuspended()) {
this.pumpState = PumpDriverState.Suspended;
if (isLoggingEnabled())
LOG.debug(getLogPrefix() + "isPumpSuspended: true");
@ -1325,17 +1379,18 @@ public class MedtronicPumpPlugin extends PumpPluginAbstract implements PumpInter
List<CustomAction> customActions = null;
CustomAction customActionWakeUpAndTune = new CustomAction(R.string.medtronic_custom_action_wake_and_tune,
MedtronicCustomActionType.WakeUpAndTune);
CustomAction customActionClearBolusBlock = new CustomAction(R.string.medtronic_custom_action_clear_bolus_block,
MedtronicCustomActionType.ClearBolusBlock);
@Override
public List<CustomAction> getCustomActions() {
if (customActions == null) {
this.customActions = new ArrayList<>();
CustomAction ca = new CustomAction(R.string.medtronic_custom_action_wake_and_tune,
MedtronicCustomActionType.WakeUpAndTune);
this.customActions.add(ca);
this.customActions = Arrays.asList(customActionWakeUpAndTune, customActionClearBolusBlock);
}
return this.customActions;
@ -1353,10 +1408,23 @@ public class MedtronicPumpPlugin extends PumpPluginAbstract implements PumpInter
ServiceTaskExecutor.startTask(new WakeAndTuneTask());
break;
case ClearBolusBlock: {
this.busyTimestamps.clear();
this.customActionClearBolusBlock.setEnabled(false);
refreshCustomActionsList();
}
break;
default:
break;
}
return null;
}
private void refreshCustomActionsList() {
MainApp.bus().post(new EventCustomActionsChanged());
}
}

View file

@ -4,8 +4,6 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.joda.time.format.DateTimeFormat;
import org.joda.time.format.DateTimeFormatter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -41,7 +39,6 @@ public abstract class MedtronicHistoryEntry implements MedtronicHistoryEntryInte
protected List<Byte> rawData;
protected static DateTimeFormatter dateTimeFormatter = DateTimeFormat.forPattern("dd.MM.yyyy HH:mm:ss");
public static final Logger LOG = LoggerFactory.getLogger(MedtronicHistoryEntry.class);
protected int[] sizes = new int[3];
@ -56,11 +53,35 @@ public abstract class MedtronicHistoryEntry implements MedtronicHistoryEntryInte
public String DT;
@Expose
public long atechDateTime;
public Long atechDateTime;
@Expose
protected Map<String, Object> decodedData;
public long phoneDateTime; // time on phone
/**
* Pump id that will be used with AAPS object (time * 1000 + historyType (max is FF = 255)
*/
public long pumpId;
/**
* if history object is already linked to AAPS object (either Treatment, TempBasal or TDD (tdd's are not actually
* linked))
*/
public boolean linked = false;
/**
* Linked object, see linked
*/
public Object linkedObject = null;
public void setLinkedObject(Object linkedObject) {
this.linked = true;
this.linkedObject = linkedObject;
}
public void setData(List<Byte> listRawData, boolean doNotProcess) {
this.rawData = listRawData;

View file

@ -6,7 +6,6 @@ import java.util.List;
import java.util.Locale;
import java.util.Map;
import org.joda.time.LocalDateTime;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -708,24 +707,24 @@ public class MedtronicPumpHistoryDecoder extends MedtronicHistoryDecoder<PumpHis
: PumpBolusType.Normal);
bolus.setAtechDateTime(entry.atechDateTime);
String dateTime = entry.DT;
// String dateTime = entry.DT;
if (bolus.getBolusType() == PumpBolusType.Extended) {
// we check if we have coresponding normal entry
if (bolusHistory.containsKey(dateTime)) {
BolusDTO bolusDTO = bolusHistory.get(dateTime);
bolusDTO.setImmediateAmount(bolus.getDeliveredAmount());
bolusDTO.setBolusType(PumpBolusType.Multiwave);
return;
}
}
// if (bolus.getBolusType() == PumpBolusType.Extended) {
// // we check if we have coresponding normal entry
// if (bolusHistory.containsKey(dateTime)) {
// BolusDTO bolusDTO = bolusHistory.get(dateTime);
//
// bolusDTO.setImmediateAmount(bolus.getDeliveredAmount());
// bolusDTO.setBolusType(PumpBolusType.Multiwave);
//
// return;
// }
// }
entry.addDecodedData("Object", bolus);
entry.setDisplayableValue(bolus.getDisplayableValue());
bolusHistory.put(dateTime, bolus);
// bolusHistory.put(dateTime, bolus);
}
@ -771,12 +770,6 @@ public class MedtronicPumpHistoryDecoder extends MedtronicHistoryDecoder<PumpHis
entry.addDecodedData("Object", tbr);
entry.setDisplayableValue(tbr.getDescription());
// entry.addDecodedData("Rate 1: ", tbrRate.getHead()[0] * 0.025);
// entry.addDecodedData("Rate 2: ", ByteUtil.asUINT8(tbrRate.getHead()[0]) * 0.025d);
// entry.addDecodedData("Rate 1.b: ", tbrRate.getHead()[0]);
// entry.addDecodedData("Rate 2.b: ", ByteUtil.asUINT8(tbrRate.getHead()[0]));
// entry.addDecodedData("Rate 3: ", (ByteUtil.asUINT8(tbrRate.getHead()[0])) / 40.0d);
}
@ -800,9 +793,6 @@ public class MedtronicPumpHistoryDecoder extends MedtronicHistoryDecoder<PumpHis
int year = fix2DigitYear(dt[4] & 0x3F); // Assuming this is correct, need to verify. Otherwise this will be
// a problem in 2016.
LocalDateTime atdate = new LocalDateTime(year, month, dayOfMonth, hour, minutes, seconds);
// entry.setLocalDateTime(atdate); // TODO remove
entry.setAtechDateTime(DateTimeUtil.toATechDate(year, month, dayOfMonth, hour, minutes, seconds));
} else if (entry.getDateTimeLength() == 2) {
@ -824,8 +814,6 @@ public class MedtronicPumpHistoryDecoder extends MedtronicHistoryDecoder<PumpHis
// int month = (((dt[0] & 0xE0) >> 4) + ((dt[1] & 0x80) >> 7));
// int year = fix2DigitYear(dt[1] & 0x3F);
LocalDateTime atdate = null;
LOG.debug("DT: {} {} {}", year, month, dayOfMonth);
if (dayOfMonth == 32) {
@ -835,22 +823,16 @@ public class MedtronicPumpHistoryDecoder extends MedtronicHistoryDecoder<PumpHis
}
if (entry.getEntryType() == PumpHistoryEntryType.EndResultTotals) {
atdate = new LocalDateTime(year, month, dayOfMonth, 23, 59, 59);
hour = 23;
minutes = 59;
seconds = 59;
} else {
atdate = new LocalDateTime(year, month, dayOfMonth, 0, 0);
}
// entry.setLocalDateTime(atdate);
entry.setAtechDateTime(DateTimeUtil.toATechDate(year, month, dayOfMonth, hour, minutes, seconds));
} else {
LOG.warn("Unknown datetime format: " + entry.getDateTimeLength());
}
// return new DateTime(year + 2000, month, dayOfMonth, hour, minutes,
// seconds);
}

View file

@ -54,6 +54,14 @@ public class PumpHistoryEntry extends MedtronicHistoryEntry {
this.sizes[0] = entryType.getHeadLength();
this.sizes[1] = entryType.getDateLength();
this.sizes[2] = entryType.getBodyLength();
if (this.entryType != null && this.atechDateTime != null)
setPumpId();
}
private void setPumpId() {
this.pumpId = this.entryType.getCode() + (this.atechDateTime * 1000L);
}

View file

@ -134,8 +134,8 @@ public class MedtronicUIPostprocessor {
ClockDTO clockDTO = (ClockDTO)uiTask.returnData;
Duration dur = new Duration(clockDTO.localDeviceTime.toDateTime(DateTimeZone.UTC),
clockDTO.pumpTime.toDateTime(DateTimeZone.UTC));
Duration dur = new Duration(clockDTO.pumpTime.toDateTime(DateTimeZone.UTC),
clockDTO.localDeviceTime.toDateTime(DateTimeZone.UTC));
clockDTO.timeDifference = (int)dur.getStandardSeconds();

View file

@ -16,6 +16,10 @@ import com.google.common.base.Splitter;
import com.google.gson.Gson;
import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.data.DetailedBolusInfo;
import info.nightscout.androidaps.db.DatabaseHelper;
import info.nightscout.androidaps.db.ExtendedBolus;
import info.nightscout.androidaps.db.Source;
import info.nightscout.androidaps.db.TDD;
import info.nightscout.androidaps.plugins.pump.common.utils.DateTimeUtil;
import info.nightscout.androidaps.plugins.pump.medtronic.MedtronicPumpPlugin;
@ -24,10 +28,13 @@ import info.nightscout.androidaps.plugins.pump.medtronic.comm.history.pump.PumpH
import info.nightscout.androidaps.plugins.pump.medtronic.comm.history.pump.PumpHistoryEntryType;
import info.nightscout.androidaps.plugins.pump.medtronic.comm.history.pump.PumpHistoryResult;
import info.nightscout.androidaps.plugins.pump.medtronic.data.dto.BasalProfile;
import info.nightscout.androidaps.plugins.pump.medtronic.data.dto.BolusDTO;
import info.nightscout.androidaps.plugins.pump.medtronic.data.dto.ClockDTO;
import info.nightscout.androidaps.plugins.pump.medtronic.data.dto.DailyTotalsDTO;
import info.nightscout.androidaps.plugins.pump.medtronic.driver.MedtronicPumpStatus;
import info.nightscout.androidaps.plugins.pump.medtronic.util.MedtronicUtil;
import info.nightscout.androidaps.plugins.treatments.Treatment;
import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin;
//import info.nightscout.androidaps.plugins.pump.medtronic.MedtronicPumpPlugin;
@ -53,6 +60,8 @@ public class MedtronicHistoryData {
private Gson gsonPretty;
private List<PumpHistoryEntry> fakeTBRs;
DatabaseHelper databaseHelper = MainApp.getDbHelper();
public MedtronicHistoryData() {
this.allHistory = new ArrayList<>();
@ -205,37 +214,14 @@ public class MedtronicHistoryData {
// TODO This logic might not be working correctly
public boolean isPumpSuspended(Boolean wasPumpSuspended) {
public boolean isPumpSuspended() {
List<PumpHistoryEntry> newAndAll = new ArrayList<>();
if (!isCollectionEmpty(this.allHistory)) {
newAndAll.addAll(this.allHistory);
}
if (!isCollectionEmpty(this.newHistory)) {
newAndAll.addAll(this.newHistory);
}
if (newAndAll.isEmpty())
return false;
this.sort(newAndAll);
List<PumpHistoryEntry> newAndAll2 = filterPumpSuspend(newAndAll);
List<PumpHistoryEntry> items = getFilteredItems(newAndAll, //
PumpHistoryEntryType.Bolus, //
PumpHistoryEntryType.TempBasalCombined, //
PumpHistoryEntryType.Prime, //
PumpHistoryEntryType.PumpSuspend, //
PumpHistoryEntryType.PumpResume, //
PumpHistoryEntryType.Rewind, //
PumpHistoryEntryType.NoDeliveryAlarm, //
PumpHistoryEntryType.BasalProfileStart);
List<PumpHistoryEntry> items = getDataForSuspends(false);
showLogs("isPumpSuspendCheck: ", MedtronicPumpPlugin.gsonInstancePretty.toJson(items));
if (!items.isEmpty()) {
PumpHistoryEntryType pumpHistoryEntryType = items.get(0).getEntryType();
LOG.debug("Last entry type: {}", pumpHistoryEntryType);
@ -245,19 +231,68 @@ public class MedtronicHistoryData {
pumpHistoryEntryType == PumpHistoryEntryType.Bolus || //
pumpHistoryEntryType == PumpHistoryEntryType.PumpResume || //
pumpHistoryEntryType == PumpHistoryEntryType.Prime);
} else
return false;
}
private List<PumpHistoryEntry> filterPumpSuspend(List<PumpHistoryEntry> newAndAll) {
private List<PumpHistoryEntry> getDataForSuspends(boolean forHistory) {
if (newAndAll.size() < 11) {
List<PumpHistoryEntry> newAndAll = new ArrayList<>();
if (!isCollectionEmpty(this.allHistory)) {
if (forHistory) {
// TODO we filter all history ang get last 2
} else {
newAndAll.addAll(this.allHistory);
}
}
if (!isCollectionEmpty(this.newHistory)) {
for (PumpHistoryEntry pumpHistoryEntry : newHistory) {
if (!newAndAll.contains(pumpHistoryEntry)) {
newAndAll.add(pumpHistoryEntry);
}
}
}
if (newAndAll.isEmpty())
return newAndAll;
this.sort(newAndAll);
List<PumpHistoryEntry> newAndAll2 = getFilteredItems(newAndAll, //
PumpHistoryEntryType.Bolus, //
PumpHistoryEntryType.TempBasalCombined, //
PumpHistoryEntryType.Prime, //
PumpHistoryEntryType.PumpSuspend, //
PumpHistoryEntryType.PumpResume, //
PumpHistoryEntryType.Rewind, //
PumpHistoryEntryType.NoDeliveryAlarm, //
PumpHistoryEntryType.BasalProfileStart);
if (!forHistory) {
newAndAll2 = filterPumpSuspend(newAndAll2, 10); // just last 10 (of relevant), for history we already
// filtered
}
return newAndAll2;
}
private List<PumpHistoryEntry> filterPumpSuspend(List<PumpHistoryEntry> newAndAll, int filterCount) {
if (newAndAll.size() <= filterCount) {
return newAndAll;
}
List<PumpHistoryEntry> newAndAllOut = new ArrayList<>();
for (int i = 0; i < 10; i++) {
for (int i = 0; i < filterCount; i++) {
newAndAllOut.add(newAndAll.get(i));
}
@ -276,14 +311,15 @@ public class MedtronicHistoryData {
LOG.debug("ProcessHistoryData: TDD [count={}, items={}]", tdds.size(), gsonPretty.toJson(tdds));
if (!isCollectionEmpty(tdds)) {
processTDDs(tdds);
//processTDDs(tdds);
}
pumpTime = MedtronicUtil.getPumpTime();
// Bolus
List<PumpHistoryEntry> treatments = getFilteredListByLastRecord(PumpHistoryEntryType.Bolus);
LOG.debug("ProcessHistoryData: Bolus [count={}, itemsCount={}]", treatments.size());
showLogs(null, gsonPretty.toJson(treatments));
LOG.debug("ProcessHistoryData: Bolus [count={}, items={}]", treatments.size(), gsonPretty.toJson(treatments));
if (treatments.size() > 0) {
//processBoluses(treatments);
@ -292,8 +328,7 @@ public class MedtronicHistoryData {
// TBR
List<PumpHistoryEntry> tbrs = getFilteredListByLastRecord(PumpHistoryEntryType.TempBasalCombined);
LOG.debug("ProcessHistoryData: TBRs [count={}, items=", tbrs.size());
showLogs(null, gsonPretty.toJson(tbrs));
LOG.debug("ProcessHistoryData: TBRs [count={}, items={}]", tbrs.size(), gsonPretty.toJson(tbrs));
if (tbrs.size() > 0) {
// processTBRs(tbrs);
@ -302,8 +337,8 @@ public class MedtronicHistoryData {
// Suspends (for suspends/resume, fakeTBR)
List<PumpHistoryEntry> suspends = getSuspends();
LOG.debug("ProcessHistoryData: FakeTBRs (suspend/resume) [count={}, items=", suspends.size());
showLogs(null, gsonPretty.toJson(suspends));
LOG.debug("ProcessHistoryData: FakeTBRs (suspend/resume) [count={}, items={}]", suspends.size(),
gsonPretty.toJson(suspends));
if (suspends.size() > 0) {
// processSuspends(treatments);
@ -317,7 +352,7 @@ public class MedtronicHistoryData {
List<PumpHistoryEntry> tdds = filterTDDs(tddsIn);
pumpTime = MedtronicUtil.getPumpTime();
// /pumpTime = MedtronicUtil.getPumpTime();
LOG.error(getLogPrefix() + "TDDs found: {}. Not processed.\n{}", tdds.size(), gsonPretty.toJson(tdds));
@ -360,15 +395,279 @@ public class MedtronicHistoryData {
int dateDifference = getOldestDateDifference(boluses);
// List<Treatment> treatmentsFromHistory = TreatmentsPlugin.getPlugin().getTreatmentsFromHistoryXMinutesAgo(
// dateDifference);
List<Treatment> treatmentsFromHistory = TreatmentsPlugin.getPlugin().getTreatmentsFromHistoryXMinutesAgo(
dateDifference);
LOG.debug("Boluses (before filter): {}, FromDb={}", gsonPretty.toJson(boluses),
gsonPretty.toJson(treatmentsFromHistory));
filterOutAlreadyAddedEntries(boluses, treatmentsFromHistory);
LOG.debug("Boluses (after filter): {}, FromDb={}", gsonPretty.toJson(boluses),
gsonPretty.toJson(treatmentsFromHistory));
if (treatmentsFromHistory.isEmpty()) {
for (PumpHistoryEntry treatment : boluses) {
LOG.debug("Add Bolus (no treatments): " + treatment);
addBolus(treatment, null);
}
} else {
for (PumpHistoryEntry treatment : boluses) {
Treatment treatmentDb = findTreatment2(treatment, treatmentsFromHistory);
LOG.debug("Add Bolus {} - (treatmentFromDb={}) ", treatment, treatmentDb);
LOG.debug("TOE. Treatment: " + treatment);
long inLocalTime = tryToGetByLocalTime(treatment.atechDateTime);
addBolus(treatment, treatmentDb);
}
}
}
private void filterOutAlreadyAddedEntries(List<PumpHistoryEntry> boluses, List<Treatment> treatmentsFromHistory) {
List<Treatment> removeTreatmentsFromHistory = new ArrayList<>();
for (Treatment treatment : treatmentsFromHistory) {
if (treatment.pumpId != 0) {
PumpHistoryEntry selectedBolus = null;
for (PumpHistoryEntry bolus : boluses) {
if (bolus.pumpId == treatment.pumpId) {
selectedBolus = bolus;
break;
}
}
if (selectedBolus != null)
boluses.remove(selectedBolus);
removeTreatmentsFromHistory.add(treatment);
}
}
for (Treatment treatment : removeTreatmentsFromHistory) {
treatmentsFromHistory.remove(treatment);
}
}
private Treatment findTreatment(PumpHistoryEntry treatment, List<Treatment> treatmentsFromHistory) {
long proposedTime = DateTimeUtil.toMillisFromATD(treatment.atechDateTime);
proposedTime += (this.pumpTime.timeDifference * 1000);
treatment.phoneDateTime = proposedTime;
List<Treatment> outList = new ArrayList<>();
for (Treatment treatment1 : treatmentsFromHistory) {
if ((treatment1.date > proposedTime - (5 * 60 * 1000))
&& (treatment1.date < proposedTime + (5 * 60 * 1000))) {
outList.add(treatment1);
}
}
if (outList.size() == 0) {
return null;
} else if (outList.size() == 1) {
return outList.get(0);
} else {
LOG.error("TODO. Multiple options: {}", outList);
Map<Treatment, Integer> data = new HashMap<>();
for (Treatment treatment1 : outList) {
int diff = Math.abs((int)(treatment1.date - proposedTime));
data.put(treatment1, diff);
}
for (int i = 1; i < 5; i++) {
List<Treatment> outList2 = new ArrayList<>();
for (Treatment treatment1 : treatmentsFromHistory) {
if ((treatment1.date > proposedTime - (i * 60 * 1000))
&& (treatment1.date < proposedTime + (i * 60 * 1000))) {
outList2.add(treatment1);
}
}
LOG.error("Treatment List: (timeDiff={},count={},list={})", (i * 60 * 1000), outList2.size(),
gsonPretty.toJson(outList2));
if (outList2.size() == 1) {
return outList2.get(0);
} else if (outList2.size() > 1) {
for (int j = 1; j < 6; j++) {
List<Treatment> outList3 = new ArrayList<>();
int ttt = (i * 60 * 1000) - (10 * j * 1000);
for (Treatment treatment1 : treatmentsFromHistory) {
if ((treatment1.date > proposedTime - ttt) && (treatment1.date < proposedTime + ttt)) {
outList3.add(treatment1);
}
}
LOG.error("Treatment List: (timeDiff={},count={},list={})", ttt, outList3.size(),
gsonPretty.toJson(outList3));
if (outList3.size() == 1) {
return outList3.get(0);
}
} // for
} // outList2
}
// TODO
} // outList
// TODO
return null;
}
private Treatment findTreatment2(PumpHistoryEntry treatment, List<Treatment> treatmentsFromHistory) {
long proposedTime = DateTimeUtil.toMillisFromATD(treatment.atechDateTime);
proposedTime += (this.pumpTime.timeDifference * 1000);
treatment.phoneDateTime = proposedTime;
for (int min = 0; min < 6; min++) {
for (int sec = 0; sec < 60; sec += 10) {
int diff = (min * 60 * 1000) + (sec * 1000);
List<Treatment> outList = new ArrayList<>();
for (Treatment treatment1 : treatmentsFromHistory) {
if ((treatment1.date > proposedTime - diff) && (treatment1.date < proposedTime + diff)) {
outList.add(treatment1);
}
}
LOG.error("Treatments: (timeDiff=[min={},sec={}],count={},list={})", min, sec, outList.size(),
gsonPretty.toJson(outList));
if (outList.size() == 1) {
return outList.get(0);
}
if (min == 0 && sec == 10 && outList.size() > 1) {
LOG.error("Too many treatments (with too small diff): (timeDiff=[min={},sec={}],count={},list={})",
min, sec, outList.size(), gsonPretty.toJson(outList));
}
}
}
return null;
}
private void addBolus(PumpHistoryEntry bolus, Treatment treatment) {
BolusDTO bolusDTO = (BolusDTO)bolus.getDecodedData().get("Object");
if (treatment == null) {
// treatment.carbs = detailedBolusInfo.carbs; // TODO later support BolusWizard ??
switch (bolusDTO.getBolusType()) {
case Normal: {
DetailedBolusInfo normalBolus = new DetailedBolusInfo();
normalBolus.date = tryToGetByLocalTime(bolus.atechDateTime);
normalBolus.source = Source.PUMP;
normalBolus.insulin = bolusDTO.getDeliveredAmount();
normalBolus.pumpId = bolus.pumpId;
normalBolus.isValid = true;
normalBolus.isSMB = false;
bolus.setLinkedObject(normalBolus);
TreatmentsPlugin.getPlugin().addToHistoryTreatment(normalBolus, true);
LOG.debug("addBolus - Normal [date={},pumpId={}, insulin={}]", normalBolus.date,
normalBolus.pumpId, normalBolus.insulin);
}
break;
case Audio:
case Extended: {
ExtendedBolus extendedBolus = new ExtendedBolus();
extendedBolus.date = tryToGetByLocalTime(bolus.atechDateTime);
extendedBolus.source = Source.PUMP;
extendedBolus.insulin = bolusDTO.getDeliveredAmount();
extendedBolus.pumpId = bolus.pumpId;
extendedBolus.isValid = true;
extendedBolus.durationInMinutes = bolusDTO.getDuration();
bolus.setLinkedObject(extendedBolus);
TreatmentsPlugin.getPlugin().addToHistoryExtendedBolus(extendedBolus);
LOG.debug("addBolus - Extended [date={},pumpId={}, insulin={}, duration={}]", extendedBolus.date,
extendedBolus.pumpId, extendedBolus.insulin, extendedBolus.durationInMinutes);
}
break;
case Multiwave: {
DetailedBolusInfo normalBolus = new DetailedBolusInfo();
normalBolus.date = tryToGetByLocalTime(bolus.atechDateTime);
normalBolus.source = Source.PUMP;
normalBolus.insulin = bolusDTO.getImmediateAmount();
normalBolus.pumpId = bolus.pumpId;
normalBolus.isValid = true;
normalBolus.isSMB = false;
bolus.setLinkedObject(normalBolus);
TreatmentsPlugin.getPlugin().addToHistoryTreatment(normalBolus, true);
LOG.debug("addBolus - Multiwave-Normal [date={},pumpId={}, insulin={}]", normalBolus.date,
normalBolus.pumpId, normalBolus.insulin);
ExtendedBolus extendedBolus = new ExtendedBolus();
extendedBolus.date = tryToGetByLocalTime(bolus.atechDateTime);
extendedBolus.source = Source.PUMP;
extendedBolus.insulin = bolusDTO.getDeliveredAmount();
extendedBolus.pumpId = bolus.pumpId;
extendedBolus.isValid = true;
extendedBolus.durationInMinutes = bolusDTO.getDuration();
TreatmentsPlugin.getPlugin().addToHistoryExtendedBolus(extendedBolus);
LOG.debug("addBolus - Multiwave-Extended [date={},pumpId={}, insulin={}, duration={}]",
extendedBolus.date, extendedBolus.pumpId, extendedBolus.insulin,
extendedBolus.durationInMinutes);
}
break;
}
} else {
treatment.insulin = bolusDTO.getDeliveredAmount();
treatment.pumpId = bolus.pumpId;
bolus.setLinkedObject(treatment);
TreatmentsPlugin.getPlugin().getService().createOrUpdate(treatment);
}
}
@ -398,7 +697,7 @@ public class MedtronicHistoryData {
// TODO needs to be implemented
public List<PumpHistoryEntry> getSuspends() {
return new ArrayList<>();
return new ArrayList<PumpHistoryEntry>();
}
@ -459,7 +758,10 @@ public class MedtronicHistoryData {
}
LocalDateTime d = DateTimeUtil.toLocalDateTime(dt);
d.minusMinutes(5);
d.minusMinutes(2);
if (this.pumpTime.timeDifference < 0) {
d.plusSeconds(this.pumpTime.timeDifference);
}
Minutes minutes = Minutes.minutesBetween(d, new LocalDateTime());

View file

@ -222,9 +222,19 @@ public class BasalProfile {
if ((mRawData[i] == 0) && (mRawData[i + 1] == 0) && (mRawData[i + 2] == 0))
break;
if ((mRawData[i] == 0) && (mRawData[i + 1] == 0) && (mRawData[i + 2] == 0x3f))
break;
r = MedtronicUtil.makeUnsignedShort(mRawData[i + 1], mRawData[i]); // readUnsignedByte(mRawData[i]);
st = readUnsignedByte(mRawData[i + 2]);
try {
entries.add(new BasalProfileEntry(r, st));
} catch (Exception ex) {
LOG.error("Error decoding basal profile from bytes: {}", ByteUtil.getHex(mRawData));
throw ex;
}
}
return entries;

View file

@ -1,6 +1,8 @@
package info.nightscout.androidaps.plugins.pump.medtronic.data.dto;
import org.joda.time.LocalTime;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import info.nightscout.androidaps.plugins.pump.medtronic.util.MedtronicUtil;
@ -11,6 +13,8 @@ import info.nightscout.androidaps.plugins.pump.medtronic.util.MedtronicUtil;
*/
public class BasalProfileEntry {
private static final Logger LOG = LoggerFactory.getLogger(BasalProfileEntry.class);
public byte[] rate_raw;
public double rate;
public byte startTime_raw;
@ -49,7 +53,16 @@ public class BasalProfileEntry {
rate_raw = MedtronicUtil.getByteArrayFromUnsignedShort(rateStrokes, true);
rate = rateStrokes * 0.025;
startTime_raw = (byte)startTimeInterval;
try {
startTime = new LocalTime(startTimeInterval / 2, (startTimeInterval % 2) * 30);
} catch (Exception ex) {
LOG.error(
"Error creating BasalProfileEntry: startTimeInterval={}, startTime_raw={}, hours={}, rateStrokes={}",
startTimeInterval, startTime_raw, startTimeInterval / 2, rateStrokes);
throw ex;
}
}

View file

@ -14,5 +14,5 @@ public class ClockDTO {
// public Duration timeDifference;
public int timeDifference; // s
public int timeDifference; // s (pump -> local)
}

View file

@ -8,7 +8,9 @@ import info.nightscout.androidaps.plugins.general.actions.defs.CustomActionType;
public enum MedtronicCustomActionType implements CustomActionType {
WakeUpAndTune()
WakeUpAndTune(), //
ClearBolusBlock(), //
ResetRileyLink(), //
;

View file

@ -489,6 +489,6 @@ public class MedtronicUtil extends RileyLinkUtil {
public static ClockDTO getPumpTime() {
return pumpTime;
return MedtronicUtil.pumpTime;
}
}

View file

@ -308,8 +308,7 @@ public class TreatmentsPlugin extends PluginBase implements TreatmentsInterface
List<Treatment> in5minback = new ArrayList<>();
long time = System.currentTimeMillis();
synchronized (treatments) {
for (Integer pos = 0; pos < treatments.size(); pos++) {
Treatment t = treatments.get(pos);
for (Treatment t : treatments) {
if (!t.isValid)
continue;
if (t.date <= time && t.date > (time - minutesAgo * 60 * 1000))

View file

@ -433,6 +433,19 @@ public class CommandQueue {
return true;
}
public synchronized boolean statusInQueue() {
if (isRunning(Command.CommandType.READSTATUS))
return true;
for (int i = 0; i < queue.size(); i++) {
if (queue.get(i).commandType == Command.CommandType.READSTATUS) {
return true;
}
}
return false;
}
// returns true if command is queued
public boolean loadHistory(byte type, Callback callback) {
if (isRunning(Command.CommandType.LOADHISTORY)) {

View file

@ -1337,6 +1337,7 @@
<string name="medtronic_pump_encoding_4b6b_rileylink">RileyLink 4b6b Encoding</string>
<string name="rileylink_mac_address">RileyLink MAC Address</string>
<string name="medtronic_custom_action_wake_and_tune">Wake and Tune Up</string>
<string name="medtronic_custom_action_clear_bolus_block">Clear Bolus Block</string>
<!-- RL BLE Scanning -->
<string name="rileylink_scanner_scan_scan">SCAN</string>