Initial bolus implementation, further connection improvements
This commit is contained in:
parent
a9ebdcfe68
commit
3027c2ffa5
12 changed files with 279 additions and 49 deletions
|
@ -27,6 +27,7 @@ dependencies {
|
|||
implementation project(':core:main')
|
||||
implementation project(':core:ui')
|
||||
implementation project(':core:validators')
|
||||
implementation project(':pump:pump-common')
|
||||
implementation project(':core:utils')
|
||||
|
||||
testImplementation project(':core:main')
|
||||
|
|
|
@ -8,12 +8,15 @@ import android.os.IBinder
|
|||
import dagger.android.HasAndroidInjector
|
||||
import info.nightscout.core.ui.toast.ToastUtils
|
||||
import info.nightscout.core.utils.fabric.FabricPrivacy
|
||||
import info.nightscout.interfaces.constraints.Constraint
|
||||
import info.nightscout.interfaces.constraints.Constraints
|
||||
import info.nightscout.interfaces.notifications.Notification
|
||||
import info.nightscout.interfaces.plugin.PluginDescription
|
||||
import info.nightscout.interfaces.plugin.PluginType
|
||||
import info.nightscout.interfaces.profile.Profile
|
||||
import info.nightscout.interfaces.profile.ProfileFunction
|
||||
import info.nightscout.interfaces.pump.DetailedBolusInfo
|
||||
import info.nightscout.interfaces.pump.DetailedBolusInfoStorage
|
||||
import info.nightscout.interfaces.pump.Pump
|
||||
import info.nightscout.interfaces.pump.PumpEnactResult
|
||||
import info.nightscout.interfaces.pump.PumpPluginBase
|
||||
|
@ -52,6 +55,7 @@ import org.json.JSONException
|
|||
import org.json.JSONObject
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
import kotlin.math.abs
|
||||
import kotlin.math.round
|
||||
|
||||
@Singleton class MedtrumPlugin @Inject constructor(
|
||||
|
@ -59,6 +63,7 @@ import kotlin.math.round
|
|||
aapsLogger: AAPSLogger,
|
||||
rh: ResourceHelper,
|
||||
commandQueue: CommandQueue,
|
||||
private val constraintChecker: Constraints,
|
||||
private val sp: SP,
|
||||
private val aapsSchedulers: AapsSchedulers,
|
||||
private val rxBus: RxBus,
|
||||
|
@ -69,6 +74,7 @@ import kotlin.math.round
|
|||
private val uiInteraction: UiInteraction,
|
||||
private val profileFunction: ProfileFunction,
|
||||
private val pumpSync: PumpSync,
|
||||
private val detailedBolusInfoStorage: DetailedBolusInfoStorage,
|
||||
private val temporaryBasalStorage: TemporaryBasalStorage
|
||||
) : PumpPluginBase(
|
||||
PluginDescription()
|
||||
|
@ -204,7 +210,7 @@ import kotlin.math.round
|
|||
}
|
||||
|
||||
override fun lastDataTime(): Long {
|
||||
return medtrumPump.lastTimeReceivedFromPump * 1000L
|
||||
return medtrumPump.lastTimeReceivedFromPump
|
||||
}
|
||||
|
||||
override val baseBasalRate: Double
|
||||
|
@ -216,14 +222,46 @@ import kotlin.math.round
|
|||
override val batteryLevel: Int
|
||||
get() = 0 // TODO
|
||||
|
||||
@Synchronized
|
||||
override fun deliverTreatment(detailedBolusInfo: DetailedBolusInfo): PumpEnactResult {
|
||||
return PumpEnactResult(injector) // TODO
|
||||
aapsLogger.debug(LTag.PUMP, "deliverTreatment: " + detailedBolusInfo.insulin + "U")
|
||||
if (!isInitialized()) return PumpEnactResult(injector).success(false).enacted(false)
|
||||
detailedBolusInfo.insulin = constraintChecker.applyBolusConstraints(Constraint(detailedBolusInfo.insulin)).value()
|
||||
return if (detailedBolusInfo.insulin > 0 && detailedBolusInfo.carbs == 0.0) {
|
||||
aapsLogger.debug(LTag.PUMP, "deliverTreatment: Delivering bolus: " + detailedBolusInfo.insulin + "U")
|
||||
detailedBolusInfoStorage.add(detailedBolusInfo) // will be picked up on reading history
|
||||
val t = EventOverviewBolusProgress.Treatment(0.0, 0, detailedBolusInfo.bolusType == DetailedBolusInfo.BolusType.SMB, detailedBolusInfo.id)
|
||||
val connectionOK = medtrumService?.setBolus(detailedBolusInfo.insulin, t) ?: false
|
||||
val result = PumpEnactResult(injector)
|
||||
result.success = connectionOK && abs(detailedBolusInfo.insulin - t.insulin) < pumpDescription.bolusStep
|
||||
result.bolusDelivered = t.insulin
|
||||
if (!result.success) {
|
||||
// Todo error code?
|
||||
result.comment = "error"
|
||||
} else {
|
||||
result.comment = "ok"
|
||||
}
|
||||
aapsLogger.debug(LTag.PUMP, "deliverTreatment: OK. Success: ${result.success} Asked: ${detailedBolusInfo.insulin} Delivered: ${result.bolusDelivered}")
|
||||
result
|
||||
} else {
|
||||
aapsLogger.debug(LTag.PUMP, "deliverTreatment: Invalid input")
|
||||
val result = PumpEnactResult(injector)
|
||||
result.success = false
|
||||
result.bolusDelivered = 0.0
|
||||
result.comment = rh.gs(info.nightscout.core.ui.R.string.invalid_input)
|
||||
aapsLogger.error("deliverTreatment: Invalid input")
|
||||
result
|
||||
}
|
||||
}
|
||||
|
||||
override fun stopBolusDelivering() {
|
||||
// TODO
|
||||
if (!isInitialized()) return
|
||||
|
||||
aapsLogger.info(LTag.PUMP, "stopBolusDelivering")
|
||||
medtrumService?.stopBolus()
|
||||
}
|
||||
|
||||
@Synchronized
|
||||
override fun setTempBasalAbsolute(absoluteRate: Double, durationInMinutes: Int, profile: Profile, enforceNew: Boolean, tbrType: PumpSync.TemporaryBasalType): PumpEnactResult {
|
||||
if (!isInitialized()) return PumpEnactResult(injector).success(false).enacted(false)
|
||||
|
||||
|
|
|
@ -12,6 +12,7 @@ import info.nightscout.pump.medtrum.comm.enums.BasalType
|
|||
import info.nightscout.pump.medtrum.comm.enums.MedtrumPumpState
|
||||
import info.nightscout.pump.medtrum.extension.toByteArray
|
||||
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.sharedPreferences.SP
|
||||
|
@ -67,6 +68,14 @@ class MedtrumPump @Inject constructor(
|
|||
_primeProgress.value = value
|
||||
}
|
||||
|
||||
private val _lastBasalRate = MutableStateFlow(0.0)
|
||||
val lastBasalRateFlow: StateFlow<Double> = _lastBasalRate
|
||||
var lastBasalRate: Double
|
||||
get() = _lastBasalRate.value
|
||||
set(value) {
|
||||
_lastBasalRate.value = value
|
||||
}
|
||||
|
||||
/** Stuff stored in SP */
|
||||
private var _patchSessionToken = 0L
|
||||
var patchSessionToken: Long
|
||||
|
@ -136,9 +145,17 @@ class MedtrumPump @Inject constructor(
|
|||
var alarmFlags = 0
|
||||
var alarmParameter = 0
|
||||
|
||||
// bolus status
|
||||
var bolusingTreatment: EventOverviewBolusProgress.Treatment? = null // actually delivered treatment
|
||||
var bolusAmountToBeDelivered = 0.0 // amount to be delivered
|
||||
var bolusProgressLastTimeStamp: Long = 0 // timestamp of last bolus progress message
|
||||
var bolusStopped = false // bolus finished
|
||||
var bolusStopForced = false // bolus forced to stop by user
|
||||
var bolusDone = false // success end
|
||||
|
||||
// Last basal status update
|
||||
// TODO: Save this in SP?
|
||||
var lastBasalRate = 0.0
|
||||
|
||||
var lastBasalSequence = 0
|
||||
var lastBasalPatchId = 0L
|
||||
var lastBasalStartTime = 0L
|
||||
|
@ -270,6 +287,17 @@ class MedtrumPump @Inject constructor(
|
|||
handleBasalStatusUpdate(basalType, basalValue, basalSequence, basalPatchId, basalStartTime, dateUtil.now())
|
||||
}
|
||||
|
||||
fun handleBolusStatusUpdate(bolusType: Int, bolusCompleted: Boolean, amountDelivered: Double) {
|
||||
aapsLogger.debug(LTag.PUMP, "handleBolusStatusUpdate: bolusType: $bolusType bolusCompleted: $bolusCompleted amountDelivered: $amountDelivered")
|
||||
bolusProgressLastTimeStamp = dateUtil.now()
|
||||
if (bolusCompleted) {
|
||||
bolusDone = true
|
||||
bolusingTreatment?.insulin = amountDelivered
|
||||
} else {
|
||||
bolusingTreatment?.insulin = amountDelivered
|
||||
}
|
||||
}
|
||||
|
||||
fun handleBasalStatusUpdate(basalType: BasalType, basalRate: Double, basalSequence: Int, basalPatchId: Long, basalStartTime: Long, receivedTime: Long) {
|
||||
aapsLogger.debug(
|
||||
LTag.PUMP,
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
package info.nightscout.pump.medtrum.comm.enums
|
||||
|
||||
enum class BolusType {
|
||||
NONE,
|
||||
NORMAL,
|
||||
EXTEND,
|
||||
COMBINATION;
|
||||
|
||||
fun getValue(): Int {
|
||||
return ordinal
|
||||
}
|
||||
}
|
|
@ -41,14 +41,6 @@ class AuthorizePacket(injector: HasAndroidInjector) : MedtrumPacket(injector) {
|
|||
}
|
||||
|
||||
override fun handleResponse(data: ByteArray): Boolean {
|
||||
if (data.size > 3) {
|
||||
val incomingOpCode: Byte = data.copyOfRange(RESP_OPCODE_START, RESP_OPCODE_END).first()
|
||||
if (incomingOpCode == CommandType.SUBSCRIBE.code) {
|
||||
// TODO: Test and see if this can be removed
|
||||
aapsLogger.error(LTag.PUMPCOMM, "handleResponse: Got subscribe response instead of authorize response, handling subscribe packet")
|
||||
return SubscribePacket(injector).handleResponse(data)
|
||||
}
|
||||
}
|
||||
val success = super.handleResponse(data)
|
||||
if (success) {
|
||||
deviceType = data.copyOfRange(RESP_DEVICE_TYPE_START, RESP_DEVICE_TYPE_END).toInt()
|
||||
|
|
|
@ -1,11 +1,13 @@
|
|||
package info.nightscout.pump.medtrum.comm.packets
|
||||
|
||||
import dagger.android.HasAndroidInjector
|
||||
import info.nightscout.interfaces.pump.DetailedBolusInfoStorage
|
||||
import info.nightscout.interfaces.pump.PumpSync
|
||||
import info.nightscout.interfaces.pump.TemporaryBasalStorage
|
||||
import info.nightscout.pump.medtrum.MedtrumPump
|
||||
import info.nightscout.pump.medtrum.comm.enums.CommandType.GET_RECORD
|
||||
import info.nightscout.pump.medtrum.comm.enums.BasalType
|
||||
import info.nightscout.pump.medtrum.comm.enums.BolusType
|
||||
import info.nightscout.pump.medtrum.extension.toByteArray
|
||||
import info.nightscout.pump.medtrum.extension.toInt
|
||||
import info.nightscout.pump.medtrum.extension.toLong
|
||||
|
@ -20,6 +22,7 @@ class GetRecordPacket(injector: HasAndroidInjector, private val recordIndex: Int
|
|||
@Inject lateinit var medtrumPump: MedtrumPump
|
||||
@Inject lateinit var pumpSync: PumpSync
|
||||
@Inject lateinit var temporaryBasalStorage: TemporaryBasalStorage
|
||||
@Inject lateinit var detailedBolusInfoStorage: DetailedBolusInfoStorage
|
||||
@Inject lateinit var dateUtil: DateUtil
|
||||
|
||||
companion object {
|
||||
|
@ -85,6 +88,51 @@ class GetRecordPacket(injector: HasAndroidInjector, private val recordIndex: Int
|
|||
when (recordType) {
|
||||
BOLUS_RECORD, BOLUS_RECORD_ALT -> {
|
||||
aapsLogger.debug(LTag.PUMPCOMM, "GetRecordPacket HandleResponse: BOLUS_RECORD")
|
||||
val typeAndWizard = data.copyOfRange(RESP_RECORD_DATA_START, RESP_RECORD_DATA_START + 1).toInt()
|
||||
val bolusCause = data.copyOfRange(RESP_RECORD_DATA_START + 1, RESP_RECORD_DATA_START + 2).toInt()
|
||||
val unknown = data.copyOfRange(RESP_RECORD_DATA_START + 2, RESP_RECORD_DATA_START + 4).toInt()
|
||||
val bolusStartTime = MedtrumTimeUtil().convertPumpTimeToSystemTimeMillis(data.copyOfRange(RESP_RECORD_DATA_START + 4, RESP_RECORD_DATA_START + 8).toLong())
|
||||
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 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()
|
||||
val bolusIOB = data.copyOfRange(RESP_RECORD_DATA_START + 22, RESP_RECORD_DATA_START + 24).toInt()
|
||||
val unkown1 = data.copyOfRange(RESP_RECORD_DATA_START + 24, RESP_RECORD_DATA_START + 26).toInt()
|
||||
val unkown2 = data.copyOfRange(RESP_RECORD_DATA_START + 26, RESP_RECORD_DATA_START + 28).toInt()
|
||||
val bolusType = enumValues<BolusType>()[typeAndWizard and 0x0F]
|
||||
val bolusWizard = (typeAndWizard and 0xF0) != 0
|
||||
aapsLogger.debug(
|
||||
LTag.PUMPCOMM,
|
||||
"GetRecordPacket HandleResponse: BOLUS_RECORD: typeAndWizard: $typeAndWizard, bolusCause: $bolusCause, unknown: $unknown, bolusStartTime: $bolusStartTime, " + "bolusNormalAmount: $bolusNormalAmount, bolusNormalDelivered: $bolusNormalDelivered, bolusExtendedAmount: $bolusExtendedAmount, bolusExtendedDuration: $bolusExtendedDuration, " + "bolusExtendedDelivered: $bolusExtendedDelivered, bolusCarb: $bolusCarb, bolusGlucose: $bolusGlucose, bolusIOB: $bolusIOB, unkown1: $unkown1, unkown2: $unkown2, " + "bolusType: $bolusType, bolusWizard: $bolusWizard"
|
||||
)
|
||||
if (bolusType == BolusType.NORMAL) {
|
||||
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)
|
||||
)
|
||||
aapsLogger.debug(
|
||||
LTag.PUMPCOMM,
|
||||
"from record: ${if (newRecord) "**NEW** " else ""}EVENT BOLUS ${dateUtil.dateAndTimeString(bolusStartTime)} ($bolusStartTime) Bolus: ${bolusNormalDelivered}U "
|
||||
)
|
||||
if (!newRecord && detailedBolusInfo != null) {
|
||||
// detailedInfo can be from another similar record. Reinsert
|
||||
detailedBolusInfoStorage.add(detailedBolusInfo)
|
||||
}
|
||||
} else {
|
||||
aapsLogger.error(
|
||||
LTag.PUMPCOMM,
|
||||
"from record: EVENT BOLUS ${dateUtil.dateAndTimeString(bolusStartTime)} ($bolusStartTime) " + "Bolus type: $bolusType not supported"
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
BASAL_RECORD, BASAL_RECORD_ALT -> {
|
||||
|
|
|
@ -98,13 +98,10 @@ class NotificationPacket(val injector: HasAndroidInjector) {
|
|||
aapsLogger.debug(LTag.PUMPCOMM, "Normal bolus notification received")
|
||||
var bolusData = data.copyOfRange(offset, offset + 1).toInt()
|
||||
var bolusType = bolusData and 0x7F
|
||||
var bolusCompleted = (bolusData shr 7) and 0x01 // TODO: Check for other flags here :)
|
||||
val bolusCompleted: Boolean = ((bolusData shr 7) and 0x01) != 0 // TODO: Check for other flags here :)
|
||||
var bolusDelivered = data.copyOfRange(offset + 1, offset + 3).toInt() * 0.05
|
||||
// TODO Sync bolus flow:
|
||||
// If bolus is known add status
|
||||
// If bolus is not known start read bolus
|
||||
// When bolus is completed, remove bolus from medtrumPump
|
||||
aapsLogger.debug(LTag.PUMPCOMM, "Bolus type: $bolusType, bolusData: $bolusData bolus completed: $bolusCompleted, bolus delivered: $bolusDelivered")
|
||||
medtrumPump.handleBolusStatusUpdate(bolusType, bolusCompleted, bolusDelivered)
|
||||
offset += 3
|
||||
}
|
||||
|
||||
|
|
|
@ -90,8 +90,8 @@ class BLEComm @Inject internal constructor(
|
|||
private val mBluetoothAdapter: BluetoothAdapter? get() = (context.getSystemService(Context.BLUETOOTH_SERVICE) as BluetoothManager?)?.adapter
|
||||
private var mBluetoothGatt: BluetoothGatt? = null
|
||||
|
||||
var isConnected = false // TODO: These may be removed have no function
|
||||
var isConnecting = false// TODO: These may be removed have no function
|
||||
private var isConnected = false // Only to track internal ble state
|
||||
private var isConnecting = false // Only to track internal ble state
|
||||
private var uartWrite: BluetoothGattCharacteristic? = null
|
||||
private var uartRead: BluetoothGattCharacteristic? = null
|
||||
|
||||
|
@ -126,14 +126,12 @@ class BLEComm @Inject internal constructor(
|
|||
|
||||
|
||||
isConnected = false
|
||||
// TODO: Maybe replace this by (or add) a isScanning parameter?
|
||||
isConnecting = true
|
||||
|
||||
// Find our Medtrum Device!
|
||||
filters.add(
|
||||
ScanFilter.Builder().setDeviceName("MT").build()
|
||||
)
|
||||
// TODO Check if we need to add MAC for reconnects? Not sure if otherwise we can find the device
|
||||
mBluetoothAdapter?.bluetoothLeScanner?.startScan(filters, settings, mScanCallback)
|
||||
return true
|
||||
}
|
||||
|
@ -159,6 +157,9 @@ class BLEComm @Inject internal constructor(
|
|||
return false
|
||||
}
|
||||
|
||||
// TODO: THIS IS A WORKAROUND TEST
|
||||
mWritePackets = WriteCommandPackets()
|
||||
|
||||
if (mDevice != null && mDeviceSN == deviceSN) {
|
||||
// Skip scanning and directly connect to gatt
|
||||
aapsLogger.debug(LTag.PUMPBTCOMM, "Skipping scan and directly connecting to gatt")
|
||||
|
@ -178,7 +179,7 @@ class BLEComm @Inject internal constructor(
|
|||
/** Connect flow: 2. When device is found this is called by onScanResult() */
|
||||
@SuppressLint("MissingPermission")
|
||||
@Synchronized
|
||||
fun connectGatt(device: BluetoothDevice) {
|
||||
private fun connectGatt(device: BluetoothDevice) {
|
||||
mBluetoothGatt =
|
||||
device.connectGatt(context, false, mGattCallback, BluetoothDevice.TRANSPORT_LE)
|
||||
}
|
||||
|
@ -196,12 +197,14 @@ class BLEComm @Inject internal constructor(
|
|||
if (isConnecting) {
|
||||
stopScan()
|
||||
}
|
||||
mBluetoothGatt?.disconnect()
|
||||
}
|
||||
|
||||
@Synchronized
|
||||
fun stopConnecting() {
|
||||
isConnecting = false
|
||||
if (isConnected) {
|
||||
mBluetoothGatt?.disconnect()
|
||||
} else {
|
||||
close()
|
||||
isConnected = false
|
||||
isConnecting = false
|
||||
mCallback?.onBLEDisconnected()
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressLint("MissingPermission")
|
||||
|
@ -347,8 +350,6 @@ class BLEComm @Inject internal constructor(
|
|||
aapsLogger.debug(LTag.PUMPBTCOMM, "Notifications enabled!")
|
||||
/** Connect flow: 6. Connected */
|
||||
mCallback?.onBLEConnected()
|
||||
isConnected = true
|
||||
isConnecting = false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -384,9 +385,9 @@ class BLEComm @Inject internal constructor(
|
|||
private fun onConnectionStateChangeSynchronized(gatt: BluetoothGatt, status: Int, newState: Int) {
|
||||
aapsLogger.debug(LTag.PUMPBTCOMM, "onConnectionStateChange newState: " + newState + " status: " + status)
|
||||
if (newState == BluetoothProfile.STATE_CONNECTED) {
|
||||
handler.postDelayed({
|
||||
mBluetoothGatt?.discoverServices()
|
||||
}, WRITE_DELAY_MILLIS)
|
||||
isConnected = true
|
||||
isConnecting = false
|
||||
mBluetoothGatt?.discoverServices()
|
||||
} else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
|
||||
close()
|
||||
isConnected = false
|
||||
|
|
|
@ -5,6 +5,7 @@ import android.content.Context
|
|||
import android.content.Intent
|
||||
import android.os.Binder
|
||||
import android.os.IBinder
|
||||
import android.os.SystemClock
|
||||
import dagger.android.DaggerService
|
||||
import dagger.android.HasAndroidInjector
|
||||
import info.nightscout.core.utils.fabric.FabricPrivacy
|
||||
|
@ -14,6 +15,7 @@ import info.nightscout.interfaces.profile.Profile
|
|||
import info.nightscout.interfaces.profile.ProfileFunction
|
||||
import info.nightscout.interfaces.pump.PumpEnactResult
|
||||
import info.nightscout.interfaces.pump.PumpSync
|
||||
import info.nightscout.interfaces.queue.Callback
|
||||
import info.nightscout.interfaces.queue.CommandQueue
|
||||
import info.nightscout.interfaces.ui.UiInteraction
|
||||
import info.nightscout.pump.medtrum.MedtrumPlugin
|
||||
|
@ -42,6 +44,7 @@ import io.reactivex.rxjava3.kotlin.plusAssign
|
|||
import java.util.*
|
||||
import javax.inject.Inject
|
||||
import kotlin.math.abs
|
||||
import kotlin.math.round
|
||||
|
||||
class MedtrumService : DaggerService(), BLECommCallback {
|
||||
|
||||
|
@ -130,12 +133,10 @@ class MedtrumService : DaggerService(), BLECommCallback {
|
|||
}
|
||||
|
||||
fun stopConnecting() {
|
||||
// TODO proper way for this might need send commands etc
|
||||
bleComm.stopConnecting()
|
||||
bleComm.disconnect("stopConnecting")
|
||||
}
|
||||
|
||||
fun disconnect(from: String) {
|
||||
// TODO proper way for this might need send commands etc
|
||||
bleComm.disconnect(from)
|
||||
}
|
||||
|
||||
|
@ -155,14 +156,58 @@ class MedtrumService : DaggerService(), BLECommCallback {
|
|||
}
|
||||
}
|
||||
|
||||
fun bolus(insulin: Double, carbs: Int, carbTime: Long, t: EventOverviewBolusProgress.Treatment): Boolean {
|
||||
fun setBolus(insulin: Double, t: EventOverviewBolusProgress.Treatment): Boolean {
|
||||
if (!isConnected) return false
|
||||
// TODO
|
||||
return false
|
||||
val result = sendPacketAndGetResponse(SetBolusPacket(injector, insulin))
|
||||
|
||||
medtrumPump.bolusDone = false
|
||||
medtrumPump.bolusingTreatment = t
|
||||
medtrumPump.bolusAmountToBeDelivered = insulin
|
||||
medtrumPump.bolusStopped = false
|
||||
medtrumPump.bolusStopForced = false
|
||||
medtrumPump.bolusProgressLastTimeStamp = dateUtil.now()
|
||||
|
||||
val bolusStart = System.currentTimeMillis()
|
||||
|
||||
val bolusingEvent = EventOverviewBolusProgress
|
||||
while (medtrumPump.bolusStopped == false && result == true && medtrumPump.bolusDone == false) {
|
||||
SystemClock.sleep(100)
|
||||
if (System.currentTimeMillis() - medtrumPump.bolusProgressLastTimeStamp > T.secs(15).msecs()) {
|
||||
medtrumPump.bolusStopped = true
|
||||
medtrumPump.bolusStopForced = true
|
||||
aapsLogger.debug(LTag.PUMPCOMM, "Communication stopped")
|
||||
bleComm.disconnect("Communication stopped")
|
||||
} else {
|
||||
bolusingEvent.t = medtrumPump.bolusingTreatment
|
||||
bolusingEvent.status = rh.gs(info.nightscout.pump.common.R.string.bolus_delivered_so_far, medtrumPump.bolusingTreatment?.insulin, medtrumPump.bolusAmountToBeDelivered)
|
||||
bolusingEvent.percent = round((medtrumPump.bolusingTreatment?.insulin?.div(medtrumPump.bolusAmountToBeDelivered) ?: 0.0) * 100).toInt() - 1
|
||||
rxBus.send(bolusingEvent)
|
||||
}
|
||||
}
|
||||
|
||||
bolusingEvent.t = medtrumPump.bolusingTreatment
|
||||
bolusingEvent.percent = 99
|
||||
medtrumPump.bolusingTreatment = null
|
||||
|
||||
val bolusDurationInMSec = (insulin * 60 * 1000)
|
||||
val expectedEnd = bolusStart + bolusDurationInMSec + 2000
|
||||
while (System.currentTimeMillis() < expectedEnd) {
|
||||
SystemClock.sleep(1000)
|
||||
}
|
||||
|
||||
// Do not call update status directly, reconnection may be needed
|
||||
commandQueue.readStatus(rh.gs(info.nightscout.pump.medtrum.R.string.gettingbolusstatus), object : Callback() {
|
||||
override fun run() {
|
||||
rxBus.send(EventPumpStatusChanged(rh.gs(info.nightscout.pump.medtrum.R.string.gettingbolusstatus)))
|
||||
bolusingEvent.percent = 100
|
||||
}
|
||||
})
|
||||
return result
|
||||
}
|
||||
|
||||
fun bolusStop() {
|
||||
// TODO
|
||||
fun stopBolus() {
|
||||
var result = sendPacketAndGetResponse(CancelBolusPacket(injector))
|
||||
aapsLogger.debug(LTag.PUMPCOMM, "bolusStop: result: $result")
|
||||
}
|
||||
|
||||
fun setTempBasal(absoluteRate: Double, durationInMinutes: Int): Boolean {
|
||||
|
@ -190,12 +235,15 @@ class MedtrumService : DaggerService(), BLECommCallback {
|
|||
}
|
||||
|
||||
fun updateBasalsInPump(profile: Profile): Boolean {
|
||||
var result = false
|
||||
val packet = medtrumPump.buildMedtrumProfileArray(profile)?.let { SetBasalProfilePacket(injector, it) }
|
||||
result = packet?.let { sendPacketAndGetResponse(it) } == true
|
||||
|
||||
// TODO: We might want to get rid of this and cancel the TBR before we set the basal profile
|
||||
var result = true
|
||||
// Update basal affects the TBR records (the pump will cancel the TBR, set our basal profile, and resume the TBR in a new record)
|
||||
// Cancel any TBR in progress
|
||||
if (medtrumPump.tempBasalInProgress) {
|
||||
result = sendPacketAndGetResponse(CancelTempBasalPacket(injector))
|
||||
}
|
||||
val packet = medtrumPump.buildMedtrumProfileArray(profile)?.let { SetBasalProfilePacket(injector, it) }
|
||||
if (result) result = packet?.let { sendPacketAndGetResponse(it) } == true
|
||||
|
||||
// Get history records, this will update the pump state and add changes in TBR to AAPS history
|
||||
if (result) result = syncRecords()
|
||||
|
||||
|
@ -211,7 +259,6 @@ class MedtrumService : DaggerService(), BLECommCallback {
|
|||
private fun syncRecords(): Boolean {
|
||||
aapsLogger.debug(LTag.PUMP, "syncRecords: called!, syncedSequenceNumber: ${medtrumPump.syncedSequenceNumber}, currentSequenceNumber: ${medtrumPump.currentSequenceNumber}")
|
||||
var result = false
|
||||
// TODO: Check if we need to sync older records as well
|
||||
// Note: medtrum app fetches all records when they sync?
|
||||
for (sequence in medtrumPump.syncedSequenceNumber..medtrumPump.currentSequenceNumber) {
|
||||
result = sendPacketAndGetResponse(GetRecordPacket(injector, sequence))
|
||||
|
|
|
@ -10,6 +10,7 @@ import info.nightscout.pump.medtrum.ui.event.UIEvent
|
|||
import info.nightscout.pump.medtrum.ui.viewmodel.BaseViewModel
|
||||
import info.nightscout.interfaces.profile.ProfileFunction
|
||||
import info.nightscout.pump.medtrum.MedtrumPump
|
||||
import info.nightscout.pump.medtrum.R
|
||||
import info.nightscout.pump.medtrum.code.ConnectionState
|
||||
import info.nightscout.pump.medtrum.comm.enums.MedtrumPumpState
|
||||
import info.nightscout.rx.AapsSchedulers
|
||||
|
@ -17,6 +18,7 @@ import info.nightscout.rx.bus.RxBus
|
|||
import info.nightscout.rx.events.EventPumpStatusChanged
|
||||
import info.nightscout.rx.logging.AAPSLogger
|
||||
import info.nightscout.rx.logging.LTag
|
||||
import info.nightscout.shared.interfaces.ResourceHelper
|
||||
import io.reactivex.rxjava3.disposables.CompositeDisposable
|
||||
import io.reactivex.rxjava3.kotlin.plusAssign
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
|
@ -27,6 +29,7 @@ import javax.inject.Inject
|
|||
|
||||
class MedtrumOverviewViewModel @Inject constructor(
|
||||
private val aapsLogger: AAPSLogger,
|
||||
private val rh: ResourceHelper,
|
||||
private val rxBus: RxBus,
|
||||
private val aapsSchedulers: AapsSchedulers,
|
||||
private val fabricPrivacy: FabricPrivacy,
|
||||
|
@ -48,6 +51,10 @@ class MedtrumOverviewViewModel @Inject constructor(
|
|||
val isPatchActivated: LiveData<Boolean>
|
||||
get() = _isPatchActivated
|
||||
|
||||
private val _runningBasalRate = SingleLiveEvent<String>()
|
||||
val runningBasalRate: LiveData<String>
|
||||
get() = _runningBasalRate
|
||||
|
||||
init {
|
||||
scope.launch {
|
||||
medtrumPump.connectionStateFlow.collect { state ->
|
||||
|
@ -77,6 +84,12 @@ class MedtrumOverviewViewModel @Inject constructor(
|
|||
}
|
||||
}
|
||||
}
|
||||
scope.launch {
|
||||
medtrumPump.lastBasalRateFlow.collect { rate ->
|
||||
aapsLogger.debug(LTag.PUMP, "MedtrumViewModel runningBasalRateFlow: $rate")
|
||||
_runningBasalRate.postValue(String.format(rh.gs(R.string.current_basal_rate), rate))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCleared() {
|
||||
|
|
|
@ -91,6 +91,54 @@
|
|||
|
||||
</LinearLayout>
|
||||
|
||||
<View
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="2dip"
|
||||
android:layout_marginLeft="20dp"
|
||||
android:layout_marginTop="5dp"
|
||||
android:layout_marginRight="20dp"
|
||||
android:layout_marginBottom="5dp"
|
||||
android:background="@color/list_delimiter" />
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginVertical="3dp"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1.5"
|
||||
android:gravity="end"
|
||||
android:paddingStart="5dp"
|
||||
android:paddingEnd="5dp"
|
||||
android:text="@string/current_basal_label"
|
||||
android:textSize="16sp" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="5dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="0"
|
||||
android:gravity="center_horizontal"
|
||||
android:paddingStart="2dp"
|
||||
android:paddingEnd="2dp"
|
||||
android:text="@string/colon"
|
||||
android:textSize="16sp" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/current_basal"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:gravity="start"
|
||||
android:paddingStart="5dp"
|
||||
android:paddingEnd="5dp"
|
||||
android:text="@{viewmodel.runningBasalRate}"
|
||||
android:textColor="@android:color/white"
|
||||
android:textSize="16sp" />
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</ScrollView>
|
||||
|
|
|
@ -12,12 +12,14 @@
|
|||
<string name="key_synced_sequence_number" translatable="false">synced_sequence_number</string>
|
||||
|
||||
<string name="medtrum">Medtrum</string>
|
||||
<string name="medtrum_pump_shortname">MEDTRUM</string>
|
||||
<string name="medtrum_pump_shortname">MT</string>
|
||||
<string name="medtrum_pump_description">Medtrum Nano</string>
|
||||
<string name="medtrumpump_settings">Medtrum pump settings</string>
|
||||
|
||||
<!-- overview fragment -->
|
||||
<string name="medtrum_ble_status">BLE Status</string>
|
||||
<string name="current_basal_label">Active basal</string>
|
||||
<string name="current_basal_rate"> %.2f U/h</string>
|
||||
<string name="string_new_patch">Start new patch</string>
|
||||
<string name="string_stop_patch">Stop patch</string>
|
||||
|
||||
|
@ -40,5 +42,8 @@
|
|||
<string name="snInput_title">SN</string>
|
||||
<string name="snInput_summary">Serial number pump base</string>
|
||||
|
||||
<string name="waitingforestimatedbolusend">Waiting for bolus end. Remaining %1$d sec.</string>
|
||||
<string name="gettingbolusstatus">Getting bolus status</string>
|
||||
|
||||
|
||||
</resources>
|
||||
|
|
Loading…
Reference in a new issue