merge
This commit is contained in:
commit
dcfd9bcdbf
14 changed files with 338 additions and 217 deletions
|
@ -31,7 +31,8 @@ class DeactivatePodFragment : ActionFragmentBase() {
|
||||||
|
|
||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
super.onViewCreated(view, savedInstanceState)
|
super.onViewCreated(view, savedInstanceState)
|
||||||
view.findViewById<Button>(R.id.omnipod_wizard_button_discard_pod)?.setOnClickListener {
|
buttonDiscardPod = view.findViewById(R.id.omnipod_wizard_button_discard_pod)
|
||||||
|
buttonDiscardPod.setOnClickListener {
|
||||||
context?.let {
|
context?.let {
|
||||||
AlertDialog.Builder(it)
|
AlertDialog.Builder(it)
|
||||||
.setIcon(android.R.drawable.ic_dialog_alert)
|
.setIcon(android.R.drawable.ic_dialog_alert)
|
||||||
|
|
|
@ -10,18 +10,25 @@ import info.nightscout.androidaps.plugins.common.ManufacturerType
|
||||||
import info.nightscout.androidaps.plugins.general.actions.defs.CustomAction
|
import info.nightscout.androidaps.plugins.general.actions.defs.CustomAction
|
||||||
import info.nightscout.androidaps.plugins.general.actions.defs.CustomActionType
|
import info.nightscout.androidaps.plugins.general.actions.defs.CustomActionType
|
||||||
import info.nightscout.androidaps.plugins.pump.common.defs.PumpType
|
import info.nightscout.androidaps.plugins.pump.common.defs.PumpType
|
||||||
|
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.common.queue.command.*
|
||||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.OmnipodDashManager
|
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.OmnipodDashManager
|
||||||
|
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.event.PodEvent
|
||||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition.ActivationProgress
|
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.BeepType
|
||||||
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.OmnipodDashPodStateManager
|
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.state.OmnipodDashPodStateManager
|
||||||
|
import info.nightscout.androidaps.plugins.pump.omnipod.dash.history.DashHistory
|
||||||
|
import info.nightscout.androidaps.plugins.pump.omnipod.dash.history.data.BolusRecord
|
||||||
|
import info.nightscout.androidaps.plugins.pump.omnipod.dash.history.data.BolusType
|
||||||
|
import info.nightscout.androidaps.plugins.pump.omnipod.dash.history.data.TempBasalRecord
|
||||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.ui.OmnipodDashOverviewFragment
|
import info.nightscout.androidaps.plugins.pump.omnipod.dash.ui.OmnipodDashOverviewFragment
|
||||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.util.mapProfileToBasalProgram
|
import info.nightscout.androidaps.plugins.pump.omnipod.dash.util.mapProfileToBasalProgram
|
||||||
import info.nightscout.androidaps.queue.commands.CustomCommand
|
import info.nightscout.androidaps.queue.commands.CustomCommand
|
||||||
import info.nightscout.androidaps.utils.TimeChangeType
|
import info.nightscout.androidaps.utils.TimeChangeType
|
||||||
import info.nightscout.androidaps.utils.resources.ResourceHelper
|
import info.nightscout.androidaps.utils.resources.ResourceHelper
|
||||||
import info.nightscout.androidaps.utils.sharedPreferences.SP
|
import info.nightscout.androidaps.utils.sharedPreferences.SP
|
||||||
|
import io.reactivex.Observable
|
||||||
import io.reactivex.Single
|
import io.reactivex.Single
|
||||||
import io.reactivex.rxkotlin.blockingSubscribeBy
|
import io.reactivex.rxkotlin.blockingSubscribeBy
|
||||||
import io.reactivex.rxkotlin.subscribeBy
|
import io.reactivex.rxkotlin.subscribeBy
|
||||||
|
@ -36,6 +43,7 @@ class OmnipodDashPumpPlugin @Inject constructor(
|
||||||
private val podStateManager: OmnipodDashPodStateManager,
|
private val podStateManager: OmnipodDashPodStateManager,
|
||||||
private val sp: SP,
|
private val sp: SP,
|
||||||
private val profileFunction: ProfileFunction,
|
private val profileFunction: ProfileFunction,
|
||||||
|
private val history: DashHistory,
|
||||||
injector: HasAndroidInjector,
|
injector: HasAndroidInjector,
|
||||||
aapsLogger: AAPSLogger,
|
aapsLogger: AAPSLogger,
|
||||||
resourceHelper: ResourceHelper,
|
resourceHelper: ResourceHelper,
|
||||||
|
@ -71,8 +79,23 @@ class OmnipodDashPumpPlugin @Inject constructor(
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun isConnected(): Boolean {
|
override fun isConnected(): Boolean {
|
||||||
// TODO
|
// NOTE: Using connected state for unconfirmed commands
|
||||||
return true
|
|
||||||
|
// We are faking connection lost on unconfirmed commands.
|
||||||
|
// During normal execution, the activeCommand is set to null after a command was executed with success or we
|
||||||
|
// were not able to send that command.
|
||||||
|
// If we are not sure if the POD received the command or not, then we answer with "success" but keep this
|
||||||
|
// activeCommand set until we can confirm/deny it.
|
||||||
|
|
||||||
|
// In order to prevent AAPS from sending us other programming commands while the current command was not
|
||||||
|
// confirmed, we are simulating "connection lost".
|
||||||
|
// We need to prevent AAPS from sending other commands because they would overwrite the ID of the last
|
||||||
|
// programming command reported by the POD. And we using that ID to confirm/deny the activeCommand.
|
||||||
|
|
||||||
|
// The effect of answering with 'false' here is that AAPS will call connect() and will not sent any new
|
||||||
|
// commands. On connect(), we are calling getPodStatus where we are always trying to confirm/deny the
|
||||||
|
// activeCommand.
|
||||||
|
return podStateManager.activeCommand == null
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun isConnecting(): Boolean {
|
override fun isConnecting(): Boolean {
|
||||||
|
@ -90,7 +113,12 @@ class OmnipodDashPumpPlugin @Inject constructor(
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun connect(reason: String) {
|
override fun connect(reason: String) {
|
||||||
// TODO
|
// See:
|
||||||
|
// NOTE: Using connected state for unconfirmed commands
|
||||||
|
if (podStateManager.activeCommand == null) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
getPumpStatus("unconfirmed command")
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun disconnect(reason: String) {
|
override fun disconnect(reason: String) {
|
||||||
|
@ -102,8 +130,11 @@ class OmnipodDashPumpPlugin @Inject constructor(
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getPumpStatus(reason: String) {
|
override fun getPumpStatus(reason: String) {
|
||||||
// TODO history
|
Observable.concat(
|
||||||
omnipodManager.getStatus(ResponseType.StatusResponseType.DEFAULT_STATUS_RESPONSE).blockingSubscribeBy(
|
omnipodManager.getStatus(ResponseType.StatusResponseType.DEFAULT_STATUS_RESPONSE),
|
||||||
|
history.updateFromState(podStateManager).toObservable(),
|
||||||
|
podStateManager.updateActiveCommand().toObservable(),
|
||||||
|
).blockingSubscribeBy(
|
||||||
onNext = { podEvent ->
|
onNext = { podEvent ->
|
||||||
aapsLogger.debug(
|
aapsLogger.debug(
|
||||||
LTag.PUMP,
|
LTag.PUMP,
|
||||||
|
@ -120,30 +151,12 @@ class OmnipodDashPumpPlugin @Inject constructor(
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun setNewBasalProfile(profile: Profile): PumpEnactResult {
|
override fun setNewBasalProfile(profile: Profile): PumpEnactResult {
|
||||||
// TODO history
|
return executeProgrammingCommand(
|
||||||
|
history.createRecord(
|
||||||
return Single.create<PumpEnactResult> { source ->
|
commandType = OmnipodCommandType.SET_BASAL_PROFILE
|
||||||
omnipodManager.setBasalProgram(mapProfileToBasalProgram(profile)).subscribeBy(
|
),
|
||||||
onNext = { podEvent ->
|
omnipodManager.setBasalProgram(mapProfileToBasalProgram(profile))
|
||||||
aapsLogger.debug(
|
|
||||||
LTag.PUMP,
|
|
||||||
"Received PodEvent in setNewBasalProfile: $podEvent"
|
|
||||||
)
|
)
|
||||||
},
|
|
||||||
onError = { throwable ->
|
|
||||||
aapsLogger.error(LTag.PUMP, "Error in setNewBasalProfile", throwable)
|
|
||||||
source.onSuccess(
|
|
||||||
PumpEnactResult(injector).success(false).enacted(false).comment(
|
|
||||||
throwable.toString()
|
|
||||||
)
|
|
||||||
)
|
|
||||||
},
|
|
||||||
onComplete = {
|
|
||||||
aapsLogger.debug("setNewBasalProfile completed")
|
|
||||||
source.onSuccess(PumpEnactResult(injector).success(true).enacted(true))
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}.blockingGet()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun isThisProfileSet(profile: Profile): Boolean = podStateManager.basalProgram?.let {
|
override fun isThisProfileSet(profile: Profile): Boolean = podStateManager.basalProgram?.let {
|
||||||
|
@ -151,7 +164,7 @@ class OmnipodDashPumpPlugin @Inject constructor(
|
||||||
} ?: true
|
} ?: true
|
||||||
|
|
||||||
override fun lastDataTime(): Long {
|
override fun lastDataTime(): Long {
|
||||||
return podStateManager.lastConnection
|
return podStateManager.lastUpdatedSystem
|
||||||
}
|
}
|
||||||
|
|
||||||
override val baseBasalRate: Double
|
override val baseBasalRate: Double
|
||||||
|
@ -174,7 +187,6 @@ class OmnipodDashPumpPlugin @Inject constructor(
|
||||||
get() = 0
|
get() = 0
|
||||||
|
|
||||||
override fun deliverTreatment(detailedBolusInfo: DetailedBolusInfo): PumpEnactResult {
|
override fun deliverTreatment(detailedBolusInfo: DetailedBolusInfo): PumpEnactResult {
|
||||||
// TODO history
|
|
||||||
// TODO update Treatments (?)
|
// TODO update Treatments (?)
|
||||||
// TODO bolus progress
|
// TODO bolus progress
|
||||||
// TODO report actual delivered amount after Pod Alarm and bolus cancellation
|
// TODO report actual delivered amount after Pod Alarm and bolus cancellation
|
||||||
|
@ -182,10 +194,23 @@ class OmnipodDashPumpPlugin @Inject constructor(
|
||||||
return Single.create<PumpEnactResult> { source ->
|
return Single.create<PumpEnactResult> { source ->
|
||||||
val bolusBeeps = sp.getBoolean(R.string.key_omnipod_common_bolus_beeps_enabled, false)
|
val bolusBeeps = sp.getBoolean(R.string.key_omnipod_common_bolus_beeps_enabled, false)
|
||||||
|
|
||||||
|
Observable.concat(
|
||||||
|
history.createRecord(
|
||||||
|
commandType = OmnipodCommandType.SET_BOLUS,
|
||||||
|
bolusRecord = BolusRecord(
|
||||||
|
detailedBolusInfo.insulin,
|
||||||
|
BolusType.fromBolusInfoBolusType(detailedBolusInfo.bolusType),
|
||||||
|
),
|
||||||
|
).flatMapObservable { recordId ->
|
||||||
|
podStateManager.createActiveCommand(recordId).toObservable()
|
||||||
|
},
|
||||||
omnipodManager.bolus(
|
omnipodManager.bolus(
|
||||||
detailedBolusInfo.insulin,
|
detailedBolusInfo.insulin,
|
||||||
bolusBeeps,
|
bolusBeeps,
|
||||||
bolusBeeps
|
bolusBeeps
|
||||||
|
),
|
||||||
|
history.updateFromState(podStateManager).toObservable(),
|
||||||
|
podStateManager.updateActiveCommand().toObservable(),
|
||||||
).subscribeBy(
|
).subscribeBy(
|
||||||
onNext = { podEvent ->
|
onNext = { podEvent ->
|
||||||
aapsLogger.debug(
|
aapsLogger.debug(
|
||||||
|
@ -204,7 +229,8 @@ class OmnipodDashPumpPlugin @Inject constructor(
|
||||||
onComplete = {
|
onComplete = {
|
||||||
aapsLogger.debug("deliverTreatment completed")
|
aapsLogger.debug("deliverTreatment completed")
|
||||||
source.onSuccess(
|
source.onSuccess(
|
||||||
PumpEnactResult(injector).success(true).enacted(true).bolusDelivered(detailedBolusInfo.insulin)
|
PumpEnactResult(injector).success(true).enacted(true)
|
||||||
|
.bolusDelivered(detailedBolusInfo.insulin)
|
||||||
.carbsDelivered(detailedBolusInfo.carbs)
|
.carbsDelivered(detailedBolusInfo.carbs)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -213,22 +239,10 @@ class OmnipodDashPumpPlugin @Inject constructor(
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun stopBolusDelivering() {
|
override fun stopBolusDelivering() {
|
||||||
// TODO history
|
|
||||||
// TODO update Treatments (?)
|
// TODO update Treatments (?)
|
||||||
|
executeProgrammingCommand(
|
||||||
omnipodManager.stopBolus().blockingSubscribeBy(
|
history.createRecord(OmnipodCommandType.CANCEL_BOLUS),
|
||||||
onNext = { podEvent ->
|
omnipodManager.stopBolus(),
|
||||||
aapsLogger.debug(
|
|
||||||
LTag.PUMP,
|
|
||||||
"Received PodEvent in stopBolusDelivering: $podEvent"
|
|
||||||
)
|
|
||||||
},
|
|
||||||
onError = { throwable ->
|
|
||||||
aapsLogger.error(LTag.PUMP, "Error in stopBolusDelivering", throwable)
|
|
||||||
},
|
|
||||||
onComplete = {
|
|
||||||
aapsLogger.debug("stopBolusDelivering completed")
|
|
||||||
}
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -239,37 +253,24 @@ class OmnipodDashPumpPlugin @Inject constructor(
|
||||||
enforceNew: Boolean,
|
enforceNew: Boolean,
|
||||||
tbrType: PumpSync.TemporaryBasalType
|
tbrType: PumpSync.TemporaryBasalType
|
||||||
): PumpEnactResult {
|
): PumpEnactResult {
|
||||||
// TODO history
|
|
||||||
// TODO update Treatments
|
// TODO update Treatments
|
||||||
|
// TODO check for existing basal
|
||||||
return Single.create<PumpEnactResult> { source ->
|
// check existing basal(locally and maybe? get status)
|
||||||
|
// if enforceNew -> cancel it()
|
||||||
|
// else -> return error that existing basal is running
|
||||||
|
// set new temp basal
|
||||||
|
// update treatments
|
||||||
|
// profit
|
||||||
|
return executeProgrammingCommand(
|
||||||
|
history.createRecord(
|
||||||
|
commandType = OmnipodCommandType.SET_TEMPORARY_BASAL,
|
||||||
|
tempBasalRecord = TempBasalRecord(duration = durationInMinutes, rate = absoluteRate)
|
||||||
|
),
|
||||||
omnipodManager.setTempBasal(
|
omnipodManager.setTempBasal(
|
||||||
absoluteRate,
|
absoluteRate,
|
||||||
durationInMinutes.toShort()
|
durationInMinutes.toShort()
|
||||||
).subscribeBy(
|
|
||||||
onNext = { podEvent ->
|
|
||||||
aapsLogger.debug(
|
|
||||||
LTag.PUMP,
|
|
||||||
"Received PodEvent in setTempBasalAbsolute: $podEvent"
|
|
||||||
)
|
|
||||||
},
|
|
||||||
onError = { throwable ->
|
|
||||||
aapsLogger.error(LTag.PUMP, "Error in setTempBasalAbsolute", throwable)
|
|
||||||
source.onSuccess(
|
|
||||||
PumpEnactResult(injector).success(false).enacted(false).comment(
|
|
||||||
throwable.toString()
|
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
},
|
|
||||||
onComplete = {
|
|
||||||
aapsLogger.debug("setTempBasalAbsolute completed")
|
|
||||||
source.onSuccess(
|
|
||||||
PumpEnactResult(injector).success(true).enacted(true).absolute(absoluteRate)
|
|
||||||
.duration(durationInMinutes)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}.blockingGet()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun setTempBasalPercent(
|
override fun setTempBasalPercent(
|
||||||
|
@ -291,33 +292,11 @@ class OmnipodDashPumpPlugin @Inject constructor(
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun cancelTempBasal(enforceNew: Boolean): PumpEnactResult {
|
override fun cancelTempBasal(enforceNew: Boolean): PumpEnactResult {
|
||||||
// TODO history
|
|
||||||
// TODO update Treatments
|
// TODO update Treatments
|
||||||
|
return executeProgrammingCommand(
|
||||||
return Single.create<PumpEnactResult> { source ->
|
history.createRecord(OmnipodCommandType.CANCEL_TEMPORARY_BASAL),
|
||||||
omnipodManager.stopTempBasal().subscribeBy(
|
omnipodManager.stopTempBasal()
|
||||||
onNext = { podEvent ->
|
|
||||||
aapsLogger.debug(
|
|
||||||
LTag.PUMP,
|
|
||||||
"Received PodEvent in cancelTempBasal: $podEvent"
|
|
||||||
)
|
)
|
||||||
},
|
|
||||||
onError = { throwable ->
|
|
||||||
aapsLogger.error(LTag.PUMP, "Error in cancelTempBasal", throwable)
|
|
||||||
source.onSuccess(
|
|
||||||
PumpEnactResult(injector).success(false).enacted(false).comment(
|
|
||||||
throwable.toString()
|
|
||||||
)
|
|
||||||
)
|
|
||||||
},
|
|
||||||
onComplete = {
|
|
||||||
aapsLogger.debug("cancelTempBasal completed")
|
|
||||||
source.onSuccess(
|
|
||||||
PumpEnactResult(injector).success(true).enacted(true)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}.blockingGet()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun cancelExtendedBolus(): PumpEnactResult {
|
override fun cancelExtendedBolus(): PumpEnactResult {
|
||||||
|
@ -342,11 +321,8 @@ class OmnipodDashPumpPlugin @Inject constructor(
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun serialNumber(): String {
|
override fun serialNumber(): String {
|
||||||
return if (podStateManager.uniqueId == null) {
|
return podStateManager.uniqueId?.toString()
|
||||||
"n/a" // TODO i18n
|
?: "n/a" // TODO i18n
|
||||||
} else {
|
|
||||||
podStateManager.uniqueId.toString()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun shortStatus(veryShort: Boolean): String {
|
override fun shortStatus(veryShort: Boolean): String {
|
||||||
|
@ -405,12 +381,15 @@ class OmnipodDashPumpPlugin @Inject constructor(
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun silenceAlerts(): PumpEnactResult {
|
private fun silenceAlerts(): PumpEnactResult {
|
||||||
// TODO history
|
|
||||||
// TODO filter alert types
|
// TODO filter alert types
|
||||||
|
|
||||||
return podStateManager.activeAlerts?.let {
|
return podStateManager.activeAlerts?.let {
|
||||||
Single.create<PumpEnactResult> { source ->
|
Single.create<PumpEnactResult> { source ->
|
||||||
omnipodManager.silenceAlerts(it).subscribeBy(
|
Observable.concat(
|
||||||
|
// TODO: is this a programming command? if yes, save to history
|
||||||
|
omnipodManager.silenceAlerts(it),
|
||||||
|
history.updateFromState(podStateManager).toObservable(),
|
||||||
|
podStateManager.updateActiveCommand().toObservable(),
|
||||||
|
).subscribeBy(
|
||||||
onNext = { podEvent ->
|
onNext = { podEvent ->
|
||||||
aapsLogger.debug(
|
aapsLogger.debug(
|
||||||
LTag.PUMP,
|
LTag.PUMP,
|
||||||
|
@ -435,75 +414,26 @@ class OmnipodDashPumpPlugin @Inject constructor(
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun suspendDelivery(): PumpEnactResult {
|
private fun suspendDelivery(): PumpEnactResult {
|
||||||
// TODO history
|
return executeProgrammingCommand(
|
||||||
|
history.createRecord(OmnipodCommandType.RESUME_DELIVERY),
|
||||||
return Single.create<PumpEnactResult> { source ->
|
omnipodManager.suspendDelivery()
|
||||||
omnipodManager.suspendDelivery().subscribeBy(
|
|
||||||
onNext = { podEvent ->
|
|
||||||
aapsLogger.debug(
|
|
||||||
LTag.PUMP,
|
|
||||||
"Received PodEvent in suspendDelivery: $podEvent"
|
|
||||||
)
|
)
|
||||||
},
|
|
||||||
onError = { throwable ->
|
|
||||||
aapsLogger.error(LTag.PUMP, "Error in suspendDelivery", throwable)
|
|
||||||
source.onSuccess(PumpEnactResult(injector).success(false).comment(throwable.toString()))
|
|
||||||
},
|
|
||||||
onComplete = {
|
|
||||||
aapsLogger.debug("suspendDelivery completed")
|
|
||||||
source.onSuccess(PumpEnactResult(injector).success(true))
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}.blockingGet()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun resumeDelivery(): PumpEnactResult {
|
private fun resumeDelivery(): PumpEnactResult {
|
||||||
// TODO history
|
|
||||||
|
|
||||||
return profileFunction.getProfile()?.let {
|
return profileFunction.getProfile()?.let {
|
||||||
|
executeProgrammingCommand(
|
||||||
Single.create<PumpEnactResult> { source ->
|
history.createRecord(OmnipodCommandType.RESUME_DELIVERY),
|
||||||
omnipodManager.setBasalProgram(mapProfileToBasalProgram(it)).subscribeBy(
|
omnipodManager.setBasalProgram(mapProfileToBasalProgram(it))
|
||||||
onNext = { podEvent ->
|
|
||||||
aapsLogger.debug(
|
|
||||||
LTag.PUMP,
|
|
||||||
"Received PodEvent in resumeDelivery: $podEvent"
|
|
||||||
)
|
)
|
||||||
},
|
|
||||||
onError = { throwable ->
|
|
||||||
aapsLogger.error(LTag.PUMP, "Error in resumeDelivery", throwable)
|
|
||||||
source.onSuccess(PumpEnactResult(injector).success(false).comment(throwable.toString()))
|
|
||||||
},
|
|
||||||
onComplete = {
|
|
||||||
aapsLogger.debug("resumeDelivery completed")
|
|
||||||
source.onSuccess(PumpEnactResult(injector).success(true))
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}.blockingGet()
|
|
||||||
} ?: PumpEnactResult(injector).success(false).enacted(false).comment("No profile active") // TODO i18n
|
} ?: PumpEnactResult(injector).success(false).enacted(false).comment("No profile active") // TODO i18n
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun deactivatePod(): PumpEnactResult {
|
private fun deactivatePod(): PumpEnactResult {
|
||||||
// TODO history
|
return executeProgrammingCommand(
|
||||||
|
history.createRecord(OmnipodCommandType.DEACTIVATE_POD),
|
||||||
return Single.create<PumpEnactResult> { source ->
|
omnipodManager.deactivatePod()
|
||||||
omnipodManager.deactivatePod().subscribeBy(
|
|
||||||
onNext = { podEvent ->
|
|
||||||
aapsLogger.debug(
|
|
||||||
LTag.PUMP,
|
|
||||||
"Received PodEvent in deactivatePod: $podEvent"
|
|
||||||
)
|
)
|
||||||
},
|
|
||||||
onError = { throwable ->
|
|
||||||
aapsLogger.error(LTag.PUMP, "Error in deactivatePod", throwable)
|
|
||||||
source.onSuccess(PumpEnactResult(injector).success(false).comment(throwable.toString()))
|
|
||||||
},
|
|
||||||
onComplete = {
|
|
||||||
aapsLogger.debug("deactivatePod completed")
|
|
||||||
source.onSuccess(PumpEnactResult(injector).success(true))
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}.blockingGet()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun handleTimeChange(): PumpEnactResult {
|
private fun handleTimeChange(): PumpEnactResult {
|
||||||
|
@ -517,31 +447,10 @@ class OmnipodDashPumpPlugin @Inject constructor(
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun playTestBeep(): PumpEnactResult {
|
private fun playTestBeep(): PumpEnactResult {
|
||||||
// TODO history
|
return executeProgrammingCommand(
|
||||||
|
history.createRecord(OmnipodCommandType.PLAY_TEST_BEEP),
|
||||||
return Single.create<PumpEnactResult> { source ->
|
omnipodManager.playBeep(BeepType.LONG_SINGLE_BEEP)
|
||||||
omnipodManager.playBeep(BeepType.LONG_SINGLE_BEEP).subscribeBy(
|
|
||||||
onNext = { podEvent ->
|
|
||||||
aapsLogger.debug(
|
|
||||||
LTag.PUMP,
|
|
||||||
"Received PodEvent in playTestBeep: $podEvent"
|
|
||||||
)
|
)
|
||||||
},
|
|
||||||
onError = { throwable ->
|
|
||||||
aapsLogger.error(LTag.PUMP, "Error in playTestBeep", throwable)
|
|
||||||
source.onSuccess(
|
|
||||||
PumpEnactResult(injector).success(false).enacted(false)
|
|
||||||
.comment(throwable.toString())
|
|
||||||
)
|
|
||||||
},
|
|
||||||
onComplete = {
|
|
||||||
aapsLogger.debug("playTestBeep completed")
|
|
||||||
source.onSuccess(
|
|
||||||
PumpEnactResult(injector).success(true).enacted(true)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}.blockingGet()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun timezoneOrDSTChanged(timeChangeType: TimeChangeType) {
|
override fun timezoneOrDSTChanged(timeChangeType: TimeChangeType) {
|
||||||
|
@ -564,4 +473,51 @@ class OmnipodDashPumpPlugin @Inject constructor(
|
||||||
|
|
||||||
commandQueue.customCommand(CommandHandleTimeChange(false), null)
|
commandQueue.customCommand(CommandHandleTimeChange(false), null)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun observeAddNewActiveCommandToHistory(observeCreateHistoryEntry: Single<String>): Observable<PodEvent> {
|
||||||
|
return observeCreateHistoryEntry.flatMapObservable {
|
||||||
|
podStateManager.createActiveCommand(it).toObservable<PodEvent>()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun executeProgrammingCommand(
|
||||||
|
observeCreateHistoryEntry: Single<String>,
|
||||||
|
command: Observable<PodEvent>
|
||||||
|
): PumpEnactResult {
|
||||||
|
return Single.create<PumpEnactResult> { source ->
|
||||||
|
Observable.concat(
|
||||||
|
listOf(
|
||||||
|
podStateManager.observeNoActiveCommand(),
|
||||||
|
observeAddNewActiveCommandToHistory(observeCreateHistoryEntry),
|
||||||
|
command,
|
||||||
|
history.updateFromState(podStateManager).toObservable(),
|
||||||
|
podStateManager.updateActiveCommand().toObservable(),
|
||||||
|
)
|
||||||
|
).subscribeBy(
|
||||||
|
onNext = { podEvent ->
|
||||||
|
aapsLogger.debug(
|
||||||
|
LTag.PUMP,
|
||||||
|
"Received PodEvent: $podEvent"
|
||||||
|
)
|
||||||
|
},
|
||||||
|
onError = { throwable ->
|
||||||
|
aapsLogger.error(LTag.PUMP, "Error executing command", throwable)
|
||||||
|
// Here we assume that onError will be called only BEFORE we manage to send a command
|
||||||
|
// If it gets called later, we will have the command as "not sent" in history and will not try to
|
||||||
|
// get it's final status, even if it was send
|
||||||
|
|
||||||
|
podStateManager.maybeMarkActiveCommandFailed()
|
||||||
|
source.onSuccess(
|
||||||
|
PumpEnactResult(injector).success(false).enacted(false).comment(throwable.toString())
|
||||||
|
)
|
||||||
|
},
|
||||||
|
onComplete = {
|
||||||
|
aapsLogger.debug("Command completed")
|
||||||
|
source.onSuccess(
|
||||||
|
PumpEnactResult(injector).success(true).enacted(true)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}.blockingGet()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver
|
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver
|
||||||
|
|
||||||
|
import android.os.SystemClock
|
||||||
import info.nightscout.androidaps.logging.AAPSLogger
|
import info.nightscout.androidaps.logging.AAPSLogger
|
||||||
import info.nightscout.androidaps.logging.LTag
|
import info.nightscout.androidaps.logging.LTag
|
||||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.OmnipodDashBleManager
|
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.OmnipodDashBleManager
|
||||||
|
@ -643,6 +644,20 @@ class OmnipodDashManagerImpl @Inject constructor(
|
||||||
}
|
}
|
||||||
|
|
||||||
is PodEvent.CommandSent -> {
|
is PodEvent.CommandSent -> {
|
||||||
|
podStateManager.activeCommand?.let {
|
||||||
|
if (it.sequence == event.command.sequenceNumber) {
|
||||||
|
it.sentRealtime = SystemClock.elapsedRealtime()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
podStateManager.increaseMessageSequenceNumber()
|
||||||
|
}
|
||||||
|
|
||||||
|
is PodEvent.CommandSendNotConfirmed -> {
|
||||||
|
podStateManager.activeCommand?.let {
|
||||||
|
if (it.sequence == event.command.sequenceNumber) {
|
||||||
|
it.sentRealtime = SystemClock.elapsedRealtime()
|
||||||
|
}
|
||||||
|
}
|
||||||
podStateManager.increaseMessageSequenceNumber()
|
podStateManager.increaseMessageSequenceNumber()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -86,8 +86,10 @@ class Connection(
|
||||||
val msgIO = MessageIO(aapsLogger, cmdBleIO, dataBleIO)
|
val msgIO = MessageIO(aapsLogger, cmdBleIO, dataBleIO)
|
||||||
|
|
||||||
fun connect() {
|
fun connect() {
|
||||||
|
if (session != null) {
|
||||||
disconnect()
|
disconnect()
|
||||||
|
}
|
||||||
|
aapsLogger.debug("Connecting")
|
||||||
if (!gattConnection.connect()) {
|
if (!gattConnection.connect()) {
|
||||||
throw FailedToConnectException("connect() returned false")
|
throw FailedToConnectException("connect() returned false")
|
||||||
}
|
}
|
||||||
|
@ -167,6 +169,6 @@ class Connection(
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
|
||||||
private const val CONNECT_TIMEOUT_MS = 7000
|
private const val CONNECT_TIMEOUT_MS = 12000
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -65,4 +65,6 @@ sealed class PodEvent {
|
||||||
return "ResponseReceived(command=$command, response=$response)"
|
return "ResponseReceived(command=$command, response=$response)"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
data class CommandConfirmed(val historyId: String, val success: Boolean) : PodEvent()
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,7 +31,7 @@ class ProgramBasalCommand private constructor(
|
||||||
private val delayUntilNextTenthPulseInUsec: Int
|
private val delayUntilNextTenthPulseInUsec: Int
|
||||||
val length: Short
|
val length: Short
|
||||||
get() = (insulinProgramElements.size * 6 + 10).toShort()
|
get() = (insulinProgramElements.size * 6 + 10).toShort()
|
||||||
val bodyLength: Byte
|
private val bodyLength: Byte
|
||||||
get() = (insulinProgramElements.size * 6 + 8).toByte()
|
get() = (insulinProgramElements.size * 6 + 8).toByte()
|
||||||
|
|
||||||
override val encoded: ByteArray
|
override val encoded: ByteArray
|
||||||
|
|
|
@ -6,4 +6,5 @@ import java.io.Serializable
|
||||||
interface Command : Encodable, Serializable {
|
interface Command : Encodable, Serializable {
|
||||||
|
|
||||||
val commandType: CommandType
|
val commandType: CommandType
|
||||||
|
val sequenceNumber: Short
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,7 @@ import java.nio.ByteBuffer
|
||||||
abstract class HeaderEnabledCommand protected constructor(
|
abstract class HeaderEnabledCommand protected constructor(
|
||||||
override val commandType: CommandType,
|
override val commandType: CommandType,
|
||||||
protected val uniqueId: Int,
|
protected val uniqueId: Int,
|
||||||
protected val sequenceNumber: Short,
|
override val sequenceNumber: Short,
|
||||||
protected val multiCommandFlag: Boolean
|
protected val multiCommandFlag: Boolean
|
||||||
) : Command {
|
) : Command {
|
||||||
|
|
||||||
|
|
|
@ -2,11 +2,15 @@ package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.state
|
||||||
|
|
||||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.Id
|
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.Id
|
||||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.pair.PairResult
|
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.pair.PairResult
|
||||||
|
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.event.PodEvent
|
||||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition.*
|
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition.*
|
||||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.response.AlarmStatusResponse
|
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.response.AlarmStatusResponse
|
||||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.response.DefaultStatusResponse
|
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.response.DefaultStatusResponse
|
||||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.response.SetUniqueIdResponse
|
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.response.SetUniqueIdResponse
|
||||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.response.VersionResponse
|
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.response.VersionResponse
|
||||||
|
import io.reactivex.Completable
|
||||||
|
import io.reactivex.Maybe
|
||||||
|
import io.reactivex.Observable
|
||||||
import java.io.Serializable
|
import java.io.Serializable
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
|
@ -18,7 +22,9 @@ interface OmnipodDashPodStateManager {
|
||||||
val isSuspended: Boolean
|
val isSuspended: Boolean
|
||||||
val isPodRunning: Boolean
|
val isPodRunning: Boolean
|
||||||
var lastConnection: Long
|
var lastConnection: Long
|
||||||
val lastUpdated: Long
|
|
||||||
|
val lastUpdatedSystem: Long // System.currentTimeMillis()
|
||||||
|
val lastStatusResponseReceived: Long
|
||||||
|
|
||||||
val messageSequenceNumber: Short
|
val messageSequenceNumber: Short
|
||||||
val sequenceNumberOfLastProgrammingCommand: Short?
|
val sequenceNumberOfLastProgrammingCommand: Short?
|
||||||
|
@ -48,6 +54,7 @@ interface OmnipodDashPodStateManager {
|
||||||
val tempBasal: TempBasal?
|
val tempBasal: TempBasal?
|
||||||
val tempBasalActive: Boolean
|
val tempBasalActive: Boolean
|
||||||
var basalProgram: BasalProgram?
|
var basalProgram: BasalProgram?
|
||||||
|
val activeCommand: ActiveCommand?
|
||||||
|
|
||||||
fun increaseMessageSequenceNumber()
|
fun increaseMessageSequenceNumber()
|
||||||
fun increaseEapAkaSequenceNumber(): ByteArray
|
fun increaseEapAkaSequenceNumber(): ByteArray
|
||||||
|
@ -59,5 +66,17 @@ interface OmnipodDashPodStateManager {
|
||||||
fun updateFromPairing(uniqueId: Id, pairResult: PairResult)
|
fun updateFromPairing(uniqueId: Id, pairResult: PairResult)
|
||||||
fun reset()
|
fun reset()
|
||||||
|
|
||||||
|
fun createActiveCommand(historyId: String): Completable
|
||||||
|
fun updateActiveCommand(): Maybe<PodEvent>
|
||||||
|
fun observeNoActiveCommand(): Observable<PodEvent>
|
||||||
|
fun maybeMarkActiveCommandFailed()
|
||||||
|
|
||||||
|
data class ActiveCommand(
|
||||||
|
val sequence: Short,
|
||||||
|
val createdRealtime: Long,
|
||||||
|
var sentRealtime: Long = 0,
|
||||||
|
val historyId: String
|
||||||
|
)
|
||||||
|
// TODO: set created to "now" on boot
|
||||||
data class TempBasal(val startTime: Long, val rate: Double, val durationInMinutes: Short) : Serializable
|
data class TempBasal(val startTime: Long, val rate: Double, val durationInMinutes: Short) : Serializable
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.state
|
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.state
|
||||||
|
|
||||||
|
import android.os.SystemClock
|
||||||
import com.google.gson.Gson
|
import com.google.gson.Gson
|
||||||
import info.nightscout.androidaps.logging.AAPSLogger
|
import info.nightscout.androidaps.logging.AAPSLogger
|
||||||
import info.nightscout.androidaps.logging.LTag
|
import info.nightscout.androidaps.logging.LTag
|
||||||
|
@ -9,12 +10,16 @@ import info.nightscout.androidaps.plugins.pump.omnipod.dash.R
|
||||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.Id
|
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.Id
|
||||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.pair.PairResult
|
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.pair.PairResult
|
||||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.session.EapSqn
|
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.session.EapSqn
|
||||||
|
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.event.PodEvent
|
||||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition.*
|
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition.*
|
||||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.response.AlarmStatusResponse
|
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.response.AlarmStatusResponse
|
||||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.response.DefaultStatusResponse
|
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.response.DefaultStatusResponse
|
||||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.response.SetUniqueIdResponse
|
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.response.SetUniqueIdResponse
|
||||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.response.VersionResponse
|
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.response.VersionResponse
|
||||||
import info.nightscout.androidaps.utils.sharedPreferences.SP
|
import info.nightscout.androidaps.utils.sharedPreferences.SP
|
||||||
|
import io.reactivex.Completable
|
||||||
|
import io.reactivex.Maybe
|
||||||
|
import io.reactivex.Observable
|
||||||
import java.io.Serializable
|
import java.io.Serializable
|
||||||
import java.util.*
|
import java.util.*
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
@ -60,8 +65,8 @@ class OmnipodDashPodStateManagerImpl @Inject constructor(
|
||||||
store()
|
store()
|
||||||
}
|
}
|
||||||
|
|
||||||
override val lastUpdated: Long
|
override val lastUpdatedSystem: Long
|
||||||
get() = podState.lastUpdated
|
get() = podState.lastUpdatedSystem
|
||||||
|
|
||||||
override val messageSequenceNumber: Short
|
override val messageSequenceNumber: Short
|
||||||
get() = podState.messageSequenceNumber
|
get() = podState.messageSequenceNumber
|
||||||
|
@ -152,6 +157,9 @@ class OmnipodDashPodStateManagerImpl @Inject constructor(
|
||||||
store()
|
store()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override val lastStatusResponseReceived: Long
|
||||||
|
get() = podState.lastStatusResponseReceived
|
||||||
|
|
||||||
override fun increaseMessageSequenceNumber() {
|
override fun increaseMessageSequenceNumber() {
|
||||||
podState.messageSequenceNumber = ((podState.messageSequenceNumber.toInt() + 1) and 0x0f).toShort()
|
podState.messageSequenceNumber = ((podState.messageSequenceNumber.toInt() + 1) and 0x0f).toShort()
|
||||||
store()
|
store()
|
||||||
|
@ -171,6 +179,76 @@ class OmnipodDashPodStateManagerImpl @Inject constructor(
|
||||||
store()
|
store()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override val activeCommand: OmnipodDashPodStateManager.ActiveCommand?
|
||||||
|
get() = podState.activeCommand
|
||||||
|
|
||||||
|
@Synchronized
|
||||||
|
override fun createActiveCommand(historyId: String) = Completable.create { source ->
|
||||||
|
if (activeCommand == null) {
|
||||||
|
podState.activeCommand = OmnipodDashPodStateManager.ActiveCommand(
|
||||||
|
podState.messageSequenceNumber,
|
||||||
|
createdRealtime = SystemClock.elapsedRealtime(),
|
||||||
|
historyId = historyId
|
||||||
|
)
|
||||||
|
source.onComplete()
|
||||||
|
} else {
|
||||||
|
source.onError(
|
||||||
|
java.lang.IllegalStateException(
|
||||||
|
"Trying to send a command " +
|
||||||
|
"and the last command was not confirmed"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Synchronized
|
||||||
|
override fun observeNoActiveCommand(): Observable<PodEvent> {
|
||||||
|
return Observable.defer {
|
||||||
|
if (activeCommand == null) {
|
||||||
|
Observable.empty()
|
||||||
|
} else {
|
||||||
|
Observable.error(
|
||||||
|
java.lang.IllegalStateException(
|
||||||
|
"Trying to send a command " +
|
||||||
|
"and the last command was not confirmed"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Synchronized
|
||||||
|
override fun maybeMarkActiveCommandFailed() {
|
||||||
|
podState.activeCommand?.run {
|
||||||
|
if (sentRealtime < createdRealtime) {
|
||||||
|
// command was not sent
|
||||||
|
podState.activeCommand = null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Synchronized
|
||||||
|
override fun updateActiveCommand() = Maybe.create<PodEvent> { source ->
|
||||||
|
podState.activeCommand?.run {
|
||||||
|
logger.debug(
|
||||||
|
"Trying to confirm active command with parameters: $activeCommand " +
|
||||||
|
"lastResponse=$lastStatusResponseReceived " +
|
||||||
|
"$sequenceNumberOfLastProgrammingCommand $historyId"
|
||||||
|
)
|
||||||
|
if (createdRealtime >= lastStatusResponseReceived)
|
||||||
|
// we did not receive a valid response yet
|
||||||
|
source.onComplete()
|
||||||
|
else {
|
||||||
|
podState.activeCommand = null
|
||||||
|
if (sequenceNumberOfLastProgrammingCommand == sequence)
|
||||||
|
source.onSuccess(PodEvent.CommandConfirmed(historyId, true))
|
||||||
|
else
|
||||||
|
source.onSuccess(PodEvent.CommandConfirmed(historyId, false))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
?: source.onComplete() // no active programming command
|
||||||
|
}
|
||||||
|
|
||||||
override fun increaseEapAkaSequenceNumber(): ByteArray {
|
override fun increaseEapAkaSequenceNumber(): ByteArray {
|
||||||
podState.eapAkaSequenceNumber++
|
podState.eapAkaSequenceNumber++
|
||||||
return EapSqn(podState.eapAkaSequenceNumber).value
|
return EapSqn(podState.eapAkaSequenceNumber).value
|
||||||
|
@ -191,7 +269,9 @@ class OmnipodDashPodStateManagerImpl @Inject constructor(
|
||||||
podState.minutesSinceActivation = response.minutesSinceActivation
|
podState.minutesSinceActivation = response.minutesSinceActivation
|
||||||
podState.activeAlerts = response.activeAlerts
|
podState.activeAlerts = response.activeAlerts
|
||||||
|
|
||||||
podState.lastUpdated = System.currentTimeMillis()
|
podState.lastUpdatedSystem = System.currentTimeMillis()
|
||||||
|
podState.lastStatusResponseReceived = SystemClock.elapsedRealtime()
|
||||||
|
|
||||||
store()
|
store()
|
||||||
rxBus.send(EventOmnipodDashPumpValuesChanged())
|
rxBus.send(EventOmnipodDashPumpValuesChanged())
|
||||||
}
|
}
|
||||||
|
@ -211,7 +291,8 @@ class OmnipodDashPodStateManagerImpl @Inject constructor(
|
||||||
podState.lotNumber = response.lotNumber
|
podState.lotNumber = response.lotNumber
|
||||||
podState.podSequenceNumber = response.podSequenceNumber
|
podState.podSequenceNumber = response.podSequenceNumber
|
||||||
|
|
||||||
podState.lastUpdated = System.currentTimeMillis()
|
podState.lastUpdatedSystem = System.currentTimeMillis()
|
||||||
|
|
||||||
store()
|
store()
|
||||||
rxBus.send(EventOmnipodDashPumpValuesChanged())
|
rxBus.send(EventOmnipodDashPumpValuesChanged())
|
||||||
}
|
}
|
||||||
|
@ -237,7 +318,8 @@ class OmnipodDashPodStateManagerImpl @Inject constructor(
|
||||||
podState.podSequenceNumber = response.podSequenceNumber
|
podState.podSequenceNumber = response.podSequenceNumber
|
||||||
podState.uniqueId = response.uniqueIdReceivedInCommand
|
podState.uniqueId = response.uniqueIdReceivedInCommand
|
||||||
|
|
||||||
podState.lastUpdated = System.currentTimeMillis()
|
podState.lastUpdatedSystem = System.currentTimeMillis()
|
||||||
|
|
||||||
store()
|
store()
|
||||||
rxBus.send(EventOmnipodDashPumpValuesChanged())
|
rxBus.send(EventOmnipodDashPumpValuesChanged())
|
||||||
}
|
}
|
||||||
|
@ -293,7 +375,8 @@ class OmnipodDashPodStateManagerImpl @Inject constructor(
|
||||||
|
|
||||||
var activationProgress: ActivationProgress = ActivationProgress.NOT_STARTED
|
var activationProgress: ActivationProgress = ActivationProgress.NOT_STARTED
|
||||||
var lastConnection: Long = 0
|
var lastConnection: Long = 0
|
||||||
var lastUpdated: Long = 0
|
var lastUpdatedSystem: Long = 0
|
||||||
|
var lastStatusResponseReceived: Long = 0
|
||||||
|
|
||||||
var messageSequenceNumber: Short = 0
|
var messageSequenceNumber: Short = 0
|
||||||
var sequenceNumberOfLastProgrammingCommand: Short? = null
|
var sequenceNumberOfLastProgrammingCommand: Short? = null
|
||||||
|
@ -322,5 +405,6 @@ class OmnipodDashPodStateManagerImpl @Inject constructor(
|
||||||
|
|
||||||
var basalProgram: BasalProgram? = null
|
var basalProgram: BasalProgram? = null
|
||||||
var tempBasal: OmnipodDashPodStateManager.TempBasal? = null
|
var tempBasal: OmnipodDashPodStateManager.TempBasal? = null
|
||||||
|
var activeCommand: OmnipodDashPodStateManager.ActiveCommand? = null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,7 @@ import com.github.guepardoapps.kulid.ULID
|
||||||
import info.nightscout.androidaps.plugins.pump.omnipod.common.definition.OmnipodCommandType
|
import info.nightscout.androidaps.plugins.pump.omnipod.common.definition.OmnipodCommandType
|
||||||
import info.nightscout.androidaps.plugins.pump.omnipod.common.definition.OmnipodCommandType.SET_BOLUS
|
import info.nightscout.androidaps.plugins.pump.omnipod.common.definition.OmnipodCommandType.SET_BOLUS
|
||||||
import info.nightscout.androidaps.plugins.pump.omnipod.common.definition.OmnipodCommandType.SET_TEMPORARY_BASAL
|
import info.nightscout.androidaps.plugins.pump.omnipod.common.definition.OmnipodCommandType.SET_TEMPORARY_BASAL
|
||||||
|
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.state.OmnipodDashPodStateManager
|
||||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.history.data.BolusRecord
|
import info.nightscout.androidaps.plugins.pump.omnipod.dash.history.data.BolusRecord
|
||||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.history.data.HistoryRecord
|
import info.nightscout.androidaps.plugins.pump.omnipod.dash.history.data.HistoryRecord
|
||||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.history.data.InitialResult
|
import info.nightscout.androidaps.plugins.pump.omnipod.dash.history.data.InitialResult
|
||||||
|
@ -22,13 +23,13 @@ class DashHistory @Inject constructor(
|
||||||
private val historyMapper: HistoryMapper
|
private val historyMapper: HistoryMapper
|
||||||
) {
|
) {
|
||||||
|
|
||||||
fun markSuccess(id: String, date: Long): Completable = dao.markResolved(
|
private fun markSuccess(id: String): Completable = dao.markResolved(
|
||||||
id,
|
id,
|
||||||
ResolvedResult.SUCCESS,
|
ResolvedResult.SUCCESS,
|
||||||
currentTimeMillis()
|
currentTimeMillis()
|
||||||
)
|
)
|
||||||
|
|
||||||
fun markFailure(id: String, date: Long): Completable = dao.markResolved(
|
private fun markFailure(id: String): Completable = dao.markResolved(
|
||||||
id,
|
id,
|
||||||
ResolvedResult.FAILURE,
|
ResolvedResult.FAILURE,
|
||||||
currentTimeMillis()
|
currentTimeMillis()
|
||||||
|
@ -37,8 +38,8 @@ class DashHistory @Inject constructor(
|
||||||
@Suppress("ReturnCount")
|
@Suppress("ReturnCount")
|
||||||
fun createRecord(
|
fun createRecord(
|
||||||
commandType: OmnipodCommandType,
|
commandType: OmnipodCommandType,
|
||||||
date: Long,
|
date: Long = System.currentTimeMillis(),
|
||||||
initialResult: InitialResult = InitialResult.UNCONFIRMED,
|
initialResult: InitialResult = InitialResult.NOT_SENT,
|
||||||
tempBasalRecord: TempBasalRecord? = null,
|
tempBasalRecord: TempBasalRecord? = null,
|
||||||
bolusRecord: BolusRecord? = null,
|
bolusRecord: BolusRecord? = null,
|
||||||
resolveResult: ResolvedResult? = null,
|
resolveResult: ResolvedResult? = null,
|
||||||
|
@ -72,4 +73,29 @@ class DashHistory @Inject constructor(
|
||||||
dao.all().map { list -> list.map(historyMapper::entityToDomain) }
|
dao.all().map { list -> list.map(historyMapper::entityToDomain) }
|
||||||
|
|
||||||
fun getRecordsAfter(time: Long): Single<List<HistoryRecordEntity>> = dao.allSince(time)
|
fun getRecordsAfter(time: Long): Single<List<HistoryRecordEntity>> = dao.allSince(time)
|
||||||
|
|
||||||
|
fun updateFromState(podState: OmnipodDashPodStateManager) = Completable.defer {
|
||||||
|
podState.activeCommand?.run {
|
||||||
|
when {
|
||||||
|
|
||||||
|
createdRealtime <= podState.lastStatusResponseReceived &&
|
||||||
|
sequence == podState.sequenceNumberOfLastProgrammingCommand ->
|
||||||
|
dao.setInitialResult(historyId, InitialResult.SENT)
|
||||||
|
.andThen(markSuccess(historyId))
|
||||||
|
|
||||||
|
createdRealtime <= podState.lastStatusResponseReceived &&
|
||||||
|
sequence != podState.sequenceNumberOfLastProgrammingCommand ->
|
||||||
|
markFailure(historyId)
|
||||||
|
|
||||||
|
// no response received after this point
|
||||||
|
createdRealtime <= sentRealtime ->
|
||||||
|
dao.setInitialResult(historyId, InitialResult.SENT)
|
||||||
|
|
||||||
|
createdRealtime > sentRealtime ->
|
||||||
|
dao.setInitialResult(historyId, InitialResult.FAILURE_SENDING)
|
||||||
|
|
||||||
|
else -> Completable.error(IllegalStateException("This can't happen. Could not update history"))
|
||||||
|
}
|
||||||
|
} ?: Completable.complete() // no active programming command
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +1,22 @@
|
||||||
package info.nightscout.androidaps.plugins.pump.omnipod.dash.history.data
|
package info.nightscout.androidaps.plugins.pump.omnipod.dash.history.data
|
||||||
|
|
||||||
|
import info.nightscout.androidaps.data.DetailedBolusInfo
|
||||||
|
|
||||||
sealed class Record
|
sealed class Record
|
||||||
|
|
||||||
data class BolusRecord(val amout: Double, val bolusType: BolusType) : Record()
|
data class BolusRecord(val amout: Double, val bolusType: BolusType) : Record()
|
||||||
|
|
||||||
data class TempBasalRecord(val duration: Long, val rate: Double) : Record()
|
data class TempBasalRecord(val duration: Int, val rate: Double) : Record()
|
||||||
|
|
||||||
enum class BolusType {
|
enum class BolusType {
|
||||||
DEFAULT, SMB
|
DEFAULT, SMB;
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
fun fromBolusInfoBolusType(type: DetailedBolusInfo.BolusType): BolusType {
|
||||||
|
return when (type) {
|
||||||
|
DetailedBolusInfo.BolusType.SMB -> SMB;
|
||||||
|
else -> DEFAULT
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
package info.nightscout.androidaps.plugins.pump.omnipod.dash.history.data
|
package info.nightscout.androidaps.plugins.pump.omnipod.dash.history.data
|
||||||
|
|
||||||
enum class InitialResult {
|
enum class InitialResult {
|
||||||
SUCCESS, FAILURE, UNCONFIRMED
|
NOT_SENT, FAILURE_SENDING, UNCONFIRMED, SENT
|
||||||
}
|
}
|
||||||
|
|
||||||
enum class ResolvedResult {
|
enum class ResolvedResult {
|
||||||
|
|
|
@ -5,6 +5,7 @@ import androidx.room.Delete
|
||||||
import androidx.room.Insert
|
import androidx.room.Insert
|
||||||
import androidx.room.OnConflictStrategy
|
import androidx.room.OnConflictStrategy
|
||||||
import androidx.room.Query
|
import androidx.room.Query
|
||||||
|
import info.nightscout.androidaps.plugins.pump.omnipod.dash.history.data.InitialResult
|
||||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.history.data.ResolvedResult
|
import info.nightscout.androidaps.plugins.pump.omnipod.dash.history.data.ResolvedResult
|
||||||
import io.reactivex.Completable
|
import io.reactivex.Completable
|
||||||
import io.reactivex.Single
|
import io.reactivex.Single
|
||||||
|
@ -32,4 +33,7 @@ abstract class HistoryRecordDao {
|
||||||
|
|
||||||
@Query("UPDATE historyrecords SET resolvedResult = :resolvedResult, resolvedAt = :resolvedAt WHERE id = :id ")
|
@Query("UPDATE historyrecords SET resolvedResult = :resolvedResult, resolvedAt = :resolvedAt WHERE id = :id ")
|
||||||
abstract fun markResolved(id: String, resolvedResult: ResolvedResult, resolvedAt: Long): Completable
|
abstract fun markResolved(id: String, resolvedResult: ResolvedResult, resolvedAt: Long): Completable
|
||||||
|
|
||||||
|
@Query("UPDATE historyrecords SET initialResult = :initialResult WHERE id = :id ")
|
||||||
|
abstract fun setInitialResult(id: String, initialResult: InitialResult): Completable
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue