Dash: Add option to disable pod expiration alarm

This commit is contained in:
jbr7rr 2023-08-24 11:05:40 +02:00
parent a7d330e87f
commit 512541b484
9 changed files with 199 additions and 70 deletions

View file

@ -9,6 +9,8 @@
<string name="key_omnipod_common_time_change_event_enabled" translatable="false">AAPS.Omnipod.time_change_enabled</string> <string name="key_omnipod_common_time_change_event_enabled" translatable="false">AAPS.Omnipod.time_change_enabled</string>
<string name="key_omnipod_common_expiration_reminder_enabled" translatable="false">AAPS.Omnipod.expiration_reminder_enabled</string> <string name="key_omnipod_common_expiration_reminder_enabled" translatable="false">AAPS.Omnipod.expiration_reminder_enabled</string>
<string name="key_omnipod_common_expiration_reminder_hours_before_shutdown" translatable="false">AAPS.Omnipod.expiration_reminder_hours_before_shutdown</string> <string name="key_omnipod_common_expiration_reminder_hours_before_shutdown" translatable="false">AAPS.Omnipod.expiration_reminder_hours_before_shutdown</string>
<string name="key_omnipod_common_expiration_alarm_enabled" translatable="false">AAPS.Omnipod.expiration_alarm_enabled</string>
<string name="key_omnipod_common_expiration_alarm_hours_before_shutdown" translatable="false">AAPS.Omnipod.expiration_alarm_hours_before_shutdown</string>
<string name="key_omnipod_common_low_reservoir_alert_enabled" translatable="false">AAPS.Omnipod.low_reservoir_alert_enabled</string> <string name="key_omnipod_common_low_reservoir_alert_enabled" translatable="false">AAPS.Omnipod.low_reservoir_alert_enabled</string>
<string name="key_omnipod_common_low_reservoir_alert_units" translatable="false">AAPS.Omnipod.low_reservoir_alert_units</string> <string name="key_omnipod_common_low_reservoir_alert_units" translatable="false">AAPS.Omnipod.low_reservoir_alert_units</string>
<string name="key_omnipod_common_automatically_silence_alerts_enabled" translatable="false">AAPS.Omnipod.automatically_acknowledge_alerts_enabled</string> <string name="key_omnipod_common_automatically_silence_alerts_enabled" translatable="false">AAPS.Omnipod.automatically_acknowledge_alerts_enabled</string>
@ -129,7 +131,9 @@
<string name="omnipod_common_preferences_suspend_delivery_button_enabled">Show Suspend Delivery button in Omnipod tab</string> <string name="omnipod_common_preferences_suspend_delivery_button_enabled">Show Suspend Delivery button in Omnipod tab</string>
<string name="omnipod_common_preferences_time_change_enabled">DST/Time zone detection enabled</string> <string name="omnipod_common_preferences_time_change_enabled">DST/Time zone detection enabled</string>
<string name="omnipod_common_preferences_expiration_reminder_enabled">Expiration reminder enabled</string> <string name="omnipod_common_preferences_expiration_reminder_enabled">Expiration reminder enabled</string>
<string name="omnipod_common_preferences_expiration_reminder_hours_before_shutdown">Hours before shutdown</string> <string name="omnipod_common_preferences_expiration_reminder_hours_before_shutdown">Reminder at hours before shutdown</string>
<string name="omnipod_common_preferences_expiration_alarm_enabled">Expiration alarm enabled</string>
<string name="omnipod_common_preferences_expiration_alarm_hours_before_shutdown">Alarm at hours before shutdown</string>
<string name="omnipod_common_preferences_low_reservoir_alert_enabled">Low reservoir alert enabled</string> <string name="omnipod_common_preferences_low_reservoir_alert_enabled">Low reservoir alert enabled</string>
<string name="omnipod_common_preferences_low_reservoir_alert_units">Number of units</string> <string name="omnipod_common_preferences_low_reservoir_alert_units">Number of units</string>
<string name="omnipod_common_preferences_automatically_silence_alerts">Automatically silence Pod alerts</string> <string name="omnipod_common_preferences_automatically_silence_alerts">Automatically silence Pod alerts</string>

View file

