Additional Notifications, handling sync of percentage TBR

This commit is contained in:
jbr7rr 2023-06-20 09:30:41 +02:00
parent 057b2e386e
commit 2302711cdf
12 changed files with 130 additions and 61 deletions

View file

@ -412,7 +412,8 @@ enum class PumpType {
isPatchPump = true,
maxReservoirReading = 400,
source = Source.Medtrum
);
),
MEDTRUM_UNTESTED(description = "Medtrum untested", model = "untested", parent = MEDTRUM_NANO);
val description: String
var manufacturer: ManufacturerType? = null

View file

@ -60,6 +60,7 @@ fun PumpType.Companion.fromDbPumpType(pt: InterfaceIDs.PumpType): PumpType =
InterfaceIDs.PumpType.DIACONN_G8 -> PumpType.DIACONN_G8
InterfaceIDs.PumpType.EOPATCH2 -> PumpType.EOFLOW_EOPATCH2
InterfaceIDs.PumpType.MEDTRUM -> PumpType.MEDTRUM_NANO
InterfaceIDs.PumpType.MEDTRUM_UNTESTED -> PumpType.MEDTRUM_UNTESTED
InterfaceIDs.PumpType.CACHE -> PumpType.CACHE
}
@ -119,5 +120,6 @@ fun PumpType.toDbPumpType(): InterfaceIDs.PumpType =
PumpType.DIACONN_G8 -> InterfaceIDs.PumpType.DIACONN_G8
PumpType.EOFLOW_EOPATCH2 -> InterfaceIDs.PumpType.EOPATCH2
PumpType.MEDTRUM_NANO -> InterfaceIDs.PumpType.MEDTRUM
PumpType.MEDTRUM_UNTESTED -> InterfaceIDs.PumpType.MEDTRUM_UNTESTED
PumpType.CACHE -> InterfaceIDs.PumpType.CACHE
}

View file

