enable beeps when delivery is suspended

This commit is contained in:
Andrei Vereha 2021-11-22 19:04:02 +01:00
parent ae573de63d
commit e903c9c055
12 changed files with 238 additions and 12 deletions

View file

@ -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"
}

View file

@ -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)
}
}

View file

@ -22,7 +22,7 @@ interface OmnipodDashManager {
fun setBasalProgram(basalProgram: BasalProgram, hasBasalBeepEnabled: Boolean): Observable<PodEvent>
fun suspendDelivery(hasBasalBeepEnabled: Boolean): Observable<PodEvent>
fun setTempBasal(rate: Double, durationInMinutes: Short, tempBasalBeeps: Boolean): Observable<PodEvent>
fun stopTempBasal(hasTempBasalBeepEnabled: Boolean): Observable<PodEvent>

View file

@ -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<PodEvent> {
return Observable.concat(
observePodRunning,
observeConnectToPod,
observeSendStopDeliveryCommand(StopDeliveryCommand.DeliveryType.ALL, hasBasalBeepEnabled)
).interceptPodEvents()
observeSuspendDeliveryCommand(hasBasalBeepEnabled)
).doOnComplete {
podStateManager.suspendAlertsEnabled = true
}.interceptPodEvents()
}
private fun observeSuspendDeliveryCommand(hasBasalBeepEnabled: Boolean): Observable<PodEvent> {
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<PodEvent> {

View file

@ -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 +

View file

@ -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<Builder, SuspendDeliveryCommand>() {
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
}
}

View file

@ -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
}

View file

@ -77,6 +77,7 @@ interface OmnipodDashPodStateManager {
var basalProgram: BasalProgram?
val activeCommand: ActiveCommand?
val lastBolus: LastBolus?
var suspendAlertsEnabled: Boolean
fun increaseMessageSequenceNumber()
fun increaseEapAkaSequenceNumber(): ByteArray

View file

@ -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

View file

@ -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
}

View file

@ -47,4 +47,6 @@
<string name="omnipod_common_history_tbr_value">Rate: %1$.2f U, duration: %2$d minutes</string>
<string name="omnipod_common_history_bolus_value">%1$.2f U</string>
<string name="dash_bolusdelivering">Delivering %1$.2f U</string>
<string name="omnipod_common_alert_delivery_suspended">Insulin delivery is suspended</string>
<string name="omnipod_common_alert_delivery_suspended2">Insulin delivery is suspended 2</string>
</resources>

View file

@ -85,7 +85,7 @@ class ProgramAlertsCommandTest {
false,
AlertTrigger.TimerTrigger(4079.toShort()),
BeepType.FOUR_TIMES_BIP_BEEP,
BeepRepetitionType.XXX2
BeepRepetitionType.EVERY_MINUTE
)
)