Merge branch 'omnipod_eros' of https://github.com/AAPS-Omnipod/AndroidAPS into omnipod_eros

This commit is contained in:
Andy Rozman 2020-01-23 15:05:12 +00:00
commit d21339700d
37 changed files with 343 additions and 130 deletions

View file

@ -109,7 +109,7 @@ android {
targetSdkVersion 28 targetSdkVersion 28
multiDexEnabled true multiDexEnabled true
versionCode 1500 versionCode 1500
version "omnipod-0.2-SNAPSHOT" version "2.6-omnipod-0.2-SNAPSHOT"
buildConfigField "String", "VERSION", '"' + version + '"' buildConfigField "String", "VERSION", '"' + version + '"'
buildConfigField "String", "DEV_VERSION", '"2.6-dev"' buildConfigField "String", "DEV_VERSION", '"2.6-dev"'
buildConfigField "String", "BUILDVERSION", '"' + generateGitBuild() + '-' + generateDate() + '"' buildConfigField "String", "BUILDVERSION", '"' + generateGitBuild() + '-' + generateDate() + '"'

View file

@ -9,6 +9,8 @@ import android.preference.PreferenceActivity;
import android.preference.PreferenceFragment; import android.preference.PreferenceFragment;
import android.preference.PreferenceGroup; import android.preference.PreferenceGroup;
import android.preference.PreferenceManager; import android.preference.PreferenceManager;
import android.preference.PreferenceScreen;
import android.preference.SwitchPreference;
import info.nightscout.androidaps.Config; import info.nightscout.androidaps.Config;
import info.nightscout.androidaps.MainApp; import info.nightscout.androidaps.MainApp;
@ -17,11 +19,13 @@ import info.nightscout.androidaps.events.EventPreferenceChange;
import info.nightscout.androidaps.events.EventRebuildTabs; import info.nightscout.androidaps.events.EventRebuildTabs;
import info.nightscout.androidaps.interfaces.PluginBase; import info.nightscout.androidaps.interfaces.PluginBase;
import info.nightscout.androidaps.interfaces.PluginType; import info.nightscout.androidaps.interfaces.PluginType;
import info.nightscout.androidaps.interfaces.PumpInterface;
import info.nightscout.androidaps.plugins.aps.loop.LoopPlugin; import info.nightscout.androidaps.plugins.aps.loop.LoopPlugin;
import info.nightscout.androidaps.plugins.aps.openAPSAMA.OpenAPSAMAPlugin; import info.nightscout.androidaps.plugins.aps.openAPSAMA.OpenAPSAMAPlugin;
import info.nightscout.androidaps.plugins.aps.openAPSMA.OpenAPSMAPlugin; import info.nightscout.androidaps.plugins.aps.openAPSMA.OpenAPSMAPlugin;
import info.nightscout.androidaps.plugins.aps.openAPSSMB.OpenAPSSMBPlugin; import info.nightscout.androidaps.plugins.aps.openAPSSMB.OpenAPSSMBPlugin;
import info.nightscout.androidaps.plugins.bus.RxBus; import info.nightscout.androidaps.plugins.bus.RxBus;
import info.nightscout.androidaps.plugins.configBuilder.ConfigBuilderPlugin;
import info.nightscout.androidaps.plugins.constraints.safety.SafetyPlugin; import info.nightscout.androidaps.plugins.constraints.safety.SafetyPlugin;
import info.nightscout.androidaps.plugins.general.automation.AutomationPlugin; import info.nightscout.androidaps.plugins.general.automation.AutomationPlugin;
import info.nightscout.androidaps.plugins.general.careportal.CareportalPlugin; import info.nightscout.androidaps.plugins.general.careportal.CareportalPlugin;
@ -199,6 +203,22 @@ public class PreferencesActivity extends PreferenceActivity implements SharedPre
for (PluginBase plugin : MainApp.getPluginsList()) { for (PluginBase plugin : MainApp.getPluginsList()) {
plugin.preprocessPreferences(this); plugin.preprocessPreferences(this);
} }
PumpInterface activePump = ConfigBuilderPlugin.getPlugin().getActivePump();
PreferenceScreen localAlertsPreferenceScreen = (PreferenceScreen) findPreference(MainApp.gs(R.string.key_preferences_screen_local_alerts));
if (activePump != null && localAlertsPreferenceScreen != null && activePump.getPumpDescription().hasFixedUnreachableAlert) {
Preference pumpUnreachableEnabledPreference = findPreference(MainApp.gs(R.string.key_enable_pump_unreachable_alert));
if (pumpUnreachableEnabledPreference != null) {
((SwitchPreference) pumpUnreachableEnabledPreference).setChecked(true);
pumpUnreachableEnabledPreference.setEnabled(false);
pumpUnreachableEnabledPreference.setShouldDisableView(true);
}
Preference pumpUnreachableThresholdPreference = findPreference(MainApp.gs(R.string.key_pump_unreachable_threshold));
if (pumpUnreachableThresholdPreference != null) {
pumpUnreachableThresholdPreference.setDependency(null);
}
}
} }
@Override @Override

View file

