diff --git a/pump/combov2/src/main/kotlin/info/nightscout/pump/combov2/ComboV2Fragment.kt b/pump/combov2/src/main/kotlin/info/nightscout/pump/combov2/ComboV2Fragment.kt
index eac6eeacab..c8d9cd62e8 100644
--- a/pump/combov2/src/main/kotlin/info/nightscout/pump/combov2/ComboV2Fragment.kt
+++ b/pump/combov2/src/main/kotlin/info/nightscout/pump/combov2/ComboV2Fragment.kt
@@ -41,6 +41,7 @@ class ComboV2Fragment : DaggerFragment() {
binding.combov2RefreshButton.setOnClickListener {
binding.combov2RefreshButton.isEnabled = false
+ combov2Plugin.clearPumpErrorObservedFlag()
commandQueue.readStatus(rh.gs(info.nightscout.core.ui.R.string.user_request), null)
}
diff --git a/pump/combov2/src/main/kotlin/info/nightscout/pump/combov2/ComboV2Plugin.kt b/pump/combov2/src/main/kotlin/info/nightscout/pump/combov2/ComboV2Plugin.kt
index 6a71eef58a..5a5b3d3afc 100644
--- a/pump/combov2/src/main/kotlin/info/nightscout/pump/combov2/ComboV2Plugin.kt
+++ b/pump/combov2/src/main/kotlin/info/nightscout/pump/combov2/ComboV2Plugin.kt
@@ -95,6 +95,8 @@ import info.nightscout.comboctl.base.Tbr as ComboCtlTbr
import info.nightscout.comboctl.main.Pump as ComboCtlPump
import info.nightscout.comboctl.main.PumpManager as ComboCtlPumpManager
+internal const val PUMP_ERROR_TIMEOUT_INTERVAL_MSECS = 1000L * 60 * 5
+
@Singleton
class ComboV2Plugin @Inject constructor (
injector: HasAndroidInjector,
@@ -161,6 +163,13 @@ class ComboV2Plugin @Inject constructor (
private var lastConnectionTimestamp = 0L
private var lastComboAlert: AlertScreenContent? = null
+ // States for when the pump reports an error. We then want isInitialized()
+ // to return false until either the user presses the Refresh button or the
+ // pumpErrorTimeoutJob expires. That way, the loop won't run until then,
+ // giving the user a chance to handle the error.
+ private var pumpErrorObserved = false
+ private var pumpErrorTimeoutJob: Job? = null
+
// Set to true if a disconnect request came in while the driver
// was in the Connecting, CheckingPump, or ExecutingCommand
// state (in other words, while isBusy() was returning true).
@@ -183,7 +192,7 @@ class ComboV2Plugin @Inject constructor (
private var activeBasalProfile: BasalProfile? = null
// This is used for checking that the correct basal profile is
// active in the Combo. If not, loop invocation is disallowed.
- // This is _not_ reset by disconect(). That's on purpose; it
+ // This is _not_ reset by disconnect(). That's on purpose; it
// is read by isLoopInvocationAllowed(), which is called even
// if the pump is not connected.
private var lastActiveBasalProfileNumber: Int? = null
@@ -381,7 +390,7 @@ class ComboV2Plugin @Inject constructor (
}
override fun isInitialized(): Boolean =
- isPaired() && (driverStateFlow.value != DriverState.NotInitialized)
+ isPaired() && (driverStateFlow.value != DriverState.NotInitialized) && !pumpErrorObserved
override fun isSuspended(): Boolean =
when (driverStateUIFlow.value) {
@@ -432,6 +441,16 @@ class ComboV2Plugin @Inject constructor (
return
}
+ if (pumpErrorObserved) {
+ aapsLogger.debug(LTag.PUMP, "Aborting connect attempt since the pumpErrorObserved flag is set")
+ uiInteraction.addNotification(
+ Notification.COMBO_PUMP_ALARM,
+ text = rh.gs(R.string.combov2_cannot_connect_pump_error_observed),
+ level = Notification.NORMAL
+ )
+ return
+ }
+
when (driverStateFlow.value) {
DriverState.Connecting,
DriverState.CheckingPump,
@@ -1398,6 +1417,14 @@ class ComboV2Plugin @Inject constructor (
commandQueue.readStatus(reason, null)
}
+ fun clearPumpErrorObservedFlag() {
+ stopPumpErrorTimeout()
+ if (pumpErrorObserved) {
+ aapsLogger.info(LTag.PUMP, "Clearing pumpErrorObserved flag")
+ pumpErrorObserved = false
+ }
+ }
+
/*** Loop constraints ***/
// These restrict the function of the loop in case of an event
// that makes running a loop too risky, for example because something
@@ -1550,6 +1577,8 @@ class ComboV2Plugin @Inject constructor (
_serialNumberUIFlow.value = ""
_bluetoothAddressUIFlow.value = ""
+ clearPumpErrorObservedFlag()
+
// The unpairing variable is set to false in
// the PumpManager onPumpUnpaired callback.
}
@@ -1748,6 +1777,23 @@ class ComboV2Plugin @Inject constructor (
}
}
+ private fun startPumpErrorTimeout() {
+ if (pumpErrorTimeoutJob != null)
+ return
+
+ pumpErrorTimeoutJob = pumpCoroutineScope.launch {
+ delay(PUMP_ERROR_TIMEOUT_INTERVAL_MSECS)
+ aapsLogger.info(LTag.PUMP, "Clearing pumpErrorObserved flag after timeout was reached")
+ pumpErrorObserved = false
+ commandQueue.readStatus(rh.gs(R.string.combov2_refresh_pump_status_after_error), null)
+ }
+ }
+
+ private fun stopPumpErrorTimeout() {
+ pumpErrorTimeoutJob?.cancel()
+ pumpErrorTimeoutJob = null
+ }
+
private fun updateBaseBasalRateUI() {
val currentHour = DateTime().hourOfDay().get()
// This sets value to null if no profile is set,
@@ -2142,6 +2188,12 @@ class ComboV2Plugin @Inject constructor (
}
private fun notifyAboutComboAlert(alert: AlertScreenContent) {
+ if (alert is AlertScreenContent.Error) {
+ aapsLogger.info(LTag.PUMP, "Error screen observed - setting pumpErrorObserved flag")
+ pumpErrorObserved = true
+ startPumpErrorTimeout()
+ }
+
uiInteraction.addNotification(
Notification.COMBO_PUMP_ALARM,
text = "${rh.gs(R.string.combov2_combo_alert)}: ${getAlertDescription(alert)}",
diff --git a/pump/combov2/src/main/res/values/strings.xml b/pump/combov2/src/main/res/values/strings.xml
index ca0047ff78..73466f753f 100644
--- a/pump/combov2/src/main/res/values/strings.xml
+++ b/pump/combov2/src/main/res/values/strings.xml
@@ -135,4 +135,6 @@ buttons at the same time to cancel pairing)\n
Date and/or time changed
Daylight savings time (DST) started
Daylight savings time (DST) ended
+ Cannot connect to pump because the pump reported an error. User must handle the error and then either wait 5 minutes or press the Refresh button in the driver tab.
+ Refreshing pump status after the pump reported an error