diff --git a/core/src/main/java/info/nightscout/androidaps/interfaces/PumpSync.kt b/core/src/main/java/info/nightscout/androidaps/interfaces/PumpSync.kt index 0ac0080f34..b8d21730d3 100644 --- a/core/src/main/java/info/nightscout/androidaps/interfaces/PumpSync.kt +++ b/core/src/main/java/info/nightscout/androidaps/interfaces/PumpSync.kt @@ -77,7 +77,7 @@ interface PumpSync { * USAGE: * Generate unique temporaryId * Call before bolus when no pumpId is known (provide timestamp, amount, temporaryId, type, pumpType, pumpSerial) - * After reading record from history or completed bolus call syncBolusWithTempId with the same temporaryId provided + * After reading record from history or completed bolus call [syncBolusWithTempId] with the same temporaryId provided * If syncBolusWithTempId is not called afterwards record remains valid and is calculated towards iob * * @param timestamp timestamp of event from pump history @@ -276,6 +276,61 @@ interface PumpSync { **/ fun syncStopTemporaryBasalWithPumpId(timestamp: Long, endPumpId: Long, pumpType: PumpType, pumpSerial: String): Boolean + /** + * Create temporary basal with temporary id + * + * Search for combination of temporaryId, PumpType, pumpSerial + * + * If db record doesn't exist, new record is created. + * If exists false is returned and data is ignored + * + * USAGE: + * Generate unique temporaryId + * Call on setting temporary basal when no pumpId is known (provide timestamp, temporaryId, type, pumpType, pumpSerial) + * After reading record from history or completed bolus call [syncTemporaryBasalWithTempId] with the same temporaryId provided + * If syncTemporaryBasalWithTempId is not called afterwards record remains valid and is calculated towards iob + * + * @param timestamp timestamp of event from pump history + * @param rate TBR rate in U/h or % (value of 100% is equal to no TBR) + * @param duration duration in milliseconds + * @param isAbsolute is TBR in U/h or % ? + * @param tempId pump id from history + * @param type type of TBR, from request sent to the driver + * @param pumpType pump type like PumpType.ACCU_CHEK_COMBO + * @param pumpSerial pump serial number + * @return true if new record is created + * + * see [info.nightscout.androidaps.database.transactions.InsertTemporaryBasalWithTempIdTransaction] + **/ + + fun addTemporaryBasalWithTempId(timestamp: Long, rate: Double, duration: Long, isAbsolute: Boolean, tempId: Long, type: TemporaryBasalType, pumpType: PumpType, pumpSerial: String): Boolean + + /** + * Synchronization of temporary basal with temporary id + * + * Search for combination of temporaryId, PumpType, pumpSerial + * + * If db record doesn't exist data is ignored and false returned. + * If exists, data is updated, type and pumpId only if provided + * isValid field is preserved + * + * USAGE: + * After reading record from history or completed bolus call syncTemporaryBasalWithTempId and + * provide updated timestamp, rate, duration, pumpId (if known), type (if change needed) with the same temporaryId, pumpType, pumpSerial + * + * @param timestamp timestamp of event from pump history + * @param rate TBR rate in U/h or % (value of 100% is equal to no TBR) + * @param duration duration in milliseconds + * @param isAbsolute is TBR in U/h or % ? + * @param temporaryId temporary id generated when pump id in not know yet + * @param type type of TBR, from request sent to the driver + * @param pumpId pump id from history + * @param pumpType pump type like PumpType.ACCU_CHEK_COMBO + * @param pumpSerial pump serial number + * @return true if record is successfully updated + **/ + fun syncTemporaryBasalWithTempId(timestamp: Long, rate: Double, duration: Long, isAbsolute: Boolean, temporaryId: Long, type: TemporaryBasalType?, pumpId: Long?, pumpType: PumpType, pumpSerial: String): Boolean + /** * Invalidate of temporary basals that failed to start * EROS specific, replace by setting duration to zero ???? @@ -284,9 +339,7 @@ interface PumpSync { * If db record doesn't exist data is ignored and false returned * * - * @param pumpId pump id of ending event from history - * @param pumpType pump type like PumpType.ACCU_CHEK_COMBO - * @param pumpSerial pump serial number + * @param id id of temporary basal * @return true if running record is found and invalidated **/ fun invalidateTemporaryBasal(id: Long): Boolean diff --git a/core/src/main/java/info/nightscout/androidaps/plugins/pump/PumpSyncImplementation.kt b/core/src/main/java/info/nightscout/androidaps/plugins/pump/PumpSyncImplementation.kt index ac9fa5ded0..0c995a3a44 100644 --- a/core/src/main/java/info/nightscout/androidaps/plugins/pump/PumpSyncImplementation.kt +++ b/core/src/main/java/info/nightscout/androidaps/plugins/pump/PumpSyncImplementation.kt @@ -124,11 +124,11 @@ class PumpSyncImplementation @Inject constructor( pumpSerial = pumpSerial ) ) - repository.runTransactionForResult(InsertPumpBolusWithTempIdTransaction(bolus)) - .doOnError { aapsLogger.error(LTag.DATABASE, "Error while saving bolus", it) } + repository.runTransactionForResult(InsertBolusWithTempIdTransaction(bolus)) + .doOnError { aapsLogger.error(LTag.DATABASE, "Error while saving Bolus", it) } .blockingGet() .also { result -> - result.inserted.forEach { aapsLogger.debug(LTag.DATABASE, "Inserted bolus $it") } + result.inserted.forEach { aapsLogger.debug(LTag.DATABASE, "Inserted Bolus $it") } return result.inserted.size > 0 } } @@ -146,11 +146,11 @@ class PumpSyncImplementation @Inject constructor( pumpSerial = pumpSerial ) ) - repository.runTransactionForResult(SyncPumpBolusWithTempIdTransaction(bolus, type?.toDBbBolusType())) - .doOnError { aapsLogger.error(LTag.DATABASE, "Error while saving bolus", it) } + repository.runTransactionForResult(SyncBolusWithTempIdTransaction(bolus, type?.toDBbBolusType())) + .doOnError { aapsLogger.error(LTag.DATABASE, "Error while saving Bolus", it) } .blockingGet() .also { result -> - result.updated.forEach { aapsLogger.debug(LTag.DATABASE, "Updated bolus $it") } + result.updated.forEach { aapsLogger.debug(LTag.DATABASE, "Updated Bolus $it") } return result.updated.size > 0 } } @@ -168,11 +168,11 @@ class PumpSyncImplementation @Inject constructor( ) ) repository.runTransactionForResult(SyncPumpBolusTransaction(bolus, type?.toDBbBolusType())) - .doOnError { aapsLogger.error(LTag.DATABASE, "Error while saving bolus", it) } + .doOnError { aapsLogger.error(LTag.DATABASE, "Error while saving Bolus", it) } .blockingGet() .also { result -> - result.inserted.forEach { aapsLogger.debug(LTag.DATABASE, "Inserted bolus $it") } - result.updated.forEach { aapsLogger.debug(LTag.DATABASE, "Updated bolus $it") } + result.inserted.forEach { aapsLogger.debug(LTag.DATABASE, "Inserted Bolus $it") } + result.updated.forEach { aapsLogger.debug(LTag.DATABASE, "Updated Bolus $it") } return result.inserted.size > 0 } } @@ -189,10 +189,10 @@ class PumpSyncImplementation @Inject constructor( pumpSerial = pumpSerial) ) repository.runTransactionForResult(InsertIfNewByTimestampCarbsTransaction(carbs)) - .doOnError { aapsLogger.error(LTag.DATABASE, "Error while saving carbs", it) } + .doOnError { aapsLogger.error(LTag.DATABASE, "Error while saving Carbs", it) } .blockingGet() .also { result -> - result.inserted.forEach { aapsLogger.debug(LTag.DATABASE, "Inserted carbs $it") } + result.inserted.forEach { aapsLogger.debug(LTag.DATABASE, "Inserted Carbs $it") } return result.inserted.size > 0 } } @@ -215,11 +215,11 @@ class PumpSyncImplementation @Inject constructor( ) repository.runTransactionForResult(InsertIfNewByTimestampTherapyEventTransaction(therapyEvent)) .doOnError { - aapsLogger.error(LTag.DATABASE, "Error while saving therapy event", it) + aapsLogger.error(LTag.DATABASE, "Error while saving TherapyEvent", it) } .blockingGet() .also { result -> - result.inserted.forEach { aapsLogger.debug(LTag.DATABASE, "Inserted therapy event $it") } + result.inserted.forEach { aapsLogger.debug(LTag.DATABASE, "Inserted TherapyEvent $it") } return result.inserted.size > 0 } } @@ -249,11 +249,11 @@ class PumpSyncImplementation @Inject constructor( ) ) repository.runTransactionForResult(SyncPumpTemporaryBasalTransaction(temporaryBasal, type?.toDbType())) - .doOnError { aapsLogger.error(LTag.DATABASE, "Error while temporary basal", it) } + .doOnError { aapsLogger.error(LTag.DATABASE, "Error while TemporaryBasal", it) } .blockingGet() .also { result -> - result.inserted.forEach { aapsLogger.debug(LTag.DATABASE, "Inserted temporary basal $it") } - result.updated.forEach { aapsLogger.debug(LTag.DATABASE, "Updated temporary basal $it") } + result.inserted.forEach { aapsLogger.debug(LTag.DATABASE, "Inserted TemporaryBasal $it") } + result.updated.forEach { aapsLogger.debug(LTag.DATABASE, "Updated TemporaryBasal $it") } return result.inserted.size > 0 } } @@ -261,23 +261,70 @@ class PumpSyncImplementation @Inject constructor( override fun syncStopTemporaryBasalWithPumpId(timestamp: Long, endPumpId: Long, pumpType: PumpType, pumpSerial: String): Boolean { if (!confirmActivePump(timestamp, pumpType, pumpSerial)) return false repository.runTransactionForResult(SyncPumpCancelTemporaryBasalIfAnyTransaction(timestamp, endPumpId, pumpType.toDbPumpType(), pumpSerial)) - .doOnError { aapsLogger.error(LTag.DATABASE, "Error while saving temporary basal", it) } + .doOnError { aapsLogger.error(LTag.DATABASE, "Error while saving TemporaryBasal", it) } .blockingGet() .also { result -> result.updated.forEach { - aapsLogger.debug(LTag.DATABASE, "Updated temporary basal $it") + aapsLogger.debug(LTag.DATABASE, "Updated TemporaryBasal $it") } return result.updated.size > 0 } } + override fun addTemporaryBasalWithTempId(timestamp: Long, rate: Double, duration: Long, isAbsolute: Boolean, tempId: Long, type: PumpSync.TemporaryBasalType, pumpType: PumpType, pumpSerial: String): Boolean { + if (!confirmActivePump(timestamp, pumpType, pumpSerial)) return false + val temporaryBasal = TemporaryBasal( + timestamp = timestamp, + rate = rate, + duration = duration, + type = type.toDbType(), + isAbsolute = isAbsolute, + interfaceIDs_backing = InterfaceIDs( + temporaryId = tempId, + pumpType = pumpType.toDbPumpType(), + pumpSerial = pumpSerial + ) + ) + repository.runTransactionForResult(InsertTemporaryBasalWithTempIdTransaction(temporaryBasal)) + .doOnError { aapsLogger.error(LTag.DATABASE, "Error while saving TemporaryBasal", it) } + .blockingGet() + .also { result -> + result.inserted.forEach { aapsLogger.debug(LTag.DATABASE, "Inserted TemporaryBasal $it") } + return result.inserted.size > 0 + } + } + + override fun syncTemporaryBasalWithTempId(timestamp: Long, rate: Double, duration: Long, isAbsolute: Boolean, temporaryId: Long, type: PumpSync.TemporaryBasalType?, pumpId: Long?, pumpType: PumpType, pumpSerial: String): Boolean { + if (!confirmActivePump(timestamp, pumpType, pumpSerial)) return false + val bolus = TemporaryBasal( + timestamp = timestamp, + rate = rate, + duration = duration, + type = TemporaryBasal.Type.NORMAL, // not used for update + isAbsolute = isAbsolute, + interfaceIDs_backing = InterfaceIDs( + temporaryId = temporaryId, + pumpId = pumpId, + pumpType = pumpType.toDbPumpType(), + pumpSerial = pumpSerial + ) + ) + repository.runTransactionForResult(SyncTemporaryBasalWithTempIdTransaction(bolus, type?.toDbType())) + .doOnError { aapsLogger.error(LTag.DATABASE, "Error while saving TemporaryBasal", it) } + .blockingGet() + .also { result -> + result.updated.forEach { aapsLogger.debug(LTag.DATABASE, "Updated TemporaryBasal $it") } + return result.updated.size > 0 + } + } + override fun invalidateTemporaryBasal(id: Long): Boolean { repository.runTransactionForResult(InvalidateTemporaryBasalTransaction(id)) - .doOnError { aapsLogger.error(LTag.DATABASE, "Error while invalidating temporary basal", it) } + .doOnError { aapsLogger.error(LTag.DATABASE, "Error while invalidating TemporaryBasal", it) } .blockingGet() .also { result -> result.invalidated.forEach { - aapsLogger.debug(LTag.DATABASE, "Invalidated temporary basal $it") + aapsLogger.debug(LTag.DATABASE, "Invalidated TemporaryBasal $it") } return result.invalidated.size > 0 } @@ -297,11 +344,11 @@ class PumpSyncImplementation @Inject constructor( ) ) repository.runTransactionForResult(SyncPumpExtendedBolusTransaction(extendedBolus)) - .doOnError { aapsLogger.error(LTag.DATABASE, "Error while extended bolus", it) } + .doOnError { aapsLogger.error(LTag.DATABASE, "Error while ExtendedBolus", it) } .blockingGet() .also { result -> - result.inserted.forEach { aapsLogger.debug(LTag.DATABASE, "Inserted extended bolus $it") } - result.updated.forEach { aapsLogger.debug(LTag.DATABASE, "Updated extended bolus $it") } + result.inserted.forEach { aapsLogger.debug(LTag.DATABASE, "Inserted ExtendedBolus $it") } + result.updated.forEach { aapsLogger.debug(LTag.DATABASE, "Updated ExtendedBolus $it") } return result.inserted.size > 0 } } @@ -309,11 +356,11 @@ class PumpSyncImplementation @Inject constructor( override fun syncStopExtendedBolusWithPumpId(timestamp: Long, endPumpId: Long, pumpType: PumpType, pumpSerial: String): Boolean { if (!confirmActivePump(timestamp, pumpType, pumpSerial)) return false repository.runTransactionForResult(SyncPumpCancelExtendedBolusIfAnyTransaction(timestamp, endPumpId, pumpType.toDbPumpType(), pumpSerial)) - .doOnError { aapsLogger.error(LTag.DATABASE, "Error while saving extended bolus", it) } + .doOnError { aapsLogger.error(LTag.DATABASE, "Error while saving ExtendedBolus", it) } .blockingGet() .also { result -> result.updated.forEach { - aapsLogger.debug(LTag.DATABASE, "Updated extended bolus $it") + aapsLogger.debug(LTag.DATABASE, "Updated ExtendedBolus $it") } return result.updated.size > 0 } diff --git a/database/src/main/java/info/nightscout/androidaps/database/daos/TemporaryBasalDao.kt b/database/src/main/java/info/nightscout/androidaps/database/daos/TemporaryBasalDao.kt index 49f0c8342c..d03cc6d91d 100644 --- a/database/src/main/java/info/nightscout/androidaps/database/daos/TemporaryBasalDao.kt +++ b/database/src/main/java/info/nightscout/androidaps/database/daos/TemporaryBasalDao.kt @@ -30,6 +30,9 @@ internal interface TemporaryBasalDao : TraceableDao { @Query("SELECT * FROM $TABLE_TEMPORARY_BASALS WHERE nightscoutId = :nsId AND referenceId IS NULL") fun findByNSId(nsId: String): TemporaryBasal? + @Query("SELECT * FROM $TABLE_TEMPORARY_BASALS WHERE temporaryId = :temporaryId AND pumpType = :pumpType AND pumpSerial = :pumpSerial AND referenceId IS NULL") + fun findByPumpTempIds(temporaryId: Long, pumpType: InterfaceIDs.PumpType, pumpSerial: String): TemporaryBasal? + @Query("SELECT * FROM $TABLE_TEMPORARY_BASALS WHERE timestamp <= :timestamp AND (timestamp + duration) > :timestamp AND pumpType = :pumpType AND pumpSerial = :pumpSerial AND referenceId IS NULL AND isValid = 1 ORDER BY timestamp DESC LIMIT 1") fun getTemporaryBasalActiveAt(timestamp: Long, pumpType: InterfaceIDs.PumpType, pumpSerial: String): Maybe diff --git a/database/src/main/java/info/nightscout/androidaps/database/transactions/InsertPumpBolusWithTempIdTransaction.kt b/database/src/main/java/info/nightscout/androidaps/database/transactions/InsertBolusWithTempIdTransaction.kt similarity index 87% rename from database/src/main/java/info/nightscout/androidaps/database/transactions/InsertPumpBolusWithTempIdTransaction.kt rename to database/src/main/java/info/nightscout/androidaps/database/transactions/InsertBolusWithTempIdTransaction.kt index 97f8286eff..2b7ad086ac 100644 --- a/database/src/main/java/info/nightscout/androidaps/database/transactions/InsertPumpBolusWithTempIdTransaction.kt +++ b/database/src/main/java/info/nightscout/androidaps/database/transactions/InsertBolusWithTempIdTransaction.kt @@ -5,9 +5,9 @@ import info.nightscout.androidaps.database.entities.Bolus /** * Creates or updates the Bolus from pump synchronization */ -class InsertPumpBolusWithTempIdTransaction( +class InsertBolusWithTempIdTransaction( private val bolus: Bolus -) : Transaction() { +) : Transaction() { override fun run(): TransactionResult { bolus.interfaceIDs.temporaryId ?: bolus.interfaceIDs.pumpType ?: bolus.interfaceIDs.pumpSerial ?: diff --git a/database/src/main/java/info/nightscout/androidaps/database/transactions/InsertTemporaryBasalWithTempIdTransaction.kt b/database/src/main/java/info/nightscout/androidaps/database/transactions/InsertTemporaryBasalWithTempIdTransaction.kt new file mode 100644 index 0000000000..27f931bcd9 --- /dev/null +++ b/database/src/main/java/info/nightscout/androidaps/database/transactions/InsertTemporaryBasalWithTempIdTransaction.kt @@ -0,0 +1,28 @@ +package info.nightscout.androidaps.database.transactions + +import info.nightscout.androidaps.database.entities.TemporaryBasal + +/** + * Creates or updates the TemporaryBasal from pump synchronization + */ +class InsertTemporaryBasalWithTempIdTransaction(private val temporaryBasal: TemporaryBasal +) : Transaction() { + + override fun run(): TransactionResult { + temporaryBasal.interfaceIDs.temporaryId ?: temporaryBasal.interfaceIDs.pumpType + ?: temporaryBasal.interfaceIDs.pumpSerial + ?: throw IllegalStateException("Some pump ID is null") + val result = TransactionResult() + val current = database.temporaryBasalDao.findByPumpTempIds(temporaryBasal.interfaceIDs.temporaryId!!, temporaryBasal.interfaceIDs.pumpType!!, temporaryBasal.interfaceIDs.pumpSerial!!) + if (current == null) { + database.temporaryBasalDao.insert(temporaryBasal) + result.inserted.add(temporaryBasal) + } + return result + } + + class TransactionResult { + + val inserted = mutableListOf() + } +} \ No newline at end of file diff --git a/database/src/main/java/info/nightscout/androidaps/database/transactions/SyncPumpBolusWithTempIdTransaction.kt b/database/src/main/java/info/nightscout/androidaps/database/transactions/SyncBolusWithTempIdTransaction.kt similarity index 90% rename from database/src/main/java/info/nightscout/androidaps/database/transactions/SyncPumpBolusWithTempIdTransaction.kt rename to database/src/main/java/info/nightscout/androidaps/database/transactions/SyncBolusWithTempIdTransaction.kt index 8fe8eb4fc3..99449f5ce7 100644 --- a/database/src/main/java/info/nightscout/androidaps/database/transactions/SyncPumpBolusWithTempIdTransaction.kt +++ b/database/src/main/java/info/nightscout/androidaps/database/transactions/SyncBolusWithTempIdTransaction.kt @@ -5,10 +5,10 @@ import info.nightscout.androidaps.database.entities.Bolus /** * Creates or updates the Bolus from pump synchronization */ -class SyncPumpBolusWithTempIdTransaction( +class SyncBolusWithTempIdTransaction( private val bolus: Bolus, private val newType: Bolus.Type? -) : Transaction() { +) : Transaction() { override fun run(): TransactionResult { bolus.interfaceIDs.temporaryId ?: bolus.interfaceIDs.pumpType ?: bolus.interfaceIDs.pumpSerial ?: diff --git a/database/src/main/java/info/nightscout/androidaps/database/transactions/SyncTemporaryBasalWithTempIdTransaction.kt b/database/src/main/java/info/nightscout/androidaps/database/transactions/SyncTemporaryBasalWithTempIdTransaction.kt new file mode 100644 index 0000000000..81f061a0ff --- /dev/null +++ b/database/src/main/java/info/nightscout/androidaps/database/transactions/SyncTemporaryBasalWithTempIdTransaction.kt @@ -0,0 +1,35 @@ +package info.nightscout.androidaps.database.transactions + +import info.nightscout.androidaps.database.entities.TemporaryBasal + +/** + * Creates or updates the TemporaryBasal from pump synchronization + */ +class SyncTemporaryBasalWithTempIdTransaction( + private val bolus: TemporaryBasal, + private val newType: TemporaryBasal.Type? +) : Transaction() { + + override fun run(): TransactionResult { + bolus.interfaceIDs.temporaryId ?: bolus.interfaceIDs.pumpType + ?: bolus.interfaceIDs.pumpSerial ?: throw IllegalStateException("Some pump ID is null") + val result = TransactionResult() + val current = database.temporaryBasalDao.findByPumpTempIds(bolus.interfaceIDs.temporaryId!!, bolus.interfaceIDs.pumpType!!, bolus.interfaceIDs.pumpSerial!!) + if (current != null) { + current.timestamp = bolus.timestamp + current.rate = bolus.rate + current.duration = bolus.duration + current.isAbsolute = bolus.isAbsolute + current.type = newType ?: current.type + current.interfaceIDs.pumpId = bolus.interfaceIDs.pumpId + database.temporaryBasalDao.updateExistingEntry(current) + result.updated.add(current) + } + return result + } + + class TransactionResult { + + val updated = mutableListOf() + } +} \ No newline at end of file