diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/OmnipodDashPumpPlugin.kt b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/OmnipodDashPumpPlugin.kt index 5cb1eeb0aa..8806e1489a 100644 --- a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/OmnipodDashPumpPlugin.kt +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/OmnipodDashPumpPlugin.kt @@ -11,6 +11,8 @@ import info.nightscout.androidaps.events.EventPreferenceChange import info.nightscout.androidaps.events.EventProfileSwitchChanged import info.nightscout.androidaps.events.EventRefreshOverview import info.nightscout.androidaps.events.EventTempBasalChange +import info.nightscout.androidaps.extensions.convertedToAbsolute +import info.nightscout.androidaps.extensions.plannedRemainingMinutes import info.nightscout.androidaps.interfaces.* import info.nightscout.androidaps.logging.AAPSLogger import info.nightscout.androidaps.logging.LTag @@ -40,6 +42,7 @@ import info.nightscout.androidaps.plugins.pump.omnipod.dash.util.Constants import info.nightscout.androidaps.plugins.pump.omnipod.dash.util.mapProfileToBasalProgram import info.nightscout.androidaps.queue.commands.Command import info.nightscout.androidaps.queue.commands.CustomCommand +import info.nightscout.androidaps.utils.DateUtil import info.nightscout.androidaps.utils.FabricPrivacy import info.nightscout.androidaps.utils.T import info.nightscout.androidaps.utils.TimeChangeType @@ -51,6 +54,7 @@ import io.reactivex.Single import io.reactivex.disposables.CompositeDisposable import io.reactivex.rxkotlin.plusAssign import org.json.JSONObject +import java.lang.Exception import java.time.Duration import java.time.ZonedDateTime import java.util.* @@ -73,6 +77,7 @@ class OmnipodDashPumpPlugin @Inject constructor( private val context: Context, private val aapsSchedulers: AapsSchedulers, private val fabricPrivacy: FabricPrivacy, + private val dateUtil: DateUtil, injector: HasAndroidInjector, aapsLogger: AAPSLogger, @@ -84,7 +89,7 @@ class OmnipodDashPumpPlugin @Inject constructor( private val handler: Handler = Handler(Looper.getMainLooper()) private lateinit var statusChecker: Runnable - var nextPodWarningCheck: Long = 0 + private var nextPodWarningCheck: Long = 0 @Volatile var stopConnecting: CountDownLatch? = null private var disposables: CompositeDisposable = CompositeDisposable() @@ -574,7 +579,7 @@ class OmnipodDashPumpPlugin @Inject constructor( ).filter { podEvent -> podEvent.isCommandSent() } .map { pumpSyncBolusStart(requestedBolusAmount, detailedBolusInfo.bolusType) } .ignoreElements(), - post = waitForBolusDeliveryToComplete(BOLUS_RETRIES, requestedBolusAmount, detailedBolusInfo.bolusType) + post = waitForBolusDeliveryToComplete(requestedBolusAmount, detailedBolusInfo.bolusType) .map { deliveredBolusAmount = it aapsLogger.info(LTag.PUMP, "deliverTreatment: deliveredBolusAmount=$deliveredBolusAmount") @@ -638,14 +643,13 @@ class OmnipodDashPumpPlugin @Inject constructor( } private fun waitForBolusDeliveryToComplete( - maxTries: Int, requestedBolusAmount: Double, bolusType: DetailedBolusInfo.BolusType ): Single = Single.defer { if (bolusCanceled && podStateManager.activeCommand != null) { var errorGettingStatus: Throwable? = null - for (tries in 1..maxTries) { + for (tries in 1..BOLUS_RETRIES) { errorGettingStatus = getPodStatus().blockingGet() if (errorGettingStatus != null) { aapsLogger.debug(LTag.PUMP, "waitForBolusDeliveryToComplete errorGettingStatus=$errorGettingStatus") @@ -676,7 +680,7 @@ class OmnipodDashPumpPlugin @Inject constructor( ) } - for (tryNumber in 1..maxTries) { + for (tryNumber in 1..BOLUS_RETRIES) { updateBolusProgressDialog("Checking delivery status", 100) val cmd = if (bolusCanceled) @@ -731,7 +735,7 @@ class OmnipodDashPumpPlugin @Inject constructor( requestedBolusAmount: Double, bolusType: DetailedBolusInfo.BolusType ): Boolean { - require(requestedBolusAmount > 0) {"requestedBolusAmount has to be positive"} + require(requestedBolusAmount > 0) { "requestedBolusAmount has to be positive" } val activeCommand = podStateManager.activeCommand if (activeCommand == null) { @@ -778,7 +782,7 @@ class OmnipodDashPumpPlugin @Inject constructor( ) val ret = executeProgrammingCommand( - pre = observeNoActiveTempBasal(true), + pre = observeNoActiveTempBasal(), historyEntry = history.createRecord( commandType = OmnipodCommandType.SET_TEMPORARY_BASAL, tempBasalRecord = TempBasalRecord(duration = durationInMinutes, rate = absoluteRate) @@ -848,38 +852,28 @@ class OmnipodDashPumpPlugin @Inject constructor( return ret } - private fun observeNoActiveTempBasal(enforceNew: Boolean): Completable { + private fun observeNoActiveTempBasal(): Completable { return Completable.defer { - when { - podStateManager.deliveryStatus !in - arrayOf(DeliveryStatus.TEMP_BASAL_ACTIVE, DeliveryStatus.BOLUS_AND_TEMP_BASAL_ACTIVE) -> { - // TODO: what happens if we try to cancel nonexistent temp basal? - aapsLogger.info(LTag.PUMP, "No temporary basal to cancel") - Completable.complete() - } - - !enforceNew -> - Completable.error( - IllegalStateException( - "Temporary basal already active and enforceNew is not set." - ) + if (podStateManager.deliveryStatus !in + arrayOf(DeliveryStatus.TEMP_BASAL_ACTIVE, DeliveryStatus.BOLUS_AND_TEMP_BASAL_ACTIVE) + ) { + // TODO: what happens if we try to cancel nonexistent temp basal? + aapsLogger.info(LTag.PUMP, "No temporary basal to cancel") + Completable.complete() + } else { + // enforceNew == true + aapsLogger.info(LTag.PUMP, "Canceling existing temp basal") + executeProgrammingCommand( + historyEntry = history.createRecord(OmnipodCommandType.CANCEL_TEMPORARY_BASAL), + command = omnipodManager.stopTempBasal(hasTempBasalBeepEnabled()).ignoreElements() + ).doOnComplete { + notifyOnUnconfirmed( + Notification.OMNIPOD_TBR_ALERTS, + "Cancelling temp basal might have failed." + + "If a temp basal was previously running, it might have been cancelled." + + "Please manually refresh the Pod status from the Omnipod tab.", // TODO: i8n + R.raw.boluserror, ) - - else -> { - // enforceNew == true - aapsLogger.info(LTag.PUMP, "Canceling existing temp basal") - executeProgrammingCommand( - historyEntry = history.createRecord(OmnipodCommandType.CANCEL_TEMPORARY_BASAL), - command = omnipodManager.stopTempBasal(hasTempBasalBeepEnabled()).ignoreElements() - ).doOnComplete { - notifyOnUnconfirmed( - Notification.OMNIPOD_TBR_ALERTS, - "Cancelling temp basal might have failed." + - "If a temp basal was previously running, it might have been cancelled." + - "Please manually refresh the Pod status from the Omnipod tab.", // TODO: i8n - R.raw.boluserror, - ) - } } } } @@ -954,8 +948,53 @@ class OmnipodDashPumpPlugin @Inject constructor( } override fun getJSONStatus(profile: Profile, profileName: String, version: String): JSONObject { - // TODO - return JSONObject() + val now = System.currentTimeMillis() + if (podStateManager.lastUpdatedSystem + 60 * 60 * 1000L < now) { + return JSONObject() + } + val pumpJson = JSONObject() + val status = JSONObject() + val extended = JSONObject() + try { + val podStatus = when { + podStateManager.isPodRunning && podStateManager.isSuspended -> + "suspended" + podStateManager.isPodRunning -> + "normal" + else -> + "no active Pod" + } + status.put("status", podStatus) + status.put("timestamp", dateUtil.toISOString(podStateManager.lastUpdatedSystem)) + + extended.put("Version", version) + try { + extended.put("ActiveProfile", profileName) + } catch (ignored: Exception) { + } + val tb = pumpSync.expectedPumpState().temporaryBasal + tb?.run { + extended.put("TempBasalAbsoluteRate", this.convertedToAbsolute(now, profile)) + extended.put("TempBasalStart", dateUtil.dateAndTimeString(this.timestamp)) + extended.put("TempBasalRemaining", this.plannedRemainingMinutes) + } + podStateManager.lastBolus?.run { + extended.put("LastBolus", dateUtil.dateAndTimeString(this.startTime)) + extended.put("LastBolusAmount", this.deliveredUnits() ?: this.requestedUnits) + } + extended.put("BaseBasalRate", baseBasalRate) + + pumpJson.put("status", status) + pumpJson.put("extended", extended) + if (podStateManager.pulsesRemaining == null) { + pumpJson.put("reservoir_display_override", "50+") + } + pumpJson.put("reservoir", reservoirLevel.toInt()) + pumpJson.put("clock", dateUtil.toISOString(now)) + } catch (e: Exception) { + aapsLogger.error(LTag.PUMP, "Unhandled exception: $e") + } + return pumpJson } override val pumpDescription: PumpDescription = Companion.pumpDescription @@ -1348,7 +1387,7 @@ class OmnipodDashPumpPlugin @Inject constructor( pumpId = historyEntry.pumpId(), pumpType = PumpType.OMNIPOD_DASH, pumpSerial = serialNumber(), - type = null // TODO: set the correct bolus type here!!! + type = null ) } rxBus.send(EventDismissNotification(Notification.OMNIPOD_UNCERTAIN_SMB)) @@ -1358,7 +1397,7 @@ class OmnipodDashPumpPlugin @Inject constructor( if (confirmation.success) { podStateManager.lastBolus?.run { val deliveredUnits = markComplete() - if (deliveredUnits < 0){ + if (deliveredUnits < 0) { aapsLogger.error(LTag.PUMP, "Negative delivered units!!! $deliveredUnits") return } diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/OmnipodDashManagerImpl.kt b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/OmnipodDashManagerImpl.kt index c50ea1b988..923109c5c1 100644 --- a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/OmnipodDashManagerImpl.kt +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/OmnipodDashManagerImpl.kt @@ -9,9 +9,9 @@ import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.* import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.GetVersionCommand.Companion.DEFAULT_UNIQUE_ID import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition.* import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition.PodConstants.Companion.MAX_POD_LIFETIME +import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition.PodConstants.Companion.POD_EXPIRATION_ALERT_HOURS import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition.PodConstants.Companion.POD_EXPIRATION_ALERT_HOURS_DURATION import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition.PodConstants.Companion.POD_EXPIRATION_IMMINENT_ALERT_HOURS -import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition.PodConstants.Companion.POD_EXPIRATION_ALERT_HOURS import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.response.* import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.state.OmnipodDashPodStateManager import info.nightscout.androidaps.utils.rx.AapsSchedulers diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/definition/PodConstants.kt b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/definition/PodConstants.kt index 06b0ae96bd..4a2124aace 100644 --- a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/definition/PodConstants.kt +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/definition/PodConstants.kt @@ -1,11 +1,10 @@ package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition import java.time.Duration -import java.util.concurrent.TimeUnit class PodConstants { companion object { - val MAX_POD_LIFETIME : Duration = Duration.ofHours(80) + val MAX_POD_LIFETIME: Duration = Duration.ofHours(80) // Expiration alert time in minutes since activation and duration in minutes const val POD_EXPIRATION_ALERT_HOURS = 72L @@ -18,6 +17,6 @@ class PodConstants { const val POD_PULSE_BOLUS_UNITS = 0.05 // Reservoir units alert threshold - const val DEFAULT_MAX_RESERVOIR_ALERT_THRESHOLD : Short = 20 + const val DEFAULT_MAX_RESERVOIR_ALERT_THRESHOLD: Short = 20 } } diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/response/DefaultStatusResponse.kt b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/response/DefaultStatusResponse.kt index e028d7d1e7..15ec19e534 100644 --- a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/response/DefaultStatusResponse.kt +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/response/DefaultStatusResponse.kt @@ -5,7 +5,6 @@ import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definitio import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition.PodStatus import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.util.AlertUtil import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.util.byValue -import info.nightscout.androidaps.plugins.pump.omnipod.dash.util.Flag import java.nio.ByteBuffer import java.util.* import kotlin.experimental.and @@ -20,7 +19,7 @@ class DefaultStatusResponse( private var last4bytes = ByteBuffer.wrap(byteArrayOf(encoded[6], encoded[7], encoded[8], encoded[9])).int val podStatus: PodStatus = byValue((encoded[1] and 0x0f), PodStatus.UNKNOWN) - val deliveryStatus: DeliveryStatus = byValue(( (encoded[1].toInt() and 0xff) shr 4 and 0x0f).toByte(), DeliveryStatus.UNKNOWN) + val deliveryStatus: DeliveryStatus = byValue(((encoded[1].toInt() and 0xff) shr 4 and 0x0f).toByte(), DeliveryStatus.UNKNOWN) val totalPulsesDelivered: Short = (first4bytes ushr 11 ushr 4 and 0x1FFF).toShort() val sequenceNumberOfLastProgrammingCommand: Short = (first4bytes ushr 11 and 0X0F).toShort() diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/state/OmnipodDashPodStateManagerImpl.kt b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/state/OmnipodDashPodStateManagerImpl.kt index 37798a8412..bc02649cb0 100644 --- a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/state/OmnipodDashPodStateManagerImpl.kt +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/state/OmnipodDashPodStateManagerImpl.kt @@ -629,8 +629,7 @@ class OmnipodDashPodStateManagerImpl @Inject constructor( override fun connectionSuccessRatio(): Float { if (connectionAttempts == 0) { return 0.0F - } - else if (connectionAttempts <= successfulConnections) { + } else if (connectionAttempts <= successfulConnections) { // Prevent bogus quality > 1 during initialisation return 1.0F } diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/ui/OmnipodDashOverviewFragment.kt b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/ui/OmnipodDashOverviewFragment.kt index fd0d3785e5..00a9cc6968 100644 --- a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/ui/OmnipodDashOverviewFragment.kt +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/ui/OmnipodDashOverviewFragment.kt @@ -32,8 +32,8 @@ import info.nightscout.androidaps.plugins.pump.omnipod.dash.databinding.OmnipodD import info.nightscout.androidaps.plugins.pump.omnipod.dash.databinding.OmnipodDashOverviewBluetoothStatusBinding import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition.ActivationProgress import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition.AlertType -import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.state.OmnipodDashPodStateManager import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition.PodConstants +import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.state.OmnipodDashPodStateManager import info.nightscout.androidaps.queue.Callback import info.nightscout.androidaps.queue.events.EventQueueChanged import info.nightscout.androidaps.utils.DateUtil diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/util/Flag.kt b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/util/Flag.kt index b059b10618..618815cbd1 100644 --- a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/util/Flag.kt +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/util/Flag.kt @@ -16,4 +16,4 @@ class Flag(var value: Int = 0) { } return 1 } -} \ No newline at end of file +} diff --git a/omnipod-dash/src/test/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/response/DefaultStatusResponseTest.kt b/omnipod-dash/src/test/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/response/DefaultStatusResponseTest.kt index 7d32ae3790..d2a14907e9 100644 --- a/omnipod-dash/src/test/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/response/DefaultStatusResponseTest.kt +++ b/omnipod-dash/src/test/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/response/DefaultStatusResponseTest.kt @@ -106,17 +106,17 @@ class DefaultStatusResponseTest { } /** response (hex) 1D990714201F0042ED8801DE - Status response: 29 - Pod status: RUNNING_BELOW_MIN_VOLUME - Basal active: true - Temp Basal active: false - Immediate bolus active: false - Extended bolus active: true - Bolus pulses remaining: 31 - sequence number of last programing command: 4 - Total full pulses delivered: 3624 - Full reservoir pulses remaining: 392 - Time since activation: 4283 + Status response: 29 + Pod status: RUNNING_BELOW_MIN_VOLUME + Basal active: true + Temp Basal active: false + Immediate bolus active: false + Extended bolus active: true + Bolus pulses remaining: 31 + sequence number of last programing command: 4 + Total full pulses delivered: 3624 + Full reservoir pulses remaining: 392 + Time since activation: 4283 */ @Test @Throws(DecoderException::class) fun testValidResponseReservoirPulsesRemaining() { val encoded = Hex.decodeHex("1D990714201F0042ED8801DE") @@ -136,17 +136,17 @@ class DefaultStatusResponseTest { } /** response (hex) 1d68002601f400002bff0368 - Status response: 29 - Pod status: RUNNING_BELOW_MIN_VOLUME - Basal active: true - Temp Basal active: false - Immediate bolus active: false - Extended bolus active: true - Bolus pulses remaining: 31 - sequence number of last programing command: 4 - Total full pulses delivered: 3624 - Full reservoir pulses remaining: 392 - Time since activation: 4283 + Status response: 29 + Pod status: RUNNING_BELOW_MIN_VOLUME + Basal active: true + Temp Basal active: false + Immediate bolus active: false + Extended bolus active: true + Bolus pulses remaining: 31 + sequence number of last programing command: 4 + Total full pulses delivered: 3624 + Full reservoir pulses remaining: 392 + Time since activation: 4283 */ @Test @Throws(DecoderException::class) fun testValidResponseBolusPulsesRemaining3() { val encoded = Hex.decodeHex("1d68002601f400002bff0368") @@ -157,17 +157,17 @@ class DefaultStatusResponseTest { Assert.assertEquals(0, response.activeAlerts.size) } /** response (hex) 1d28002e91e400002fff8256 - Status response: 29 - Pod status: RUNNING_BELOW_MIN_VOLUME - Basal active: true - Temp Basal active: false - Immediate bolus active: false - Extended bolus active: true - Bolus pulses remaining: 31 - sequence number of last programing command: 4 - Total full pulses delivered: 3624 - Full reservoir pulses remaining: 392 - Time since activation: 4283 + Status response: 29 + Pod status: RUNNING_BELOW_MIN_VOLUME + Basal active: true + Temp Basal active: false + Immediate bolus active: false + Extended bolus active: true + Bolus pulses remaining: 31 + sequence number of last programing command: 4 + Total full pulses delivered: 3624 + Full reservoir pulses remaining: 392 + Time since activation: 4283 */ @Test @Throws(DecoderException::class) fun testValidResponseBolusPulsesRemaining4() { val encoded = Hex.decodeHex("1d28002e91e400002fff8256")