@ -100,7 +100,7 @@ public interface PumpInterface {
void timeDateOrTimeZoneChanged(); void timeDateOrTimeZoneChanged();
/* Only used for pump types where hasFixedUnreachableAlert=true */ /* Only used for pump types where hasFixedUnreachableAlert=true */
default boolean isFixedUnreachableAlertTimeoutExceeded() { default boolean isFixedUnreachableAlertTimeoutExceeded(long alertTimeoutMilliseconds) {
return false; return false;
} }

View file

@ -70,7 +70,6 @@ import info.nightscout.androidaps.plugins.pump.omnipod.util.OmnipodUtil;
import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin; import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin;
import info.nightscout.androidaps.utils.FabricPrivacy; import info.nightscout.androidaps.utils.FabricPrivacy;
import info.nightscout.androidaps.utils.SP; import info.nightscout.androidaps.utils.SP;
import info.nightscout.androidaps.utils.T;
import io.reactivex.disposables.CompositeDisposable; import io.reactivex.disposables.CompositeDisposable;
import io.reactivex.schedulers.Schedulers; import io.reactivex.schedulers.Schedulers;
@ -108,7 +107,6 @@ public class OmnipodPumpPlugin extends PumpPluginAbstract implements OmnipodPump
boolean omnipodServiceRunning = false; boolean omnipodServiceRunning = false;
private long nextPodCheck = 0L; private long nextPodCheck = 0L;
private static long UNREACHABLE_ALERT_THRESHOLD_MILLIS = T.mins(30).msecs();
private OmnipodPumpPlugin() { private OmnipodPumpPlugin() {
@ -942,11 +940,11 @@ public class OmnipodPumpPlugin extends PumpPluginAbstract implements OmnipodPump
@Override @Override
public boolean isFixedUnreachableAlertTimeoutExceeded() { public boolean isFixedUnreachableAlertTimeoutExceeded(long unreachableTimeoutMilliseconds) {
getPodPumpStatusObject(); getPodPumpStatusObject();
if (pumpStatusLocal.lastConnection != 0 || pumpStatusLocal.lastErrorConnection != 0) { if (pumpStatusLocal.lastConnection != 0 || pumpStatusLocal.lastErrorConnection != 0) {
if (pumpStatusLocal.lastConnection + UNREACHABLE_ALERT_THRESHOLD_MILLIS < System.currentTimeMillis()) { if (pumpStatusLocal.lastConnection + unreachableTimeoutMilliseconds < System.currentTimeMillis()) {
if (pumpStatusLocal.lastErrorConnection > pumpStatusLocal.lastConnection) { if (pumpStatusLocal.lastErrorConnection > pumpStatusLocal.lastConnection) {
// We exceeded the alert threshold, and our last connection failed // We exceeded the alert threshold, and our last connection failed
// We should show an alert // We should show an alert
@ -960,8 +958,6 @@ public class OmnipodPumpPlugin extends PumpPluginAbstract implements OmnipodPump
} }
// If we have no last connection and error data, don't show any alert
// FIXME is this appropriate?
return false; return false;
} }
} }

View file

@ -102,6 +102,11 @@ public class OmnipodCommunicationService extends RileyLinkCommunicationManager {
} }
public synchronized <T extends MessageBlock> T exchangeMessages(Class<T> responseClass, PodState podState, OmnipodMessage message, Integer addressOverride, Integer ackAddressOverride, boolean automaticallyResyncNonce) { public synchronized <T extends MessageBlock> T exchangeMessages(Class<T> responseClass, PodState podState, OmnipodMessage message, Integer addressOverride, Integer ackAddressOverride, boolean automaticallyResyncNonce) {
if (isLoggingEnabled()) {
LOG.debug("Exchanging OmnipodMessage [responseClass={}, podState={}, message={}, addressOverride={}, ackAddressOverride={}, automaticallyResyncNonce={}]: {}", //
responseClass.getSimpleName(), podState, message, addressOverride, ackAddressOverride, automaticallyResyncNonce, message);
}
for (int i = 0; 2 > i; i++) { for (int i = 0; 2 > i; i++) {
if (podState.hasNonceState() && message.isNonceResyncable()) { if (podState.hasNonceState() && message.isNonceResyncable()) {

View file

@ -33,6 +33,7 @@ import info.nightscout.androidaps.plugins.pump.omnipod.defs.BeepType;
import info.nightscout.androidaps.plugins.pump.omnipod.defs.DeliveryStatus; import info.nightscout.androidaps.plugins.pump.omnipod.defs.DeliveryStatus;
import info.nightscout.androidaps.plugins.pump.omnipod.defs.DeliveryType; import info.nightscout.androidaps.plugins.pump.omnipod.defs.DeliveryType;
import info.nightscout.androidaps.plugins.pump.omnipod.defs.PodInfoType; import info.nightscout.androidaps.plugins.pump.omnipod.defs.PodInfoType;
import info.nightscout.androidaps.plugins.pump.omnipod.defs.PodProgressStatus;
import info.nightscout.androidaps.plugins.pump.omnipod.defs.SetupProgress; import info.nightscout.androidaps.plugins.pump.omnipod.defs.SetupProgress;
import info.nightscout.androidaps.plugins.pump.omnipod.defs.schedule.BasalSchedule; import info.nightscout.androidaps.plugins.pump.omnipod.defs.schedule.BasalSchedule;
import info.nightscout.androidaps.plugins.pump.omnipod.defs.state.PodSessionState; import info.nightscout.androidaps.plugins.pump.omnipod.defs.state.PodSessionState;
@ -158,13 +159,13 @@ public class OmnipodManager {
} }
} }
public synchronized void acknowledgeAlerts() { public synchronized StatusResponse acknowledgeAlerts() {
assertReadyForDelivery(); assertReadyForDelivery();
logStartingCommandExecution("acknowledgeAlerts"); logStartingCommandExecution("acknowledgeAlerts");
try { try {
executeAndVerify(() -> communicationService.executeAction(new AcknowledgeAlertsAction(podState, podState.getActiveAlerts()))); return executeAndVerify(() -> communicationService.executeAction(new AcknowledgeAlertsAction(podState, podState.getActiveAlerts())));
} finally { } finally {
logCommandExecutionFinished("acknowledgeAlerts"); logCommandExecutionFinished("acknowledgeAlerts");
} }
@ -172,7 +173,7 @@ public class OmnipodManager {
// CAUTION: cancels all delivery // CAUTION: cancels all delivery
// CAUTION: suspends and then resumes delivery. An OmnipodException[certainFailure=false] indicates that the pod is or might be suspended // CAUTION: suspends and then resumes delivery. An OmnipodException[certainFailure=false] indicates that the pod is or might be suspended
public synchronized void setBasalSchedule(BasalSchedule schedule, boolean acknowledgementBeep) { public synchronized StatusResponse setBasalSchedule(BasalSchedule schedule, boolean acknowledgementBeep) {
assertReadyForDelivery(); assertReadyForDelivery();
logStartingCommandExecution("setBasalSchedule [basalSchedule=" + schedule + ", acknowledgementBeep=" + acknowledgementBeep + "]"); logStartingCommandExecution("setBasalSchedule [basalSchedule=" + schedule + ", acknowledgementBeep=" + acknowledgementBeep + "]");
@ -186,7 +187,7 @@ public class OmnipodManager {
try { try {
try { try {
executeAndVerify(() -> communicationService.executeAction(new SetBasalScheduleAction(podState, schedule, return executeAndVerify(() -> communicationService.executeAction(new SetBasalScheduleAction(podState, schedule,
false, podState.getScheduleOffset(), acknowledgementBeep))); false, podState.getScheduleOffset(), acknowledgementBeep)));
} catch (OmnipodException ex) { } catch (OmnipodException ex) {
// Treat all exceptions as uncertain failures, because all delivery has been suspended here. // Treat all exceptions as uncertain failures, because all delivery has been suspended here.
@ -200,7 +201,7 @@ public class OmnipodManager {
} }
// CAUTION: cancels temp basal and then sets new temp basal. An OmnipodException[certainFailure=false] indicates that the pod might have cancelled the previous temp basal, but did not set a new temp basal // CAUTION: cancels temp basal and then sets new temp basal. An OmnipodException[certainFailure=false] indicates that the pod might have cancelled the previous temp basal, but did not set a new temp basal
public synchronized void setTemporaryBasal(double rate, Duration duration, boolean acknowledgementBeep, boolean completionBeep) { public synchronized StatusResponse setTemporaryBasal(double rate, Duration duration, boolean acknowledgementBeep, boolean completionBeep) {
assertReadyForDelivery(); assertReadyForDelivery();
logStartingCommandExecution("setTemporaryBasal [rate=" + rate + ", duration=" + duration + ", acknowledgementBeep=" + acknowledgementBeep + ", completionBeep=" + completionBeep + "]"); logStartingCommandExecution("setTemporaryBasal [rate=" + rate + ", duration=" + duration + ", acknowledgementBeep=" + acknowledgementBeep + ", completionBeep=" + completionBeep + "]");
@ -213,7 +214,7 @@ public class OmnipodManager {
} }
try { try {
executeAndVerify(() -> communicationService.executeAction(new SetTempBasalAction( return executeAndVerify(() -> communicationService.executeAction(new SetTempBasalAction(
podState, rate, duration, podState, rate, duration,
acknowledgementBeep, completionBeep))); acknowledgementBeep, completionBeep)));
} catch (OmnipodException ex) { } catch (OmnipodException ex) {
@ -230,17 +231,18 @@ public class OmnipodManager {
cancelDelivery(EnumSet.of(DeliveryType.TEMP_BASAL), acknowledgementBeep); cancelDelivery(EnumSet.of(DeliveryType.TEMP_BASAL), acknowledgementBeep);
} }
private synchronized void cancelDelivery(EnumSet<DeliveryType> deliveryTypes, boolean acknowledgementBeep) { private synchronized StatusResponse cancelDelivery(EnumSet<DeliveryType> deliveryTypes, boolean acknowledgementBeep) {
assertReadyForDelivery(); assertReadyForDelivery();
logStartingCommandExecution("cancelDelivery [deliveryTypes=" + deliveryTypes + ", acknowledgementBeep=" + acknowledgementBeep + "]"); logStartingCommandExecution("cancelDelivery [deliveryTypes=" + deliveryTypes + ", acknowledgementBeep=" + acknowledgementBeep + "]");
try { try {
executeAndVerify(() -> { return executeAndVerify(() -> {
StatusResponse statusResponse = communicationService.executeAction(new CancelDeliveryAction(podState, deliveryTypes, acknowledgementBeep)); StatusResponse statusResponse = communicationService.executeAction(new CancelDeliveryAction(podState, deliveryTypes, acknowledgementBeep));
if (isLoggingEnabled()) { if (isLoggingEnabled()) {
LOG.info("Status response after cancel delivery[types={}]: {}", deliveryTypes.toString(), statusResponse.toString()); LOG.info("Status response after cancel delivery[types={}]: {}", deliveryTypes.toString(), statusResponse.toString());
} }
return statusResponse;
}); });
} finally { } finally {
logCommandExecutionFinished("cancelDelivery"); logCommandExecutionFinished("cancelDelivery");
@ -303,10 +305,11 @@ public class OmnipodManager {
.observeOn(Schedulers.io()) // .observeOn(Schedulers.io()) //
.doOnComplete(() -> { .doOnComplete(() -> {
synchronized (bolusDataMutex) { synchronized (bolusDataMutex) {
StatusResponse statusResponse = null;
for (int i = 0; i < ACTION_VERIFICATION_TRIES; i++) { for (int i = 0; i < ACTION_VERIFICATION_TRIES; i++) {
try { try {
// Retrieve a status response in order to update the pod state // Retrieve a status response in order to update the pod state
StatusResponse statusResponse = getPodStatus(); statusResponse = getPodStatus();
if (statusResponse.getDeliveryStatus().isBolusing()) { if (statusResponse.getDeliveryStatus().isBolusing()) {
throw new IllegalDeliveryStatusException(DeliveryStatus.NORMAL, statusResponse.getDeliveryStatus()); throw new IllegalDeliveryStatusException(DeliveryStatus.NORMAL, statusResponse.getDeliveryStatus());
} else { } else {
@ -319,8 +322,11 @@ public class OmnipodManager {
} }
} }
// Substract units not delivered in case of a Pod failure
double unitsNotDelivered = statusResponse != null && PodProgressStatus.FAULT_EVENT_OCCURRED.equals(statusResponse.getPodProgressStatus()) ? statusResponse.getInsulinNotDelivered() : 0.0D;
if (hasActiveBolus()) { if (hasActiveBolus()) {
activeBolusData.bolusCompletionSubject.onSuccess(new BolusDeliveryResult(units)); activeBolusData.bolusCompletionSubject.onSuccess(new BolusDeliveryResult(units - unitsNotDelivered));
activeBolusData = null; activeBolusData = null;
} }
} }
@ -341,22 +347,23 @@ public class OmnipodManager {
logStartingCommandExecution("cancelBolus [acknowledgementBeep=" + acknowledgementBeep + "]"); logStartingCommandExecution("cancelBolus [acknowledgementBeep=" + acknowledgementBeep + "]");
try { try {
cancelDelivery(EnumSet.of(DeliveryType.BOLUS), acknowledgementBeep); StatusResponse statusResponse = cancelDelivery(EnumSet.of(DeliveryType.BOLUS), acknowledgementBeep);
discardActiveBolusData(statusResponse.getInsulinNotDelivered());
} catch (PodFaultException ex) { } catch (PodFaultException ex) {
discardActiveBolusData(); discardActiveBolusData(ex.getFaultEvent().getInsulinNotDelivered());
throw ex; throw ex;
} finally { } finally {
logCommandExecutionFinished("cancelBolus"); logCommandExecutionFinished("cancelBolus");
} }
discardActiveBolusData();
} }
} }
private void discardActiveBolusData() { private void discardActiveBolusData(double unitsNotDelivered) {
activeBolusData.getDisposables().dispose(); synchronized (bolusDataMutex) {
activeBolusData.getBolusCompletionSubject().onSuccess(new BolusDeliveryResult(activeBolusData.estimateUnitsDelivered())); activeBolusData.getDisposables().dispose();
activeBolusData = null; activeBolusData.getBolusCompletionSubject().onSuccess(new BolusDeliveryResult(activeBolusData.getUnits() - unitsNotDelivered));
activeBolusData = null;
}
} }
public synchronized void suspendDelivery(boolean acknowledgementBeep) { public synchronized void suspendDelivery(boolean acknowledgementBeep) {
@ -364,12 +371,12 @@ public class OmnipodManager {
} }
// Same as setting basal schedule, but without suspending delivery first // Same as setting basal schedule, but without suspending delivery first
public synchronized void resumeDelivery(boolean acknowledgementBeep) { public synchronized StatusResponse resumeDelivery(boolean acknowledgementBeep) {
assertReadyForDelivery(); assertReadyForDelivery();
logStartingCommandExecution("resumeDelivery"); logStartingCommandExecution("resumeDelivery");
try { try {
executeAndVerify(() -> communicationService.executeAction(new SetBasalScheduleAction(podState, podState.getBasalSchedule(), return executeAndVerify(() -> communicationService.executeAction(new SetBasalScheduleAction(podState, podState.getBasalSchedule(),
false, podState.getScheduleOffset(), acknowledgementBeep))); false, podState.getScheduleOffset(), acknowledgementBeep)));
} finally { } finally {
logCommandExecutionFinished("resumeDelivery"); logCommandExecutionFinished("resumeDelivery");
@ -439,10 +446,13 @@ public class OmnipodManager {
logCommandExecutionFinished("deactivatePod"); logCommandExecutionFinished("deactivatePod");
} }
resetPodState(); resetPodState(false);
} }
public void resetPodState() { public void resetPodState(boolean forcedByUser) {
if(isLoggingEnabled()) {
LOG.warn("resetPodState has been called. forcedByUser={}", forcedByUser);
}
podState = null; podState = null;
SP.remove(OmnipodConst.Prefs.PodState); SP.remove(OmnipodConst.Prefs.PodState);
} }
@ -475,34 +485,46 @@ public class OmnipodManager {
} }
// Only works for commands with nonce resyncable message blocks // Only works for commands with nonce resyncable message blocks
private void executeAndVerify(Runnable runnable) { // FIXME method is too big, needs refactoring
private StatusResponse executeAndVerify(VerifiableAction runnable) {
try { try {
runnable.run(); return runnable.run();
} catch (Exception ex) { } catch (Exception originalException) {
if (isCertainFailure(ex)) { if (isCertainFailure(originalException)) {
throw ex; throw originalException;
} else { } else {
if (isLoggingEnabled()) { if (isLoggingEnabled()) {
LOG.debug("Caught exception in executeAndVerify: ", ex); LOG.warn("Caught exception in executeAndVerify. Verifying command by using cancel none command to verify nonce", originalException);
} }
CommandDeliveryStatus verificationResult = verifyCommand(); try {
logStartingCommandExecution("verifyCommand");
StatusResponse statusResponse = communicationService.sendCommand(StatusResponse.class, podState,
new CancelDeliveryCommand(podState.getCurrentNonce(), BeepType.NO_BEEP, DeliveryType.NONE), false);
if (isLoggingEnabled()) {
LOG.info("Command status resolved to SUCCESS. Status response after cancelDelivery[types=DeliveryType.NONE]: {}", statusResponse);
}
switch (verificationResult) { return statusResponse;
case CERTAIN_FAILURE: } catch (NonceOutOfSyncException verificationException) {
if (ex instanceof OmnipodException) { if (isLoggingEnabled()) {
((OmnipodException) ex).setCertainFailure(true); LOG.error("Command resolved to FAILURE (CERTAIN_FAILURE)", verificationException);
throw ex; }
} else { if (originalException instanceof OmnipodException) {
OmnipodException newException = new CommunicationException(CommunicationException.Type.UNEXPECTED_EXCEPTION, ex); ((OmnipodException) originalException).setCertainFailure(true);
newException.setCertainFailure(true); throw originalException;
throw newException; } else {
} OmnipodException newException = new CommunicationException(CommunicationException.Type.UNEXPECTED_EXCEPTION, originalException);
case UNCERTAIN_FAILURE: newException.setCertainFailure(true);
throw ex; throw newException;
case SUCCESS: }
// Ignore original exception } catch (Exception verificationException) {
break; if (isLoggingEnabled()) {
LOG.error("Command unresolved (UNCERTAIN_FAILURE)", verificationException);
}
throw originalException;
} finally {
logCommandExecutionFinished("verifyCommand");
} }
} }
} }
@ -537,40 +559,6 @@ public class OmnipodManager {
return result; return result;
} }
// Only works for commands which contain nonce resyncable message blocks
private CommandDeliveryStatus verifyCommand() {
if (isLoggingEnabled()) {
LOG.warn("Verifying command by using cancel none command to verify nonce");
}
try {
logStartingCommandExecution("verifyCommand");
StatusResponse statusResponse = communicationService.sendCommand(StatusResponse.class, podState,
new CancelDeliveryCommand(podState.getCurrentNonce(), BeepType.NO_BEEP, DeliveryType.NONE), false);
if (isLoggingEnabled()) {
LOG.info("Status response after verifyCommand (cancelDelivery[types=DeliveryType.NONE]): {}", statusResponse.toString());
}
} catch (NonceOutOfSyncException ex) {
if (isLoggingEnabled()) {
LOG.info("Command resolved to FAILURE (CERTAIN_FAILURE)", ex);
}
return CommandDeliveryStatus.CERTAIN_FAILURE;
} catch (Exception ex) {
if (isLoggingEnabled()) {
LOG.error("Command unresolved (UNCERTAIN_FAILURE)", ex);
}
return CommandDeliveryStatus.UNCERTAIN_FAILURE;
} finally {
logCommandExecutionFinished("verifyCommand");
}
if (isLoggingEnabled()) {
if (isLoggingEnabled()) {
LOG.info("Command status resolved to SUCCESS");
}
}
return CommandDeliveryStatus.SUCCESS;
}
private void logStartingCommandExecution(String action) { private void logStartingCommandExecution(String action) {
if (isLoggingEnabled()) { if (isLoggingEnabled()) {
LOG.debug("Starting command execution for action: " + action); LOG.debug("Starting command execution for action: " + action);
@ -670,10 +658,6 @@ public class OmnipodManager {
return bolusCompletionSubject; return bolusCompletionSubject;
} }
public void setBolusCompletionSubject(SingleSubject<BolusDeliveryResult> bolusCompletionSubject) {
this.bolusCompletionSubject = bolusCompletionSubject;
}
public double estimateUnitsDelivered() { public double estimateUnitsDelivered() {
long elapsedMillis = new Duration(startDate, DateTime.now()).getMillis(); long elapsedMillis = new Duration(startDate, DateTime.now()).getMillis();
long totalDurationMillis = (long) (units / OmnipodConst.POD_BOLUS_DELIVERY_RATE * 1000); long totalDurationMillis = (long) (units / OmnipodConst.POD_BOLUS_DELIVERY_RATE * 1000);
@ -684,4 +668,10 @@ public class OmnipodManager {
return (double) Math.round(estimatedUnits * roundingDivisor) / roundingDivisor; return (double) Math.round(estimatedUnits * roundingDivisor) / roundingDivisor;
} }
} }
// Could be replaced with Supplier<StatusResponse> when min API level >= 24
@FunctionalInterface
private interface VerifiableAction {
StatusResponse run();
}
} }

View file

@ -7,10 +7,8 @@ import java.util.List;
import info.nightscout.androidaps.plugins.pump.omnipod.comm.OmnipodCommunicationService; import info.nightscout.androidaps.plugins.pump.omnipod.comm.OmnipodCommunicationService;
import info.nightscout.androidaps.plugins.pump.omnipod.comm.message.MessageBlock; import info.nightscout.androidaps.plugins.pump.omnipod.comm.message.MessageBlock;
import info.nightscout.androidaps.plugins.pump.omnipod.comm.message.OmnipodMessage; import info.nightscout.androidaps.plugins.pump.omnipod.comm.message.OmnipodMessage;
import info.nightscout.androidaps.plugins.pump.omnipod.comm.message.command.BeepConfigCommand;
import info.nightscout.androidaps.plugins.pump.omnipod.comm.message.command.CancelDeliveryCommand; import info.nightscout.androidaps.plugins.pump.omnipod.comm.message.command.CancelDeliveryCommand;
import info.nightscout.androidaps.plugins.pump.omnipod.comm.message.response.StatusResponse; import info.nightscout.androidaps.plugins.pump.omnipod.comm.message.response.StatusResponse;
import info.nightscout.androidaps.plugins.pump.omnipod.defs.BeepConfigType;
import info.nightscout.androidaps.plugins.pump.omnipod.defs.BeepType; import info.nightscout.androidaps.plugins.pump.omnipod.defs.BeepType;
import info.nightscout.androidaps.plugins.pump.omnipod.defs.DeliveryType; import info.nightscout.androidaps.plugins.pump.omnipod.defs.DeliveryType;
import info.nightscout.androidaps.plugins.pump.omnipod.defs.state.PodSessionState; import info.nightscout.androidaps.plugins.pump.omnipod.defs.state.PodSessionState;
@ -38,18 +36,18 @@ public class CancelDeliveryAction implements OmnipodAction<StatusResponse> {
public StatusResponse execute(OmnipodCommunicationService communicationService) { public StatusResponse execute(OmnipodCommunicationService communicationService) {
List<MessageBlock> messageBlocks = new ArrayList<>(); List<MessageBlock> messageBlocks = new ArrayList<>();
messageBlocks.add(new CancelDeliveryCommand(podState.getCurrentNonce(),
acknowledgementBeep && deliveryTypes.size() == 1 ? BeepType.BEEP : BeepType.NO_BEEP, deliveryTypes));
if (acknowledgementBeep && deliveryTypes.size() > 1) { if (acknowledgementBeep && deliveryTypes.size() > 1) {
// Workaround for strange beep behaviour when cancelling multiple delivery types at the same time // Workaround for strange beep behaviour when cancelling multiple delivery types
List<DeliveryType> deliveryTypeList = new ArrayList<>(deliveryTypes);
// FIXME we should use other constructor with all beep configs. EnumSet<DeliveryType> deliveryTypeWithBeep = EnumSet.of(deliveryTypeList.remove(deliveryTypeList.size() - 1));
// Theoretically, if we would cancel multiple delivery types but not all, EnumSet<DeliveryType> deliveryTypesWithoutBeep = EnumSet.copyOf(deliveryTypeList);
// we should keep the beep config for delivery types that we're not cancelling.
// We currently have no use case that though, messageBlocks.add(new CancelDeliveryCommand(podState.getCurrentNonce(), BeepType.NO_BEEP, deliveryTypesWithoutBeep));
// as we either cancel 1 type or all types, messageBlocks.add(new CancelDeliveryCommand(podState.getCurrentNonce(), BeepType.BEEP, deliveryTypeWithBeep));
messageBlocks.add(new BeepConfigCommand(BeepConfigType.BEEP)); } else {
messageBlocks.add(new CancelDeliveryCommand(podState.getCurrentNonce(),
acknowledgementBeep && deliveryTypes.size() == 1 ? BeepType.BEEP : BeepType.NO_BEEP, deliveryTypes));
} }
return communicationService.exchangeMessages(StatusResponse.class, podState, return communicationService.exchangeMessages(StatusResponse.class, podState,

View file

@ -31,7 +31,7 @@ public class InsertCannulaService {
DateTime endOfServiceTime = podState.getActivatedAt().plus(OmnipodConst.SERVICE_DURATION); DateTime endOfServiceTime = podState.getActivatedAt().plus(OmnipodConst.SERVICE_DURATION);
Duration timeUntilExpirationAdvisoryAlarm = new Duration(DateTime.now(), Duration timeUntilExpirationAdvisoryAlarm = new Duration(DateTime.now(),
endOfServiceTime.minus(OmnipodConst.END_OF_SERVICE_IMMINENT_WINDOW).minus(OmnipodConst.EXPIRATION_ADVISORY_WINDOW)); endOfServiceTime.minus(OmnipodConst.EXPIRATION_ADVISORY_WINDOW));
Duration timeUntilShutdownImminentAlarm = new Duration(DateTime.now(), Duration timeUntilShutdownImminentAlarm = new Duration(DateTime.now(),
endOfServiceTime.minus(OmnipodConst.END_OF_SERVICE_IMMINENT_WINDOW)); endOfServiceTime.minus(OmnipodConst.END_OF_SERVICE_IMMINENT_WINDOW));

View file

@ -105,15 +105,6 @@ public class OmnipodMessage {
return sequenceNumber; return sequenceNumber;
} }
@Override
public String toString() {
return "OmnipodMessage{" +
"address=" + address +
", encoded=" + ByteUtil.shortHexString(getEncoded()) +
", sequenceNumber=" + sequenceNumber +
'}';
}
public boolean isNonceResyncable() { public boolean isNonceResyncable() {
return containsBlock(NonceResyncableMessageBlock.class); return containsBlock(NonceResyncableMessageBlock.class);
} }
@ -143,4 +134,15 @@ public class OmnipodMessage {
} }
return false; return false;
} }
@Override
public String toString() {
return "OmnipodMessage{" +
"address=" + address +
", messageBlocks=" + messageBlocks +
", encoded=" + ByteUtil.shortHexStringWithoutSpaces(getEncoded()) +
", sequenceNumber=" + sequenceNumber +
'}';
}
} }

View file

@ -43,4 +43,12 @@ public class AcknowledgeAlertsCommand extends NonceResyncableMessageBlock {
this.nonce = nonce; this.nonce = nonce;
encode(); encode();
} }
@Override
public String toString() {
return "AcknowledgeAlertsCommand{" +
"alerts=" + alerts +
", nonce=" + nonce +
'}';
}
} }

View file

@ -22,4 +22,10 @@ public class AssignAddressCommand extends MessageBlock {
return MessageBlockType.ASSIGN_ADDRESS; return MessageBlockType.ASSIGN_ADDRESS;
} }
@Override
public String toString() {
return "AssignAddressCommand{" +
"address=" + address +
'}';
}
} }

View file

@ -111,4 +111,17 @@ public class BasalScheduleExtraCommand extends MessageBlock {
public List<RateEntry> getRateEntries() { public List<RateEntry> getRateEntries() {
return new ArrayList<>(rateEntries); return new ArrayList<>(rateEntries);
} }
@Override
public String toString() {
return "BasalScheduleExtraCommand{" +
"acknowledgementBeep=" + acknowledgementBeep +
", completionBeep=" + completionBeep +
", programReminderInterval=" + programReminderInterval +
", currentEntryIndex=" + currentEntryIndex +
", remainingPulses=" + remainingPulses +
", delayUntilNextTenthOfPulseInSeconds=" + delayUntilNextTenthOfPulseInSeconds +
", rateEntries=" + rateEntries +
'}';
}
} }

View file

@ -45,4 +45,17 @@ public class BeepConfigCommand extends MessageBlock {
public MessageBlockType getType() { public MessageBlockType getType() {
return MessageBlockType.BEEP_CONFIG; return MessageBlockType.BEEP_CONFIG;
} }
@Override
public String toString() {
return "BeepConfigCommand{" +
"beepType=" + beepType +
", basalCompletionBeep=" + basalCompletionBeep +
", basalIntervalBeep=" + basalIntervalBeep +
", tempBasalCompletionBeep=" + tempBasalCompletionBeep +
", tempBasalIntervalBeep=" + tempBasalIntervalBeep +
", bolusCompletionBeep=" + bolusCompletionBeep +
", bolusIntervalBeep=" + bolusIntervalBeep +
'}';
}
} }

View file

@ -60,4 +60,17 @@ public class BolusExtraCommand extends MessageBlock {
public MessageBlockType getType() { public MessageBlockType getType() {
return MessageBlockType.BOLUS_EXTRA; return MessageBlockType.BOLUS_EXTRA;
} }
@Override
public String toString() {
return "BolusExtraCommand{" +
"acknowledgementBeep=" + acknowledgementBeep +
", completionBeep=" + completionBeep +
", programReminderInterval=" + programReminderInterval +
", units=" + units +
", timeBetweenPulses=" + timeBetweenPulses +
", squareWaveUnits=" + squareWaveUnits +
", squareWaveDuration=" + squareWaveDuration +
'}';
}
} }

View file

@ -59,4 +59,13 @@ public class CancelDeliveryCommand extends NonceResyncableMessageBlock {
this.nonce = nonce; this.nonce = nonce;
encode(); encode();
} }
@Override
public String toString() {
return "CancelDeliveryCommand{" +
"beepType=" + beepType +
", deliveryTypes=" + deliveryTypes +
", nonce=" + nonce +
'}';
}
} }

View file

@ -39,4 +39,12 @@ public class ConfigureAlertsCommand extends NonceResyncableMessageBlock {
this.nonce = nonce; this.nonce = nonce;
encode(); encode();
} }
@Override
public String toString() {
return "ConfigureAlertsCommand{" +
"configurations=" + configurations +
", nonce=" + nonce +
'}';
}
} }

View file

@ -43,4 +43,14 @@ public class ConfigurePodCommand extends MessageBlock {
encodedData = ByteUtil.concat(encodedData, ByteUtil.getBytesFromInt(lot)); encodedData = ByteUtil.concat(encodedData, ByteUtil.getBytesFromInt(lot));
encodedData = ByteUtil.concat(encodedData, ByteUtil.getBytesFromInt(tid)); encodedData = ByteUtil.concat(encodedData, ByteUtil.getBytesFromInt(tid));
} }
@Override
public String toString() {
return "ConfigurePodCommand{" +
"lot=" + lot +
", tid=" + tid +
", date=" + date +
", address=" + address +
'}';
}
} }

View file

@ -31,4 +31,11 @@ public class DeactivatePodCommand extends NonceResyncableMessageBlock {
this.nonce = nonce; this.nonce = nonce;
encode(); encode();
} }
@Override
public String toString() {
return "DeactivatePodCommand{" +
"nonce=" + nonce +
'}';
}
} }

View file

@ -38,4 +38,13 @@ public class FaultConfigCommand extends NonceResyncableMessageBlock {
this.nonce = nonce; this.nonce = nonce;
encode(); encode();
} }
@Override
public String toString() {
return "FaultConfigCommand{" +
"tab5sub16=" + tab5sub16 +
", tab5sub17=" + tab5sub17 +
", nonce=" + nonce +
'}';
}
} }

View file

@ -20,4 +20,11 @@ public class GetStatusCommand extends MessageBlock {
public MessageBlockType getType() { public MessageBlockType getType() {
return MessageBlockType.GET_STATUS; return MessageBlockType.GET_STATUS;
} }
@Override
public String toString() {
return "GetStatusCommand{" +
"podInfoType=" + podInfoType +
'}';
}
} }

View file

@ -87,4 +87,12 @@ public class SetInsulinScheduleCommand extends NonceResyncableMessageBlock {
this.nonce = nonce; this.nonce = nonce;
encode(); encode();
} }
@Override
public String toString() {
return "SetInsulinScheduleCommand{" +
"schedule=" + schedule +
", nonce=" + nonce +
'}';
}
} }

View file

@ -93,4 +93,16 @@ public class TempBasalExtraCommand extends MessageBlock {
public List<RateEntry> getRateEntries() { public List<RateEntry> getRateEntries() {
return new ArrayList<>(rateEntries); return new ArrayList<>(rateEntries);
} }
@Override
public String toString() {
return "TempBasalExtraCommand{" +
"acknowledgementBeep=" + acknowledgementBeep +
", completionBeep=" + completionBeep +
", programReminderInterval=" + programReminderInterval +
", remainingPulses=" + remainingPulses +
", delayUntilNextPulse=" + delayUntilNextPulse +
", rateEntries=" + rateEntries +
'}';
}
} }

