From e903c9c055d162de91224574ccd21d56a633bf03 Mon Sep 17 00:00:00 2001 From: Andrei Vereha Date: Mon, 22 Nov 2021 19:04:02 +0100 Subject: [PATCH] enable beeps when delivery is suspended --- .../command/CommandDisableSuspendAlerts.kt | 9 ++ .../omnipod/dash/OmnipodDashPumpPlugin.kt | 53 +++++++- .../omnipod/dash/driver/OmnipodDashManager.kt | 2 +- .../dash/driver/OmnipodDashManagerImpl.kt | 28 +++- .../pod/command/ProgramAlertsCommand.kt | 12 ++ .../pod/command/SuspendDeliveryCommand.kt | 125 ++++++++++++++++++ .../pod/definition/BeepRepetitionType.kt | 4 +- .../pod/state/OmnipodDashPodStateManager.kt | 1 + .../state/OmnipodDashPodStateManagerImpl.kt | 8 ++ .../dash/ui/OmnipodDashOverviewFragment.kt | 4 + omnipod-dash/src/main/res/values/strings.xml | 2 + .../pod/command/ProgramAlertsCommandTest.kt | 2 +- 12 files changed, 238 insertions(+), 12 deletions(-) create mode 100644 omnipod-common/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/common/queue/command/CommandDisableSuspendAlerts.kt create mode 100644 omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/SuspendDeliveryCommand.kt diff --git a/omnipod-common/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/common/queue/command/CommandDisableSuspendAlerts.kt b/omnipod-common/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/common/queue/command/CommandDisableSuspendAlerts.kt new file mode 100644 index 0000000000..384c115d27 --- /dev/null +++ b/omnipod-common/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/common/queue/command/CommandDisableSuspendAlerts.kt @@ -0,0 +1,9 @@ +package info.nightscout.androidaps.plugins.pump.omnipod.common.queue.command + +import info.nightscout.androidaps.queue.commands.CustomCommand + +class CommandDisableSuspendAlerts: CustomCommand { + + override val statusDescription: String + get() = "DISABLE SUSPEND ALERTS" +} 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 1baa37737e..ec66db8f4f 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 @@ -502,7 +502,10 @@ class OmnipodDashPumpPlugin @Inject constructor( // prevent setBasal requests return true } - // TODO: what do we have to answer here if delivery is suspended? + if (podStateManager.isSuspended) { + // set new basal profile failed midway + return false + } val running = podStateManager.basalProgram val equal = (mapProfileToBasalProgram(profile) == running) aapsLogger.info(LTag.PUMP, "set: $equal. profile=$profile, running=$running") @@ -1101,7 +1104,8 @@ class OmnipodDashPumpPlugin @Inject constructor( updateAlertConfiguration() is CommandPlayTestBeep -> playTestBeep() - + is CommandDisableSuspendAlerts -> + disableSuspendAlerts() else -> { aapsLogger.warn(LTag.PUMP, "Unsupported custom command: " + customCommand.javaClass.name) PumpEnactResult(injector).success(false).enacted(false).comment( @@ -1114,6 +1118,7 @@ class OmnipodDashPumpPlugin @Inject constructor( } } + private fun silenceAlerts(): PumpEnactResult { // TODO filter alert types return podStateManager.activeAlerts?.let { @@ -1124,6 +1129,41 @@ class OmnipodDashPumpPlugin @Inject constructor( } ?: PumpEnactResult(injector).success(false).enacted(false).comment("No active alerts") // TODO i18n } + private fun disableSuspendAlerts(): PumpEnactResult { + val alerts = listOf( + AlertConfiguration( + AlertType.SUSPEND_IN_PROGRESS, + enabled = false, + durationInMinutes = 0, + autoOff = false, + AlertTrigger.TimerTrigger( + 0 + ), + BeepType.XXX, + BeepRepetitionType.XXX4 + ), + AlertConfiguration( + AlertType.SUSPEND_ENDED, + enabled = false, + durationInMinutes = 0, + autoOff = false, + AlertTrigger.TimerTrigger( + 0 + ), + BeepType.FOUR_TIMES_BIP_BEEP, + BeepRepetitionType.EVERY_MINUTE + ), + ) + val ret = executeProgrammingCommand( + historyEntry = history.createRecord(OmnipodCommandType.CONFIGURE_ALERTS), + command = omnipodManager.programAlerts(alerts).ignoreElements(), + ).toPumpEnactResult() + if (ret.success && ret.enacted) { + podStateManager.suspendAlertsEnabled = false + } + return ret + } + private fun suspendDelivery(): PumpEnactResult { return executeProgrammingCommand( historyEntry = history.createRecord(OmnipodCommandType.SUSPEND_DELIVERY), @@ -1249,7 +1289,7 @@ class OmnipodDashPumpPlugin @Inject constructor( expiryAlertDelay.toMinutes().toShort() ), BeepType.FOUR_TIMES_BIP_BEEP, - BeepRepetitionType.XXX2 + BeepRepetitionType.EVERY_MINUTE ) ) return executeProgrammingCommand( @@ -1369,9 +1409,11 @@ class OmnipodDashPumpPlugin @Inject constructor( ) podStateManager.tempBasal = null rxBus.send(EventDismissNotification(Notification.OMNIPOD_POD_SUSPENDED)) + rxBus.send(EventDismissNotification(Notification.FAILED_UPDATE_PROFILE)) + rxBus.send(EventDismissNotification(Notification.OMNIPOD_TBR_ALERTS)) + rxBus.send(EventDismissNotification(Notification.OMNIPOD_TIME_OUT_OF_SYNC)) + commandQueue.customCommand(CommandDisableSuspendAlerts(), null) } - rxBus.send(EventDismissNotification(Notification.OMNIPOD_TBR_ALERTS)) - rxBus.send(EventDismissNotification(Notification.OMNIPOD_TIME_OUT_OF_SYNC)) } OmnipodCommandType.SET_BASAL_PROFILE -> { @@ -1394,6 +1436,7 @@ class OmnipodDashPumpPlugin @Inject constructor( rxBus.send(EventDismissNotification(Notification.FAILED_UPDATE_PROFILE)) rxBus.send(EventDismissNotification(Notification.OMNIPOD_TBR_ALERTS)) rxBus.send(EventDismissNotification(Notification.OMNIPOD_TIME_OUT_OF_SYNC)) + commandQueue.customCommand(CommandDisableSuspendAlerts(), null) } } diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/OmnipodDashManager.kt b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/OmnipodDashManager.kt index 4f3f682892..d20c790159 100644 --- a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/OmnipodDashManager.kt +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/OmnipodDashManager.kt @@ -22,7 +22,7 @@ interface OmnipodDashManager { fun setBasalProgram(basalProgram: BasalProgram, hasBasalBeepEnabled: Boolean): Observable fun suspendDelivery(hasBasalBeepEnabled: Boolean): Observable - + fun setTempBasal(rate: Double, durationInMinutes: Short, tempBasalBeeps: Boolean): Observable fun stopTempBasal(hasTempBasalBeepEnabled: Boolean): Observable 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 0d62eb9a68..fc1502d074 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 @@ -437,7 +437,7 @@ class OmnipodDashManagerImpl @Inject constructor( userExpiryAlertDelay.toMinutes().toShort() ), BeepType.FOUR_TIMES_BIP_BEEP, - BeepRepetitionType.XXX2 + BeepRepetitionType.EVERY_MINUTE ) ) } @@ -498,12 +498,34 @@ class OmnipodDashManagerImpl @Inject constructor( } } + override fun suspendDelivery(hasBasalBeepEnabled: Boolean): Observable { return Observable.concat( observePodRunning, observeConnectToPod, - observeSendStopDeliveryCommand(StopDeliveryCommand.DeliveryType.ALL, hasBasalBeepEnabled) - ).interceptPodEvents() + observeSuspendDeliveryCommand(hasBasalBeepEnabled) + ).doOnComplete { + podStateManager.suspendAlertsEnabled = true + }.interceptPodEvents() + } + + private fun observeSuspendDeliveryCommand(hasBasalBeepEnabled: Boolean): Observable { + return Observable.defer { + val beepType = if (!hasBasalBeepEnabled) + BeepType.SILENT + else + BeepType.LONG_SINGLE_BEEP + + bleManager.sendCommand( + SuspendDeliveryCommand.Builder() + .setSequenceNumber(podStateManager.messageSequenceNumber) + .setUniqueId(podStateManager.uniqueId!!.toInt()) + .setNonce(NONCE) + .setBeepType(beepType) + .build(), + DefaultStatusResponse::class + ) + } } private fun observeSendProgramTempBasalCommand(rate: Double, durationInMinutes: Short, tempBasalBeeps: Boolean): Observable { diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/ProgramAlertsCommand.kt b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/ProgramAlertsCommand.kt index b13ed65498..21b041b953 100644 --- a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/ProgramAlertsCommand.kt +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/ProgramAlertsCommand.kt @@ -38,6 +38,18 @@ class ProgramAlertsCommand private constructor( return appendCrc(byteBuffer.array()) } + val encodedWithoutHeaderAndCRC32: ByteArray + get() { + val byteBuffer: ByteBuffer = ByteBuffer.allocate(getLength().toInt()) + .put(commandType.value) + .put(getBodyLength()) + .putInt(nonce) + for (configuration in alertConfigurations) { + byteBuffer.put(configuration.encoded) + } + return byteBuffer.array() + } + override fun toString(): String { return "ProgramAlertsCommand{" + "alertConfigurations=" + alertConfigurations + diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/SuspendDeliveryCommand.kt b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/SuspendDeliveryCommand.kt new file mode 100644 index 0000000000..df7a847b25 --- /dev/null +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/SuspendDeliveryCommand.kt @@ -0,0 +1,125 @@ +package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command + +import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.base.CommandType +import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.base.NonceEnabledCommand +import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.base.builder.NonceEnabledCommandBuilder +import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition.* +import java.nio.ByteBuffer +import java.util.* + +// StopDelivery.ALL followed by ProgramAlerts +class SuspendDeliveryCommand private constructor( + uniqueId: Int, + sequenceNumber: Short, + multiCommandFlag: Boolean, + private val beepType: BeepType, + nonce: Int +) : NonceEnabledCommand(CommandType.STOP_DELIVERY, uniqueId, sequenceNumber, multiCommandFlag, nonce) { + + override val encoded: ByteArray + get() { + val alerts = listOf( + AlertConfiguration( + AlertType.SUSPEND_IN_PROGRESS, + enabled = true, + durationInMinutes = 10, + autoOff = false, + AlertTrigger.TimerTrigger( + 1 + ), + BeepType.XXX, + BeepRepetitionType.XXX4 + ), + AlertConfiguration( + AlertType.SUSPEND_ENDED, + enabled = true, + durationInMinutes = 0, + autoOff = false, + AlertTrigger.TimerTrigger( + 10 + ), + BeepType.FOUR_TIMES_BIP_BEEP, + BeepRepetitionType.EVERY_MINUTE + ), + ) + val programAlerts = ProgramAlertsCommand.Builder() + .setNonce(nonce) + .setUniqueId(uniqueId) + .setAlertConfigurations(alerts) + .setSequenceNumber(sequenceNumber) + .setMultiCommandFlag(false) + .build() + .encodedWithoutHeaderAndCRC32 + + val byteBuffer = ByteBuffer.allocate(LENGTH + HEADER_LENGTH + programAlerts.size) + .put(encodeHeader(uniqueId, sequenceNumber, (LENGTH + programAlerts.size).toShort(), multiCommandFlag)) + .put(commandType.value) + .put(BODY_LENGTH) + .putInt(nonce) + .put((beepType.value.toInt() shl 4 or DeliveryType.ALL.encoded[0].toInt()).toByte()) + .put(programAlerts) + .array() + + return appendCrc( + byteBuffer + ) + } + + override fun toString(): String { + return "SuspendDeliveryCommand{" + + "deliveryType=" + DeliveryType.ALL + + ", beepType=" + beepType + + ", nonce=" + nonce + + ", commandType=" + commandType + + ", uniqueId=" + uniqueId + + ", sequenceNumber=" + sequenceNumber + + ", multiCommandFlag=" + multiCommandFlag + + '}' + } + + enum class DeliveryType( + private val basal: Boolean, + private val tempBasal: Boolean, + private val bolus: Boolean + ) : Encodable { + + BASAL(true, false, false), TEMP_BASAL(false, true, false), BOLUS(false, false, true), ALL(true, true, true); + + override val encoded: ByteArray + get() { + val bitSet = BitSet(8) + bitSet[0] = basal + bitSet[1] = tempBasal + bitSet[2] = bolus + return bitSet.toByteArray() + } + } + + class Builder : NonceEnabledCommandBuilder() { + private var beepType: BeepType? = BeepType.LONG_SINGLE_BEEP + + fun setBeepType(beepType: BeepType): Builder { + this.beepType = beepType + return this + } + + override fun buildCommand(): SuspendDeliveryCommand { + requireNotNull(beepType) { "beepType can not be null" } + + return SuspendDeliveryCommand( + uniqueId!!, + sequenceNumber!!, + multiCommandFlag, + beepType!!, + nonce!! + ) + } + } + + companion object { + + private const val LENGTH: Short = 7 + private const val BODY_LENGTH: Byte = 5 + } + +} \ No newline at end of file diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/definition/BeepRepetitionType.kt b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/definition/BeepRepetitionType.kt index cf668aa036..514dc1e874 100644 --- a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/definition/BeepRepetitionType.kt +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/definition/BeepRepetitionType.kt @@ -6,8 +6,8 @@ enum class BeepRepetitionType( ) { XXX(0x01.toByte()), // Used in lump of coal alert, LOW_RESERVOIR - XXX2(0x03.toByte()), // Used in USER_SET_EXPIRATION + EVERY_MINUTE(0x03.toByte()), // Used in USER_SET_EXPIRATION, suspend delivery XXX3(0x05.toByte()), // published system expiration alert - XXX4(0x06.toByte()), // Used in imminent pod expiration alert, suspend in progress + XXX4(0x06.toByte()), // Used in imminent pod expiration alert, suspend in progress. No repeat? XXX5(0x08.toByte()); // Lump of coal alert } 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 fa38444317..c3efc76604 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 @@ -77,6 +77,7 @@ interface OmnipodDashPodStateManager { var basalProgram: BasalProgram? val activeCommand: ActiveCommand? val lastBolus: LastBolus? + var suspendAlertsEnabled: Boolean fun increaseMessageSequenceNumber() fun increaseEapAkaSequenceNumber(): ByteArray 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 41d26e3e94..040d2a7df4 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 @@ -224,6 +224,13 @@ class OmnipodDashPodStateManagerImpl @Inject constructor( store() } + override var suspendAlertsEnabled: Boolean + get() = podState.suspendAlertsEnabled + set(enabled) { + podState.suspendAlertsEnabled = enabled + store() + } + override val lastStatusResponseReceived: Long get() = podState.lastStatusResponseReceived @@ -713,6 +720,7 @@ class OmnipodDashPodStateManagerImpl @Inject constructor( var timeZoneOffset: Int? = null var timeZoneUpdated: Long? = null var alarmSynced: Boolean = false + var suspendAlertsEnabled: Boolean = false var bleVersion: SoftwareVersion? = null var firmwareVersion: SoftwareVersion? = null 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 e7c5917015..4900b51eb2 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 @@ -439,6 +439,10 @@ class OmnipodDashOverviewFragment : DaggerFragment() { R.string.omnipod_common_alert_expiration_advisory AlertType.AUTO_OFF -> R.string.omnipod_common_alert_shutdown_imminent + AlertType.SUSPEND_IN_PROGRESS -> + R.string.omnipod_common_alert_delivery_suspended + AlertType.SUSPEND_ENDED -> + R.string.omnipod_common_alert_delivery_suspended2 else -> R.string.omnipod_common_alert_unknown_alert } diff --git a/omnipod-dash/src/main/res/values/strings.xml b/omnipod-dash/src/main/res/values/strings.xml index 607f6ebdc5..4e5953a980 100644 --- a/omnipod-dash/src/main/res/values/strings.xml +++ b/omnipod-dash/src/main/res/values/strings.xml @@ -47,4 +47,6 @@ Rate: %1$.2f U, duration: %2$d minutes %1$.2f U Delivering %1$.2f U + Insulin delivery is suspended + Insulin delivery is suspended 2 diff --git a/omnipod-dash/src/test/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/ProgramAlertsCommandTest.kt b/omnipod-dash/src/test/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/ProgramAlertsCommandTest.kt index ebd52957b2..3cbea38f9a 100644 --- a/omnipod-dash/src/test/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/ProgramAlertsCommandTest.kt +++ b/omnipod-dash/src/test/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/ProgramAlertsCommandTest.kt @@ -85,7 +85,7 @@ class ProgramAlertsCommandTest { false, AlertTrigger.TimerTrigger(4079.toShort()), BeepType.FOUR_TIMES_BIP_BEEP, - BeepRepetitionType.XXX2 + BeepRepetitionType.EVERY_MINUTE ) )