@ -22,6 +22,7 @@ import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definitio
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition.BeepType import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition.BeepType
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition.DeliveryStatus import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition.DeliveryStatus
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition.PodConstants import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition.PodConstants
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition.PodConstants.Companion.POD_EXPIRATION_IMMINENT_ALERT_HOURS_REMAINING
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.response.ResponseType import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.response.ResponseType
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.state.CommandConfirmed import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.state.CommandConfirmed
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.state.OmnipodDashPodStateManager import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.state.OmnipodDashPodStateManager
@ -84,6 +85,7 @@ import java.time.Duration
import java.time.ZonedDateTime import java.time.ZonedDateTime
import java.util.Date import java.util.Date
import java.util.concurrent.CountDownLatch import java.util.concurrent.CountDownLatch
import java.util.concurrent.TimeUnit
import javax.inject.Inject import javax.inject.Inject
import javax.inject.Singleton import javax.inject.Singleton
import kotlin.concurrent.thread import kotlin.concurrent.thread
@ -481,6 +483,8 @@ class OmnipodDashPumpPlugin @Inject constructor(
{ {
if (it.isChanged(rh.gs(info.nightscout.androidaps.plugins.pump.omnipod.common.R.string.key_omnipod_common_expiration_reminder_enabled)) || if (it.isChanged(rh.gs(info.nightscout.androidaps.plugins.pump.omnipod.common.R.string.key_omnipod_common_expiration_reminder_enabled)) ||
it.isChanged(rh.gs(info.nightscout.androidaps.plugins.pump.omnipod.common.R.string.key_omnipod_common_expiration_reminder_hours_before_shutdown)) || it.isChanged(rh.gs(info.nightscout.androidaps.plugins.pump.omnipod.common.R.string.key_omnipod_common_expiration_reminder_hours_before_shutdown)) ||
it.isChanged(rh.gs(info.nightscout.androidaps.plugins.pump.omnipod.common.R.string.key_omnipod_common_expiration_alarm_enabled)) ||
it.isChanged(rh.gs(info.nightscout.androidaps.plugins.pump.omnipod.common.R.string.key_omnipod_common_expiration_alarm_hours_before_shutdown)) ||
it.isChanged(rh.gs(info.nightscout.androidaps.plugins.pump.omnipod.common.R.string.key_omnipod_common_low_reservoir_alert_enabled)) || it.isChanged(rh.gs(info.nightscout.androidaps.plugins.pump.omnipod.common.R.string.key_omnipod_common_low_reservoir_alert_enabled)) ||
it.isChanged(rh.gs(info.nightscout.androidaps.plugins.pump.omnipod.common.R.string.key_omnipod_common_low_reservoir_alert_units)) it.isChanged(rh.gs(info.nightscout.androidaps.plugins.pump.omnipod.common.R.string.key_omnipod_common_low_reservoir_alert_units))
) { ) {
@ -1102,16 +1106,22 @@ class OmnipodDashPumpPlugin @Inject constructor(
return when (customCommand) { return when (customCommand) {
is CommandSilenceAlerts -> is CommandSilenceAlerts ->
silenceAlerts() silenceAlerts()
is CommandResumeDelivery -> is CommandResumeDelivery ->
resumeDelivery() resumeDelivery()
is CommandDeactivatePod -> is CommandDeactivatePod ->
deactivatePod() deactivatePod()
is CommandHandleTimeChange -> is CommandHandleTimeChange ->
handleTimeChange() handleTimeChange()
is CommandUpdateAlertConfiguration -> is CommandUpdateAlertConfiguration ->
updateAlertConfiguration() updateAlertConfiguration()
is CommandPlayTestBeep -> is CommandPlayTestBeep ->
playTestBeep() playTestBeep()
is CommandDisableSuspendAlerts -> is CommandDisableSuspendAlerts ->
disableSuspendAlerts() disableSuspendAlerts()
@ -1214,14 +1224,18 @@ class OmnipodDashPumpPlugin @Inject constructor(
private fun updateAlertConfiguration(): PumpEnactResult { private fun updateAlertConfiguration(): PumpEnactResult {
val expirationReminderEnabled = sp.getBoolean(info.nightscout.androidaps.plugins.pump.omnipod.common.R.string.key_omnipod_common_expiration_reminder_enabled, true) val expirationReminderEnabled = sp.getBoolean(info.nightscout.androidaps.plugins.pump.omnipod.common.R.string.key_omnipod_common_expiration_reminder_enabled, true)
val expirationHours = sp.getInt(info.nightscout.androidaps.plugins.pump.omnipod.common.R.string.key_omnipod_common_expiration_reminder_hours_before_shutdown, 7) val expirationReminderHours = sp.getInt(info.nightscout.androidaps.plugins.pump.omnipod.common.R.string.key_omnipod_common_expiration_reminder_hours_before_shutdown, 7)
val expirationAlarmEnabled = sp.getBoolean(info.nightscout.androidaps.plugins.pump.omnipod.common.R.string.key_omnipod_common_expiration_alarm_enabled, true)
val expirationAlarmHours = sp.getInt(info.nightscout.androidaps.plugins.pump.omnipod.common.R.string.key_omnipod_common_expiration_alarm_hours_before_shutdown, 8)
val lowReservoirAlertEnabled = sp.getBoolean(info.nightscout.androidaps.plugins.pump.omnipod.common.R.string.key_omnipod_common_low_reservoir_alert_enabled, true) val lowReservoirAlertEnabled = sp.getBoolean(info.nightscout.androidaps.plugins.pump.omnipod.common.R.string.key_omnipod_common_low_reservoir_alert_enabled, true)
val lowReservoirAlertUnits = sp.getInt(info.nightscout.androidaps.plugins.pump.omnipod.common.R.string.key_omnipod_common_low_reservoir_alert_units, 10) val lowReservoirAlertUnits = sp.getInt(info.nightscout.androidaps.plugins.pump.omnipod.common.R.string.key_omnipod_common_low_reservoir_alert_units, 10)
when { when {
podStateManager.sameAlertSettings( podStateManager.sameAlertSettings(
expirationReminderEnabled, expirationReminderEnabled,
expirationHours, expirationReminderHours,
expirationAlarmEnabled,
expirationAlarmHours,
lowReservoirAlertEnabled, lowReservoirAlertEnabled,
lowReservoirAlertUnits lowReservoirAlertUnits
) -> { ) -> {
@ -1236,7 +1250,7 @@ class OmnipodDashPumpPlugin @Inject constructor(
} }
val podLifeLeft = Duration.between(ZonedDateTime.now(), podStateManager.expiry) val podLifeLeft = Duration.between(ZonedDateTime.now(), podStateManager.expiry)
val expiryAlertDelay = podLifeLeft.minus(Duration.ofHours(expirationHours.toLong())) val expiryAlertDelay = podLifeLeft.minus(Duration.ofHours(expirationReminderHours.toLong()))
if (expiryAlertDelay.isNegative) { if (expiryAlertDelay.isNegative) {
aapsLogger.warn( aapsLogger.warn(
LTag.PUMPBTCOMM, LTag.PUMPBTCOMM,
@ -1245,6 +1259,24 @@ class OmnipodDashPumpPlugin @Inject constructor(
) )
PumpEnactResult(injector).success(false).enacted(false) PumpEnactResult(injector).success(false).enacted(false)
} }
val expiryAlarmDelay = podLifeLeft.minus(Duration.ofHours(expirationAlarmHours.toLong()))
if (expiryAlarmDelay.isNegative) {
aapsLogger.warn(
LTag.PUMPBTCOMM,
"updateAlertConfiguration negative " +
"expiryAlarmDuration=$expiryAlarmDelay"
)
PumpEnactResult(injector).success(false).enacted(false)
}
val expiryImminentDelay = podLifeLeft.minus(Duration.ofHours(POD_EXPIRATION_IMMINENT_ALERT_HOURS_REMAINING))
if (expiryImminentDelay.isNegative) {
aapsLogger.warn(
LTag.PUMPBTCOMM,
"updateAlertConfiguration negative " +
"expiryImminentDuration=$expiryImminentDelay"
)
PumpEnactResult(injector).success(false).enacted(false)
}
val alerts = listOf( val alerts = listOf(
AlertConfiguration( AlertConfiguration(
AlertType.LOW_RESERVOIR, AlertType.LOW_RESERVOIR,
@ -1265,14 +1297,39 @@ class OmnipodDashPumpPlugin @Inject constructor(
), ),
BeepType.FOUR_TIMES_BIP_BEEP, BeepType.FOUR_TIMES_BIP_BEEP,
BeepRepetitionType.EVERY_MINUTE_AND_EVERY_15_MIN BeepRepetitionType.EVERY_MINUTE_AND_EVERY_15_MIN
),
AlertConfiguration(
AlertType.EXPIRATION,
enabled = expirationAlarmEnabled,
durationInMinutes = TimeUnit.HOURS.toMinutes(expirationAlarmHours.toLong()).toShort(),
autoOff = false,
AlertTrigger.TimerTrigger(
expiryAlarmDelay.toMinutes().toShort()
),
BeepType.FOUR_TIMES_BIP_BEEP,
BeepRepetitionType.XXX3
),
AlertConfiguration(
AlertType.EXPIRATION_IMMINENT,
enabled = expirationAlarmEnabled,
durationInMinutes = 0,
autoOff = false,
AlertTrigger.TimerTrigger(
expiryImminentDelay.toMinutes().toShort()
),
BeepType.FOUR_TIMES_BIP_BEEP,
BeepRepetitionType.XXX3
) )
) )
return executeProgrammingCommand( return executeProgrammingCommand(
historyEntry = history.createRecord(OmnipodCommandType.CONFIGURE_ALERTS), historyEntry = history.createRecord(OmnipodCommandType.CONFIGURE_ALERTS),
command = omnipodManager.programAlerts(alerts).ignoreElements(), command = omnipodManager.programAlerts(alerts).ignoreElements(),
post = podStateManager.updateExpirationAlertSettings( post = podStateManager.updateExpirationAlertSettings(
expirationReminderEnabled, expirationReminderEnabled,
expirationHours expirationReminderHours,
expirationAlarmEnabled,
expirationAlarmHours
).andThen( ).andThen(
podStateManager.updateLowReservoirAlertSettings( podStateManager.updateLowReservoirAlertSettings(
lowReservoirAlertEnabled, lowReservoirAlertEnabled,
@ -1513,10 +1570,10 @@ class OmnipodDashPumpPlugin @Inject constructor(
// Cancel TBR running on Pump // Cancel TBR running on Pump
return@defer observeNoActiveTempBasal() return@defer observeNoActiveTempBasal()
.concatWith(podStateManager.updateActiveCommand() .concatWith(podStateManager.updateActiveCommand()
.map { handleCommandConfirmation(it) } .map { handleCommandConfirmation(it) }
.ignoreElement()) .ignoreElement())
} }
return@defer Completable.complete() return@defer Completable.complete()
} }
@ -1537,10 +1594,13 @@ class OmnipodDashPumpPlugin @Inject constructor(
return when (notificationType) { return when (notificationType) {
Notification.OMNIPOD_TBR_ALERTS -> Notification.OMNIPOD_TBR_ALERTS ->
sp.getBoolean(info.nightscout.androidaps.plugins.pump.omnipod.common.R.string.key_omnipod_common_notification_uncertain_tbr_sound_enabled, true) sp.getBoolean(info.nightscout.androidaps.plugins.pump.omnipod.common.R.string.key_omnipod_common_notification_uncertain_tbr_sound_enabled, true)
Notification.OMNIPOD_UNCERTAIN_SMB -> Notification.OMNIPOD_UNCERTAIN_SMB ->
sp.getBoolean(info.nightscout.androidaps.plugins.pump.omnipod.common.R.string.key_omnipod_common_notification_uncertain_smb_sound_enabled, true) sp.getBoolean(info.nightscout.androidaps.plugins.pump.omnipod.common.R.string.key_omnipod_common_notification_uncertain_smb_sound_enabled, true)
Notification.OMNIPOD_POD_SUSPENDED -> Notification.OMNIPOD_POD_SUSPENDED ->
sp.getBoolean(R.string.key_omnipod_common_notification_delivery_suspended_sound_enabled, true) sp.getBoolean(R.string.key_omnipod_common_notification_delivery_suspended_sound_enabled, true)
else -> true else -> true
} }
} }

View file

@ -15,7 +15,7 @@ interface OmnipodDashManager {
fun activatePodPart1(lowReservoirAlertTrigger: AlertTrigger.ReservoirVolumeTrigger?): Observable<PodEvent> fun activatePodPart1(lowReservoirAlertTrigger: AlertTrigger.ReservoirVolumeTrigger?): Observable<PodEvent>
fun activatePodPart2(basalProgram: BasalProgram, userConfiguredExpirationHours: Long?): Observable<PodEvent> fun activatePodPart2(basalProgram: BasalProgram, userConfiguredExpirationReminderHours: Long?, userConfiguredExpirationAlarmHours: Long?): Observable<PodEvent>
fun getStatus(type: ResponseType.StatusResponseType): Observable<PodEvent> fun getStatus(type: ResponseType.StatusResponseType): Observable<PodEvent>

View file

@ -23,11 +23,9 @@ import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definitio
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition.BasalProgram import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition.BasalProgram
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition.BeepRepetitionType import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition.BeepRepetitionType
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition.BeepType import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition.BeepType
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition.PodConstants
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.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_REMAINING_DEFAULT
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_REMAINING
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_PULSE_BOLUS_UNITS import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition.PodConstants.Companion.POD_PULSE_BOLUS_UNITS
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition.PodStatus import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition.PodStatus
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition.ProgramReminder import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition.ProgramReminder
@ -161,9 +159,9 @@ class OmnipodDashManagerImpl @Inject constructor(
// TODO move somewhere else // TODO move somewhere else
val expectedResponseType = when (type) { val expectedResponseType = when (type) {
ResponseType.StatusResponseType.DEFAULT_STATUS_RESPONSE -> DefaultStatusResponse::class ResponseType.StatusResponseType.DEFAULT_STATUS_RESPONSE -> DefaultStatusResponse::class
ResponseType.StatusResponseType.ALARM_STATUS -> AlarmStatusResponse::class ResponseType.StatusResponseType.ALARM_STATUS -> AlarmStatusResponse::class
else -> return Observable.error(UnsupportedOperationException("No response type to class mapping for ${type.name}")) else -> return Observable.error(UnsupportedOperationException("No response type to class mapping for ${type.name}"))
} }
return Observable.defer { return Observable.defer {
@ -368,19 +366,19 @@ class OmnipodDashManagerImpl @Inject constructor(
return observables.reversed() return observables.reversed()
} }
override fun activatePodPart2(basalProgram: BasalProgram, userConfiguredExpirationHours: Long?): override fun activatePodPart2(basalProgram: BasalProgram, userConfiguredExpirationReminderHours: Long?, userConfiguredExpirationAlarmHours: Long?):
Observable<PodEvent> { Observable<PodEvent> {
return Observable.concat( return Observable.concat(
observePodReadyForActivationPart2, observePodReadyForActivationPart2,
observeConnectToPod, observeConnectToPod,
observeActivationPart2Commands(basalProgram, userConfiguredExpirationHours) observeActivationPart2Commands(basalProgram, userConfiguredExpirationReminderHours, userConfiguredExpirationAlarmHours)
).doOnComplete(ActivationProgressUpdater(ActivationProgress.COMPLETED)) ).doOnComplete(ActivationProgressUpdater(ActivationProgress.COMPLETED))
.interceptPodEvents() .interceptPodEvents()
} }
private fun observeActivationPart2Commands(basalProgram: BasalProgram, userConfiguredExpirationHours: Long?): private fun observeActivationPart2Commands(basalProgram: BasalProgram, userConfiguredExpirationReminderHours: Long?, userConfiguredExpirationAlarmHours: Long?):
Observable<PodEvent> { Observable<PodEvent> {
val observables = createActivationPart2Observables(basalProgram, userConfiguredExpirationHours) val observables = createActivationPart2Observables(basalProgram, userConfiguredExpirationReminderHours, userConfiguredExpirationAlarmHours)
return if (observables.isEmpty()) { return if (observables.isEmpty()) {
Observable.empty() Observable.empty()
@ -391,7 +389,8 @@ class OmnipodDashManagerImpl @Inject constructor(
private fun createActivationPart2Observables( private fun createActivationPart2Observables(
basalProgram: BasalProgram, basalProgram: BasalProgram,
userConfiguredExpirationHours: Long? userConfiguredExpirationReminderHours: Long?,
userConfiguredExpirationAlarmHours: Long?
): ):
List<Observable<PodEvent>> { List<Observable<PodEvent>> {
val observables = ArrayList<Observable<PodEvent>>() val observables = ArrayList<Observable<PodEvent>>()
@ -422,32 +421,42 @@ class OmnipodDashManagerImpl @Inject constructor(
if (podStateManager.activationProgress.isBefore(ActivationProgress.UPDATED_EXPIRATION_ALERTS)) { if (podStateManager.activationProgress.isBefore(ActivationProgress.UPDATED_EXPIRATION_ALERTS)) {
val podLifeLeft = Duration.between(ZonedDateTime.now(), podStateManager.expiry) val podLifeLeft = Duration.between(ZonedDateTime.now(), podStateManager.expiry)
val expirationAlarmEnabled = userConfiguredExpirationAlarmHours != null && userConfiguredExpirationAlarmHours > 0
val expirationAlarmDelay = podLifeLeft.minus(
Duration.ofHours(userConfiguredExpirationAlarmHours ?: POD_EXPIRATION_ALERT_HOURS_REMAINING_DEFAULT)
)
val expirationImminnentDelay = podLifeLeft.minus(
Duration.ofHours(POD_EXPIRATION_IMMINENT_ALERT_HOURS_REMAINING)
)
val alerts = mutableListOf( val alerts = mutableListOf(
AlertConfiguration( AlertConfiguration(
AlertType.EXPIRATION, AlertType.EXPIRATION,
enabled = true, enabled = expirationAlarmEnabled,
durationInMinutes = TimeUnit.HOURS.toMinutes(POD_EXPIRATION_ALERT_HOURS_DURATION).toShort(), durationInMinutes = TimeUnit.HOURS.toMinutes(
userConfiguredExpirationAlarmHours ?: POD_EXPIRATION_ALERT_HOURS_REMAINING_DEFAULT
).toShort(),
autoOff = false, autoOff = false,
AlertTrigger.TimerTrigger( AlertTrigger.TimerTrigger(
TimeUnit.HOURS.toMinutes(POD_EXPIRATION_ALERT_HOURS).toShort() expirationAlarmDelay.toMinutes().toShort()
), // FIXME use activation time ),
BeepType.FOUR_TIMES_BIP_BEEP, BeepType.FOUR_TIMES_BIP_BEEP,
BeepRepetitionType.XXX3 BeepRepetitionType.XXX3
), ),
AlertConfiguration( AlertConfiguration(
AlertType.EXPIRATION_IMMINENT, AlertType.EXPIRATION_IMMINENT,
enabled = true, enabled = expirationAlarmEnabled,
durationInMinutes = 0, durationInMinutes = 0,
autoOff = false, autoOff = false,
AlertTrigger.TimerTrigger( AlertTrigger.TimerTrigger(
TimeUnit.HOURS.toMinutes(POD_EXPIRATION_IMMINENT_ALERT_HOURS).toShort() expirationImminnentDelay.toMinutes().toShort()
), // FIXME use activation time ),
BeepType.FOUR_TIMES_BIP_BEEP, BeepType.FOUR_TIMES_BIP_BEEP,
BeepRepetitionType.XXX4 BeepRepetitionType.XXX4
) )
) )
val userExpiryAlertDelay = podLifeLeft.minus( val userExpiryAlertDelay = podLifeLeft.minus(
Duration.ofHours(userConfiguredExpirationHours ?: MAX_POD_LIFETIME.toHours() + 1) Duration.ofHours(userConfiguredExpirationReminderHours ?: MAX_POD_LIFETIME.toHours() + 1)
) )
if (userExpiryAlertDelay.isNegative) { if (userExpiryAlertDelay.isNegative) {
logger.warn( logger.warn(
@ -693,16 +702,16 @@ class OmnipodDashManagerImpl @Inject constructor(
logger.debug(LTag.PUMP, "Intercepted PodEvent in OmnipodDashManagerImpl: ${event.javaClass.simpleName}") logger.debug(LTag.PUMP, "Intercepted PodEvent in OmnipodDashManagerImpl: ${event.javaClass.simpleName}")
when (event) { when (event) {
is PodEvent.AlreadyConnected -> { is PodEvent.AlreadyConnected -> {
} }
is PodEvent.BluetoothConnected -> { is PodEvent.BluetoothConnected -> {
} }
is PodEvent.Connected -> { is PodEvent.Connected -> {
} }
is PodEvent.CommandSent -> { is PodEvent.CommandSent -> {
logger.debug(LTag.PUMP, "Command sent: ${event.command.commandType}") logger.debug(LTag.PUMP, "Command sent: ${event.command.commandType}")
podStateManager.activeCommand?.let { podStateManager.activeCommand?.let {
if (it.sequence == event.command.sequenceNumber) { if (it.sequence == event.command.sequenceNumber) {
@ -721,16 +730,16 @@ class OmnipodDashManagerImpl @Inject constructor(
podStateManager.increaseMessageSequenceNumber() podStateManager.increaseMessageSequenceNumber()
} }
is PodEvent.ResponseReceived -> { is PodEvent.ResponseReceived -> {
podStateManager.increaseMessageSequenceNumber() podStateManager.increaseMessageSequenceNumber()
handleResponse(event.response) handleResponse(event.response)
} }
is PodEvent.Paired -> { is PodEvent.Paired -> {
podStateManager.uniqueId = event.uniqueId.toLong() podStateManager.uniqueId = event.uniqueId.toLong()
} }
else -> { else -> {
// Do nothing // Do nothing
} }
} }
@ -738,11 +747,11 @@ class OmnipodDashManagerImpl @Inject constructor(
private fun handleResponse(response: Response) { private fun handleResponse(response: Response) {
when (response) { when (response) {
is VersionResponse -> { is VersionResponse -> {
podStateManager.updateFromVersionResponse(response) podStateManager.updateFromVersionResponse(response)
} }
is SetUniqueIdResponse -> { is SetUniqueIdResponse -> {
podStateManager.updateFromSetUniqueIdResponse(response) podStateManager.updateFromSetUniqueIdResponse(response)
} }
@ -750,7 +759,7 @@ class OmnipodDashManagerImpl @Inject constructor(
podStateManager.updateFromDefaultStatusResponse(response) podStateManager.updateFromDefaultStatusResponse(response)
} }
is AlarmStatusResponse -> { is AlarmStatusResponse -> {
podStateManager.updateFromAlarmStatusResponse(response) podStateManager.updateFromAlarmStatusResponse(response)
} }
} }

View file

@ -6,12 +6,11 @@ class PodConstants {
companion object { 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 // Expiration alert time in hours before lifetime end
const val POD_EXPIRATION_ALERT_HOURS = 72L const val POD_EXPIRATION_ALERT_HOURS_REMAINING_DEFAULT = 7L
const val POD_EXPIRATION_ALERT_HOURS_DURATION = 7L
// Expiration eminent alert time in minutes since activation // Imminent expiration alert time in hours before lifetime end
const val POD_EXPIRATION_IMMINENT_ALERT_HOURS = 79L const val POD_EXPIRATION_IMMINENT_ALERT_HOURS_REMAINING = 1L
// Bolus & Priming units // Bolus & Priming units
const val POD_PULSE_BOLUS_UNITS = 0.05 const val POD_PULSE_BOLUS_UNITS = 0.05

View file

@ -112,8 +112,20 @@ interface OmnipodDashPodStateManager {
- after getPodStatus was successful(we have an up-to-date podStatus) - after getPodStatus was successful(we have an up-to-date podStatus)
*/ */
fun recoverActivationFromPodStatus(): String? fun recoverActivationFromPodStatus(): String?
fun sameAlertSettings(expirationReminderEnabled: Boolean, expirationHours: Int, lowReservoirAlertEnabled: Boolean, lowReservoirAlertUnits: Int): Boolean fun sameAlertSettings(
fun updateExpirationAlertSettings(expirationReminderEnabled: Boolean, expirationHours: Int): Completable expirationReminderEnabled: Boolean,
expirationReminderHours: Int,
expirationAlarmEnabled: Boolean,
expirationAlarmHours: Int,
lowReservoirAlertEnabled: Boolean,
lowReservoirAlertUnits: Int
): Boolean
fun updateExpirationAlertSettings(
expirationReminderEnabled: Boolean,
expirationReminderHours: Int,
expirationAlarmEnabled: Boolean,
expirationAlarmHours: Int
): Completable
fun updateLowReservoirAlertSettings(lowReservoirAlertEnabled: Boolean, lowReservoirAlertUnits: Int): Completable fun updateLowReservoirAlertSettings(lowReservoirAlertEnabled: Boolean, lowReservoirAlertUnits: Int): Completable
data class ActiveCommand( data class ActiveCommand(

View file

@ -415,19 +415,25 @@ class OmnipodDashPodStateManagerImpl @Inject constructor(
override fun recoverActivationFromPodStatus(): String? { override fun recoverActivationFromPodStatus(): String? {
val newActivationProgress = when (podState.podStatus) { val newActivationProgress = when (podState.podStatus) {
PodStatus.FILLED -> PodStatus.FILLED ->
ActivationProgress.NOT_STARTED ActivationProgress.NOT_STARTED
PodStatus.UID_SET ->
PodStatus.UID_SET ->
ActivationProgress.SET_UNIQUE_ID ActivationProgress.SET_UNIQUE_ID
PodStatus.ENGAGING_CLUTCH_DRIVE, PodStatus.PRIMING ->
PodStatus.ENGAGING_CLUTCH_DRIVE, PodStatus.PRIMING ->
return "Busy" return "Busy"
PodStatus.CLUTCH_DRIVE_ENGAGED ->
PodStatus.CLUTCH_DRIVE_ENGAGED ->
ActivationProgress.PRIME_COMPLETED ActivationProgress.PRIME_COMPLETED
PodStatus.BASAL_PROGRAM_SET ->
PodStatus.BASAL_PROGRAM_SET ->
ActivationProgress.PROGRAMMED_BASAL ActivationProgress.PROGRAMMED_BASAL
PodStatus.RUNNING_ABOVE_MIN_VOLUME, PodStatus.RUNNING_BELOW_MIN_VOLUME -> PodStatus.RUNNING_ABOVE_MIN_VOLUME, PodStatus.RUNNING_BELOW_MIN_VOLUME ->
ActivationProgress.CANNULA_INSERTED ActivationProgress.CANNULA_INSERTED
else ->
else ->
null null
} }
newActivationProgress?.let { newActivationProgress?.let {
@ -447,7 +453,7 @@ class OmnipodDashPodStateManagerImpl @Inject constructor(
val cmdConfirmation = getCommandConfirmationFromState() val cmdConfirmation = getCommandConfirmationFromState()
logger.info(LTag.PUMPCOMM, "Update active command with confirmation: $cmdConfirmation") logger.info(LTag.PUMPCOMM, "Update active command with confirmation: $cmdConfirmation")
when (cmdConfirmation) { when (cmdConfirmation) {
CommandSendingFailure -> { CommandSendingFailure -> {
podState.activeCommand = null podState.activeCommand = null
source.onError( source.onError(
activeCommand.sendError activeCommand.sendError
@ -463,7 +469,7 @@ class OmnipodDashPodStateManagerImpl @Inject constructor(
source.onComplete() source.onComplete()
} }
CommandConfirmationDenied -> { CommandConfirmationDenied -> {
podState.activeCommand = null podState.activeCommand = null
source.onSuccess(CommandConfirmed(activeCommand, false)) source.onSuccess(CommandConfirmed(activeCommand, false))
} }
@ -474,7 +480,7 @@ class OmnipodDashPodStateManagerImpl @Inject constructor(
source.onSuccess(CommandConfirmed(activeCommand, true)) source.onSuccess(CommandConfirmed(activeCommand, true))
} }
NoActiveCommand -> { NoActiveCommand -> {
source.onComplete() source.onComplete()
} }
} }
@ -482,20 +488,30 @@ class OmnipodDashPodStateManagerImpl @Inject constructor(
override fun sameAlertSettings( override fun sameAlertSettings(
expirationReminderEnabled: Boolean, expirationReminderEnabled: Boolean,
expirationHours: Int, expirationReminderHours: Int,
expirationAlarmEnabled: Boolean,
expirationAlarmHours: Int,
lowReservoirAlertEnabled: Boolean, lowReservoirAlertEnabled: Boolean,
lowReservoirAlertUnits: Int lowReservoirAlertUnits: Int
): Boolean { ): Boolean {
return podState.expirationReminderEnabled == expirationReminderEnabled && return podState.expirationReminderEnabled == expirationReminderEnabled &&
podState.expirationHours == expirationHours && podState.expirationReminderHours == expirationReminderHours &&
podState.expirationAlarmEnabled == expirationAlarmEnabled &&
podState.expirationAlarmHours == expirationAlarmHours &&
podState.lowReservoirAlertEnabled == lowReservoirAlertEnabled && podState.lowReservoirAlertEnabled == lowReservoirAlertEnabled &&
podState.lowReservoirAlertUnits == lowReservoirAlertUnits podState.lowReservoirAlertUnits == lowReservoirAlertUnits
} }
override fun updateExpirationAlertSettings(expirationReminderEnabled: Boolean, expirationHours: Int): override fun updateExpirationAlertSettings(
Completable = Completable.defer { expirationReminderEnabled: Boolean,
expirationReminderHours: Int,
expirationAlarmEnabled: Boolean,
expirationAlarmHours: Int
): Completable = Completable.defer {
podState.expirationReminderEnabled = expirationReminderEnabled podState.expirationReminderEnabled = expirationReminderEnabled
podState.expirationHours = expirationHours podState.expirationReminderHours = expirationReminderHours
podState.expirationAlarmEnabled = expirationAlarmEnabled
podState.expirationAlarmHours = expirationAlarmHours
Completable.complete() Completable.complete()
} }
@ -520,15 +536,18 @@ class OmnipodDashPodStateManagerImpl @Inject constructor(
createdRealtime <= podState.lastStatusResponseReceived && createdRealtime <= podState.lastStatusResponseReceived &&
sequence == podState.sequenceNumberOfLastProgrammingCommand -> sequence == podState.sequenceNumberOfLastProgrammingCommand ->
CommandConfirmationSuccess CommandConfirmationSuccess
createdRealtime <= podState.lastStatusResponseReceived && createdRealtime <= podState.lastStatusResponseReceived &&
sequence != podState.sequenceNumberOfLastProgrammingCommand -> sequence != podState.sequenceNumberOfLastProgrammingCommand ->
CommandConfirmationDenied CommandConfirmationDenied
// no response received after this point // no response received after this point
createdRealtime <= sentRealtime -> createdRealtime <= sentRealtime ->
CommandSendingNotConfirmed CommandSendingNotConfirmed
createdRealtime > sentRealtime ->
createdRealtime > sentRealtime ->
CommandSendingFailure CommandSendingFailure
else -> // this can't happen, see the previous two conditions
else -> // this can't happen, see the previous two conditions
NoActiveCommand NoActiveCommand
} }
} ?: NoActiveCommand } ?: NoActiveCommand
@ -555,7 +574,7 @@ class OmnipodDashPodStateManagerImpl @Inject constructor(
podState.activeCommand = newCommand podState.activeCommand = newCommand
} }
CommandSendingNotConfirmed -> { CommandSendingNotConfirmed -> {
val now = SystemClock.elapsedRealtime() val now = SystemClock.elapsedRealtime()
val newCommand = podState.activeCommand?.copy( val newCommand = podState.activeCommand?.copy(
createdRealtime = now, createdRealtime = now,
@ -565,7 +584,7 @@ class OmnipodDashPodStateManagerImpl @Inject constructor(
podState.lastStatusResponseReceived = 0 podState.lastStatusResponseReceived = 0
} }
CommandSendingFailure, NoActiveCommand -> { CommandSendingFailure, NoActiveCommand -> {
podState.activeCommand = null podState.activeCommand = null
podState.lastStatusResponseReceived = 0 podState.lastStatusResponseReceived = 0
} }
@ -745,7 +764,9 @@ class OmnipodDashPodStateManagerImpl @Inject constructor(
var secondPrimeBolusVolume: Short? = null, var secondPrimeBolusVolume: Short? = null,
var expirationReminderEnabled: Boolean? = null, var expirationReminderEnabled: Boolean? = null,
var expirationHours: Int? = null, var expirationReminderHours: Int? = null,
var expirationAlarmEnabled: Boolean? = null,
var expirationAlarmHours: Int? = null,
var lowReservoirAlertEnabled: Boolean? = null, var lowReservoirAlertEnabled: Boolean? = null,
var lowReservoirAlertUnits: Int? = null, var lowReservoirAlertUnits: Int? = null,

View file

@ -67,16 +67,24 @@ class DashInsertCannulaViewModel @Inject constructor(
basalProgram basalProgram
) )
val expirationReminderEnabled = sp.getBoolean(info.nightscout.androidaps.plugins.pump.omnipod.common.R.string.key_omnipod_common_expiration_reminder_enabled, true) val expirationReminderEnabled = sp.getBoolean(info.nightscout.androidaps.plugins.pump.omnipod.common.R.string.key_omnipod_common_expiration_reminder_enabled, true)
val expirationHours = sp.getInt(info.nightscout.androidaps.plugins.pump.omnipod.common.R.string.key_omnipod_common_expiration_reminder_hours_before_shutdown, 9) val expirationReminderHours = sp.getInt(info.nightscout.androidaps.plugins.pump.omnipod.common.R.string.key_omnipod_common_expiration_reminder_hours_before_shutdown, 9)
val expirationHoursBeforeShutdown = if (expirationReminderEnabled) val expirationReminderHoursBeforeShutdown = if (expirationReminderEnabled)
expirationHours.toLong() expirationReminderHours.toLong()
else else
null null
super.disposable += omnipodManager.activatePodPart2(basalProgram, expirationHoursBeforeShutdown) val expirationAlarmEnabled = sp.getBoolean(info.nightscout.androidaps.plugins.pump.omnipod.common.R.string.key_omnipod_common_expiration_alarm_enabled, true)
val expirationAlarmHours = sp.getInt(info.nightscout.androidaps.plugins.pump.omnipod.common.R.string.key_omnipod_common_expiration_alarm_hours_before_shutdown, 8)
val expirationAlarmHoursBeforeShutdown = if (expirationAlarmEnabled)
expirationAlarmHours.toLong()
else
null
super.disposable += omnipodManager.activatePodPart2(basalProgram, expirationReminderHoursBeforeShutdown, expirationAlarmHoursBeforeShutdown)
.ignoreElements() .ignoreElements()
.andThen(podStateManager.updateExpirationAlertSettings(expirationReminderEnabled, expirationHours)) .andThen(podStateManager.updateExpirationAlertSettings(expirationReminderEnabled, expirationReminderHours, expirationAlarmEnabled, expirationAlarmHours))
.andThen( .andThen(
history.createRecord( history.createRecord(
OmnipodCommandType.INSERT_CANNULA, OmnipodCommandType.INSERT_CANNULA,

View file

@ -50,6 +50,22 @@
validate:minNumber="2" validate:minNumber="2"
validate:testType="numericRange" /> validate:testType="numericRange" />
<SwitchPreference
android:defaultValue="true"
android:key="@string/key_omnipod_common_expiration_alarm_enabled"
android:title="@string/omnipod_common_preferences_expiration_alarm_enabled" />
<info.nightscout.core.validators.ValidatingEditTextPreference
android:defaultValue="8"
android:dependency="@string/key_omnipod_common_expiration_alarm_enabled"
android:digits="0123456789"
android:inputType="number"
android:key="@string/key_omnipod_common_expiration_alarm_hours_before_shutdown"
android:title="@string/omnipod_common_preferences_expiration_alarm_hours_before_shutdown"
validate:maxNumber="24"
validate:minNumber="1"
validate:testType="numericRange" />
<SwitchPreference <SwitchPreference
android:defaultValue="true" android:defaultValue="true"
android:key="@string/key_omnipod_common_low_reservoir_alert_enabled" android:key="@string/key_omnipod_common_low_reservoir_alert_enabled"