Merge pull request #929 from andyrozman/bug798_meal_tbr

Bug798 - smb to meal bolus and zero tbr termination
This commit is contained in:
Milos Kozak 2021-11-15 00:31:21 +01:00 committed by GitHub
commit a7118b1a7e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
12 changed files with 2072 additions and 92 deletions

View file

@ -265,11 +265,11 @@ public class DateTimeUtil {
} }
public static long getATDWithAddedMinutes(long atd, int minutesDiff) { public static long getATDWithAddedSeconds(Long atd, int addedSeconds) {
GregorianCalendar oldestEntryTime = DateTimeUtil.toGregorianCalendar(atd); GregorianCalendar oldestEntryTime = DateTimeUtil.toGregorianCalendar(atd);
oldestEntryTime.add(Calendar.MINUTE, minutesDiff); oldestEntryTime.add(Calendar.SECOND, addedSeconds);
return oldestEntryTime.getTimeInMillis(); return toATechDate(oldestEntryTime.getTimeInMillis());
} }
@ -279,7 +279,6 @@ public class DateTimeUtil {
return toATechDate(oldestEntryTime); return toATechDate(oldestEntryTime);
} }
public static long getTimeInFutureFromMinutes(long startTime, int minutes) { public static long getTimeInFutureFromMinutes(long startTime, int minutes) {
return startTime + getTimeInMs(minutes); return startTime + getTimeInMs(minutes);
} }

11
medtronic/Changelog.txt Normal file
View file

@ -0,0 +1,11 @@
V1 - Medtronic initial implementation
... lots of changes
V2 - Rewrite into kotlin, new database (for v3.0)
0001 - initial version
0002 - some fixes
0003 - SMB fix (798)
0004 - Zero TBR Duration fix (798), refactoring of TempBasalProcessDTO
0005 - fixes to MedtronicHistoryEntry lateinit problem

View file