View file

@ -1,5 +1,7 @@
package info.nightscout.androidaps.plugins.pump.omnipod.defs; package info.nightscout.androidaps.plugins.pump.omnipod.defs;
import java.util.Arrays;
public class NonceState { public class NonceState {
private final long[] table = new long[21]; private final long[] table = new long[21];
private int index; private int index;
@ -44,7 +46,7 @@ public class NonceState {
@Override @Override
public String toString() { public String toString() {
return "NonceState{" + return "NonceState{" +
"currentNonce=" + getCurrentNonce() + "table=" + Arrays.toString(table) +
", index=" + index + ", index=" + index +
'}'; '}';
} }

View file

@ -14,8 +14,8 @@ public enum PodProgressStatus {
ONE_NOT_USED_BUT_IN_33((byte) 0x0a), ONE_NOT_USED_BUT_IN_33((byte) 0x0a),
TWO_NOT_USED_BUT_IN_33((byte) 0x0b), TWO_NOT_USED_BUT_IN_33((byte) 0x0b),
THREE_NOT_USED_BUT_IN_33((byte) 0x0c), THREE_NOT_USED_BUT_IN_33((byte) 0x0c),
ERROR_EVENT_LOGGED_SHUTTING_DOWN((byte) 0x0d), FAULT_EVENT_OCCURRED((byte) 0x0d),
DELAYED_PRIME((byte) 0x0e), FAILED_TO_INITIALIZE_IN_TIME((byte) 0x0e),
INACTIVE((byte) 0x0f); INACTIVE((byte) 0x0f);
private byte value; private byte value;

View file

@ -48,4 +48,14 @@ public class BasalDeliverySchedule extends DeliverySchedule implements IRawRepre
return checksum; return checksum;
} }
@Override
public String toString() {
return "BasalDeliverySchedule{" +
"currentSegment=" + currentSegment +
", secondsRemaining=" + secondsRemaining +
", pulsesRemaining=" + pulsesRemaining +
", basalTable=" + basalTable +
'}';
}
} }