@ -44,6 +44,7 @@ data class InterfaceIDs(
DIACONN_G8,
EOPATCH2,
MEDTRUM,
MEDTRUM_UNTESTED,
USER,
CACHE;

View file

@ -363,7 +363,7 @@ import kotlin.math.round
}
override fun model(): PumpType {
return medtrumPump.pumpType
return medtrumPump.pumpType()
}
override fun serialNumber(): String {
@ -371,7 +371,7 @@ import kotlin.math.round
}
override val pumpDescription: PumpDescription
get() = PumpDescription(medtrumPump.pumpType)
get() = PumpDescription(medtrumPump.pumpType())
override fun shortStatus(veryShort: Boolean): String {
var ret = ""

View file

@ -15,6 +15,7 @@ import info.nightscout.pump.medtrum.extension.toInt
import info.nightscout.rx.events.EventOverviewBolusProgress
import info.nightscout.rx.logging.AAPSLogger
import info.nightscout.rx.logging.LTag
import info.nightscout.shared.interfaces.ResourceHelper
import info.nightscout.shared.sharedPreferences.SP
import info.nightscout.shared.utils.DateUtil
import info.nightscout.shared.utils.T
@ -28,6 +29,7 @@ import kotlin.math.round
@Singleton
class MedtrumPump @Inject constructor(
private val aapsLogger: AAPSLogger,
private val rh: ResourceHelper,
private val sp: SP,
private val dateUtil: DateUtil,
private val pumpSync: PumpSync,
@ -168,7 +170,7 @@ class MedtrumPump @Inject constructor(
sp.putLong(R.string.key_last_connection, value)
}
private var _deviceType: Int = 0 // As reported by pump
private var _deviceType: Int = 80 // As reported by pump
var deviceType: Int
get() = _deviceType
set(value) {
@ -196,16 +198,10 @@ class MedtrumPump @Inject constructor(
val pumpSN: Long
get() = _pumpSN
val pumpType: PumpType = PumpType.MEDTRUM_NANO // TODO, type based on deviceType from pump
var lastTimeReceivedFromPump = 0L // Time in ms! // TODO: Consider removing as is not used?
var suspendTime = 0L // Time in ms!
var patchAge = 0L // Time in seconds?! // TODO: Not used
var alarmFlags = 0
var alarmParameter = 0
// bolus status
var bolusingTreatment: EventOverviewBolusProgress.Treatment? = null // actually delivered treatment
var bolusAmountToBeDelivered = 0.0 // amount to be delivered
@ -270,6 +266,12 @@ class MedtrumPump @Inject constructor(
}
}
fun pumpType(): PumpType =
when(deviceType) {
80, 88 -> PumpType.MEDTRUM_NANO
else -> PumpType.MEDTRUM_UNTESTED
}
fun loadUserSettingsFromSP() {
desiredPatchExpiration = sp.getBoolean(info.nightscout.pump.medtrum.R.string.key_patch_expiration, false)
val alarmSettingCode = sp.getString(info.nightscout.pump.medtrum.R.string.key_alarm_setting, AlarmSetting.LIGHT_VIBRATE_AND_BEEP.code.toString()).toByte()
@ -356,7 +358,7 @@ class MedtrumPump @Inject constructor(
LTag.PUMP,
"handleBasalStatusUpdate: basalType: $basalType basalValue: $basalRate basalSequence: $basalSequence basalPatchId: $basalPatchId basalStartTime: $basalStartTime " + "receivedTime: $receivedTime"
)
@Suppress("UNNECESSARY_SAFE_CALL") // Safe call to allow mocks to retun null
@Suppress("UNNECESSARY_SAFE_CALL") // Safe call to allow mocks to return null
val expectedTemporaryBasal = pumpSync.expectedPumpState()?.temporaryBasal
if (basalType.isTempBasal() && expectedTemporaryBasal?.pumpId != basalStartTime) {
// Note: temporaryBasalInfo will be removed from temporaryBasalStorage after this call
@ -364,14 +366,19 @@ class MedtrumPump @Inject constructor(
// If duration is unknown, no way to get it now, set patch lifetime as duration
val duration = temporaryBasalInfo?.duration ?: T.mins(FAKE_TBR_LENGTH).msecs()
val adjustedBasalRate = if (basalType == BasalType.ABSOLUTE_TEMP) {
basalRate
} else {
(basalRate / baseBasalRate) * 100 // calculate the percentage of the original basal rate
}
val newRecord = pumpSync.syncTemporaryBasalWithPumpId(
timestamp = basalStartTime,
rate = basalRate, // TODO: Support percent here, this will break things? Check if this is correct
rate = adjustedBasalRate,
duration = duration,
isAbsolute = (basalType == BasalType.ABSOLUTE_TEMP),
type = temporaryBasalInfo?.type,
pumpId = basalStartTime,
pumpType = pumpType,
pumpType = pumpType(),
pumpSerial = pumpSN.toString(radix = 16)
)
aapsLogger.debug(
@ -386,7 +393,7 @@ class MedtrumPump @Inject constructor(
isAbsolute = true,
type = PumpSync.TemporaryBasalType.PUMP_SUSPEND,
pumpId = basalStartTime,
pumpType = pumpType,
pumpType = pumpType(),
pumpSerial = pumpSN.toString(radix = 16)
)
aapsLogger.debug(
@ -439,7 +446,7 @@ class MedtrumPump @Inject constructor(
isAbsolute = true,
type = PumpSync.TemporaryBasalType.PUMP_SUSPEND,
pumpId = dateUtil.now(),
pumpType = pumpType,
pumpType = pumpType(),
pumpSerial = pumpSN.toString(radix = 16)
)
aapsLogger.debug(
@ -468,6 +475,31 @@ class MedtrumPump @Inject constructor(
saveActiveAlarms()
}
fun alarmStateToString(alarmState: AlarmState): String {
val stringId = when (alarmState) {
AlarmState.NONE -> R.string.alarm_none
AlarmState.PUMP_LOW_BATTERY -> R.string.alarm_pump_low_battery
AlarmState.PUMP_LOW_RESERVOIR -> R.string.alarm_pump_low_reservoir
AlarmState.PUMP_EXPIRES_SOON -> R.string.alarm_pump_expires_soon
AlarmState.LOWBG_SUSPENDED -> R.string.alarm_lowbg_suspended
AlarmState.LOWBG_SUSPENDED2 -> R.string.alarm_lowbg_suspended2
AlarmState.AUTO_SUSPENDED -> R.string.alarm_auto_suspended
AlarmState.HMAX_SUSPENDED -> R.string.alarm_hmax_suspended
AlarmState.DMAX_SUSPENDED -> R.string.alarm_dmax_suspended
AlarmState.SUSPENDED -> R.string.alarm_suspended
AlarmState.PAUSED -> R.string.alarm_paused
AlarmState.OCCLUSION -> R.string.alarm_occlusion
AlarmState.EXPIRED -> R.string.alarm_expired
AlarmState.RESERVOIR_EMPTY -> R.string.alarm_reservoir_empty
AlarmState.PATCH_FAULT -> R.string.alarm_patch_fault
AlarmState.PATCH_FAULT2 -> R.string.alarm_patch_fault2
AlarmState.BASE_FAULT -> R.string.alarm_base_fault
AlarmState.BATTERY_OUT -> R.string.alarm_battery_out
AlarmState.NO_CALIBRATION -> R.string.alarm_no_calibration
}
return rh.gs(stringId)
}
private fun saveActiveAlarms() {
val alarmsStr = activeAlarms.joinToString(separator = ",") { it.name }
sp.putString(R.string.key_active_alarms, alarmsStr)

View file

@ -3,6 +3,6 @@ package info.nightscout.pump.medtrum.comm.enums
enum class BolusType {
NONE,
NORMAL,
EXTEND,
COMBINATION;
EXTENDED,
COMBI;
}

View file

@ -107,13 +107,13 @@ class ActivatePacket(injector: HasAndroidInjector, private val basalProfile: Byt
pumpSync.insertTherapyEventIfNewWithTimestamp(
timestamp = System.currentTimeMillis(),
type = DetailedBolusInfo.EventType.CANNULA_CHANGE,
pumpType = medtrumPump.pumpType,
pumpType = medtrumPump.pumpType(),
pumpSerial = medtrumPump.pumpSN.toString(radix = 16)
)
pumpSync.insertTherapyEventIfNewWithTimestamp(
timestamp = System.currentTimeMillis(),
type = DetailedBolusInfo.EventType.INSULIN_CHANGE,
pumpType = medtrumPump.pumpType,
pumpType = medtrumPump.pumpType(),
pumpSerial = medtrumPump.pumpSN.toString(radix = 16)
)
}

View file

@ -53,7 +53,7 @@ class CancelTempBasalPacket(injector: HasAndroidInjector) : MedtrumPacket(inject
pumpSync.syncStopTemporaryBasalWithPumpId(
timestamp = basalStartTime, // Time of normal basal start = time of tbr end
endPumpId = basalStartTime,
pumpType = medtrumPump.pumpType,
pumpType = medtrumPump.pumpType(),
pumpSerial = medtrumPump.pumpSN.toString(radix = 16)
)
aapsLogger.debug(

View file

@ -94,7 +94,7 @@ class GetRecordPacket(injector: HasAndroidInjector, private val recordIndex: Int
val bolusNormalAmount = data.copyOfRange(RESP_RECORD_DATA_START + 8, RESP_RECORD_DATA_START + 10).toInt() * 0.05
val bolusNormalDelivered = data.copyOfRange(RESP_RECORD_DATA_START + 10, RESP_RECORD_DATA_START + 12).toInt() * 0.05
val bolusExtendedAmount = data.copyOfRange(RESP_RECORD_DATA_START + 12, RESP_RECORD_DATA_START + 14).toInt() * 0.05
val bolusExtendedDuration = data.copyOfRange(RESP_RECORD_DATA_START + 14, RESP_RECORD_DATA_START + 16).toInt()
val bolusExtendedDuration = data.copyOfRange(RESP_RECORD_DATA_START + 14, RESP_RECORD_DATA_START + 16).toLong() * 1000
val bolusExtendedDelivered = data.copyOfRange(RESP_RECORD_DATA_START + 16, RESP_RECORD_DATA_START + 18).toInt() * 0.05
val bolusCarb = data.copyOfRange(RESP_RECORD_DATA_START + 18, RESP_RECORD_DATA_START + 20).toInt()
val bolusGlucose = data.copyOfRange(RESP_RECORD_DATA_START + 20, RESP_RECORD_DATA_START + 22).toInt()
@ -114,7 +114,7 @@ class GetRecordPacket(injector: HasAndroidInjector, private val recordIndex: Int
amount = bolusNormalDelivered,
type = detailedBolusInfo?.bolusType,
pumpId = bolusStartTime,
pumpType = medtrumPump.pumpType,
pumpType = medtrumPump.pumpType(),
pumpSerial = medtrumPump.pumpSN.toString(radix = 16)
)
aapsLogger.debug(
@ -129,12 +129,54 @@ class GetRecordPacket(injector: HasAndroidInjector, private val recordIndex: Int
medtrumPump.lastBolusTime = bolusStartTime
medtrumPump.lastBolusAmount = bolusNormalDelivered
}
} else {
// TODO: at least record the bolus
} else if (bolusType == BolusType.EXTENDED) {
val newRecord = pumpSync.syncExtendedBolusWithPumpId(
timestamp = bolusStartTime,
amount = bolusExtendedDelivered,
duration = bolusExtendedDuration,
isEmulatingTB = false,
pumpId = bolusStartTime,
pumpType = medtrumPump.pumpType(),
pumpSerial = medtrumPump.pumpSN.toString(radix = 16)
)
aapsLogger.debug(
LTag.PUMPCOMM,
"from record: ${if (newRecord) "**NEW** " else ""}EVENT EXTENDED BOLUS ${dateUtil.dateAndTimeString(bolusStartTime)} ($bolusStartTime) Bolus: ${bolusNormalDelivered}U "
)
} else if (bolusType == BolusType.COMBI) {
// Note, this should never happen, as we don't use combo bolus
val detailedBolusInfo = detailedBolusInfoStorage.findDetailedBolusInfo(bolusStartTime, bolusNormalDelivered)
val newRecord = pumpSync.syncBolusWithPumpId(
timestamp = bolusStartTime,
amount = bolusNormalDelivered,
type = detailedBolusInfo?.bolusType,
pumpId = bolusStartTime,
pumpType = medtrumPump.pumpType(),
pumpSerial = medtrumPump.pumpSN.toString(radix = 16)
)
pumpSync.syncExtendedBolusWithPumpId(
timestamp = bolusStartTime,
amount = bolusExtendedDelivered,
duration = bolusExtendedDuration,
isEmulatingTB = false,
pumpId = bolusStartTime,
pumpType = medtrumPump.pumpType(),
pumpSerial = medtrumPump.pumpSN.toString(radix = 16)
)
aapsLogger.error(
LTag.PUMPCOMM,
"from record: EVENT BOLUS ${dateUtil.dateAndTimeString(bolusStartTime)} ($bolusStartTime) " + "Bolus type: $bolusType not supported"
"from record: ${if (newRecord) "**NEW** " else ""}EVENT COMBI BOLUS ${dateUtil.dateAndTimeString(bolusStartTime)} ($bolusStartTime) Bolus: ${bolusNormalDelivered}U Extended: ${bolusExtendedDelivered} THIS SHOULD NOT HAPPEN!!!"
)
if (!newRecord && detailedBolusInfo != null) {
// detailedInfo can be from another similar record. Reinsert
detailedBolusInfoStorage.add(detailedBolusInfo)
}
if (bolusStartTime > medtrumPump.lastBolusTime) {
medtrumPump.lastBolusTime = bolusStartTime
medtrumPump.lastBolusAmount = bolusNormalDelivered
}
} else {
aapsLogger.error(LTag.PUMPCOMM, "GetRecordPacket HandleResponse: BOLUS_RECORD: Unknown bolus type: $bolusType")
}
}
@ -171,7 +213,7 @@ class GetRecordPacket(injector: HasAndroidInjector, private val recordIndex: Int
isAbsolute = (basalType == BasalType.ABSOLUTE_TEMP),
type = PumpSync.TemporaryBasalType.NORMAL,
pumpId = basalStartTime,
pumpType = medtrumPump.pumpType,
pumpType = medtrumPump.pumpType(),
pumpSerial = medtrumPump.pumpSN.toString(radix = 16)
)
aapsLogger.debug(
@ -183,7 +225,7 @@ class GetRecordPacket(injector: HasAndroidInjector, private val recordIndex: Int
pumpSync.syncStopTemporaryBasalWithPumpId(
timestamp = basalEndTime,
endPumpId = basalEndTime,
pumpType = medtrumPump.pumpType,
pumpType = medtrumPump.pumpType(),
pumpSerial = medtrumPump.pumpSN.toString(radix = 16)
)
aapsLogger.warn(
@ -202,7 +244,7 @@ class GetRecordPacket(injector: HasAndroidInjector, private val recordIndex: Int
isAbsolute = true,
type = PumpSync.TemporaryBasalType.PUMP_SUSPEND,
pumpId = basalStartTime,
pumpType = medtrumPump.pumpType,
pumpType = medtrumPump.pumpType(),
pumpSerial = medtrumPump.pumpSN.toString(radix = 16)
)
aapsLogger.debug(
@ -210,11 +252,9 @@ class GetRecordPacket(injector: HasAndroidInjector, private val recordIndex: Int
"handleBasalStatusUpdate from record: ${if (newRecord) "**NEW** " else ""}EVENT SUSPEND: ($basalType) ${dateUtil.dateAndTimeString(basalStartTime)} ($basalStartTime) " +
"Rate: $basalRate Duration: ${duration}"
)
}
else -> {
aapsLogger.error(LTag.PUMPCOMM, "GetRecordPacket HandleResponse: BASAL_RECORD: Unknown basal type: $basalType")
// TODO: Error warning
}
}
}

View file

@ -15,6 +15,7 @@ import info.nightscout.interfaces.plugin.ActivePlugin
import info.nightscout.interfaces.profile.Profile
import info.nightscout.interfaces.profile.ProfileFunction
import info.nightscout.interfaces.pump.PumpSync
import info.nightscout.interfaces.pump.defs.PumpType
import info.nightscout.interfaces.queue.Callback
import info.nightscout.interfaces.queue.CommandQueue
import info.nightscout.interfaces.ui.UiInteraction
@ -473,7 +474,7 @@ class MedtrumService : DaggerService(), BLECommCallback {
// Pump suspended due to error, show error!
uiInteraction.addNotificationWithSound(
Notification.PUMP_ERROR,
rh.gs(R.string.pump_error, state.toString()),
rh.gs(R.string.pump_error, alarmState?.let { medtrumPump.alarmStateToString(it) }),
Notification.URGENT,
info.nightscout.core.ui.R.raw.alarm
)
@ -626,7 +627,21 @@ class MedtrumService : DaggerService(), BLECommCallback {
// Succes!
responseHandled = true
responseSuccess = true
// Check if we have a supported pump
if (medtrumPump.pumpType() == PumpType.MEDTRUM_UNTESTED) {
// Throw error
aapsLogger.error(LTag.PUMPCOMM, "Unsupported pump type")
uiInteraction.addNotificationWithSound(
Notification.PUMP_ERROR,
rh.gs(R.string.pump_unsupported, medtrumPump.deviceType),
Notification.URGENT,
info.nightscout.core.ui.R.raw.alarm
)
bleComm.disconnect("Unsupported pump")
toState(IdleState())
} else {
toState(GetDeviceTypeState())
}
} else if (mPacket?.failed == true) {
// Failure
responseHandled = true

View file

@ -150,9 +150,11 @@ class MedtrumOverviewViewModel @Inject constructor(
fun updateGUI() {
// Update less dynamic values
if (medtrumPump.lastConnection != 0L) {
val agoMilliseconds = System.currentTimeMillis() - medtrumPump.lastConnection
val agoMinutes = agoMilliseconds / 1000 / 60
_lastConnectionMinAgo.postValue(rh.gs(info.nightscout.shared.R.string.minago, agoMinutes))
}
if (medtrumPump.lastBolusTime != 0L) {
val agoMilliseconds = System.currentTimeMillis() - medtrumPump.lastBolusTime
val agoHours = agoMilliseconds.toDouble() / 60.0 / 60.0 / 1000.0
@ -169,7 +171,7 @@ class MedtrumOverviewViewModel @Inject constructor(
_lastBolus.postValue("")
}
val activeAlarmStrings = medtrumPump.activeAlarms.map { alarmStateToString(it) }
val activeAlarmStrings = medtrumPump.activeAlarms.map { medtrumPump.alarmStateToString(it) }
_activeAlarms.postValue(activeAlarmStrings.joinToString("\n"))
_pumpType.postValue(medtrumPump.deviceType.toString())
_fwVersion.postValue(medtrumPump.swVersion)
@ -182,30 +184,5 @@ class MedtrumOverviewViewModel @Inject constructor(
_patchExpiry.postValue(rh.gs(R.string.expiry_not_enabled))
}
}
private fun alarmStateToString(alarmState: AlarmState): String {
val stringId = when (alarmState) {
AlarmState.NONE -> R.string.alarm_none
AlarmState.PUMP_LOW_BATTERY -> R.string.alarm_pump_low_battery
AlarmState.PUMP_LOW_RESERVOIR -> R.string.alarm_pump_low_reservoir
AlarmState.PUMP_EXPIRES_SOON -> R.string.alarm_pump_expires_soon
AlarmState.LOWBG_SUSPENDED -> R.string.alarm_lowbg_suspended
AlarmState.LOWBG_SUSPENDED2 -> R.string.alarm_lowbg_suspended2
AlarmState.AUTO_SUSPENDED -> R.string.alarm_auto_suspended
AlarmState.HMAX_SUSPENDED -> R.string.alarm_hmax_suspended
AlarmState.DMAX_SUSPENDED -> R.string.alarm_dmax_suspended
AlarmState.SUSPENDED -> R.string.alarm_suspended
AlarmState.PAUSED -> R.string.alarm_paused
AlarmState.OCCLUSION -> R.string.alarm_occlusion
AlarmState.EXPIRED -> R.string.alarm_expired
AlarmState.RESERVOIR_EMPTY -> R.string.alarm_reservoir_empty
AlarmState.PATCH_FAULT -> R.string.alarm_patch_fault
AlarmState.PATCH_FAULT2 -> R.string.alarm_patch_fault2
AlarmState.BASE_FAULT -> R.string.alarm_base_fault
AlarmState.BATTERY_OUT -> R.string.alarm_battery_out
AlarmState.NO_CALIBRATION -> R.string.alarm_no_calibration
}
return rh.gs(stringId)
}
}

View file

@ -27,6 +27,7 @@
<string name="medtrum_pump_description">Medtrum Nano</string>
<string name="medtrumpump_settings">Medtrum pump settings</string>
<string name="pump_error">Pump error: %1$s !! </string>
<string name="pump_unsupported">Pump untested: %1$d! Please contact us at discord or github for support</string>
<string name="pump_is_suspended">Pump is suspended</string>
<string name="pump_is_suspended_hour_max">Pump is suspended due to hourly max insulin exceeded</string>
<string name="pump_is_suspended_day_max">Pump is suspended due to daily max insulin exceeded</string>