@ -32,6 +32,7 @@ import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.service.Riley
import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.service.tasks.ResetRileyLinkConfigurationTask import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.service.tasks.ResetRileyLinkConfigurationTask
import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.service.tasks.ServiceTaskExecutor import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.service.tasks.ServiceTaskExecutor
import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.service.tasks.WakeAndTuneTask import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.service.tasks.WakeAndTuneTask
import info.nightscout.androidaps.plugins.pump.common.sync.PumpDbEntryTBR
import info.nightscout.androidaps.plugins.pump.common.utils.DateTimeUtil import info.nightscout.androidaps.plugins.pump.common.utils.DateTimeUtil
import info.nightscout.androidaps.plugins.pump.common.utils.ProfileUtil import info.nightscout.androidaps.plugins.pump.common.utils.ProfileUtil
import info.nightscout.androidaps.plugins.pump.medtronic.comm.history.pump.PumpHistoryEntry import info.nightscout.androidaps.plugins.pump.medtronic.comm.history.pump.PumpHistoryEntry
@ -111,7 +112,7 @@ class MedtronicPumpPlugin @Inject constructor(
private var isBusy = false private var isBusy = false
override fun onStart() { override fun onStart() {
aapsLogger.debug(LTag.PUMP, deviceID() + " started.") aapsLogger.debug(LTag.PUMP, deviceID() + " started. (V2.0005)")
serviceConnection = object : ServiceConnection { serviceConnection = object : ServiceConnection {
override fun onServiceDisconnected(name: ComponentName) { override fun onServiceDisconnected(name: ComponentName) {
aapsLogger.debug(LTag.PUMP, "RileyLinkMedtronicService is disconnected") aapsLogger.debug(LTag.PUMP, "RileyLinkMedtronicService is disconnected")
@ -468,6 +469,7 @@ class MedtronicPumpPlugin @Inject constructor(
} }
} }
@Synchronized
override fun isThisProfileSet(profile: Profile): Boolean { override fun isThisProfileSet(profile: Profile): Boolean {
aapsLogger.debug(LTag.PUMP, "isThisProfileSet: basalInitalized=" + medtronicPumpStatus.basalProfileStatus) aapsLogger.debug(LTag.PUMP, "isThisProfileSet: basalInitalized=" + medtronicPumpStatus.basalProfileStatus)
if (!isInitialized) return true if (!isInitialized) return true
@ -580,6 +582,7 @@ class MedtronicPumpPlugin @Inject constructor(
scheduleNextRefresh(MedtronicStatusRefreshType.PumpTime, 0) scheduleNextRefresh(MedtronicStatusRefreshType.PumpTime, 0)
} }
@Synchronized
override fun deliverBolus(detailedBolusInfo: DetailedBolusInfo): PumpEnactResult { override fun deliverBolus(detailedBolusInfo: DetailedBolusInfo): PumpEnactResult {
aapsLogger.info(LTag.PUMP, "MedtronicPumpPlugin::deliverBolus - " + BolusDeliveryType.DeliveryPrepared) aapsLogger.info(LTag.PUMP, "MedtronicPumpPlugin::deliverBolus - " + BolusDeliveryType.DeliveryPrepared)
setRefreshButtonEnabled(false) setRefreshButtonEnabled(false)
@ -691,6 +694,7 @@ class MedtronicPumpPlugin @Inject constructor(
// if enforceNew===true current temp basal is canceled and new TBR set (duration is prolonged), // if enforceNew===true current temp basal is canceled and new TBR set (duration is prolonged),
// if false and the same rate is requested enacted=false and success=true is returned and TBR is not changed // if false and the same rate is requested enacted=false and success=true is returned and TBR is not changed
@Synchronized
override fun setTempBasalAbsolute(absoluteRate: Double, durationInMinutes: Int, profile: Profile, enforceNew: Boolean, tbrType: TemporaryBasalType): PumpEnactResult { override fun setTempBasalAbsolute(absoluteRate: Double, durationInMinutes: Int, profile: Profile, enforceNew: Boolean, tbrType: TemporaryBasalType): PumpEnactResult {
setRefreshButtonEnabled(false) setRefreshButtonEnabled(false)
if (isPumpNotReachable) { if (isPumpNotReachable) {
@ -742,6 +746,7 @@ class MedtronicPumpPlugin @Inject constructor(
return PumpEnactResult(injector).success(false).enacted(false) return PumpEnactResult(injector).success(false).enacted(false)
.comment(R.string.medtronic_cmd_cant_cancel_tbr_stop_op) .comment(R.string.medtronic_cmd_cant_cancel_tbr_stop_op)
} else { } else {
//cancelTBRWithTemporaryId()
aapsLogger.info(LTag.PUMP, logPrefix + "setTempBasalAbsolute - Current TBR cancelled.") aapsLogger.info(LTag.PUMP, logPrefix + "setTempBasalAbsolute - Current TBR cancelled.")
} }
} }
@ -760,8 +765,9 @@ class MedtronicPumpPlugin @Inject constructor(
medtronicPumpStatus.tempBasalAmount = absoluteRate medtronicPumpStatus.tempBasalAmount = absoluteRate
medtronicPumpStatus.tempBasalLength = durationInMinutes medtronicPumpStatus.tempBasalLength = durationInMinutes
val tempData = info.nightscout.androidaps.plugins.pump.common.sync.PumpDbEntryTBR(absoluteRate, true, durationInMinutes, tbrType) val tempData = PumpDbEntryTBR(absoluteRate, true, durationInMinutes, tbrType)
medtronicPumpStatus.runningTBRWithTemp = tempData
pumpSyncStorage.addTemporaryBasalRateWithTempId(tempData, true, this) pumpSyncStorage.addTemporaryBasalRateWithTempId(tempData, true, this)
incrementStatistics(MedtronicConst.Statistics.TBRsSet) incrementStatistics(MedtronicConst.Statistics.TBRsSet)
@ -771,6 +777,63 @@ class MedtronicPumpPlugin @Inject constructor(
} }
} }
@Deprecated("Not used, TBRs fixed in history, should be removed.")
private fun cancelTBRWithTemporaryId() {
val tbrs : MutableList<PumpDbEntryTBR> = pumpSyncStorage.getTBRs()
if (tbrs.size > 0 && medtronicPumpStatus.runningTBRWithTemp!=null) {
aapsLogger.info(LTag.PUMP, logPrefix + "cancelTBRWithTemporaryId - TBR items: ${tbrs.size}")
var item : PumpDbEntryTBR? = null
if (tbrs.size==1) {
item = tbrs.get(0);
} else {
for (tbr in tbrs) {
if (tbr.date == medtronicPumpStatus.runningTBRWithTemp!!.date) {
item = tbr
break;
}
}
}
if (item!=null) {
aapsLogger.debug(LTag.PUMP, "DD: cancelTBRWithTemporaryId: tempIdEntry=${item}")
val differenceS = (System.currentTimeMillis() - item.date) / 1000
aapsLogger.debug(LTag.PUMP, "syncTemporaryBasalWithTempId " +
"[date=${item.date}, " +
"rate=${item.rate}, " +
"duration=${differenceS} s, " +
"isAbsolute=${!item.isAbsolute}, temporaryId=${item.temporaryId}, " +
"pumpId=NO, pumpType=${medtronicPumpStatus.pumpType}, " +
"pumpSerial=${medtronicPumpStatus.serialNumber}]")
val result = pumpSync.syncTemporaryBasalWithTempId(
timestamp = item.date,
rate = item.rate,
duration= differenceS * 1000L,
isAbsolute = item.isAbsolute,
temporaryId = item.temporaryId,
type = item.tbrType,
pumpId = null,
pumpType = medtronicPumpStatus.pumpType,
pumpSerial = medtronicPumpStatus.serialNumber)
aapsLogger.debug(LTag.PUMP, "syncTemporaryBasalWithTempId - Result: $result")
}
} else {
aapsLogger.info(LTag.PUMP, logPrefix + "cancelTBRWithTemporaryId - TBR items: ${tbrs.size}, runningTBRWithTemp=${medtronicPumpStatus.runningTBRWithTemp}")
}
if (medtronicPumpStatus.runningTBRWithTemp!=null) {
medtronicPumpStatus.runningTBRWithTemp = null
}
}
@Synchronized
override fun setTempBasalPercent(percent: Int, durationInMinutes: Int, profile: Profile, enforceNew: Boolean, tbrType: TemporaryBasalType): PumpEnactResult { override fun setTempBasalPercent(percent: Int, durationInMinutes: Int, profile: Profile, enforceNew: Boolean, tbrType: TemporaryBasalType): PumpEnactResult {
return if (percent == 0) { return if (percent == 0) {
setTempBasalAbsolute(0.0, durationInMinutes, profile, enforceNew, tbrType) setTempBasalAbsolute(0.0, durationInMinutes, profile, enforceNew, tbrType)
@ -966,6 +1029,7 @@ class MedtronicPumpPlugin @Inject constructor(
} }
} }
@Synchronized
override fun cancelTempBasal(enforceNew: Boolean): PumpEnactResult { override fun cancelTempBasal(enforceNew: Boolean): PumpEnactResult {
aapsLogger.info(LTag.PUMP, logPrefix + "cancelTempBasal - started") aapsLogger.info(LTag.PUMP, logPrefix + "cancelTempBasal - started")
if (isPumpNotReachable) { if (isPumpNotReachable) {
@ -1001,7 +1065,7 @@ class MedtronicPumpPlugin @Inject constructor(
aapsLogger.info(LTag.PUMP, logPrefix + "cancelTempBasal - Cancel TBR successful.") aapsLogger.info(LTag.PUMP, logPrefix + "cancelTempBasal - Cancel TBR successful.")
val runningTBR = medtronicPumpStatus.runningTBR val runningTBR = medtronicPumpStatus.runningTBR
// TODO
if (runningTBR != null) { if (runningTBR != null) {
if (medtronicHistoryData.isTBRActive(runningTBR)) { if (medtronicHistoryData.isTBRActive(runningTBR)) {
@ -1026,6 +1090,8 @@ class MedtronicPumpPlugin @Inject constructor(
} }
} }
//cancelTBRWithTemporaryId()
PumpEnactResult(injector).success(true).enacted(true) // PumpEnactResult(injector).success(true).enacted(true) //
.isTempCancel(true) .isTempCancel(true)
} }
@ -1043,6 +1109,7 @@ class MedtronicPumpPlugin @Inject constructor(
return medtronicPumpStatus.serialNumber return medtronicPumpStatus.serialNumber
} }
@Synchronized
override fun setNewBasalProfile(profile: Profile): PumpEnactResult { override fun setNewBasalProfile(profile: Profile): PumpEnactResult {
aapsLogger.info(LTag.PUMP, logPrefix + "setNewBasalProfile") aapsLogger.info(LTag.PUMP, logPrefix + "setNewBasalProfile")

View file

@ -14,13 +14,13 @@ import info.nightscout.androidaps.plugins.pump.common.utils.StringUtil
*/ */
abstract class MedtronicHistoryEntry : MedtronicHistoryEntryInterface { abstract class MedtronicHistoryEntry : MedtronicHistoryEntryInterface {
lateinit var rawData: List<Byte> var rawData: List<Byte> = listOf()
protected var sizes = IntArray(3) protected var sizes = IntArray(3)
lateinit var head: ByteArray var head: ByteArray = byteArrayOf()
lateinit var datetime: ByteArray var datetime: ByteArray = byteArrayOf()
lateinit var body: ByteArray var body: ByteArray = byteArrayOf()
var id: Long = 0 var id: Long = 0
@ -41,7 +41,13 @@ abstract class MedtronicHistoryEntry : MedtronicHistoryEntryInterface {
/** /**
* Pump id that will be used with AAPS object (time * 1000 + historyType (max is FF = 255) * Pump id that will be used with AAPS object (time * 1000 + historyType (max is FF = 255)
*/ */
open var pumpId: Long = 0L var pumpId: Long = 0L
get() {
if (field == 0L) {
field = generatePumpId()
}
return field
}
/** /**
* if history object is already linked to AAPS object (either Treatment, TempBasal or TDD (tdd's * if history object is already linked to AAPS object (either Treatment, TempBasal or TDD (tdd's
@ -158,7 +164,7 @@ abstract class MedtronicHistoryEntry : MedtronicHistoryEntryInterface {
sb.append("]") sb.append("]")
return sb.toString() return sb.toString()
} }
if (head.size != 0) { if (head!=null && head.size != 0) {
sb.append(", head=") sb.append(", head=")
sb.append(ByteUtil.shortHexString(head)) sb.append(ByteUtil.shortHexString(head))
} }

View file

@ -92,14 +92,6 @@ class PumpHistoryEntry : MedtronicHistoryEntry() {
} }
} }
override var pumpId: Long = 0L
get() {
if (field == 0L) {
field = generatePumpId()
}
return field
}
fun hasBolusChanged(entry: PumpHistoryEntry): Boolean { fun hasBolusChanged(entry: PumpHistoryEntry): Boolean {
if (entryType == PumpHistoryEntryType.Bolus) { if (entryType == PumpHistoryEntryType.Bolus) {
val thisOne: BolusDTO = this.decodedData["Object"] as BolusDTO val thisOne: BolusDTO = this.decodedData["Object"] as BolusDTO

View file

@ -508,25 +508,25 @@ class MedtronicHistoryData @Inject constructor(
if (temporaryId != null) { if (temporaryId != null) {
val result = pumpSync.syncBolusWithTempId( val result = pumpSync.syncBolusWithTempId(
tryToGetByLocalTime(bolus.atechDateTime), timestamp = tryToGetByLocalTime(bolus.atechDateTime),
deliveredAmount, amount = deliveredAmount,
temporaryId, temporaryId = temporaryId,
type, type = null,
bolus.pumpId, pumpId = bolus.pumpId,
medtronicPumpStatus.pumpType, pumpType = medtronicPumpStatus.pumpType,
medtronicPumpStatus.serialNumber) pumpSerial = medtronicPumpStatus.serialNumber)
aapsLogger.debug(LTag.PUMP, String.format(Locale.ENGLISH, "syncBolusWithTempId [date=%d, temporaryId=%d, pumpId=%d, insulin=%.2f, pumpSerial=%s] - Result: %b", aapsLogger.debug(LTag.PUMP, String.format(Locale.ENGLISH, "syncBolusWithTempId [date=%d, temporaryId=%d, pumpId=%d, insulin=%.2f, pumpSerial=%s] - Result: %b",
bolus.atechDateTime, temporaryId, bolus.pumpId, deliveredAmount, bolus.atechDateTime, temporaryId, bolus.pumpId, deliveredAmount,
medtronicPumpStatus.serialNumber, result)) medtronicPumpStatus.serialNumber, result))
} else { } else {
val result = pumpSync.syncBolusWithPumpId( val result = pumpSync.syncBolusWithPumpId(
tryToGetByLocalTime(bolus.atechDateTime), timestamp = tryToGetByLocalTime(bolus.atechDateTime),
deliveredAmount, amount = deliveredAmount,
type, type = null,
bolus.pumpId, pumpId = bolus.pumpId,
medtronicPumpStatus.pumpType, pumpType = medtronicPumpStatus.pumpType,
medtronicPumpStatus.serialNumber) pumpSerial = medtronicPumpStatus.serialNumber)
aapsLogger.debug(LTag.PUMP, String.format(Locale.ENGLISH, "syncBolusWithPumpId [date=%d, pumpId=%d, insulin=%.2f, pumpSerial=%s] - Result: %b", aapsLogger.debug(LTag.PUMP, String.format(Locale.ENGLISH, "syncBolusWithPumpId [date=%d, pumpId=%d, insulin=%.2f, pumpSerial=%s] - Result: %b",
bolus.atechDateTime, bolus.pumpId, deliveredAmount, bolus.atechDateTime, bolus.pumpId, deliveredAmount,
@ -571,62 +571,42 @@ class MedtronicHistoryData @Inject constructor(
private fun processTBREntries(entryList: MutableList<PumpHistoryEntry>) { private fun processTBREntries(entryList: MutableList<PumpHistoryEntry>) {
entryList.reverse() entryList.reverse()
val tbr = entryList[0].getDecodedDataEntry("Object") as TempBasalPair val tbr = entryList[0].getDecodedDataEntry("Object") as TempBasalPair
var readOldItem = false // var readOldItem = false
if (tbr.isCancelTBR) {
val oneMoreEntryFromHistory = getOneMoreEntryFromHistory(PumpHistoryEntryType.TempBasalCombined) val oneMoreEntryFromHistory = getOneMoreEntryFromHistory(PumpHistoryEntryType.TempBasalCombined)
if (tbr.isCancelTBR) { // if we have cancel we need to limit previous TBR with this cancel
if (oneMoreEntryFromHistory != null) { if (oneMoreEntryFromHistory != null) {
entryList.add(0, oneMoreEntryFromHistory) entryList.add(0, oneMoreEntryFromHistory)
readOldItem = true
} else { } else {
entryList.removeAt(0) entryList.removeAt(0)
} }
} else {
if (oneMoreEntryFromHistory != null) {
val tbrPrev = oneMoreEntryFromHistory.getDecodedDataEntry("Object") as TempBasalPair
if (tbrPrev.isZeroTBR) { // if we had Zere TBR in last previous TBR, then we need to limit it, so we need to process it too
entryList.add(0, oneMoreEntryFromHistory)
}
}
} }
val tbrRecords = pumpSyncStorage.getTBRs() val tbrRecords = pumpSyncStorage.getTBRs()
aapsLogger.debug(LTag.PUMP, String.format(Locale.ENGLISH, ProcessHistoryRecord.TBR.description + " List (before filter): %s, FromDb=%s", gson.toJson(entryList),
tbrRecords)) val processList: MutableList<TempBasalProcessDTO> = createTBRProcessList(entryList);
var processDTO: TempBasalProcessDTO? = null
val processList: MutableList<TempBasalProcessDTO> = mutableListOf()
for (treatment in entryList) {
val tbr2 = treatment.getDecodedDataEntry("Object") as TempBasalPair
if (tbr2.isCancelTBR) {
if (processDTO != null) {
processDTO.itemTwo = treatment
processDTO.cancelPresent = true
if (readOldItem) {
processDTO.processOperation = TempBasalProcessDTO.Operation.Edit
readOldItem = false
}
} else {
aapsLogger.warn(LTag.PUMP, "processDTO was null - shouldn't happen, ignoring item. ItemTwo=$treatment")
}
} else {
if (processDTO != null) {
processList.add(processDTO)
}
processDTO = TempBasalProcessDTO(
itemOne = treatment,
processOperation = TempBasalProcessDTO.Operation.Add,
aapsLogger = aapsLogger,
objectType = TempBasalProcessDTO.ObjectType.TemporaryBasal
)
}
}
if (processDTO != null) {
processList.add(processDTO)
}
if (processList.isNotEmpty()) { if (processList.isNotEmpty()) {
for (tempBasalProcessDTO in processList) { for (tempBasalProcessDTO in processList) {
aapsLogger.debug(LTag.PUMP, "DD: tempBasalProcessDTO.itemOne: " + gson.toJson(tempBasalProcessDTO.itemOne)) aapsLogger.debug(LTag.PUMP, "DD: tempBasalProcessDTO: " + tempBasalProcessDTO.toTreatmentString())
aapsLogger.debug(LTag.PUMP, "DD: tempBasalProcessDTO.itemTwo: " + (if (tempBasalProcessDTO.itemTwo == null) "null" else gson.toJson(tempBasalProcessDTO.itemTwo!!))) //aapsLogger.debug(LTag.PUMP, "DD: tempBasalProcessDTO.itemOne: " + gson.toJson(tempBasalProcessDTO.itemOne))
//aapsLogger.debug(LTag.PUMP, "DD: tempBasalProcessDTO.itemTwo: " + (if (tempBasalProcessDTO.itemTwo == null) "null" else gson.toJson(tempBasalProcessDTO.itemTwo!!)))
@Suppress("Unchecked_Cast") @Suppress("Unchecked_Cast")
val entryWithTempId = findDbEntry(tempBasalProcessDTO.itemOne, tbrRecords as MutableList<PumpDbEntry>) as PumpDbEntryTBR? val entryWithTempId = findDbEntry(tempBasalProcessDTO.itemOne, tbrRecords as MutableList<PumpDbEntry>) as PumpDbEntryTBR?
aapsLogger.debug(LTag.PUMP, "DD: entryWithTempId: " + (entryWithTempId?.toString() ?: "null")) aapsLogger.debug(LTag.PUMP, "DD: entryWithTempId: " + (entryWithTempId?.toString() ?: "null"))
val tbrEntry = tempBasalProcessDTO.itemOneTbr //.getDecodedDataEntry("Object") as TempBasalPair val tbrEntry = tempBasalProcessDTO.itemOneTbr
aapsLogger.debug(LTag.PUMP, String.format("DD: tbrEntry=%s, tempBasalProcessDTO=%s", gson.toJson(tbrEntry), gson.toJson(tempBasalProcessDTO))) aapsLogger.debug(LTag.PUMP, String.format("DD: tbrEntry=%s, tempBasalProcessDTO=%s", gson.toJson(tbrEntry), gson.toJson(tempBasalProcessDTO)))
@ -649,7 +629,7 @@ class MedtronicHistoryData @Inject constructor(
tryToGetByLocalTime(tempBasalProcessDTO.atechDateTime), tryToGetByLocalTime(tempBasalProcessDTO.atechDateTime),
tbrEntry.insulinRate, tbrEntry.insulinRate,
tempBasalProcessDTO.durationAsSeconds * 1000L, tempBasalProcessDTO.durationAsSeconds * 1000L,
!tbrEntry.isPercent, isAbsolute = !tbrEntry.isPercent,
entryWithTempId.temporaryId, entryWithTempId.temporaryId,
PumpSync.TemporaryBasalType.NORMAL, PumpSync.TemporaryBasalType.NORMAL,
tempBasalProcessDTO.pumpId, tempBasalProcessDTO.pumpId,
@ -705,10 +685,10 @@ class MedtronicHistoryData @Inject constructor(
date = tryToGetByLocalTime(tempBasalProcessDTO.atechDateTime), date = tryToGetByLocalTime(tempBasalProcessDTO.atechDateTime),
pumpType = medtronicPumpStatus.pumpType, pumpType = medtronicPumpStatus.pumpType,
serialNumber = medtronicPumpStatus.serialNumber, serialNumber = medtronicPumpStatus.serialNumber,
entry = PumpDbEntryTBR(rate = tbrEntry.insulinRate, rate = tbrEntry.insulinRate,
isAbsolute = !tbrEntry.isPercent, isAbsolute = !tbrEntry.isPercent,
durationInSeconds = tempBasalProcessDTO.durationAsSeconds, durationInSeconds = tempBasalProcessDTO.durationAsSeconds,
tbrType = PumpSync.TemporaryBasalType.NORMAL), tbrType = PumpSync.TemporaryBasalType.NORMAL,
pumpId = tempBasalProcessDTO.pumpId) pumpId = tempBasalProcessDTO.pumpId)
} }
} }
@ -720,6 +700,56 @@ class MedtronicHistoryData @Inject constructor(
} // collection } // collection
} }
fun createTBRProcessList(entryList: MutableList<PumpHistoryEntry>) : MutableList<TempBasalProcessDTO> {
aapsLogger.debug(LTag.PUMP, "${ProcessHistoryRecord.TBR.description} List (before filter): ${gson.toJson(entryList)}")
var processDTO: TempBasalProcessDTO? = null
val processList: MutableList<TempBasalProcessDTO> = mutableListOf()
for (treatment in entryList) {
val tbr2 = treatment.getDecodedDataEntry("Object") as TempBasalPair
if (tbr2.isCancelTBR) {
if (processDTO != null) {
processDTO.itemTwo = treatment
} else {
aapsLogger.warn(LTag.PUMP, "processDTO was null - shouldn't happen, ignoring item. ItemTwo=$treatment")
}
} else {
if (processDTO != null) {
processList.add(processDTO)
}
processDTO = TempBasalProcessDTO(
itemOne = treatment,
aapsLogger = aapsLogger,
objectType = TempBasalProcessDTO.ObjectType.TemporaryBasal
)
}
}
if (processDTO != null) {
processList.add(processDTO)
}
var previousItem: TempBasalProcessDTO? = null
// fix for Zero TBRs
for (tempBasalProcessDTO in processList) {
if (previousItem!=null) {
var pheEnd = PumpHistoryEntry()
pheEnd.atechDateTime = DateTimeUtil.getATDWithAddedSeconds(tempBasalProcessDTO.itemOne.atechDateTime, -2)
pheEnd.addDecodedData("Object", TempBasalPair(0.0, false, 0))
previousItem.itemTwo = pheEnd
previousItem = null
}
if (tempBasalProcessDTO.itemOneTbr!!.isZeroTBR) {
previousItem = tempBasalProcessDTO
}
}
return processList
}
fun isTBRActive(dbEntry: PumpDbEntryTBR): Boolean { fun isTBRActive(dbEntry: PumpDbEntryTBR): Boolean {
@ -881,7 +911,6 @@ class MedtronicHistoryData @Inject constructor(
while (i < filtered2Items.size) { while (i < filtered2Items.size) {
val tbrProcess = TempBasalProcessDTO( val tbrProcess = TempBasalProcessDTO(
itemOne = filtered2Items[i], itemOne = filtered2Items[i],
processOperation = TempBasalProcessDTO.Operation.Add,
aapsLogger = aapsLogger, aapsLogger = aapsLogger,
objectType = TempBasalProcessDTO.ObjectType.Suspend) objectType = TempBasalProcessDTO.ObjectType.Suspend)
@ -959,7 +988,6 @@ class MedtronicHistoryData @Inject constructor(
if (items.size > 0) { if (items.size > 0) {
val tbrProcess = TempBasalProcessDTO( val tbrProcess = TempBasalProcessDTO(
itemOne = items[items.size - 1], itemOne = items[items.size - 1],
processOperation = TempBasalProcessDTO.Operation.Add,
aapsLogger = aapsLogger, aapsLogger = aapsLogger,
objectType = TempBasalProcessDTO.ObjectType.Suspend) objectType = TempBasalProcessDTO.ObjectType.Suspend)
@ -975,7 +1003,6 @@ class MedtronicHistoryData @Inject constructor(
if (items.size > 0) { if (items.size > 0) {
val tbrProcess = TempBasalProcessDTO( val tbrProcess = TempBasalProcessDTO(
itemOne = items[0], itemOne = items[0],
processOperation = TempBasalProcessDTO.Operation.Add,
aapsLogger = aapsLogger, aapsLogger = aapsLogger,
objectType = TempBasalProcessDTO.ObjectType.Suspend) objectType = TempBasalProcessDTO.ObjectType.Suspend)

View file

@ -91,6 +91,9 @@ class TempBasalPair : TempBasalPair {
val isCancelTBR: Boolean val isCancelTBR: Boolean
get() = MedtronicUtil.isSame(insulinRate, 0.0) && durationMinutes == 0 get() = MedtronicUtil.isSame(insulinRate, 0.0) && durationMinutes == 0
val isZeroTBR: Boolean
get() = MedtronicUtil.isSame(insulinRate, 0.0) && durationMinutes != 0
val description: String val description: String
get() { get() {
if (isCancelTBR) { if (isCancelTBR) {

View file

@ -4,9 +4,9 @@ import info.nightscout.androidaps.logging.AAPSLogger
import info.nightscout.androidaps.logging.LTag import info.nightscout.androidaps.logging.LTag
import info.nightscout.androidaps.plugins.pump.common.utils.DateTimeUtil import info.nightscout.androidaps.plugins.pump.common.utils.DateTimeUtil
import info.nightscout.androidaps.plugins.pump.medtronic.comm.history.pump.PumpHistoryEntry import info.nightscout.androidaps.plugins.pump.medtronic.comm.history.pump.PumpHistoryEntry
import java.lang.StringBuilder
class TempBasalProcessDTO constructor(var itemOne: PumpHistoryEntry, class TempBasalProcessDTO constructor(var itemOne: PumpHistoryEntry,
var processOperation: Operation = Operation.None,
var aapsLogger: AAPSLogger, var aapsLogger: AAPSLogger,
var objectType: ObjectType = ObjectType.TemporaryBasal) { var objectType: ObjectType = ObjectType.TemporaryBasal) {
@ -21,8 +21,6 @@ class TempBasalProcessDTO constructor(var itemOne: PumpHistoryEntry,
var itemOneTbr: TempBasalPair? = null var itemOneTbr: TempBasalPair? = null
var itemTwoTbr: TempBasalPair? = null var itemTwoTbr: TempBasalPair? = null
var cancelPresent: Boolean = false
val atechDateTime: Long val atechDateTime: Long
get() = itemOne.atechDateTime get() = itemOne.atechDateTime
@ -31,26 +29,26 @@ class TempBasalProcessDTO constructor(var itemOne: PumpHistoryEntry,
val durationAsSeconds: Int val durationAsSeconds: Int
get() { get() {
aapsLogger.debug(LTag.PUMP, "durationAsSeconds: [objectType=$objectType]") //aapsLogger.debug(LTag.PUMP, "durationAsSeconds: [objectType=$objectType]")
if (objectType == ObjectType.TemporaryBasal) { if (objectType == ObjectType.TemporaryBasal) {
if (itemTwo == null) { if (itemTwo == null) {
if (itemOneTbr != null) { if (itemOneTbr != null) {
aapsLogger.debug("TemporaryBasalPair - itemOneSingle: $itemOneTbr") //aapsLogger.debug("TemporaryBasalPair - itemOneSingle: $itemOneTbr")
return itemOneTbr!!.durationMinutes * 60 return itemOneTbr!!.durationMinutes * 60
} else { } else {
aapsLogger.error("Couldn't find TempBasalPair in entry: $itemOne") //aapsLogger.error("Couldn't find TempBasalPair in entry: $itemOne")
return 0 return 0
} }
} else { } else {
aapsLogger.debug(LTag.PUMP, "Found 2 items for duration: itemOne=$itemOne, itemTwo=$itemTwo") //aapsLogger.debug(LTag.PUMP, "Found 2 items for duration: itemOne=$itemOne, itemTwo=$itemTwo")
val secondsDiff = DateTimeUtil.getATechDateDiferenceAsSeconds(itemOne.atechDateTime, itemTwo!!.atechDateTime) val secondsDiff = DateTimeUtil.getATechDateDiferenceAsSeconds(itemOne.atechDateTime, itemTwo!!.atechDateTime)
aapsLogger.debug(LTag.PUMP, "Difference in seconds: $secondsDiff") //aapsLogger.debug(LTag.PUMP, "Difference in seconds: $secondsDiff")
return secondsDiff return secondsDiff
} }
} else { } else {
aapsLogger.debug(LTag.PUMP, "Found 2 items for duration (in SuspendMode): itemOne=$itemOne, itemTwo=$itemTwo") //aapsLogger.debug(LTag.PUMP, "Found 2 items for duration (in SuspendMode): itemOne=$itemOne, itemTwo=$itemTwo")
val secondsDiff = DateTimeUtil.getATechDateDiferenceAsSeconds(itemOne.atechDateTime, itemTwo!!.atechDateTime) val secondsDiff = DateTimeUtil.getATechDateDiferenceAsSeconds(itemOne.atechDateTime, itemTwo!!.atechDateTime)
aapsLogger.debug(LTag.PUMP, "Difference in seconds: $secondsDiff") //aapsLogger.debug(LTag.PUMP, "Difference in seconds: $secondsDiff")
return secondsDiff return secondsDiff
} }
} }
@ -61,8 +59,31 @@ class TempBasalProcessDTO constructor(var itemOne: PumpHistoryEntry,
} }
} }
fun toTreatmentString(): String {
val stringBuilder = StringBuilder()
stringBuilder.append(itemOne.DT)
if (itemTwo!=null) {
stringBuilder.append(" - ")
stringBuilder.append(itemTwo!!.DT)
}
var dur = durationAsSeconds
stringBuilder.append(" " + durationAsSeconds + " s (" + durationAsSeconds/60 + ")")
if (itemTwoTbr!=null) {
stringBuilder.append(" " + itemOneTbr!!.insulinRate + " / " + itemTwoTbr!!.insulinRate)
} else {
stringBuilder.append(" " + itemOneTbr!!.insulinRate)
}
return stringBuilder.toString()
}
override fun toString(): String { override fun toString(): String {
return "ItemOne: $itemOne, ItemTwo: $itemTwo, Duration: $durationAsSeconds, Operation: $processOperation, ObjectType: $objectType" return "ItemOne: $itemOne, ItemTwo: $itemTwo, Duration: $durationAsSeconds, ObjectType: $objectType"
} }
enum class Operation { enum class Operation {

View file

@ -34,6 +34,7 @@ class MedtronicPumpStatus @Inject constructor(private val rh: ResourceHelper,
var maxBolus: Double? = null var maxBolus: Double? = null
var maxBasal: Double? = null var maxBasal: Double? = null
var runningTBR: PumpDbEntryTBR? = null var runningTBR: PumpDbEntryTBR? = null
var runningTBRWithTemp: PumpDbEntryTBR? = null
// statuses // statuses
var pumpDeviceState = PumpDeviceState.NeverContacted var pumpDeviceState = PumpDeviceState.NeverContacted

View file

@ -0,0 +1,91 @@
package info.nightscout.androidaps.plugins.pump.medtronic.data
import java.lang.reflect.Type
import com.google.gson.reflect.TypeToken
import com.google.gson.Gson
import com.google.gson.GsonBuilder
import com.google.gson.internal.LinkedTreeMap
import dagger.android.AndroidInjector
import dagger.android.HasAndroidInjector
import info.nightscout.androidaps.TestBase
import info.nightscout.androidaps.interfaces.ActivePlugin
import info.nightscout.androidaps.interfaces.PumpSync
import info.nightscout.androidaps.logging.AAPSLogger
import info.nightscout.androidaps.plugins.pump.common.sync.PumpSyncStorage
import info.nightscout.androidaps.plugins.pump.medtronic.comm.history.pump.MedtronicPumpHistoryDecoder
import info.nightscout.androidaps.plugins.pump.medtronic.comm.history.pump.PumpHistoryEntry
import info.nightscout.androidaps.plugins.pump.medtronic.data.dto.TempBasalPair
import info.nightscout.androidaps.plugins.pump.medtronic.driver.MedtronicPumpStatus
import info.nightscout.androidaps.plugins.pump.medtronic.util.MedtronicUtil
import info.nightscout.androidaps.utils.sharedPreferences.SP
import org.hamcrest.Matchers.notNullValue
import org.junit.Assert.*
import org.junit.Test
import org.mockito.Mock
import java.io.File
import java.net.URL
class MedtronicHistoryDataUTest : TestBase() {
@Mock lateinit var activePlugin: ActivePlugin
@Mock lateinit var medtronicUtil: MedtronicUtil
@Mock lateinit var medtronicPumpHistoryDecoder: MedtronicPumpHistoryDecoder
@Mock lateinit var medtronicPumpStatus: MedtronicPumpStatus
@Mock lateinit var pumpSync: PumpSync
@Mock lateinit var pumpSyncStorage: PumpSyncStorage
@Mock lateinit var sp: SP
private val packetInjector = HasAndroidInjector {
AndroidInjector {
}
}
@Test
fun createTBRProcessList() {
var unitToTest = MedtronicHistoryData(packetInjector, aapsLogger, sp, activePlugin,
medtronicUtil, medtronicPumpHistoryDecoder,
medtronicPumpStatus,
pumpSync,
pumpSyncStorage)
val gson = Gson()
val fileText = ClassLoader.getSystemResource("tbr_data.json").readText()
val listType: Type = object : TypeToken<MutableList<PumpHistoryEntry?>?>() {}.getType()
val yourClassList: MutableList<PumpHistoryEntry> = gson.fromJson(fileText, listType)
for (pumpHistoryEntry in yourClassList) {
val stringObject = pumpHistoryEntry.decodedData["Object"] as LinkedTreeMap<String,Object>
val rate : Double = stringObject.get("insulinRate") as Double
val durationMinutes: Double = stringObject.get("durationMinutes") as Double
val durationMinutesInt : Int = durationMinutes.toInt()
var tmbPair = TempBasalPair(rate, false, durationMinutesInt)
pumpHistoryEntry.decodedData.remove("Object")
pumpHistoryEntry.addDecodedData("Object", tmbPair)
}
System.out.println("TBR Pre-Process List: " + gson.toJson(yourClassList))
val createTBRProcessList = unitToTest.createTBRProcessList(yourClassList)
System.out.println("TBR Process List: " + createTBRProcessList.size)
for (tempBasalProcessDTO in createTBRProcessList) {
System.out.println(tempBasalProcessDTO.toTreatmentString())
}
}
}

File diff suppressed because it is too large Load diff

View file

@ -323,6 +323,7 @@ abstract class PumpPluginAbstract protected constructor(
return ret return ret
} }
@Synchronized
override fun deliverTreatment(detailedBolusInfo: DetailedBolusInfo): PumpEnactResult { override fun deliverTreatment(detailedBolusInfo: DetailedBolusInfo): PumpEnactResult {
return try { return try {
if (detailedBolusInfo.insulin == 0.0 && detailedBolusInfo.carbs == 0.0) { if (detailedBolusInfo.insulin == 0.0 && detailedBolusInfo.carbs == 0.0) {