View file

@ -90,6 +90,13 @@ public class BasalDeliveryTable {
return numSegments; return numSegments;
} }
@Override
public String toString() {
return "BasalDeliveryTable{" +
"entries=" + entries +
'}';
}
private class TempSegment { private class TempSegment {
private int pulses; private int pulses;

View file

@ -41,4 +41,13 @@ public class BasalTableEntry implements IRawRepresentable {
public boolean isAlternateSegmentPulse() { public boolean isAlternateSegmentPulse() {
return alternateSegmentPulse; return alternateSegmentPulse;
} }
@Override
public String toString() {
return "BasalTableEntry{" +
"segments=" + segments +
", pulses=" + pulses +
", alternateSegmentPulse=" + alternateSegmentPulse +
'}';
}
} }

View file

@ -49,4 +49,12 @@ public class BolusDeliverySchedule extends DeliverySchedule implements IRawRepre
} }
return checksum; return checksum;
} }
@Override
public String toString() {
return "BolusDeliverySchedule{" +
"units=" + units +
", timeBetweenPulses=" + timeBetweenPulses +
'}';
}
} }

View file

@ -66,4 +66,12 @@ public class RateEntry implements IRawRepresentable {
} }
return rawData; return rawData;
} }
@Override
public String toString() {
return "RateEntry{" +
"totalPulses=" + totalPulses +
", delayBetweenPulsesInSeconds=" + delayBetweenPulsesInSeconds +
'}';
}
} }

