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 ae2f855ad2..2e54cd7f3d 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 @@ -1,6 +1,10 @@ package info.nightscout.androidaps.plugins.pump.omnipod.dash +import android.content.Context +import android.os.Handler +import android.os.Looper import dagger.android.HasAndroidInjector +import info.nightscout.androidaps.activities.ErrorHelperActivity.Companion.runAlarm import info.nightscout.androidaps.data.DetailedBolusInfo import info.nightscout.androidaps.data.PumpEnactResult import info.nightscout.androidaps.events.EventProfileSwitchChanged @@ -12,12 +16,15 @@ import info.nightscout.androidaps.plugins.bus.RxBusWrapper import info.nightscout.androidaps.plugins.common.ManufacturerType import info.nightscout.androidaps.plugins.general.actions.defs.CustomAction import info.nightscout.androidaps.plugins.general.actions.defs.CustomActionType +import info.nightscout.androidaps.plugins.general.overview.events.EventDismissNotification +import info.nightscout.androidaps.plugins.general.overview.events.EventNewNotification import info.nightscout.androidaps.plugins.general.overview.events.EventOverviewBolusProgress +import info.nightscout.androidaps.plugins.general.overview.notifications.Notification import info.nightscout.androidaps.plugins.pump.common.defs.PumpType +import info.nightscout.androidaps.plugins.pump.common.utils.DateTimeUtil import info.nightscout.androidaps.plugins.pump.omnipod.common.definition.OmnipodCommandType import info.nightscout.androidaps.plugins.pump.omnipod.common.queue.command.* import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.OmnipodDashManager -import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.OmnipodDashBleManager import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition.ActivationProgress import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition.BeepType import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition.DeliveryStatus @@ -36,7 +43,6 @@ import info.nightscout.androidaps.queue.commands.CustomCommand import info.nightscout.androidaps.utils.T import info.nightscout.androidaps.utils.TimeChangeType import info.nightscout.androidaps.utils.resources.ResourceHelper -import info.nightscout.androidaps.utils.rx.AapsSchedulers import info.nightscout.androidaps.utils.sharedPreferences.SP import io.reactivex.Completable import io.reactivex.Single @@ -56,11 +62,7 @@ class OmnipodDashPumpPlugin @Inject constructor( private val history: DashHistory, private val pumpSync: PumpSync, private val rxBus: RxBusWrapper, - private val aapsSchedulers: AapsSchedulers, - private val bleManager: OmnipodDashBleManager, - -// private val disposable: CompositeDisposable = CompositeDisposable(), - // private val aapsSchedulers: AapsSchedulers, + private val context: Context, injector: HasAndroidInjector, aapsLogger: AAPSLogger, @@ -68,10 +70,14 @@ class OmnipodDashPumpPlugin @Inject constructor( commandQueue: CommandQueueProvider ) : PumpPluginBase(pluginDescription, injector, aapsLogger, resourceHelper, commandQueue), Pump { @Volatile var bolusCanceled = false + private val handler: Handler = Handler(Looper.getMainLooper()) + lateinit private var statusChecker: Runnable + var nextPodWarningCheck : Long = 0 companion object { private const val BOLUS_RETRY_INTERVAL_MS = 2000.toLong() - private const val BOLUS_RETRIES = 5 // numer of retries for cancel/get bolus status + private const val BOLUS_RETRIES = 5 // number of retries for cancel/get bolus status + private const val STATUS_CHECK_INTERVAL_MS = (60L * 1000) private val pluginDescription = PluginDescription() .mainType(PluginType.PUMP) @@ -85,6 +91,52 @@ class OmnipodDashPumpPlugin @Inject constructor( private val pumpDescription = PumpDescription(PumpType.OMNIPOD_DASH) } + init { + statusChecker = Runnable { + refreshStatusOnUnacknowledgedCommands() + updatePodWarnings() + handler.postDelayed(statusChecker, STATUS_CHECK_INTERVAL_MS) + } + } + + private fun updatePodWarnings() { + if (System.currentTimeMillis() > nextPodWarningCheck) { + if (!podStateManager.isPodRunning) { + val notification = + Notification( + Notification.OMNIPOD_POD_NOT_ATTACHED, + "Pod not activated", + Notification.NORMAL + ) + rxBus.send(EventNewNotification(notification)) + } else { + rxBus.send(EventDismissNotification(Notification.OMNIPOD_POD_NOT_ATTACHED)) + if (podStateManager.isSuspended) { + val notification = + Notification( + Notification.OMNIPOD_POD_SUSPENDED, + "Insulin delivery suspended", + Notification.NORMAL + ) + rxBus.send(EventNewNotification(notification)) + } else { + rxBus.send(EventDismissNotification(Notification.OMNIPOD_POD_SUSPENDED)) + // TODO: time out of sync notification? + } + } + nextPodWarningCheck = DateTimeUtil.getTimeInFutureFromMinutes(15) + } + } + + private fun refreshStatusOnUnacknowledgedCommands() { + if (podStateManager.isPodRunning && + podStateManager.activeCommand != null && + commandQueue.size() == 0 && + commandQueue.performing() == null) { + commandQueue.readStatus("Unconfirmed command", null) + } + } + override fun isInitialized(): Boolean { // TODO return true @@ -130,12 +182,27 @@ class OmnipodDashPumpPlugin @Inject constructor( // TODO } + + override fun getPumpStatus(reason: String) { + aapsLogger.debug(LTag.PUMP, "getPumpStatus reason=$reason") + if (reason != "REQUESTED BY USER" && !podStateManager.isActivationCompleted) { + // prevent races on BLE when the pod is not activated + return + } + val throwable = getPodStatus().blockingGet() if (throwable != null) { aapsLogger.error(LTag.PUMP, "Error in getPumpStatus", throwable) } else { aapsLogger.info(LTag.PUMP, "getPumpStatus executed with success") + if (!podStateManager.isActivationCompleted) { + val msg = podStateManager.recoverActivationFromPodStatus() + msg?.let { + // TODO: show dialog with "try again, the pod is busy now" + aapsLogger.info(LTag.PUMP, "recoverActivationFromPodStatus msg=$msg") + } + } } } @@ -183,6 +250,12 @@ class OmnipodDashPumpPlugin @Inject constructor( aapsLogger.info(LTag.PUMP, "syncBolusWithPumpId on CANCEL_BOLUS returned: $sync") } } + showNotification( + Notification.OMNIPOD_POD_FAULT, + podStateManager.alarmType.toString(), + Notification.URGENT, + R.raw.boluserror + ) } Completable.complete() } @@ -191,21 +264,45 @@ class OmnipodDashPumpPlugin @Inject constructor( if (!podStateManager.isActivationCompleted) { return PumpEnactResult(injector).success(true).enacted(true) } + aapsLogger.debug(LTag.PUMP, "setNewBasalProfile profile=$profile") val basalProgram = mapProfileToBasalProgram(profile) + var deliverySuspended = false return executeProgrammingCommand( - pre = suspendDeliveryIfActive(), + pre = suspendDeliveryIfActive().doOnComplete { + if (podStateManager.activeCommand == null) { + // suspend delivery is confirmed + deliverySuspended = true + } + }, historyEntry = history.createRecord(commandType = OmnipodCommandType.SET_BASAL_PROFILE), activeCommandEntry = { historyId -> podStateManager.createActiveCommand(historyId, basalProgram = basalProgram) }, command = omnipodManager.setBasalProgram(basalProgram, hasBasalBeepEnabled()).ignoreElements(), - post = failWhenUnconfirmed(), + post = failWhenUnconfirmed(deliverySuspended), // mark as failed even if it worked OK and try again vs. mark ok and + // deny later ).toPumpEnactResult() } - private fun failWhenUnconfirmed(): Completable = Completable.defer { + private fun failWhenUnconfirmed(deliverySuspended: Boolean): Completable = Completable.defer { rxBus.send(EventTempBasalChange()) if (podStateManager.activeCommand != null) { + if (deliverySuspended) { + showNotification( + Notification.FAILED_UPDATE_PROFILE, + "Failed to set the new basal profile. Delivery suspended", + Notification.URGENT, + R.raw.boluserror + ) + } else { + showNotification( + Notification.FAILED_UPDATE_PROFILE, + "Setting basal profile might have failed. Delivery might be suspended!" + + " Please manually refresh the Pod status from the Omnipod tab and resume delivery if needed.", + Notification.URGENT, + R.raw.boluserror + ) + } Completable.error(java.lang.IllegalStateException("Command not confirmed")) } else { Completable.complete() @@ -229,15 +326,26 @@ class OmnipodDashPumpPlugin @Inject constructor( rxBus.send(EventTempBasalChange()) } .ignoreElements() - ) + ).doOnComplete { + notifyOnUnconfirmed( + Notification.FAILED_UPDATE_PROFILE, + "Suspend delivery is unconfirmed! " + + "Please manually refresh the Pod status from the Omnipod tab and resume delivery if needed.", + R.raw.boluserror, + ) + } } - /* override fun onStop() { - super.onStop() - disposable.clear() - } + override fun onStart() { + super.onStart() + podStateManager.onStart() + handler.postDelayed(statusChecker, STATUS_CHECK_INTERVAL_MS) + } - */ + override fun onStop() { + super.onStop() + handler.removeCallbacks(statusChecker) + } private fun observeDeliverySuspended(): Completable = Completable.defer { if (podStateManager.deliveryStatus == DeliveryStatus.SUSPENDED) @@ -351,7 +459,23 @@ class OmnipodDashPumpPlugin @Inject constructor( aapsLogger.info(LTag.PUMP, "deliverTreatment: deliveredBolusAmount=$deliveredBolusAmount") } .ignoreElement() - ).toSingleDefault( + ).doFinally { + if (detailedBolusInfo.bolusType == DetailedBolusInfo.BolusType.SMB) { + notifyOnUnconfirmed( + Notification.OMNIPOD_UNCERTAIN_SMB, + "Unable to verify whether SMB bolus ($requestedBolusAmount U) succeeded. " + + "Refresh pod status to confirm or deny this command.", + R.raw.boluserror + ) + } else { + if (podStateManager.activeCommand != null) { + showErrorDialog( + "Bolus delivery status uncertain. Refresh pod status to confirm or deny.", + R.raw.boluserror + ) + } + } + }.toSingleDefault( PumpEnactResult(injector).success(true).enacted(true).bolusDelivered(deliveredBolusAmount) ) .onErrorReturnItem( @@ -415,7 +539,10 @@ class OmnipodDashPumpPlugin @Inject constructor( continue } val percent = (waited.toFloat() / estimatedDeliveryTimeSeconds) * 100 - updateBolusProgressDialog(resourceHelper.gs(R.string.bolusdelivering, requestedBolusAmount), percent.toInt()) + updateBolusProgressDialog( + resourceHelper.gs(R.string.bolusdelivering, requestedBolusAmount), + percent.toInt() + ) } for (tryNumber in 1..maxTries) { @@ -508,8 +635,11 @@ class OmnipodDashPumpPlugin @Inject constructor( val tempBasalBeeps = hasTempBasalBeepEnabled() aapsLogger.info( LTag.PUMP, - "setTempBasalAbsolute: duration=$durationInMinutes min, rate=$absoluteRate U/h :: " + - "enforce=$enforceNew, tbrType=$tbrType" + "setTempBasalAbsolute: " + + "duration=$durationInMinutes min :: " + + "rate=$absoluteRate U/h :: " + + "enforce=$enforceNew ::" + + "tbrType=$tbrType" ) val ret = executeProgrammingCommand( @@ -536,7 +666,15 @@ class OmnipodDashPumpPlugin @Inject constructor( .filter { podEvent -> podEvent.isCommandSent() } .map { pumpSyncTempBasal(absoluteRate, durationInMinutes.toLong(), tbrType) } .ignoreElements(), - ).toPumpEnactResult() + ).doOnComplete { + notifyOnUnconfirmed( + Notification.OMNIPOD_TBR_ALERTS, + "Setting temp basal might have basal failed. If a temp basal was previously running, " + + "it has been cancelled. Please manually refresh the Pod status from the Omnipod tab.", + R.raw.boluserror, + ) + }.toPumpEnactResult() + if (ret.success && ret.enacted) { ret.isPercent(false).absolute(absoluteRate).duration(durationInMinutes) } @@ -557,7 +695,10 @@ class OmnipodDashPumpPlugin @Inject constructor( ) } val historyEntry = history.getById(activeCommand.historyId) - aapsLogger.debug(LTag.PUMP, "pumpSyncTempBasal: absoluteRate=$absoluteRate, durationInMinutes=$durationInMinutes") + aapsLogger.debug( + LTag.PUMP, + "pumpSyncTempBasal: absoluteRate=$absoluteRate, durationInMinutes=$durationInMinutes" + ) val ret = pumpSync.syncTemporaryBasalWithPumpId( timestamp = historyEntry.createdAt, rate = absoluteRate, @@ -595,7 +736,15 @@ class OmnipodDashPumpPlugin @Inject constructor( 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, + ) + } } } } @@ -638,7 +787,20 @@ class OmnipodDashPumpPlugin @Inject constructor( return executeProgrammingCommand( historyEntry = history.createRecord(OmnipodCommandType.CANCEL_TEMPORARY_BASAL), command = omnipodManager.stopTempBasal(hasTempBasalBeepEnabled()).ignoreElements(), - ).toPumpEnactResult() + ).doOnComplete { + notifyOnUnconfirmed( + Notification.OMNIPOD_TBR_ALERTS, + "Cancel temp basal result is uncertain", // TODO: i8n, + R.raw.boluserror, // TODO: add setting for this + ) + }.toPumpEnactResult() + } + + private fun notifyOnUnconfirmed(notificationId: Int, msg: String, sound: Int?) { + if (podStateManager.activeCommand != null) { + aapsLogger.debug(LTag.PUMP, "Notification for active command: ${podStateManager.activeCommand}") + showNotification(notificationId, msg, Notification.URGENT, sound) + } } private fun Completable.toPumpEnactResult(): PumpEnactResult { @@ -755,7 +917,13 @@ class OmnipodDashPumpPlugin @Inject constructor( } .ignoreElements(), pre = observeDeliveryActive(), - ).toPumpEnactResult() + ).doFinally { + notifyOnUnconfirmed( + Notification.PUMP_ERROR, + "Unconfirmed suspendDelivery command. Please refresh pod status", + R.raw.boluserror + ) + }.toPumpEnactResult() } private fun observeDeliveryActive(): Completable = Completable.defer { @@ -770,8 +938,15 @@ class OmnipodDashPumpPlugin @Inject constructor( executeProgrammingCommand( pre = observeDeliverySuspended(), historyEntry = history.createRecord(OmnipodCommandType.RESUME_DELIVERY), - command = omnipodManager.setBasalProgram(mapProfileToBasalProgram(it), hasBasalBeepEnabled()).ignoreElements() - ).toPumpEnactResult() + command = omnipodManager.setBasalProgram(mapProfileToBasalProgram(it), hasBasalBeepEnabled()) + .ignoreElements() + ).doFinally { + notifyOnUnconfirmed( + Notification.FAILED_UPDATE_PROFILE, + "Unconfirmed resumeDelivery command. Please refresh pod status", + R.raw.boluserror + ) + }.toPumpEnactResult() } ?: PumpEnactResult(injector).success(false).enacted(false).comment("No profile active") // TODO i18n } @@ -779,7 +954,10 @@ class OmnipodDashPumpPlugin @Inject constructor( val ret = executeProgrammingCommand( historyEntry = history.createRecord(OmnipodCommandType.DEACTIVATE_POD), command = omnipodManager.deactivatePod().ignoreElements() - ).toPumpEnactResult() + ).doOnComplete { + rxBus.send(EventDismissNotification(Notification.OMNIPOD_POD_FAULT)) + }.toPumpEnactResult() + if (podStateManager.activeCommand != null) { ret.success(false) } @@ -862,8 +1040,19 @@ class OmnipodDashPumpPlugin @Inject constructor( val historyEntry = history.getById(command.historyId) aapsLogger.debug(LTag.PUMPCOMM, "handling command confirmation: $confirmation") when (historyEntry.commandType) { - OmnipodCommandType.CANCEL_TEMPORARY_BASAL, - OmnipodCommandType.RESUME_DELIVERY -> + OmnipodCommandType.CANCEL_TEMPORARY_BASAL -> { + if (confirmation.success) { + pumpSync.syncStopTemporaryBasalWithPumpId( + historyEntry.createdAt, + historyEntry.pumpId(), + PumpType.OMNIPOD_DASH, + serialNumber() + ) + podStateManager.tempBasal = null + } + rxBus.send(EventDismissNotification(Notification.OMNIPOD_TBR_ALERTS)) + } + OmnipodCommandType.RESUME_DELIVERY -> { // We can't invalidate this command, // and this is why it is pumpSync-ed at this point if (confirmation.success) { @@ -874,7 +1063,10 @@ class OmnipodDashPumpPlugin @Inject constructor( serialNumber() ) podStateManager.tempBasal = null + rxBus.send(EventDismissNotification(Notification.OMNIPOD_POD_SUSPENDED)) } + rxBus.send(EventDismissNotification(Notification.OMNIPOD_TBR_ALERTS)) + } OmnipodCommandType.SET_BASAL_PROFILE -> { if (confirmation.success) { @@ -892,6 +1084,9 @@ class OmnipodDashPumpPlugin @Inject constructor( PumpType.OMNIPOD_DASH, serialNumber() ) + rxBus.send(EventDismissNotification(Notification.OMNIPOD_POD_SUSPENDED)) + rxBus.send(EventDismissNotification(Notification.FAILED_UPDATE_PROFILE)) + rxBus.send(EventDismissNotification(Notification.OMNIPOD_TBR_ALERTS)) } } @@ -907,11 +1102,16 @@ class OmnipodDashPumpPlugin @Inject constructor( } else { podStateManager.tempBasal = command.tempBasal } + rxBus.send(EventDismissNotification(Notification.OMNIPOD_TBR_ALERTS)) } OmnipodCommandType.SUSPEND_DELIVERY -> { if (!confirmation.success) { - pumpSync.invalidateTemporaryBasalWithPumpId(historyEntry.pumpId(), PumpType.OMNIPOD_DASH, serialNumber()) + pumpSync.invalidateTemporaryBasalWithPumpId( + historyEntry.pumpId(), + PumpType.OMNIPOD_DASH, + serialNumber() + ) } else { podStateManager.tempBasal = null } @@ -947,17 +1147,17 @@ class OmnipodDashPumpPlugin @Inject constructor( type = null // TODO: set the correct bolus type here!!! ) } + rxBus.send(EventDismissNotification(Notification.OMNIPOD_UNCERTAIN_SMB)) } OmnipodCommandType.CANCEL_BOLUS -> { if (confirmation.success) { - podStateManager.lastBolus?.run { val deliveredUnits = markComplete() val bolusHistoryEntry = history.getById(historyId) val sync = pumpSync.syncBolusWithPumpId( timestamp = bolusHistoryEntry.createdAt, - amount = deliveredUnits, // we just marked this bolus as complete + amount = deliveredUnits, pumpId = bolusHistoryEntry.pumpId(), pumpType = PumpType.OMNIPOD_DASH, pumpSerial = serialNumber(), @@ -976,4 +1176,26 @@ class OmnipodDashPumpPlugin @Inject constructor( ) } } + + private fun showErrorDialog(message: String, sound: Int) { + runAlarm(context, message, resourceHelper.gs(R.string.error), sound) + } + + private fun showNotification(id: Int, message: String, urgency: Int, sound: Int?) { + val notification = Notification( + id, + message, + urgency + ) + // TODO add back sound when we have options to disable it + /* + if (sound != null) { + notification.soundId = sound + }*/ + rxBus.send(EventNewNotification(notification)) + } + + private fun dismissNotification(id: Int) { + rxBus.send(EventDismissNotification(id)) + } } 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 78b778def9..487ecf2c6c 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 @@ -173,8 +173,7 @@ class OmnipodDashManagerImpl @Inject constructor( DefaultStatusResponse::class ) }.doOnComplete { - // TODO: remove podStateManager.basalProgram? - podStateManager.basalProgram = basalProgram + podStateManager.timeZone = TimeZone.getDefault() } } @@ -246,6 +245,7 @@ class OmnipodDashManagerImpl @Inject constructor( observeVerifyPrime.doOnComplete(ActivationProgressUpdater(ActivationProgress.PRIME_COMPLETED)) ) } + if (podStateManager.activationProgress.isBefore(ActivationProgress.PRIMING)) { observables.add(observeConnectToPod) // connection can time out while waiting observables.add( @@ -270,6 +270,7 @@ class OmnipodDashManagerImpl @Inject constructor( }.doOnComplete(ActivationProgressUpdater(ActivationProgress.PRIMING)) ) } + if (podStateManager.activationProgress.isBefore(ActivationProgress.REPROGRAMMED_LUMP_OF_COAL_ALERT)) { observables.add( observeSendProgramAlertsCommand( @@ -304,6 +305,7 @@ class OmnipodDashManagerImpl @Inject constructor( ).doOnComplete(ActivationProgressUpdater(ActivationProgress.PROGRAMMED_LOW_RESERVOIR_ALERTS)) ) } + if (podStateManager.activationProgress.isBefore(ActivationProgress.SET_UNIQUE_ID)) { observables.add( observeSendSetUniqueIdCommand.doOnComplete(ActivationProgressUpdater(ActivationProgress.SET_UNIQUE_ID)) diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/OmnipodDashBleManagerImpl.kt b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/OmnipodDashBleManagerImpl.kt index a01a3b985b..24885e70e2 100644 --- a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/OmnipodDashBleManagerImpl.kt +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/OmnipodDashBleManagerImpl.kt @@ -125,7 +125,7 @@ class OmnipodDashBleManagerImpl @Inject constructor( for (i in 1..MAX_NUMBER_OF_CONNECTION_ATTEMPTS) { try { // wait i * CONNECTION_TIMEOUT - conn.connect(i) + conn.connect(CONNECT_TIMEOUT_MULTIPLIER) break } catch (e: Exception) { aapsLogger.warn(LTag.PUMPBTCOMM, "connect error=$e") @@ -240,7 +240,8 @@ class OmnipodDashBleManagerImpl @Inject constructor( } companion object { - const val MAX_NUMBER_OF_CONNECTION_ATTEMPTS = 3 + const val MAX_NUMBER_OF_CONNECTION_ATTEMPTS = 2 const val CONTROLLER_ID = 4242 // TODO read from preferences or somewhere else. + private const val CONNECT_TIMEOUT_MULTIPLIER = 4 } } diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/ServiceDiscoverer.kt b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/ServiceDiscoverer.kt index 284b6d975d..664db805e0 100644 --- a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/ServiceDiscoverer.kt +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/ServiceDiscoverer.kt @@ -21,6 +21,7 @@ class ServiceDiscoverer( */ fun discoverServices(): Map { logger.debug(LTag.PUMPBTCOMM, "Discovering services") + bleCallbacks.startServiceDiscovery() val discover = gatt.discoverServices() if (!discover) { throw ConnectException("Could not start discovering services`") diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/callbacks/BleCommCallbacks.kt b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/callbacks/BleCommCallbacks.kt index de2fceafe9..3d4d3d1339 100644 --- a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/callbacks/BleCommCallbacks.kt +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/callbacks/BleCommCallbacks.kt @@ -61,6 +61,10 @@ class BleCommCallbacks( } } + fun startServiceDiscovery() { + serviceDiscoveryComplete = CountDownLatch(1) + } + fun waitForServiceDiscovery(timeoutMs: Int) { try { serviceDiscoveryComplete.await(timeoutMs.toLong(), TimeUnit.MILLISECONDS) diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/session/ConnectionStateChangeHandler.kt b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/session/ConnectionStateChangeHandler.kt new file mode 100644 index 0000000000..8396850d70 --- /dev/null +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/session/ConnectionStateChangeHandler.kt @@ -0,0 +1,6 @@ +package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.session + +interface ConnectionStateChangeHandler { + + fun onConnectionStateChange(status: Int, newState: Int) +} diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/state/OmnipodDashPodStateManager.kt b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/state/OmnipodDashPodStateManager.kt index 7fe5a8dfe9..ebf81c8de9 100644 --- a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/state/OmnipodDashPodStateManager.kt +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/state/OmnipodDashPodStateManager.kt @@ -13,6 +13,9 @@ import io.reactivex.Completable import io.reactivex.Maybe import io.reactivex.Observable import io.reactivex.Single +import org.joda.time.DateTime +import org.joda.time.DateTimeZone +import org.joda.time.Duration import java.io.Serializable import java.util.* @@ -33,8 +36,12 @@ interface OmnipodDashPodStateManager { val isPodKaput: Boolean var bluetoothConnectionState: BluetoothConnectionState + var timeZone: TimeZone val lastUpdatedSystem: Long // System.currentTimeMillis() val lastStatusResponseReceived: Long + val time: DateTime? + val timeDrift: Duration? + val expiry: DateTime? val messageSequenceNumber: Short val sequenceNumberOfLastProgrammingCommand: Short? @@ -90,6 +97,13 @@ interface OmnipodDashPodStateManager { fun createLastBolus(requestedUnits: Double, historyId: String, bolusType: DetailedBolusInfo.BolusType) fun markLastBolusComplete(): LastBolus? + fun onStart() + /* + This is called only:. It overwrites activationStatus + - when activation was interrupted(application crash, killed, etc) + - after getPodStatus was successful(we have an up-to-date podStatus) + */ + fun recoverActivationFromPodStatus(): String? data class ActiveCommand( val sequence: Short, 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 34404ab09e..ed2e9d88d4 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 @@ -22,6 +22,9 @@ import io.reactivex.Completable import io.reactivex.Maybe import io.reactivex.Observable import io.reactivex.Single +import org.joda.time.DateTime +import org.joda.time.DateTimeZone +import org.joda.time.Duration import java.io.Serializable import java.util.* import javax.inject.Inject @@ -97,6 +100,13 @@ class OmnipodDashPodStateManagerImpl @Inject constructor( } } + override var timeZone: TimeZone + get() = TimeZone.getTimeZone(podState.timeZone) + set(tz) { + podState.timeZone = tz.getDisplayName(true, TimeZone.SHORT) + store() + } + override val bluetoothVersion: SoftwareVersion? get() = podState.bleVersion @@ -173,6 +183,34 @@ class OmnipodDashPodStateManagerImpl @Inject constructor( override val lastStatusResponseReceived: Long get() = podState.lastStatusResponseReceived + override val time: DateTime? + get() { + val minutesSinceActivation = podState.minutesSinceActivation + val activationTime = podState.activationTime + if ((activationTime != null) && (minutesSinceActivation != null)) { + return DateTime(activationTime) + .plusMinutes(minutesSinceActivation.toInt()) + .plus(Duration(podState.lastUpdatedSystem, System.currentTimeMillis())) + } + return null + } + + override val timeDrift: Duration? + get() { + return Duration(DateTime.now(), time) + } + + override val expiry: DateTime? + // TODO: Consider storing expiry datetime in pod state saving continuously recalculating to the same value + get() { + val podLifeInHours = podLifeInHours + val activationTime = podState.activationTime + if (podLifeInHours != null && activationTime != null) { + return DateTime(podState.activationTime).plusHours(podLifeInHours.toInt()) + } + return null + } + override var bluetoothConnectionState: OmnipodDashPodStateManager.BluetoothConnectionState get() = podState.bluetoothConnectionState set(bluetoothConnectionState) { @@ -286,6 +324,29 @@ class OmnipodDashPodStateManagerImpl @Inject constructor( } } + override fun recoverActivationFromPodStatus(): String? { + val newActivationProgress = when (podState.podStatus) { + PodStatus.FILLED -> + ActivationProgress.NOT_STARTED + PodStatus.UID_SET -> + ActivationProgress.SET_UNIQUE_ID + PodStatus.ENGAGING_CLUTCH_DRIVE, PodStatus.PRIMING -> + return "Busy" + PodStatus.CLUTCH_DRIVE_ENGAGED -> + ActivationProgress.PRIME_COMPLETED + PodStatus.BASAL_PROGRAM_SET -> + ActivationProgress.PROGRAMMED_BASAL + PodStatus.RUNNING_ABOVE_MIN_VOLUME, PodStatus.RUNNING_BELOW_MIN_VOLUME -> + ActivationProgress.CANNULA_INSERTED + else -> + null + } + newActivationProgress?.let { + podState.activationProgress = it + } + return null + } + @Synchronized override fun updateActiveCommand() = Maybe.create { source -> val activeCommand = podState.activeCommand @@ -365,6 +426,32 @@ class OmnipodDashPodStateManagerImpl @Inject constructor( store() } + override fun onStart() { + when (getCommandConfirmationFromState()) { + CommandConfirmationSuccess, CommandConfirmationDenied -> { + val now = System.currentTimeMillis() + val newCommand = podState.activeCommand?.copy( + createdRealtime = now, + sentRealtime = now + 1 + ) + podState.lastStatusResponseReceived = now + 2 + podState.activeCommand = newCommand + } + + CommandSendingNotConfirmed -> { + val now = System.currentTimeMillis() + val newCommand = podState.activeCommand?.copy( + createdRealtime = now, + sentRealtime = now + 1 + ) + podState.lastStatusResponseReceived = 0 + } + + CommandSendingFailure, NoActiveCommand -> + podState.activeCommand = null + } + } + override fun updateFromDefaultStatusResponse(response: DefaultStatusResponse) { logger.debug(LTag.PUMPCOMM, "Default status response :$response") podState.deliveryStatus = response.deliveryStatus @@ -380,6 +467,9 @@ class OmnipodDashPodStateManagerImpl @Inject constructor( podState.lastUpdatedSystem = System.currentTimeMillis() podState.lastStatusResponseReceived = SystemClock.elapsedRealtime() updateLastBolusFromResponse(response.bolusPulsesRemaining) + if (podState.activationTime == null) { + podState.activationTime = System.currentTimeMillis() - (response.minutesSinceActivation * 60_000) + } store() rxBus.send(EventOmnipodDashPumpValuesChanged()) @@ -428,12 +518,6 @@ class OmnipodDashPodStateManagerImpl @Inject constructor( podState.uniqueId = response.uniqueIdReceivedInCommand podState.lastUpdatedSystem = System.currentTimeMillis() - // TODO: what is considered to be the pod activation time? - // LTK negotiation ? - // setUniqueId? - // compute it from the number of "minutesOnPod"? - podState.activationTime = System.currentTimeMillis() - store() rxBus.send(EventOmnipodDashPumpValuesChanged()) } @@ -514,6 +598,7 @@ class OmnipodDashPodStateManagerImpl @Inject constructor( var ltk: ByteArray? = null var eapAkaSequenceNumber: Long = 1 var bolusPulsesRemaining: Short = 0 + var timeZone: String = "" // TimeZone ID (e.g. "Europe/Amsterdam") var bleVersion: SoftwareVersion? = null var firmwareVersion: SoftwareVersion? = null diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/ui/DashPodManagementActivity.kt b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/ui/DashPodManagementActivity.kt index a293e04b74..3d89be5da8 100644 --- a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/ui/DashPodManagementActivity.kt +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/ui/DashPodManagementActivity.kt @@ -125,8 +125,8 @@ class DashPodManagementActivity : NoSplashAppCompatActivity() { binding.buttonActivatePod.isEnabled = podStateManager.activationProgress.isBefore(ActivationProgress.COMPLETED) binding.buttonDeactivatePod.isEnabled = - podStateManager.activationProgress.isAtLeast(ActivationProgress.PHASE_1_COMPLETED) || - podStateManager.podStatus == PodStatus.ALARM + podStateManager.ltk != null || + podStateManager.podStatus == PodStatus.ALARM if (podStateManager.activationProgress.isAtLeast(ActivationProgress.PHASE_1_COMPLETED)) { if (commandQueue.isCustomCommandInQueue(CommandPlayTestBeep::class.java)) { 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 6531f461f7..59e90ef7dc 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 @@ -45,7 +45,6 @@ import io.reactivex.disposables.CompositeDisposable import io.reactivex.rxkotlin.plusAssign import org.apache.commons.lang3.StringUtils import org.joda.time.DateTime -import org.joda.time.DateTimeZone import org.joda.time.Duration import java.util.* import javax.inject.Inject @@ -69,6 +68,7 @@ class OmnipodDashOverviewFragment : DaggerFragment() { private const val REFRESH_INTERVAL_MILLIS = 15 * 1000L // 15 seconds private const val PLACEHOLDER = "-" + private const val MAX_TIME_DEVIATION_MINUTES = 10L } private var disposables: CompositeDisposable = CompositeDisposable() @@ -236,29 +236,6 @@ class OmnipodDashOverviewFragment : DaggerFragment() { } } - // Get time on pos from activation time and minutes since activation - private fun getTimeOnPod(): DateTime? { - var timeOnPod: DateTime? = null - val minutesSinceActivation = podStateManager.minutesSinceActivation - val activationTime = podStateManager.activationTime - if ((activationTime != null) and (minutesSinceActivation != null)) { - timeOnPod = DateTime(activationTime!!).plusMinutes(minutesSinceActivation!!.toInt()) - } - return timeOnPod - } - - // TODO: Consider storing expiry datetime in pod state saving continuesly recalculating to the same value - private fun getExpiryAt(): DateTime? { - var expiresAt: DateTime? = null - val podLifeInHours = podStateManager.podLifeInHours - val minutesSinceActivation = podStateManager.minutesSinceActivation - if ((podLifeInHours != null) and (minutesSinceActivation != null)) { - val expiresInMinutes = (podLifeInHours!! * 60) - minutesSinceActivation!! - expiresAt = DateTime().plusMinutes(expiresInMinutes) - } - return expiresAt - } - private fun updateOmnipodStatus() { updateLastConnection() updateLastBolus() @@ -291,52 +268,36 @@ class OmnipodDashOverviewFragment : DaggerFragment() { ) // Update time on Pod - // TODO: For now: derive from podStateManager.minutesSinceActivation - val timeOnPod = getTimeOnPod() - if (timeOnPod == null) { - podInfoBinding.timeOnPod.text = "???" - } else { - podInfoBinding.timeOnPod.text = readableZonedTime(timeOnPod) - } + podInfoBinding.timeOnPod.text = podStateManager.time?.let { + readableZonedTime(it) + } ?: PLACEHOLDER - // TODO - /* - podInfoBinding.timeOnPod.setTextColor(if (podStateManager.timeDeviatesMoreThan(OmnipodConstants.TIME_DEVIATION_THRESHOLD)) { - Color.RED - } else { - Color.WHITE - }) - */ - - // TODO: Active command - if (podStateManager.activeCommand != null) { - podInfoBinding.podExpiryDate.setTextColor(Color.RED) - podInfoBinding.podExpiryDate.text = "Active command" - } else { - podInfoBinding.podExpiryDate.text = PLACEHOLDER - podInfoBinding.podExpiryDate.setTextColor(Color.WHITE) - } + podInfoBinding.timeOnPod.setTextColor( + podStateManager.timeDrift?.let { + if (it.abs().isLongerThan(Duration.standardMinutes(MAX_TIME_DEVIATION_MINUTES))) { + Color.RED + } else { + Color.WHITE + } + } ?: Color.WHITE + ) // Update Pod expiry time - val expiresAt = getExpiryAt() - if (expiresAt is Nothing) { + val expiresAt = podStateManager.expiry + if (expiresAt == null) { podInfoBinding.podExpiryDate.text = PLACEHOLDER podInfoBinding.podExpiryDate.setTextColor(Color.WHITE) } else { - podInfoBinding.podExpiryDate.text = readableZonedTime(expiresAt!!) - podInfoBinding.podExpiryDate.setTextColor(if (DateTime.now().isAfter(expiresAt)) { - Color.RED - } else { - Color.WHITE - }) + podInfoBinding.podExpiryDate.text = readableZonedTime(expiresAt) + podInfoBinding.podExpiryDate.setTextColor( + if (DateTime.now().isAfter(expiresAt)) { + Color.RED + } else { + Color.WHITE + } + ) } - /* TODO - if (podStateManager.isPodFaulted) { - val faultEventCode = podStateManager.faultEventCode - errors.add(resourceHelper.gs(R.string.omnipod_common_pod_status_pod_fault_description, faultEventCode.value, faultEventCode.name)) - } - */ podStateManager.alarmType?.let { errors.add( resourceHelper.gs( @@ -425,9 +386,7 @@ class OmnipodDashOverviewFragment : DaggerFragment() { podInfoBinding.lastConnection.setTextColor(lastConnectionColor) } else { podInfoBinding.lastConnection.setTextColor(Color.WHITE) - podInfoBinding.lastConnection.text = readableDuration( - Duration(podStateManager.lastUpdatedSystem, System.currentTimeMillis()) - ) + podInfoBinding.lastConnection.text = PLACEHOLDER } } @@ -564,7 +523,6 @@ class OmnipodDashOverviewFragment : DaggerFragment() { private fun updateRefreshStatusButton() { buttonBinding.buttonRefreshStatus.isEnabled = podStateManager.isUniqueIdSet && - podStateManager.activationProgress.isAtLeast(ActivationProgress.PHASE_1_COMPLETED) && isQueueEmpty() } @@ -625,7 +583,6 @@ class OmnipodDashOverviewFragment : DaggerFragment() { } private fun isSuspendDeliveryButtonEnabled(): Boolean { - R.string.key_omnipod_common_basal_beeps_enabled return sp.getBoolean(R.string.key_omnipod_common_suspend_delivery_button_enabled, false) } @@ -643,25 +600,41 @@ class OmnipodDashOverviewFragment : DaggerFragment() { } } - private fun getTimeZone(): DateTimeZone { - // TODO: Get timezone as configured/podState - // return getSafe(() -> podState.getTimeZone()); - return DateTimeZone.getDefault() + // private fun getTimeZone(): DateTimeZone { + // // return getSafe(() -> podState.getTimeZone()); + // return podStateManager.timeZone + // } + private fun getTimeZone(): TimeZone { + // Return timezone ID (e.g "Europe/Amsterdam") + return podStateManager.timeZone } private fun readableZonedTime(time: DateTime): String { val timeAsJavaData = time.toLocalDateTime().toDate() + return dateUtil.dateAndTimeString(timeAsJavaData.time) - val timeZone = getTimeZone().toTimeZone() - if (timeZone == TimeZone.getDefault()) { - return dateUtil.dateAndTimeString(timeAsJavaData.time) - } - - // Get full timezoned time - val isDaylightTime = timeZone.inDaylightTime(timeAsJavaData) - val locale = resources.configuration.locales.get(0) - val timeZoneDisplayName = timeZone.getDisplayName(isDaylightTime, TimeZone.SHORT, locale) + " " + timeZone.getDisplayName(isDaylightTime, TimeZone.LONG, locale) - return resourceHelper.gs(R.string.omnipod_common_time_with_timezone, dateUtil.dateAndTimeString(timeAsJavaData.time), timeZoneDisplayName) + // // TODO: Handle timeZone ID + // val timeZone = getTimeZone() + // if (timeZone == "") { + // // No timezone defined, use local time (default) + // return dateUtil.dateAndTimeString(timeAsJavaData.time) + // } + // else { + // // Get full timezoned time + // val isDaylightTime = timeZone.inDaylightTime(timeAsJavaData) + // val locale = resources.configuration.locales.get(0) + // val timeZoneDisplayName = + // timeZone.getDisplayName(isDaylightTime, TimeZone.SHORT, locale) + " " + timeZone.getDisplayName( + // isDaylightTime, + // TimeZone.LONG, + // locale + // ) + // return resourceHelper.gs( + // R.string.omnipod_common_time_with_timezone, + // dateUtil.dateAndTimeString(timeAsJavaData.time), + // timeZoneDisplayName + // ) + // } } private fun readableDuration(duration: Duration): String { diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/ui/wizard/activation/viewmodel/action/DashInsertCannulaViewModel.kt b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/ui/wizard/activation/viewmodel/action/DashInsertCannulaViewModel.kt index c7bc85a539..143fb8fb91 100644 --- a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/ui/wizard/activation/viewmodel/action/DashInsertCannulaViewModel.kt +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/ui/wizard/activation/viewmodel/action/DashInsertCannulaViewModel.kt @@ -2,13 +2,17 @@ package info.nightscout.androidaps.plugins.pump.omnipod.dash.ui.wizard.activatio import androidx.annotation.StringRes import dagger.android.HasAndroidInjector +import info.nightscout.androidaps.data.DetailedBolusInfo import info.nightscout.androidaps.data.PumpEnactResult import info.nightscout.androidaps.interfaces.ProfileFunction +import info.nightscout.androidaps.interfaces.PumpSync import info.nightscout.androidaps.logging.AAPSLogger import info.nightscout.androidaps.logging.LTag +import info.nightscout.androidaps.plugins.pump.common.defs.PumpType import info.nightscout.androidaps.plugins.pump.omnipod.common.ui.wizard.activation.viewmodel.action.InsertCannulaViewModel import info.nightscout.androidaps.plugins.pump.omnipod.dash.R import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.OmnipodDashManager +import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.state.OmnipodDashPodStateManager import info.nightscout.androidaps.plugins.pump.omnipod.dash.util.mapProfileToBasalProgram import io.reactivex.Single import io.reactivex.rxkotlin.subscribeBy @@ -17,6 +21,8 @@ import javax.inject.Inject class DashInsertCannulaViewModel @Inject constructor( private val omnipodManager: OmnipodDashManager, private val profileFunction: ProfileFunction, + private val pumpSync: PumpSync, + private val podStateManager: OmnipodDashPodStateManager, injector: HasAndroidInjector, logger: AAPSLogger ) : InsertCannulaViewModel(injector, logger) { @@ -52,6 +58,19 @@ class DashInsertCannulaViewModel @Inject constructor( }, onComplete = { logger.debug("Pod activation part 2 completed") + pumpSync.connectNewPump() + pumpSync.insertTherapyEventIfNewWithTimestamp( + timestamp = System.currentTimeMillis(), + type = DetailedBolusInfo.EventType.CANNULA_CHANGE, + pumpType = PumpType.OMNIPOD_DASH, + pumpSerial = podStateManager.uniqueId?.toString() ?: "n/a" + ) + pumpSync.insertTherapyEventIfNewWithTimestamp( + timestamp = System.currentTimeMillis(), + type = DetailedBolusInfo.EventType.INSULIN_CHANGE, + pumpType = PumpType.OMNIPOD_DASH, + pumpSerial = podStateManager.uniqueId?.toString() ?: "n/a" + ) source.onSuccess(PumpEnactResult(injector).success(true)) } ) diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/ui/wizard/deactivation/viewmodel/action/DashDeactivatePodViewModel.kt b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/ui/wizard/deactivation/viewmodel/action/DashDeactivatePodViewModel.kt index e7508214b6..c3507e5f1d 100644 --- a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/ui/wizard/deactivation/viewmodel/action/DashDeactivatePodViewModel.kt +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/ui/wizard/deactivation/viewmodel/action/DashDeactivatePodViewModel.kt @@ -5,6 +5,9 @@ import dagger.android.HasAndroidInjector import info.nightscout.androidaps.data.PumpEnactResult import info.nightscout.androidaps.interfaces.CommandQueueProvider import info.nightscout.androidaps.logging.AAPSLogger +import info.nightscout.androidaps.plugins.bus.RxBusWrapper +import info.nightscout.androidaps.plugins.general.overview.events.EventDismissNotification +import info.nightscout.androidaps.plugins.general.overview.notifications.Notification import info.nightscout.androidaps.plugins.pump.omnipod.common.R import info.nightscout.androidaps.plugins.pump.omnipod.common.queue.command.CommandDeactivatePod import info.nightscout.androidaps.plugins.pump.omnipod.common.ui.wizard.deactivation.viewmodel.action.DeactivatePodViewModel @@ -16,6 +19,7 @@ import javax.inject.Inject class DashDeactivatePodViewModel @Inject constructor( private val podStateManager: OmnipodDashPodStateManager, private val commandQueueProvider: CommandQueueProvider, + private val rxBus: RxBusWrapper, injector: HasAndroidInjector, logger: AAPSLogger ) : DeactivatePodViewModel(injector, logger) { @@ -33,6 +37,7 @@ class DashDeactivatePodViewModel @Inject constructor( override fun discardPod() { podStateManager.reset() + rxBus.send(EventDismissNotification(Notification.OMNIPOD_POD_FAULT)) } @StringRes diff --git a/wear/build.gradle b/wear/build.gradle index b18138cb08..237d585dfc 100644 --- a/wear/build.gradle +++ b/wear/build.gradle @@ -150,7 +150,7 @@ dependencies { } testImplementation "org.skyscreamer:jsonassert:1.5.0" testImplementation "org.hamcrest:hamcrest-all:1.3" - implementation "androidx.core:core-ktx:+" + implementation "androidx.core:core-ktx:$coreVersion" implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" } repositories {