View file

@ -57,4 +57,13 @@ public class TempBasalDeliverySchedule extends DeliverySchedule implements IRawR
public BasalDeliveryTable getBasalTable() { public BasalDeliveryTable getBasalTable() {
return basalTable; return basalTable;
} }
@Override
public String toString() {
return "TempBasalDeliverySchedule{" +
"secondsRemaining=" + secondsRemaining +
", firstSegmentPulses=" + firstSegmentPulses +
", basalTable=" + basalTable +
'}';
}
} }

View file

@ -266,7 +266,7 @@ public class AapsOmnipodManager implements OmnipodCommunicationManagerInterface
@Override @Override
public PumpEnactResult resetPodStatus() { public PumpEnactResult resetPodStatus() {
delegate.resetPodState(); delegate.resetPodState(true);
reportImplicitlyCanceledTbr(); reportImplicitlyCanceledTbr();

View file

@ -45,9 +45,9 @@ public class OmnipodConst {
public static final Duration AVERAGE_BOLUS_COMMAND_COMMUNICATION_DURATION = Duration.millis(1500); public static final Duration AVERAGE_BOLUS_COMMAND_COMMUNICATION_DURATION = Duration.millis(1500);
public static final Duration SERVICE_DURATION = Duration.standardHours(80); public static final Duration SERVICE_DURATION = Duration.standardHours(80);
public static final Duration EXPIRATION_ADVISORY_WINDOW = Duration.standardHours(2); public static final Duration EXPIRATION_ADVISORY_WINDOW = Duration.standardHours(9);
public static final Duration END_OF_SERVICE_IMMINENT_WINDOW = Duration.standardHours(1); public static final Duration END_OF_SERVICE_IMMINENT_WINDOW = Duration.standardHours(1);
public static final Duration NOMINAL_POD_LIFE = SERVICE_DURATION.minus(END_OF_SERVICE_IMMINENT_WINDOW).minus(EXPIRATION_ADVISORY_WINDOW); public static final Duration NOMINAL_POD_LIFE = Duration.standardHours(72);
public static final double LOW_RESERVOIR_ALERT = 20.0; public static final double LOW_RESERVOIR_ALERT = 20.0;
public static final double POD_PRIME_BOLUS_UNITS = 2.6; public static final double POD_PRIME_BOLUS_UNITS = 2.6;

View file

@ -13,6 +13,7 @@ import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.interfaces.PumpInterface; import info.nightscout.androidaps.interfaces.PumpInterface;
import info.nightscout.androidaps.logging.L; import info.nightscout.androidaps.logging.L;
import info.nightscout.androidaps.plugins.configBuilder.ConfigBuilderPlugin; import info.nightscout.androidaps.plugins.configBuilder.ConfigBuilderPlugin;
import info.nightscout.androidaps.plugins.pump.omnipod.util.OmnipodUtil;
public class TimeDateOrTZChangeReceiver extends BroadcastReceiver { public class TimeDateOrTZChangeReceiver extends BroadcastReceiver {
@ -26,6 +27,8 @@ public class TimeDateOrTZChangeReceiver extends BroadcastReceiver {
LOG.debug("Date, Time and/or TimeZone changed."); LOG.debug("Date, Time and/or TimeZone changed.");
LOG.debug("TimeDateOrTZChangeReceiver::Intent::{}", OmnipodUtil.getGsonInstance().toJson(intent));
if (action != null && activePump != null) { if (action != null && activePump != null) {
LOG.debug("Date, Time and/or TimeZone changed. Notifying pump driver."); LOG.debug("Date, Time and/or TimeZone changed. Notifying pump driver.");
activePump.timeDateOrTimeZoneChanged(); activePump.timeDateOrTimeZoneChanged();

View file

@ -36,7 +36,7 @@ public class LocalAlertUtils {
public static void checkPumpUnreachableAlarm(long lastConnection, boolean isStatusOutdated) { public static void checkPumpUnreachableAlarm(long lastConnection, boolean isStatusOutdated) {
PumpInterface activePump = ConfigBuilderPlugin.getPlugin().getActivePump(); PumpInterface activePump = ConfigBuilderPlugin.getPlugin().getActivePump();
if(activePump != null && activePump.getPumpDescription().hasFixedUnreachableAlert) { if (activePump != null && activePump.getPumpDescription().hasFixedUnreachableAlert) {
checkPumpUnreachableAlarmStatic(activePump); checkPumpUnreachableAlarmStatic(activePump);
} else { } else {
checkPumpUnreachableAlarmConfigured(lastConnection, isStatusOutdated); checkPumpUnreachableAlarmConfigured(lastConnection, isStatusOutdated);
@ -44,14 +44,16 @@ public class LocalAlertUtils {
} }
private static void checkPumpUnreachableAlarmStatic(PumpInterface pump) { private static void checkPumpUnreachableAlarmStatic(PumpInterface pump) {
if(pump == null) { if (pump == null) {
return; return;
} }
if(pump.isFixedUnreachableAlertTimeoutExceeded()) { long pumpUnreachableThresholdMilliseconds = pumpUnreachableThreshold();
if (pump.isFixedUnreachableAlertTimeoutExceeded(pumpUnreachableThresholdMilliseconds)) {
log.debug("Generating static pump unreachable alarm."); log.debug("Generating static pump unreachable alarm.");
showUnreachableNotification(T.mins(30).msecs()); showUnreachableNotification(pumpUnreachableThresholdMilliseconds);
} else { } else {
RxBus.INSTANCE.send(new EventDismissNotification(Notification.PUMP_UNREACHABLE)); RxBus.INSTANCE.send(new EventDismissNotification(Notification.PUMP_UNREACHABLE));
} }
@ -85,10 +87,10 @@ public class LocalAlertUtils {
* Call only at startup! * Call only at startup!
*/ */
public static void presnoozeAlarms() { public static void presnoozeAlarms() {
if (SP.getLong("nextMissedReadingsAlarm", 0l) < System.currentTimeMillis()) { if (SP.getLong("nextMissedReadingsAlarm", 0L) < System.currentTimeMillis()) {
SP.putLong("nextMissedReadingsAlarm", System.currentTimeMillis() + 5 * 60 * 1000); SP.putLong("nextMissedReadingsAlarm", System.currentTimeMillis() + 5 * 60 * 1000);
} }
if (SP.getLong("nextPumpDisconnectedAlarm", 0l) < System.currentTimeMillis()) { if (SP.getLong("nextPumpDisconnectedAlarm", 0L) < System.currentTimeMillis()) {
SP.putLong("nextPumpDisconnectedAlarm", System.currentTimeMillis() + 5 * 60 * 1000); SP.putLong("nextPumpDisconnectedAlarm", System.currentTimeMillis() + 5 * 60 * 1000);
} }
} }
@ -112,7 +114,7 @@ public class LocalAlertUtils {
if (pump != null && profile != null) { if (pump != null && profile != null) {
long lastConnection = pump.lastDataTime(); long lastConnection = pump.lastDataTime();
long earliestAlarmTime = lastConnection + pumpUnreachableThreshold(); long earliestAlarmTime = lastConnection + pumpUnreachableThreshold();
if (SP.getLong("nextPumpDisconnectedAlarm", 0l) < earliestAlarmTime) { if (SP.getLong("nextPumpDisconnectedAlarm", 0L) < earliestAlarmTime) {
SP.putLong("nextPumpDisconnectedAlarm", earliestAlarmTime); SP.putLong("nextPumpDisconnectedAlarm", earliestAlarmTime);
} }
} }
@ -122,7 +124,7 @@ public class LocalAlertUtils {
BgReading bgReading = DatabaseHelper.lastBg(); BgReading bgReading = DatabaseHelper.lastBg();
if (SP.getBoolean(MainApp.gs(R.string.key_enable_missed_bg_readings_alert), false) if (SP.getBoolean(MainApp.gs(R.string.key_enable_missed_bg_readings_alert), false)
&& bgReading != null && bgReading.date + missedReadingsThreshold() < System.currentTimeMillis() && bgReading != null && bgReading.date + missedReadingsThreshold() < System.currentTimeMillis()
&& SP.getLong("nextMissedReadingsAlarm", 0l) < System.currentTimeMillis()) { && SP.getLong("nextMissedReadingsAlarm", 0L) < System.currentTimeMillis()) {
Notification n = new Notification(Notification.BG_READINGS_MISSED, MainApp.gs(R.string.missed_bg_readings), Notification.URGENT); Notification n = new Notification(Notification.BG_READINGS_MISSED, MainApp.gs(R.string.missed_bg_readings), Notification.URGENT);
n.soundId = R.raw.alarm; n.soundId = R.raw.alarm;
SP.putLong("nextMissedReadingsAlarm", System.currentTimeMillis() + missedReadingsThreshold()); SP.putLong("nextMissedReadingsAlarm", System.currentTimeMillis() + missedReadingsThreshold());

View file

@ -812,6 +812,7 @@
<string name="raise_notifications_as_android_notifications">Use system notifications for alerts and notifications</string> <string name="raise_notifications_as_android_notifications">Use system notifications for alerts and notifications</string>
<string name="key_enable_pump_unreachable_alert" translatable="false">enable_pump_unreachable_alert</string> <string name="key_enable_pump_unreachable_alert" translatable="false">enable_pump_unreachable_alert</string>
<string name="key_enable_missed_bg_readings_alert" translatable="false">enable_missed_bg_readings</string> <string name="key_enable_missed_bg_readings_alert" translatable="false">enable_missed_bg_readings</string>
<string name="key_preferences_screen_local_alerts" translatable="false">preferences_screen_local_alerts</string>
<string name="localalertsettings_title">Local alerts</string> <string name="localalertsettings_title">Local alerts</string>
<string name="enable_missed_bg_readings_alert">Alert if no BG data is received</string> <string name="enable_missed_bg_readings_alert">Alert if no BG data is received</string>
<string name="enable_pump_unreachable_alert">Alert if pump is unreachable</string> <string name="enable_pump_unreachable_alert">Alert if pump is unreachable</string>

View file

@ -72,7 +72,7 @@
android:key="@string/key_short_tabtitles" android:key="@string/key_short_tabtitles"
android:title="@string/short_tabtitles" /> android:title="@string/short_tabtitles" />
</PreferenceCategory> </PreferenceCategory>
<PreferenceScreen android:title="@string/localalertsettings_title"> <PreferenceScreen android:key="@string/key_preferences_screen_local_alerts" android:title="@string/localalertsettings_title">
<SwitchPreference <SwitchPreference
android:defaultValue="false" android:defaultValue="false"
android:key="@string/key_enable_missed_bg_readings_alert" android:key="@string/key_enable_missed_bg_readings_alert"
@ -89,7 +89,7 @@
android:title="@string/enable_pump_unreachable_alert" /> android:title="@string/enable_pump_unreachable_alert" />
<com.andreabaccega.widget.ValidatingEditTextPreference <com.andreabaccega.widget.ValidatingEditTextPreference
validate:testType="numericRange" validate:testType="numericRange"
validate:minNumber="30" validate:minNumber="20"
validate:maxNumber="300" validate:maxNumber="300"
android:defaultValue="30" android:defaultValue="30"
android:dependency="@string/key_enable_pump_unreachable_alert" android:dependency="@string/key_enable_pump_unreachable_alert"

View file

@ -60,7 +60,7 @@ public class PodInfoFaultEventTest {
public void testPodInfoFaultEventErrorShuttingDown() { public void testPodInfoFaultEventErrorShuttingDown() {
PodInfoFaultEvent podInfoFaultEvent = new PodInfoFaultEvent(ByteUtil.fromHexString("020d0000000407f28609ff03ff0a0200000823080000")); PodInfoFaultEvent podInfoFaultEvent = new PodInfoFaultEvent(ByteUtil.fromHexString("020d0000000407f28609ff03ff0a0200000823080000"));
assertEquals(PodProgressStatus.ERROR_EVENT_LOGGED_SHUTTING_DOWN, podInfoFaultEvent.getPodProgressStatus()); assertEquals(PodProgressStatus.FAULT_EVENT_OCCURRED, podInfoFaultEvent.getPodProgressStatus());
assertEquals(DeliveryStatus.SUSPENDED, podInfoFaultEvent.getDeliveryStatus()); assertEquals(DeliveryStatus.SUSPENDED, podInfoFaultEvent.getDeliveryStatus());
assertEquals(101.7, podInfoFaultEvent.getTotalInsulinDelivered(), 0.000001); assertEquals(101.7, podInfoFaultEvent.getTotalInsulinDelivered(), 0.000001);
assertEquals(0, podInfoFaultEvent.getInsulinNotDelivered(), 0.000001); assertEquals(0, podInfoFaultEvent.getInsulinNotDelivered(), 0.000001);
@ -77,7 +77,7 @@ public class PodInfoFaultEventTest {
} }
@Test @Test
public void testPodInfoFaultEventIsulinNotDelivered() { public void testPodInfoFaultEventInsulinNotDelivered() {
PodInfoFaultEvent podInfoFaultEvent = new PodInfoFaultEvent(ByteUtil.fromHexString("020f0000010200ec6a026803ff026b000028a7082023")); PodInfoFaultEvent podInfoFaultEvent = new PodInfoFaultEvent(ByteUtil.fromHexString("020f0000010200ec6a026803ff026b000028a7082023"));
assertEquals(PodProgressStatus.INACTIVE, podInfoFaultEvent.getPodProgressStatus()); assertEquals(PodProgressStatus.INACTIVE, podInfoFaultEvent.getPodProgressStatus());
@ -95,4 +95,24 @@ public class PodInfoFaultEventTest {
assertEquals(2, podInfoFaultEvent.getReceiverLowGain()); assertEquals(2, podInfoFaultEvent.getReceiverLowGain());
assertEquals(39, podInfoFaultEvent.getRadioRSSI()); assertEquals(39, podInfoFaultEvent.getRadioRSSI());
} }
@Test
public void testPodInfoFaultEventMaxInsulinNotDelivered() {
PodInfoFaultEvent podInfoFaultEvent = new PodInfoFaultEvent(ByteUtil.fromHexString("020f00ffff0200ec6a026803ff026b000028a7082023"));
assertEquals(PodProgressStatus.INACTIVE, podInfoFaultEvent.getPodProgressStatus());
assertEquals(DeliveryStatus.SUSPENDED, podInfoFaultEvent.getDeliveryStatus());
assertEquals(11.8, podInfoFaultEvent.getTotalInsulinDelivered(), 0.000001);
assertEquals(3276.75, podInfoFaultEvent.getInsulinNotDelivered(), 0.000001); // Insane and will not happen, but this verifies that we convert it to an unsigned int
assertEquals(0x02, podInfoFaultEvent.getPodMessageCounter());
assertEquals(FaultEventType.OCCLUSION_CHECK_ABOVE_THRESHOLD, podInfoFaultEvent.getFaultEventType());
assertTrue(Duration.standardMinutes(616).isEqual(podInfoFaultEvent.getFaultEventTime()));
assertNull(podInfoFaultEvent.getReservoirLevel());
assertEquals(0, podInfoFaultEvent.getUnacknowledgedAlerts().getRawValue());
assertFalse(podInfoFaultEvent.isFaultAccessingTables());
assertEquals(LogEventErrorCode.INTERNAL_2_BIT_VARIABLE_SET_AND_MANIPULATED_IN_MAIN_LOOP_ROUTINES_2, podInfoFaultEvent.getLogEventErrorType());
assertEquals(PodProgressStatus.RUNNING_ABOVE_FIFTY_UNITS, podInfoFaultEvent.getPodProgressStatusAtTimeOfFirstLoggedFaultEvent());
assertEquals(2, podInfoFaultEvent.getReceiverLowGain());
assertEquals(39, podInfoFaultEvent.getRadioRSSI());
}
} }