From 299d0a9b01df60e1ee7354c1c7fa05db94b3f786 Mon Sep 17 00:00:00 2001 From: Milos Kozak Date: Tue, 30 Mar 2021 22:45:45 +0200 Subject: [PATCH 1/5] finish Dana pumps --- .../maintenance/MaintenanceFragment.kt | 3 ++ .../danaRKorean/DanaRKoreanPlugin.java | 2 +- .../androidaps/danaRv2/DanaRv2Plugin.java | 6 ++- .../danaRv2/comm/MsgHistoryEvents_v2.kt | 42 +++++++++---------- .../androidaps/danar/AbstractDanaRPlugin.java | 6 ++- .../androidaps/danar/DanaRPlugin.java | 23 ++++++++-- 6 files changed, 53 insertions(+), 29 deletions(-) diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/maintenance/MaintenanceFragment.kt b/app/src/main/java/info/nightscout/androidaps/plugins/general/maintenance/MaintenanceFragment.kt index e2473b5005..97a99468c9 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/maintenance/MaintenanceFragment.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/maintenance/MaintenanceFragment.kt @@ -11,6 +11,7 @@ import info.nightscout.androidaps.database.AppRepository import info.nightscout.androidaps.database.entities.UserEntry.Action import info.nightscout.androidaps.databinding.MaintenanceFragmentBinding import info.nightscout.androidaps.events.EventNewBG +import info.nightscout.androidaps.interfaces.DataSyncSelector import info.nightscout.androidaps.interfaces.DatabaseHelperInterface import info.nightscout.androidaps.interfaces.ImportExportPrefsInterface import info.nightscout.androidaps.logging.AAPSLogger @@ -36,6 +37,7 @@ class MaintenanceFragment : DaggerFragment() { @Inject lateinit var repository: AppRepository @Inject lateinit var databaseHelper: DatabaseHelperInterface @Inject lateinit var uel: UserEntryLogger + @Inject lateinit var dataSyncSelector: DataSyncSelector private val compositeDisposable = CompositeDisposable() @@ -65,6 +67,7 @@ class MaintenanceFragment : DaggerFragment() { fromAction { databaseHelper.resetDatabases() repository.clearDatabases() + dataSyncSelector.resetToNextFullSync() } .subscribeOn(aapsSchedulers.io) .observeOn(aapsSchedulers.main) diff --git a/danar/src/main/java/info/nightscout/androidaps/danaRKorean/DanaRKoreanPlugin.java b/danar/src/main/java/info/nightscout/androidaps/danaRKorean/DanaRKoreanPlugin.java index 2dcafe1fa5..0a15328ea3 100644 --- a/danar/src/main/java/info/nightscout/androidaps/danaRKorean/DanaRKoreanPlugin.java +++ b/danar/src/main/java/info/nightscout/androidaps/danaRKorean/DanaRKoreanPlugin.java @@ -71,7 +71,7 @@ public class DanaRKoreanPlugin extends AbstractDanaRPlugin { PumpSync pumpSync, FabricPrivacy fabricPrivacy ) { - super(injector, danaPump, resourceHelper, constraintChecker, aapsLogger, aapsSchedulers, commandQueue, rxBus, activePlugin, sp, dateUtil); + super(injector, danaPump, resourceHelper, constraintChecker, aapsLogger, aapsSchedulers, commandQueue, rxBus, activePlugin, sp, dateUtil, pumpSync); this.aapsLogger = aapsLogger; this.context = context; this.resourceHelper = resourceHelper; diff --git a/danar/src/main/java/info/nightscout/androidaps/danaRv2/DanaRv2Plugin.java b/danar/src/main/java/info/nightscout/androidaps/danaRv2/DanaRv2Plugin.java index c53d025a78..9f1fb6f616 100644 --- a/danar/src/main/java/info/nightscout/androidaps/danaRv2/DanaRv2Plugin.java +++ b/danar/src/main/java/info/nightscout/androidaps/danaRv2/DanaRv2Plugin.java @@ -24,6 +24,7 @@ import info.nightscout.androidaps.events.EventAppExit; import info.nightscout.androidaps.interfaces.ActivePluginProvider; import info.nightscout.androidaps.interfaces.CommandQueueProvider; import info.nightscout.androidaps.interfaces.Constraint; +import info.nightscout.androidaps.interfaces.PumpSync; import info.nightscout.androidaps.logging.AAPSLogger; import info.nightscout.androidaps.logging.LTag; import info.nightscout.androidaps.plugins.bus.RxBusWrapper; @@ -69,9 +70,10 @@ public class DanaRv2Plugin extends AbstractDanaRPlugin { CommandQueueProvider commandQueue, DetailedBolusInfoStorage detailedBolusInfoStorage, DateUtil dateUtil, - FabricPrivacy fabricPrivacy + FabricPrivacy fabricPrivacy, + PumpSync pumpSync ) { - super(injector, danaPump, resourceHelper, constraintChecker, aapsLogger, aapsSchedulers, commandQueue, rxBus, activePlugin, sp, dateUtil); + super(injector, danaPump, resourceHelper, constraintChecker, aapsLogger, aapsSchedulers, commandQueue, rxBus, activePlugin, sp, dateUtil, pumpSync); this.aapsLogger = aapsLogger; this.context = context; this.resourceHelper = resourceHelper; diff --git a/danar/src/main/java/info/nightscout/androidaps/danaRv2/comm/MsgHistoryEvents_v2.kt b/danar/src/main/java/info/nightscout/androidaps/danaRv2/comm/MsgHistoryEvents_v2.kt index 83fe642c80..5c939bda8d 100644 --- a/danar/src/main/java/info/nightscout/androidaps/danaRv2/comm/MsgHistoryEvents_v2.kt +++ b/danar/src/main/java/info/nightscout/androidaps/danaRv2/comm/MsgHistoryEvents_v2.kt @@ -3,7 +3,6 @@ package info.nightscout.androidaps.danaRv2.comm import dagger.android.HasAndroidInjector import info.nightscout.androidaps.danar.R import info.nightscout.androidaps.danar.comm.MessageBase -import info.nightscout.androidaps.data.DetailedBolusInfo import info.nightscout.androidaps.db.ExtendedBolus import info.nightscout.androidaps.db.Source import info.nightscout.androidaps.db.TemporaryBasal @@ -91,26 +90,26 @@ class MsgHistoryEvents_v2 constructor( info.nightscout.androidaps.dana.DanaPump.BOLUS -> { val detailedBolusInfo = detailedBolusInfoStorage.findDetailedBolusInfo(datetime, param1 / 100.0) - ?: DetailedBolusInfo() - detailedBolusInfo.bolusTimestamp = datetime - detailedBolusInfo.pumpType = PumpType.DANA_RV2 - detailedBolusInfo.pumpSerial = danaPump.serialNumber - detailedBolusInfo.bolusPumpId = datetime - detailedBolusInfo.insulin = param1 / 100.0 - val newRecord = activePlugin.activeTreatments.addToHistoryTreatment(detailedBolusInfo, false) + val newRecord = pumpSync.syncBolusWithPumpId( + timestamp = datetime, + amount = param1 / 100.0, + type = detailedBolusInfo?.bolusType, + pumpId = datetime, + pumpType = PumpType.DANA_RV2, + pumpSerial = danaPump.serialNumber) aapsLogger.debug(LTag.PUMPBTCOMM, (if (newRecord) "**NEW** " else "") + "EVENT BOLUS (" + recordCode + ") " + dateUtil.dateAndTimeString(datetime) + " (" + datetime + ")" + " Bolus: " + param1 / 100.0 + "U Duration: " + param2 + "min") status = "BOLUS " + dateUtil.timeString(datetime) } info.nightscout.androidaps.dana.DanaPump.DUALBOLUS -> { val detailedBolusInfo = detailedBolusInfoStorage.findDetailedBolusInfo(datetime, param1 / 100.0) - ?: DetailedBolusInfo() - detailedBolusInfo.bolusTimestamp = datetime - detailedBolusInfo.pumpType = PumpType.DANA_RV2 - detailedBolusInfo.pumpSerial = danaPump.serialNumber - detailedBolusInfo.bolusPumpId = datetime - detailedBolusInfo.insulin = param1 / 100.0 - val newRecord = activePlugin.activeTreatments.addToHistoryTreatment(detailedBolusInfo, false) + val newRecord = pumpSync.syncBolusWithPumpId( + timestamp = datetime, + amount = param1 / 100.0, + type = detailedBolusInfo?.bolusType, + pumpId = datetime, + pumpType = PumpType.DANA_RV2, + pumpSerial = danaPump.serialNumber) aapsLogger.debug(LTag.PUMPBTCOMM, (if (newRecord) "**NEW** " else "") + "EVENT DUALBOLUS (" + recordCode + ") " + dateUtil.dateAndTimeString(datetime) + " (" + datetime + ")" + " Bolus: " + param1 / 100.0 + "U Duration: " + param2 + "min") status = "DUALBOLUS " + dateUtil.timeString(datetime) } @@ -155,13 +154,12 @@ class MsgHistoryEvents_v2 constructor( } info.nightscout.androidaps.dana.DanaPump.CARBS -> { - val emptyCarbsInfo = DetailedBolusInfo() - emptyCarbsInfo.carbs = param1.toDouble() - emptyCarbsInfo.carbsTimestamp = datetime - emptyCarbsInfo.pumpType = PumpType.DANA_RV2 - emptyCarbsInfo.pumpSerial = danaPump.serialNumber - emptyCarbsInfo.carbsPumpId = datetime - val newRecord = activePlugin.activeTreatments.addToHistoryTreatment(emptyCarbsInfo, false) + val newRecord = pumpSync.syncCarbsWithTimestamp( + timestamp = datetime, + amount = param1.toDouble(), + pumpId = datetime, + pumpType = PumpType.DANA_RV2, + pumpSerial = danaPump.serialNumber) aapsLogger.debug(LTag.PUMPBTCOMM, (if (newRecord) "**NEW** " else "") + "EVENT CARBS (" + recordCode + ") " + dateUtil.dateAndTimeString(datetime) + " (" + datetime + ")" + " Carbs: " + param1 + "g") status = "CARBS " + dateUtil.timeString(datetime) } diff --git a/danar/src/main/java/info/nightscout/androidaps/danar/AbstractDanaRPlugin.java b/danar/src/main/java/info/nightscout/androidaps/danar/AbstractDanaRPlugin.java index 819b503d3b..0927406653 100644 --- a/danar/src/main/java/info/nightscout/androidaps/danar/AbstractDanaRPlugin.java +++ b/danar/src/main/java/info/nightscout/androidaps/danar/AbstractDanaRPlugin.java @@ -29,6 +29,7 @@ import info.nightscout.androidaps.interfaces.PluginType; import info.nightscout.androidaps.interfaces.PumpDescription; import info.nightscout.androidaps.interfaces.PumpInterface; import info.nightscout.androidaps.interfaces.PumpPluginBase; +import info.nightscout.androidaps.interfaces.PumpSync; import info.nightscout.androidaps.logging.AAPSLogger; import info.nightscout.androidaps.logging.LTag; import info.nightscout.androidaps.plugins.bus.RxBusWrapper; @@ -64,6 +65,7 @@ public abstract class AbstractDanaRPlugin extends PumpPluginBase implements Pump protected SP sp; protected DateUtil dateUtil; protected AapsSchedulers aapsSchedulers; + protected PumpSync pumpSync; protected AbstractDanaRPlugin( HasAndroidInjector injector, @@ -76,7 +78,8 @@ public abstract class AbstractDanaRPlugin extends PumpPluginBase implements Pump RxBusWrapper rxBus, ActivePluginProvider activePlugin, SP sp, - DateUtil dateUtil + DateUtil dateUtil, + PumpSync pumpSync ) { super(new PluginDescription() .mainType(PluginType.PUMP) @@ -95,6 +98,7 @@ public abstract class AbstractDanaRPlugin extends PumpPluginBase implements Pump this.sp = sp; this.dateUtil = dateUtil; this.aapsSchedulers = aapsSchedulers; + this.pumpSync = pumpSync; } @Override protected void onStart() { diff --git a/danar/src/main/java/info/nightscout/androidaps/danar/DanaRPlugin.java b/danar/src/main/java/info/nightscout/androidaps/danar/DanaRPlugin.java index d2ea26c091..5d52f0cd2d 100644 --- a/danar/src/main/java/info/nightscout/androidaps/danar/DanaRPlugin.java +++ b/danar/src/main/java/info/nightscout/androidaps/danar/DanaRPlugin.java @@ -25,6 +25,7 @@ import info.nightscout.androidaps.interfaces.ActivePluginProvider; import info.nightscout.androidaps.interfaces.CommandQueueProvider; import info.nightscout.androidaps.interfaces.Constraint; import info.nightscout.androidaps.interfaces.PluginType; +import info.nightscout.androidaps.interfaces.PumpSync; import info.nightscout.androidaps.logging.AAPSLogger; import info.nightscout.androidaps.logging.LTag; import info.nightscout.androidaps.plugins.bus.RxBusWrapper; @@ -34,6 +35,7 @@ import info.nightscout.androidaps.plugins.pump.common.defs.PumpType; import info.nightscout.androidaps.utils.DateUtil; import info.nightscout.androidaps.utils.FabricPrivacy; import info.nightscout.androidaps.utils.Round; +import info.nightscout.androidaps.utils.T; import info.nightscout.androidaps.utils.resources.ResourceHelper; import info.nightscout.androidaps.utils.rx.AapsSchedulers; import info.nightscout.androidaps.utils.sharedPreferences.SP; @@ -63,9 +65,10 @@ public class DanaRPlugin extends AbstractDanaRPlugin { CommandQueueProvider commandQueue, DanaPump danaPump, DateUtil dateUtil, - FabricPrivacy fabricPrivacy + FabricPrivacy fabricPrivacy, + PumpSync pumpSync ) { - super(injector, danaPump, resourceHelper, constraintChecker, aapsLogger, aapsSchedulers, commandQueue, rxBus, activePlugin, sp, dateUtil); + super(injector, danaPump, resourceHelper, constraintChecker, aapsLogger, aapsSchedulers, commandQueue, rxBus, activePlugin, sp, dateUtil, pumpSync); this.aapsLogger = aapsLogger; this.context = context; this.resourceHelper = resourceHelper; @@ -176,7 +179,21 @@ public class DanaRPlugin extends AbstractDanaRPlugin { aapsLogger.debug(LTag.PUMP, "deliverTreatment: OK. Asked: " + detailedBolusInfo.insulin + " Delivered: " + result.getBolusDelivered()); detailedBolusInfo.insulin = t.insulin; detailedBolusInfo.timestamp = System.currentTimeMillis(); - activePlugin.getActiveTreatments().addToHistoryTreatment(detailedBolusInfo, false); + if (detailedBolusInfo.insulin > 0) + pumpSync.syncBolusWithPumpId( + detailedBolusInfo.timestamp, + detailedBolusInfo.insulin, + detailedBolusInfo.getBolusType(), + dateUtil._now(), + PumpType.DANA_R, + serialNumber()); + if (detailedBolusInfo.carbs > 0) + pumpSync.syncCarbsWithTimestamp( + detailedBolusInfo.timestamp + T.mins(detailedBolusInfo.carbTime).msecs(), + detailedBolusInfo.carbs, + null, + PumpType.DANA_R, + serialNumber()); return result; } else { PumpEnactResult result = new PumpEnactResult(getInjector()); From d9ceeb043ed12c80fc9599dd707aab82c088b271 Mon Sep 17 00:00:00 2001 From: AdrianLxM Date: Tue, 30 Mar 2021 23:19:53 +0200 Subject: [PATCH 2/5] expandable carbs query --- .../info/nightscout/androidaps/database/AppRepository.kt | 6 ++++-- .../info/nightscout/androidaps/database/daos/CarbsDao.kt | 6 ++++++ 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/database/src/main/java/info/nightscout/androidaps/database/AppRepository.kt b/database/src/main/java/info/nightscout/androidaps/database/AppRepository.kt index a467cf1ecd..e0b8b39b0e 100644 --- a/database/src/main/java/info/nightscout/androidaps/database/AppRepository.kt +++ b/database/src/main/java/info/nightscout/androidaps/database/AppRepository.kt @@ -330,6 +330,8 @@ open class AppRepository @Inject internal constructor( private fun Single>.expand() = this.map { it.map(::expandCarbs).flatten() } private fun Single>.filterOutExtended() = this.map { it.filter { c -> c.duration == 0L } } private fun Single>.fromTo(from: Long, to: Long) = this.map { it.filter { c -> c.timestamp in from..to } } + private fun Single>.until(to: Long) = this.map { it.filter { c -> c.timestamp <= to } } + private fun Single>.from(start: Long) = this.map { it.filter { c -> c.timestamp >= start } } private fun Single>.sort() = this.map { it.sortedBy { c -> c.timestamp } } /* @@ -386,7 +388,7 @@ open class AppRepository @Inject internal constructor( .subscribeOn(Schedulers.io()) fun getCarbsDataFromTimeToTimeExpanded(from: Long, to: Long, ascending: Boolean): Single> = - database.carbsDao.getCarbsFromTimeToTime(from - timeBackForExpand, to) + database.carbsDao.getCarbsFromTimeToTimeExpandable(from, to) .expand() .fromTo(from, to) .sort() @@ -399,7 +401,7 @@ open class AppRepository @Inject internal constructor( .subscribeOn(Schedulers.io()) fun getCarbsIncludingInvalidFromTimeToTimeExpanded(from: Long, to: Long, ascending: Boolean): Single> = - database.carbsDao.getCarbsIncludingInvalidFromTimeToTime(from - timeBackForExpand, to) + database.carbsDao.getCarbsIncludingInvalidFromTimeToTimeExpandable(from, to) .expand() .fromTo(from, to) .sort() diff --git a/database/src/main/java/info/nightscout/androidaps/database/daos/CarbsDao.kt b/database/src/main/java/info/nightscout/androidaps/database/daos/CarbsDao.kt index e85d68885a..f52d0d3a60 100644 --- a/database/src/main/java/info/nightscout/androidaps/database/daos/CarbsDao.kt +++ b/database/src/main/java/info/nightscout/androidaps/database/daos/CarbsDao.kt @@ -38,12 +38,18 @@ internal interface CarbsDao : TraceableDao { @Query("SELECT * FROM $TABLE_CARBS WHERE isValid = 1 AND timestamp >= :from AND timestamp <= :to AND referenceId IS NULL ORDER BY id DESC") fun getCarbsFromTimeToTime(from: Long, to: Long): Single> + @Query("SELECT * FROM $TABLE_CARBS WHERE isValid = 1 AND timestamp + duration >= :from AND timestamp <= :to AND referenceId IS NULL ORDER BY id DESC") + fun getCarbsFromTimeToTimeExpandable(from: Long, to: Long): Single> + @Query("SELECT * FROM $TABLE_CARBS WHERE timestamp >= :timestamp AND referenceId IS NULL ORDER BY id DESC") fun getCarbsIncludingInvalidFromTime(timestamp: Long): Single> @Query("SELECT * FROM $TABLE_CARBS WHERE timestamp >= :from AND timestamp <= :to AND referenceId IS NULL ORDER BY id DESC") fun getCarbsIncludingInvalidFromTimeToTime(from: Long, to: Long): Single> + @Query("SELECT * FROM $TABLE_CARBS WHERE timestamp >= :from AND timestamp <= :to AND referenceId IS NULL ORDER BY id DESC") + fun getCarbsIncludingInvalidFromTimeToTimeExpandable(from: Long, to: Long): Single> + // This query will be used with v3 to get all changed records @Query("SELECT * FROM $TABLE_CARBS WHERE id > :id AND referenceId IS NULL OR id IN (SELECT DISTINCT referenceId FROM $TABLE_CARBS WHERE id > :id) ORDER BY id ASC") fun getModifiedFrom(id: Long): Single> From 93b1b3702194bc300d5c61e729a598639bb45639 Mon Sep 17 00:00:00 2001 From: AdrianLxM Date: Tue, 30 Mar 2021 23:24:31 +0200 Subject: [PATCH 3/5] expandable carbs query extended --- .../nightscout/androidaps/database/AppRepository.kt | 13 ++++++++++--- .../nightscout/androidaps/database/daos/CarbsDao.kt | 8 +++++++- 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/database/src/main/java/info/nightscout/androidaps/database/AppRepository.kt b/database/src/main/java/info/nightscout/androidaps/database/AppRepository.kt index e0b8b39b0e..00c5e2c503 100644 --- a/database/src/main/java/info/nightscout/androidaps/database/AppRepository.kt +++ b/database/src/main/java/info/nightscout/androidaps/database/AppRepository.kt @@ -312,7 +312,6 @@ open class AppRepository @Inject internal constructor( // CARBS - val timeBackForExpand = 8 * 60 * 60 * 1000 private fun expandCarbs(carbs: Carbs): List = if (carbs.duration == 0L) { listOf(carbs) @@ -377,8 +376,9 @@ open class AppRepository @Inject internal constructor( .subscribeOn(Schedulers.io()) fun getCarbsDataFromTimeExpanded(timestamp: Long, ascending: Boolean): Single> = - database.carbsDao.getCarbsFromTime(timestamp - timeBackForExpand) + database.carbsDao.getCarbsFromTimeExpandable(timestamp) .expand() + .from(timestamp) .map { if (!ascending) it.reversed() else it } .subscribeOn(Schedulers.io()) @@ -396,7 +396,14 @@ open class AppRepository @Inject internal constructor( .subscribeOn(Schedulers.io()) fun getCarbsIncludingInvalidFromTime(timestamp: Long, ascending: Boolean): Single> = - database.carbsDao.getCarbsIncludingInvalidFromTime(timestamp - timeBackForExpand) + database.carbsDao.getCarbsIncludingInvalidFromTime(timestamp) + .map { if (!ascending) it.reversed() else it } + .subscribeOn(Schedulers.io()) + + fun getCarbsIncludingInvalidFromTimeExpanded(timestamp: Long, ascending: Boolean): Single> = + database.carbsDao.getCarbsIncludingInvalidFromTimeExpandable(timestamp) + .expand() + .from(timestamp) .map { if (!ascending) it.reversed() else it } .subscribeOn(Schedulers.io()) diff --git a/database/src/main/java/info/nightscout/androidaps/database/daos/CarbsDao.kt b/database/src/main/java/info/nightscout/androidaps/database/daos/CarbsDao.kt index f52d0d3a60..025eb04a02 100644 --- a/database/src/main/java/info/nightscout/androidaps/database/daos/CarbsDao.kt +++ b/database/src/main/java/info/nightscout/androidaps/database/daos/CarbsDao.kt @@ -35,6 +35,9 @@ internal interface CarbsDao : TraceableDao { @Query("SELECT * FROM $TABLE_CARBS WHERE isValid = 1 AND timestamp >= :timestamp AND referenceId IS NULL ORDER BY id DESC") fun getCarbsFromTime(timestamp: Long): Single> + @Query("SELECT * FROM $TABLE_CARBS WHERE isValid = 1 AND timestamp + duration >= :timestamp AND referenceId IS NULL ORDER BY id DESC") + fun getCarbsFromTimeExpandable(timestamp: Long): Single> + @Query("SELECT * FROM $TABLE_CARBS WHERE isValid = 1 AND timestamp >= :from AND timestamp <= :to AND referenceId IS NULL ORDER BY id DESC") fun getCarbsFromTimeToTime(from: Long, to: Long): Single> @@ -44,10 +47,13 @@ internal interface CarbsDao : TraceableDao { @Query("SELECT * FROM $TABLE_CARBS WHERE timestamp >= :timestamp AND referenceId IS NULL ORDER BY id DESC") fun getCarbsIncludingInvalidFromTime(timestamp: Long): Single> + @Query("SELECT * FROM $TABLE_CARBS WHERE timestamp + duration >= :timestamp AND referenceId IS NULL ORDER BY id DESC") + fun getCarbsIncludingInvalidFromTimeExpandable(timestamp: Long): Single> + @Query("SELECT * FROM $TABLE_CARBS WHERE timestamp >= :from AND timestamp <= :to AND referenceId IS NULL ORDER BY id DESC") fun getCarbsIncludingInvalidFromTimeToTime(from: Long, to: Long): Single> - @Query("SELECT * FROM $TABLE_CARBS WHERE timestamp >= :from AND timestamp <= :to AND referenceId IS NULL ORDER BY id DESC") + @Query("SELECT * FROM $TABLE_CARBS WHERE timestamp + duration >= :from AND timestamp <= :to AND referenceId IS NULL ORDER BY id DESC") fun getCarbsIncludingInvalidFromTimeToTimeExpandable(from: Long, to: Long): Single> // This query will be used with v3 to get all changed records From f4a76a1e24377dc5a8f966a6795fda234cc4ce53 Mon Sep 17 00:00:00 2001 From: Johannes Mockenhaupt Date: Wed, 31 Mar 2021 20:35:37 +0200 Subject: [PATCH 4/5] Document PumpInterface.deliverTreatment contract. --- .../info/nightscout/androidaps/interfaces/PumpInterface.kt | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/core/src/main/java/info/nightscout/androidaps/interfaces/PumpInterface.kt b/core/src/main/java/info/nightscout/androidaps/interfaces/PumpInterface.kt index a57003433a..602acf6bba 100644 --- a/core/src/main/java/info/nightscout/androidaps/interfaces/PumpInterface.kt +++ b/core/src/main/java/info/nightscout/androidaps/interfaces/PumpInterface.kt @@ -38,6 +38,12 @@ interface PumpInterface { val reservoirLevel: Double val batteryLevel: Int // in percent as integer + /** + * Request a bolus to be delivered, carbs to be stored on pump or both. + * + * @param detailedBolusInfo it's the caller's responsibility to ensure the request can be satisfied by the pump, + * e.g. DBI will not contain carbs if the pump can't store carbs. + */ fun deliverTreatment(detailedBolusInfo: DetailedBolusInfo): PumpEnactResult fun stopBolusDelivering() fun setTempBasalAbsolute(absoluteRate: Double, durationInMinutes: Int, profile: Profile, enforceNew: Boolean): PumpEnactResult From a5ea0d90278e9277598f07b84e228eb8190ed979 Mon Sep 17 00:00:00 2001 From: Milos Kozak Date: Wed, 31 Mar 2021 21:54:49 +0200 Subject: [PATCH 5/5] DeviceStatus --- .../dependencyInjection/ReceiversModule.kt | 1 + .../androidaps/plugins/aps/loop/LoopPlugin.kt | 19 +- .../DataSyncSelectorImplementation.kt | 32 + .../nsclient/services/NSClientService.java | 20 +- .../androidaps/receivers/KeepAliveReceiver.kt | 181 +- app/src/main/res/values/strings.xml | 1 + .../androidaps/interfaces/DataSyncSelector.kt | 6 + .../plugins/general/nsclient/NSUpload.java | 77 - .../extensions/DeviceStatusExtension.kt} | 128 +- .../10.json | 2931 +++++++++++++++++ .../androidaps/database/AppDatabase.kt | 6 +- .../androidaps/database/AppRepository.kt | 20 + .../database/DelegatedAppDatabase.kt | 1 + .../androidaps/database/TableNames.kt | 4 +- .../database/daos/DeviceStatusDao.kt | 41 + .../delegated/DelegatedDeviceStatusDao.kt | 6 + .../database/entities/DeviceStatus.kt | 44 + .../UpdateNsIdDeviceStatusTransaction.kt | 12 + 18 files changed, 3324 insertions(+), 206 deletions(-) rename core/src/main/java/info/nightscout/androidaps/{plugins/aps/loop/DeviceStatus.java => utils/extensions/DeviceStatusExtension.kt} (75%) create mode 100644 database/schemas/info.nightscout.androidaps.database.AppDatabase/10.json create mode 100644 database/src/main/java/info/nightscout/androidaps/database/daos/DeviceStatusDao.kt create mode 100644 database/src/main/java/info/nightscout/androidaps/database/daos/delegated/DelegatedDeviceStatusDao.kt create mode 100644 database/src/main/java/info/nightscout/androidaps/database/entities/DeviceStatus.kt create mode 100644 database/src/main/java/info/nightscout/androidaps/database/transactions/UpdateNsIdDeviceStatusTransaction.kt diff --git a/app/src/main/java/info/nightscout/androidaps/dependencyInjection/ReceiversModule.kt b/app/src/main/java/info/nightscout/androidaps/dependencyInjection/ReceiversModule.kt index a6e7e4104c..2100914ed9 100644 --- a/app/src/main/java/info/nightscout/androidaps/dependencyInjection/ReceiversModule.kt +++ b/app/src/main/java/info/nightscout/androidaps/dependencyInjection/ReceiversModule.kt @@ -17,6 +17,7 @@ abstract class ReceiversModule { @ContributesAndroidInjector abstract fun contributesChargingStateReceiver(): ChargingStateReceiver @ContributesAndroidInjector abstract fun contributesDataReceiver(): DataReceiver @ContributesAndroidInjector abstract fun contributesKeepAliveReceiver(): KeepAliveReceiver + @ContributesAndroidInjector abstract fun contributesKeepAliveWorker(): KeepAliveReceiver.KeepAliveWorker @ContributesAndroidInjector abstract fun contributesRileyLinkBluetoothStateReceiver(): RileyLinkBluetoothStateReceiver @ContributesAndroidInjector abstract fun contributesSmsReceiver(): SmsReceiver @ContributesAndroidInjector abstract fun contributesTimeDateOrTZChangeReceiver(): TimeDateOrTZChangeReceiver diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/aps/loop/LoopPlugin.kt b/app/src/main/java/info/nightscout/androidaps/plugins/aps/loop/LoopPlugin.kt index 8d7a2f783d..197c38b2e3 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/aps/loop/LoopPlugin.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/aps/loop/LoopPlugin.kt @@ -32,6 +32,7 @@ import info.nightscout.androidaps.plugins.aps.loop.events.EventLoopUpdateGui import info.nightscout.androidaps.plugins.aps.loop.events.EventNewOpenLoopNotification import info.nightscout.androidaps.plugins.bus.RxBusWrapper import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker +import info.nightscout.androidaps.plugins.configBuilder.RunningConfiguration import info.nightscout.androidaps.plugins.general.nsclient.NSUpload import info.nightscout.androidaps.plugins.general.overview.events.EventDismissNotification import info.nightscout.androidaps.plugins.general.overview.events.EventNewNotification @@ -48,6 +49,7 @@ import info.nightscout.androidaps.utils.DateUtil import info.nightscout.androidaps.utils.FabricPrivacy import info.nightscout.androidaps.utils.HardLimits import info.nightscout.androidaps.utils.T +import info.nightscout.androidaps.utils.extensions.buildDeviceStatus import info.nightscout.androidaps.utils.resources.ResourceHelper import info.nightscout.androidaps.utils.rx.AapsSchedulers import info.nightscout.androidaps.utils.sharedPreferences.SP @@ -78,7 +80,8 @@ open class LoopPlugin @Inject constructor( private val fabricPrivacy: FabricPrivacy, private val nsUpload: NSUpload, private val dateUtil: DateUtil, - private val repository: AppRepository + private val repository: AppRepository, + private val runningConfiguration: RunningConfiguration ) : PluginBase(PluginDescription() .mainType(PluginType.LOOP) .fragmentClass(LoopFragment::class.java.name) @@ -316,7 +319,12 @@ open class LoopPlugin @Inject constructor( lastRun!!.lastTBRRequest = 0 lastRun!!.lastSMBEnact = 0 lastRun!!.lastSMBRequest = 0 - nsUpload.uploadDeviceStatus(this, iobCobCalculatorPlugin, profileFunction, activePlugin.activePump, receiverStatusStore, BuildConfig.VERSION_NAME + "-" + BuildConfig.BUILDVERSION) + buildDeviceStatus(dateUtil, this, iobCobCalculatorPlugin, profileFunction, + activePlugin.activePump, receiverStatusStore, runningConfiguration, + BuildConfig.VERSION_NAME + "-" + BuildConfig.BUILDVERSION)?.also { + repository.insert(it) + } + if (isSuspended) { aapsLogger.debug(LTag.APS, resourceHelper.gs(R.string.loopsuspended)) rxBus.send(EventLoopSetLastRunGui(resourceHelper.gs(R.string.loopsuspended))) @@ -489,7 +497,6 @@ open class LoopPlugin @Inject constructor( fun acceptChangeRequest() { val profile = profileFunction.getProfile() - val lp = this applyTBRRequest(lastRun!!.constraintsProcessed, profile, object : Callback() { override fun run() { if (result.enacted) { @@ -497,7 +504,11 @@ open class LoopPlugin @Inject constructor( lastRun!!.lastTBRRequest = lastRun!!.lastAPSRun lastRun!!.lastTBREnact = DateUtil.now() lastRun!!.lastOpenModeAccept = DateUtil.now() - nsUpload.uploadDeviceStatus(lp, iobCobCalculatorPlugin, profileFunction, activePlugin.activePump, receiverStatusStore, BuildConfig.VERSION_NAME + "-" + BuildConfig.BUILDVERSION) + buildDeviceStatus(dateUtil, this@LoopPlugin, iobCobCalculatorPlugin, profileFunction, + activePlugin.activePump, receiverStatusStore, runningConfiguration, + BuildConfig.VERSION_NAME + "-" + BuildConfig.BUILDVERSION)?.also { + repository.insert(it) + } sp.incInt(R.string.key_ObjectivesmanualEnacts) } rxBus.send(EventAcceptOpenLoopChange()) diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/nsclient/DataSyncSelectorImplementation.kt b/app/src/main/java/info/nightscout/androidaps/plugins/general/nsclient/DataSyncSelectorImplementation.kt index 386c6da064..7d8c8d3dd2 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/nsclient/DataSyncSelectorImplementation.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/nsclient/DataSyncSelectorImplementation.kt @@ -2,6 +2,7 @@ package info.nightscout.androidaps.plugins.general.nsclient import info.nightscout.androidaps.R import info.nightscout.androidaps.database.AppRepository +import info.nightscout.androidaps.database.entities.DeviceStatus import info.nightscout.androidaps.database.entities.* import info.nightscout.androidaps.interfaces.ActivePluginProvider import info.nightscout.androidaps.interfaces.DataSyncSelector @@ -28,6 +29,7 @@ class DataSyncSelectorImplementation @Inject constructor( sp.remove(R.string.key_ns_bolus_last_synced_id) sp.remove(R.string.key_ns_carbs_last_synced_id) sp.remove(R.string.key_ns_bolus_calculator_result_last_synced_id) + sp.remove(R.string.key_ns_device_status_last_synced_id) } override fun confirmLastBolusIdIfGreater(lastSynced: Long) { @@ -294,4 +296,34 @@ class DataSyncSelectorImplementation @Inject constructor( return false } + override fun confirmLastDeviceStatusIdIfGreater(lastSynced: Long) { + if (lastSynced > sp.getLong(R.string.key_ns_device_status_last_synced_id, 0)) { + aapsLogger.debug(LTag.NSCLIENT, "Setting DeviceStatus data sync from $lastSynced") + sp.putLong(R.string.key_ns_device_status_last_synced_id, lastSynced) + } + } + + override fun changedDeviceStatuses(): List { + val startId = sp.getLong(R.string.key_ns_device_status_last_synced_id, 0) + return appRepository.getModifiedDeviceStatusDataFromId(startId).blockingGet().also { + aapsLogger.debug(LTag.NSCLIENT, "Loading DeviceStatus data for sync from $startId. Records ${it.size}") + } + } + + override fun processChangedDeviceStatusesCompat(): Boolean { + val startId = sp.getLong(R.string.key_ns_device_status_last_synced_id, 0) + appRepository.getNextSyncElementDeviceStatus(startId).blockingGet()?.let { deviceStatus -> + aapsLogger.info(LTag.DATABASE, "Loading DeviceStatus data Start: $startId ID: ${deviceStatus.id}") + when { + // without nsId = create new + deviceStatus.interfaceIDs.nightscoutId == null -> + nsClientPlugin.nsClientService?.dbAdd("devicestatus", deviceStatus.toJson(), deviceStatus) + // with nsId = ignore + deviceStatus.interfaceIDs.nightscoutId != null -> Any() + } + return true + } + return false + } + } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/nsclient/services/NSClientService.java b/app/src/main/java/info/nightscout/androidaps/plugins/general/nsclient/services/NSClientService.java index c899a317e3..8f8d2bc0ea 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/nsclient/services/NSClientService.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/nsclient/services/NSClientService.java @@ -32,10 +32,11 @@ import dagger.android.HasAndroidInjector; import info.nightscout.androidaps.Config; import info.nightscout.androidaps.R; import info.nightscout.androidaps.database.AppRepository; -import info.nightscout.androidaps.database.entities.Carbs; +import info.nightscout.androidaps.database.entities.DeviceStatus; import info.nightscout.androidaps.database.transactions.UpdateNsIdBolusCalculatorResultTransaction; import info.nightscout.androidaps.database.transactions.UpdateNsIdBolusTransaction; import info.nightscout.androidaps.database.transactions.UpdateNsIdCarbsTransaction; +import info.nightscout.androidaps.database.transactions.UpdateNsIdDeviceStatusTransaction; import info.nightscout.androidaps.database.transactions.UpdateNsIdFoodTransaction; import info.nightscout.androidaps.database.transactions.UpdateNsIdGlucoseValueTransaction; import info.nightscout.androidaps.database.transactions.UpdateNsIdTemporaryTargetTransaction; @@ -339,6 +340,22 @@ public class NSClientService extends DaggerService { dataSyncSelector.processChangedBolusCalculatorResultsCompat(); return; } + if (ack.getOriginalObject() instanceof DeviceStatus) { + DeviceStatus deviceStatus = (DeviceStatus) ack.getOriginalObject(); + deviceStatus.getInterfaceIDs().setNightscoutId(ack.getId()); + + disposable.add(repository.runTransactionForResult(new UpdateNsIdDeviceStatusTransaction(deviceStatus)) + .observeOn(aapsSchedulers.getIo()) + .subscribe( + result -> aapsLogger.debug(LTag.DATABASE, "Updated ns id of DeviceStatus " + deviceStatus), + error -> aapsLogger.error(LTag.DATABASE, "Updated ns id of DeviceStatus failed", error) + )); + dataSyncSelector.confirmLastDeviceStatusIdIfGreater(deviceStatus.getId()); + rxBus.send(new EventNSClientNewLog("DBADD", "Acked DeviceStatus" + deviceStatus.getInterfaceIDs().getNightscoutId())); + // Send new if waiting + dataSyncSelector.processChangedBolusCalculatorResultsCompat(); + return; + } // old way if (ack.nsClientID != null) { uploadQueue.removeByNsClientIdIfExists(ack.json); @@ -977,6 +994,7 @@ public class NSClientService extends DaggerService { dataSyncSelector.processChangedTempTargetsCompat(); dataSyncSelector.processChangedFoodsCompat(); dataSyncSelector.processChangedTherapyEventsCompat(); + dataSyncSelector.processChangedDeviceStatusesCompat(); if (uploadQueue.size() == 0) return; diff --git a/app/src/main/java/info/nightscout/androidaps/receivers/KeepAliveReceiver.kt b/app/src/main/java/info/nightscout/androidaps/receivers/KeepAliveReceiver.kt index eb20d8acb4..05f6603305 100644 --- a/app/src/main/java/info/nightscout/androidaps/receivers/KeepAliveReceiver.kt +++ b/app/src/main/java/info/nightscout/androidaps/receivers/KeepAliveReceiver.kt @@ -3,13 +3,19 @@ package info.nightscout.androidaps.receivers import android.app.AlarmManager import android.app.PendingIntent import android.app.PendingIntent.CanceledException +import android.app.PendingIntent.FLAG_IMMUTABLE import android.content.Context import android.content.Intent -import android.os.PowerManager import android.os.SystemClock +import androidx.work.OneTimeWorkRequest +import androidx.work.WorkManager +import androidx.work.Worker +import androidx.work.WorkerParameters import dagger.android.DaggerBroadcastReceiver +import dagger.android.HasAndroidInjector import info.nightscout.androidaps.BuildConfig import info.nightscout.androidaps.Config +import info.nightscout.androidaps.database.AppRepository import info.nightscout.androidaps.events.EventProfileNeedsUpdate import info.nightscout.androidaps.interfaces.ActivePluginProvider import info.nightscout.androidaps.interfaces.CommandQueueProvider @@ -18,55 +24,124 @@ import info.nightscout.androidaps.logging.AAPSLogger import info.nightscout.androidaps.logging.LTag import info.nightscout.androidaps.plugins.aps.loop.LoopPlugin import info.nightscout.androidaps.plugins.bus.RxBusWrapper -import info.nightscout.androidaps.plugins.general.nsclient.NSUpload +import info.nightscout.androidaps.plugins.configBuilder.RunningConfiguration import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorPlugin import info.nightscout.androidaps.queue.commands.Command import info.nightscout.androidaps.utils.DateUtil import info.nightscout.androidaps.utils.FabricPrivacy import info.nightscout.androidaps.utils.LocalAlertUtils import info.nightscout.androidaps.utils.T +import info.nightscout.androidaps.utils.extensions.buildDeviceStatus import javax.inject.Inject import kotlin.math.abs class KeepAliveReceiver : DaggerBroadcastReceiver() { @Inject lateinit var aapsLogger: AAPSLogger - @Inject lateinit var rxBus: RxBusWrapper - @Inject lateinit var activePlugin: ActivePluginProvider - @Inject lateinit var commandQueue: CommandQueueProvider - @Inject lateinit var profileFunction: ProfileFunction - @Inject lateinit var loopPlugin: LoopPlugin - @Inject lateinit var iobCobCalculatorPlugin: IobCobCalculatorPlugin - @Inject lateinit var localAlertUtils: LocalAlertUtils - @Inject lateinit var fabricPrivacy: FabricPrivacy - @Inject lateinit var receiverStatusStore: ReceiverStatusStore - @Inject lateinit var config: Config - @Inject lateinit var nsUpload: NSUpload - @Inject lateinit var dateUtil: DateUtil companion object { private val KEEP_ALIVE_MILLISECONDS = T.mins(5).msecs() - private val STATUS_UPDATE_FREQUENCY = T.mins(15).msecs() - private val IOB_UPDATE_FREQUENCY_IN_MINS = 5L - - private var lastReadStatus: Long = 0 - private var lastRun: Long = 0 - private var lastIobUpload: Long = 0 - } override fun onReceive(context: Context, intent: Intent) { super.onReceive(context, intent) aapsLogger.debug(LTag.CORE, "KeepAlive received") - val pm = context.getSystemService(Context.POWER_SERVICE) as PowerManager - val wl = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "AndroidAPS:KeepAliveReceiver") - wl.acquire(T.mins(2).msecs()) - localAlertUtils.shortenSnoozeInterval() - localAlertUtils.checkStaleBGAlert() - checkPump() - checkAPS() - wl.release() + + WorkManager.getInstance(context) + .enqueue(OneTimeWorkRequest.Builder(KeepAliveWorker::class.java).build()) + } + + class KeepAliveWorker( + context: Context, + params: WorkerParameters + ) : Worker(context, params) { + + @Inject lateinit var aapsLogger: AAPSLogger + @Inject lateinit var localAlertUtils: LocalAlertUtils + @Inject lateinit var repository: AppRepository + @Inject lateinit var config: Config + @Inject lateinit var iobCobCalculatorPlugin: IobCobCalculatorPlugin + @Inject lateinit var loopPlugin: LoopPlugin + @Inject lateinit var dateUtil: DateUtil + @Inject lateinit var activePlugin: ActivePluginProvider + @Inject lateinit var profileFunction: ProfileFunction + @Inject lateinit var runningConfiguration: RunningConfiguration + @Inject lateinit var receiverStatusStore: ReceiverStatusStore + @Inject lateinit var rxBus: RxBusWrapper + @Inject lateinit var commandQueue: CommandQueueProvider + @Inject lateinit var fabricPrivacy: FabricPrivacy + + init { + (context.applicationContext as HasAndroidInjector).androidInjector().inject(this) + } + + companion object { + + private val STATUS_UPDATE_FREQUENCY = T.mins(15).msecs() + private const val IOB_UPDATE_FREQUENCY_IN_MINUTES = 5L + + private var lastReadStatus: Long = 0 + private var lastRun: Long = 0 + private var lastIobUpload: Long = 0 + + } + + override fun doWork(): Result { + localAlertUtils.shortenSnoozeInterval() + localAlertUtils.checkStaleBGAlert() + checkPump() + checkAPS() + return Result.success() + } + + // Usually deviceStatus is uploaded through LoopPlugin after every loop cycle. + // if there is no BG available, we have to upload anyway to have correct + // IOB displayed in NS + private fun checkAPS() { + var shouldUploadStatus = false + if (config.NSCLIENT) return + if (config.PUMPCONTROL) shouldUploadStatus = true + else if (!loopPlugin.isEnabled() || iobCobCalculatorPlugin.actualBg() == null) + shouldUploadStatus = true + else if (DateUtil.isOlderThan(activePlugin.activeAPS.lastAPSRun, 5)) shouldUploadStatus = true + if (DateUtil.isOlderThan(lastIobUpload, IOB_UPDATE_FREQUENCY_IN_MINUTES) && shouldUploadStatus) { + lastIobUpload = dateUtil._now() + buildDeviceStatus(dateUtil, loopPlugin, iobCobCalculatorPlugin, profileFunction, + activePlugin.activePump, receiverStatusStore, runningConfiguration, + BuildConfig.VERSION_NAME + "-" + BuildConfig.BUILDVERSION)?.also { + repository.insert(it) + } + } + } + + private fun checkPump() { + val pump = activePlugin.activePump + val profile = profileFunction.getProfile() ?: return + val lastConnection = pump.lastDataTime() + val isStatusOutdated = lastConnection + STATUS_UPDATE_FREQUENCY < System.currentTimeMillis() + val isBasalOutdated = abs(profile.basal - pump.baseBasalRate) > pump.pumpDescription.basalStep + aapsLogger.debug(LTag.CORE, "Last connection: " + dateUtil.dateAndTimeString(lastConnection)) + // sometimes keep alive broadcast stops + // as as workaround test if readStatus was requested before an alarm is generated + if (lastReadStatus != 0L && lastReadStatus > System.currentTimeMillis() - T.mins(5).msecs()) { + localAlertUtils.checkPumpUnreachableAlarm(lastConnection, isStatusOutdated, loopPlugin.isDisconnected) + } + if (!pump.isThisProfileSet(profile) && !commandQueue.isRunning(Command.CommandType.BASAL_PROFILE)) { + rxBus.send(EventProfileNeedsUpdate()) + } else if (isStatusOutdated && !pump.isBusy()) { + lastReadStatus = System.currentTimeMillis() + commandQueue.readStatus("KeepAlive. Status outdated.", null) + } else if (isBasalOutdated && !pump.isBusy()) { + lastReadStatus = System.currentTimeMillis() + commandQueue.readStatus("KeepAlive. Basal outdated.", null) + } + if (lastRun != 0L && System.currentTimeMillis() - lastRun > T.mins(10).msecs()) { + aapsLogger.error(LTag.CORE, "KeepAlive fail") + fabricPrivacy.logCustom("KeepAliveFail") + } + lastRun = System.currentTimeMillis() + } } class KeepAliveManager @Inject constructor( @@ -82,7 +157,7 @@ class KeepAliveReceiver : DaggerBroadcastReceiver() { localAlertUtils.preSnoozeAlarms() val am = context.getSystemService(Context.ALARM_SERVICE) as AlarmManager val i = Intent(context, KeepAliveReceiver::class.java) - val pi = PendingIntent.getBroadcast(context, 0, i, 0) + val pi = PendingIntent.getBroadcast(context, 0, i, FLAG_IMMUTABLE) try { pi.send() } catch (e: CanceledException) { @@ -94,53 +169,9 @@ class KeepAliveReceiver : DaggerBroadcastReceiver() { fun cancelAlarm(context: Context) { aapsLogger.debug(LTag.CORE, "KeepAlive canceled") val intent = Intent(context, KeepAliveReceiver::class.java) - val sender = PendingIntent.getBroadcast(context, 0, intent, 0) + val sender = PendingIntent.getBroadcast(context, 0, intent, FLAG_IMMUTABLE) val alarmManager = context.getSystemService(Context.ALARM_SERVICE) as AlarmManager alarmManager.cancel(sender) } } - - // Usually deviceStatus is uploaded through LoopPlugin after every loop cycle. - // if there is no BG available, we have to upload anyway to have correct - // IOB displayed in NS - private fun checkAPS() { - var shouldUploadStatus = false - if (config.NSCLIENT) return - if (config.PUMPCONTROL) shouldUploadStatus = true - else if (!loopPlugin.isEnabled() || iobCobCalculatorPlugin.actualBg() == null) - shouldUploadStatus = true - else if (DateUtil.isOlderThan(activePlugin.activeAPS.lastAPSRun, 5)) shouldUploadStatus = true - if (DateUtil.isOlderThan(lastIobUpload, IOB_UPDATE_FREQUENCY_IN_MINS) && shouldUploadStatus) { - lastIobUpload = DateUtil.now() - nsUpload.uploadDeviceStatus(loopPlugin, iobCobCalculatorPlugin, profileFunction, activePlugin.activePump, receiverStatusStore, BuildConfig.VERSION_NAME + "-" + BuildConfig.BUILDVERSION) - } - } - - private fun checkPump() { - val pump = activePlugin.activePump - val profile = profileFunction.getProfile() ?: return - val lastConnection = pump.lastDataTime() - val isStatusOutdated = lastConnection + STATUS_UPDATE_FREQUENCY < System.currentTimeMillis() - val isBasalOutdated = abs(profile.basal - pump.baseBasalRate) > pump.pumpDescription.basalStep - aapsLogger.debug(LTag.CORE, "Last connection: " + dateUtil.dateAndTimeString(lastConnection)) - // sometimes keep alive broadcast stops - // as as workaround test if readStatus was requested before an alarm is generated - if (lastReadStatus != 0L && lastReadStatus > System.currentTimeMillis() - T.mins(5).msecs()) { - localAlertUtils.checkPumpUnreachableAlarm(lastConnection, isStatusOutdated, loopPlugin.isDisconnected) - } - if (!pump.isThisProfileSet(profile) && !commandQueue.isRunning(Command.CommandType.BASAL_PROFILE)) { - rxBus.send(EventProfileNeedsUpdate()) - } else if (isStatusOutdated && !pump.isBusy()) { - lastReadStatus = System.currentTimeMillis() - commandQueue.readStatus("KeepAlive. Status outdated.", null) - } else if (isBasalOutdated && !pump.isBusy()) { - lastReadStatus = System.currentTimeMillis() - commandQueue.readStatus("KeepAlive. Basal outdated.", null) - } - if (lastRun != 0L && System.currentTimeMillis() - lastRun > T.mins(10).msecs()) { - aapsLogger.error(LTag.CORE, "KeepAlive fail") - fabricPrivacy.logCustom("KeepAliveFail") - } - lastRun = System.currentTimeMillis() - } } \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index a93c050aa5..e4a9da1074 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -43,6 +43,7 @@ ns_bolus_calculator_result_last_synced_id ns_carbs_last_synced_id ns_bolus_last_synced_id + ns_device_status_last_synced_id Treatments safety Max allowed bolus [U] diff --git a/core/src/main/java/info/nightscout/androidaps/interfaces/DataSyncSelector.kt b/core/src/main/java/info/nightscout/androidaps/interfaces/DataSyncSelector.kt index 167fd41b8c..1eb751d224 100644 --- a/core/src/main/java/info/nightscout/androidaps/interfaces/DataSyncSelector.kt +++ b/core/src/main/java/info/nightscout/androidaps/interfaces/DataSyncSelector.kt @@ -1,5 +1,6 @@ package info.nightscout.androidaps.interfaces +import info.nightscout.androidaps.database.entities.DeviceStatus import info.nightscout.androidaps.database.entities.* interface DataSyncSelector { @@ -48,4 +49,9 @@ interface DataSyncSelector { fun changedFoods() : List // Until NS v3 fun processChangedFoodsCompat(): Boolean + + fun confirmLastDeviceStatusIdIfGreater(lastSynced: Long) + fun changedDeviceStatuses() : List + // Until NS v3 + fun processChangedDeviceStatusesCompat(): Boolean } \ No newline at end of file diff --git a/core/src/main/java/info/nightscout/androidaps/plugins/general/nsclient/NSUpload.java b/core/src/main/java/info/nightscout/androidaps/plugins/general/nsclient/NSUpload.java index a15f0340a2..b5c2a664da 100644 --- a/core/src/main/java/info/nightscout/androidaps/plugins/general/nsclient/NSUpload.java +++ b/core/src/main/java/info/nightscout/androidaps/plugins/general/nsclient/NSUpload.java @@ -1,35 +1,22 @@ package info.nightscout.androidaps.plugins.general.nsclient; -import android.os.Build; - import org.json.JSONException; import org.json.JSONObject; -import java.util.Date; - import javax.inject.Inject; import javax.inject.Singleton; import info.nightscout.androidaps.core.R; import info.nightscout.androidaps.data.DetailedBolusInfo; -import info.nightscout.androidaps.data.IobTotal; import info.nightscout.androidaps.data.Profile; import info.nightscout.androidaps.database.entities.TherapyEvent; import info.nightscout.androidaps.db.DbRequest; import info.nightscout.androidaps.db.ExtendedBolus; import info.nightscout.androidaps.db.ProfileSwitch; import info.nightscout.androidaps.db.TemporaryBasal; -import info.nightscout.androidaps.interfaces.IobCobCalculator; -import info.nightscout.androidaps.interfaces.LoopInterface; -import info.nightscout.androidaps.interfaces.ProfileFunction; -import info.nightscout.androidaps.interfaces.PumpInterface; import info.nightscout.androidaps.interfaces.UploadQueueInterface; import info.nightscout.androidaps.logging.AAPSLogger; -import info.nightscout.androidaps.logging.LTag; -import info.nightscout.androidaps.plugins.aps.loop.APSResult; -import info.nightscout.androidaps.plugins.aps.loop.DeviceStatus; import info.nightscout.androidaps.plugins.configBuilder.RunningConfiguration; -import info.nightscout.androidaps.receivers.ReceiverStatusStore; import info.nightscout.androidaps.utils.DateUtil; import info.nightscout.androidaps.utils.sharedPreferences.SP; @@ -165,70 +152,6 @@ public class NSUpload { } } - public void uploadDeviceStatus(LoopInterface loopPlugin, IobCobCalculator iobCobCalculatorPlugin, ProfileFunction profileFunction, PumpInterface pumpInterface, ReceiverStatusStore receiverStatusStore, String version) { - Profile profile = profileFunction.getProfile(); - String profileName = profileFunction.getProfileName(); - - if (profile == null) { - aapsLogger.error("Profile is null. Skipping upload"); - return; - } - - DeviceStatus deviceStatus = new DeviceStatus(aapsLogger); - try { - LoopInterface.LastRun lastRun = loopPlugin.getLastRun(); - if (lastRun != null && lastRun.getLastAPSRun() > System.currentTimeMillis() - 300 * 1000L) { - // do not send if result is older than 1 min - APSResult apsResult = lastRun.getRequest(); - apsResult.json().put("timestamp", DateUtil.toISOString(lastRun.getLastAPSRun())); - deviceStatus.suggested = apsResult.json(); - - deviceStatus.iob = lastRun.getRequest().getIob().json(); - deviceStatus.iob.put("time", DateUtil.toISOString(lastRun.getLastAPSRun())); - - JSONObject requested = new JSONObject(); - - if (lastRun.getTbrSetByPump() != null && lastRun.getTbrSetByPump().getEnacted()) { // enacted - deviceStatus.enacted = lastRun.getRequest().json(); - deviceStatus.enacted.put("rate", lastRun.getTbrSetByPump().json(profile).get("rate")); - deviceStatus.enacted.put("duration", lastRun.getTbrSetByPump().json(profile).get("duration")); - deviceStatus.enacted.put("recieved", true); - requested.put("duration", lastRun.getRequest().getDuration()); - requested.put("rate", lastRun.getRequest().getRate()); - requested.put("temp", "absolute"); - deviceStatus.enacted.put("requested", requested); - } - if (lastRun.getTbrSetByPump() != null && lastRun.getTbrSetByPump().getEnacted()) { // enacted - if (deviceStatus.enacted == null) { - deviceStatus.enacted = lastRun.getRequest().json(); - } - deviceStatus.enacted.put("smb", lastRun.getTbrSetByPump().getBolusDelivered()); - requested.put("smb", lastRun.getRequest().getSmb()); - deviceStatus.enacted.put("requested", requested); - } - } else { - aapsLogger.debug(LTag.NSCLIENT, "OpenAPS data too old to upload, sending iob only"); - IobTotal[] iob = iobCobCalculatorPlugin.calculateIobArrayInDia(profile); - if (iob.length > 0) { - deviceStatus.iob = iob[0].json(); - deviceStatus.iob.put("time", DateUtil.toISOString(dateUtil._now())); - } - } - deviceStatus.device = "openaps://" + Build.MANUFACTURER + " " + Build.MODEL; - JSONObject pumpstatus = pumpInterface.getJSONStatus(profile, profileName, version); - deviceStatus.pump = pumpstatus; - - deviceStatus.uploaderBattery = receiverStatusStore.getBatteryLevel(); - - deviceStatus.created_at = DateUtil.toISOString(new Date()); - - deviceStatus.configuration = runningConfiguration.configuration(); - - uploadQueue.add(new DbRequest("dbAdd", "devicestatus", deviceStatus.mongoRecord(), System.currentTimeMillis())); - } catch (JSONException e) { - aapsLogger.error("Unhandled exception", e); - } - } public void uploadTreatmentRecord(DetailedBolusInfo detailedBolusInfo) { throw new IllegalStateException("DO NOT USE"); diff --git a/core/src/main/java/info/nightscout/androidaps/plugins/aps/loop/DeviceStatus.java b/core/src/main/java/info/nightscout/androidaps/utils/extensions/DeviceStatusExtension.kt similarity index 75% rename from core/src/main/java/info/nightscout/androidaps/plugins/aps/loop/DeviceStatus.java rename to core/src/main/java/info/nightscout/androidaps/utils/extensions/DeviceStatusExtension.kt index f883c49da7..db61c992a9 100644 --- a/core/src/main/java/info/nightscout/androidaps/plugins/aps/loop/DeviceStatus.java +++ b/core/src/main/java/info/nightscout/androidaps/utils/extensions/DeviceStatusExtension.kt @@ -1,12 +1,88 @@ -package info.nightscout.androidaps.plugins.aps.loop; +package info.nightscout.androidaps.utils.extensions -import org.json.JSONException; -import org.json.JSONObject; -import org.slf4j.Logger; +import android.os.Build +import info.nightscout.androidaps.database.entities.DeviceStatus +import info.nightscout.androidaps.interfaces.IobCobCalculator +import info.nightscout.androidaps.interfaces.LoopInterface +import info.nightscout.androidaps.interfaces.ProfileFunction +import info.nightscout.androidaps.interfaces.PumpInterface +import info.nightscout.androidaps.plugins.configBuilder.RunningConfiguration +import info.nightscout.androidaps.receivers.ReceiverStatusStore +import info.nightscout.androidaps.utils.DateUtil +import org.json.JSONObject -import info.nightscout.androidaps.logging.AAPSLogger; -import info.nightscout.androidaps.logging.LTag; -import info.nightscout.androidaps.logging.StacktraceLoggerWrapper; +fun DeviceStatus.toJson(): JSONObject = + JSONObject() + .put("created_at", DateUtil.toISOString(timestamp)) + .also { + if (device != null) it.put("device", device) + if (pump != null) it.put("pump", JSONObject(pump)) + it.put("openaps", JSONObject().also { openaps -> + if (enacted != null) openaps.put("enacted", JSONObject(enacted)) + if (suggested != null) openaps.put("suggested", JSONObject(suggested)) + if (iob != null) openaps.put("iob", iob) + }) + if (uploaderBattery != 0) it.put("uploaderBattery", uploaderBattery) + if (configuration != null) it.put("configuration", JSONObject(configuration)) + } + +fun buildDeviceStatus( + dateUtil: DateUtil, + loopPlugin: LoopInterface, + iobCobCalculatorPlugin: IobCobCalculator, + profileFunction: ProfileFunction, + pumpInterface: PumpInterface, + receiverStatusStore: ReceiverStatusStore, + runningConfiguration: RunningConfiguration, + version: String +): DeviceStatus? { + val profile = profileFunction.getProfile() ?: return null + val profileName = profileFunction.getProfileName() ?: return null + + val lastRun = loopPlugin.lastRun + var apsResult: JSONObject? = null + var iob: JSONObject? = null + var enacted: JSONObject? = null + if (lastRun != null && lastRun.lastAPSRun > dateUtil._now() - 300 * 1000L) { + // do not send if result is older than 1 min + apsResult = lastRun.request?.json()?.also { + it.put("timestamp", DateUtil.toISOString(lastRun.lastAPSRun)) + } + iob = lastRun.request?.iob?.json()?.also { + it.put("time", DateUtil.toISOString(lastRun.lastAPSRun)) + } + val requested = JSONObject() + if (lastRun.tbrSetByPump?.enacted == true) { // enacted + enacted = lastRun.request?.json()?.also { + it.put("rate", lastRun.tbrSetByPump!!.json(profile)["rate"]) + it.put("duration", lastRun.tbrSetByPump!!.json(profile)["duration"]) + it.put("received", true) + } + requested.put("duration", lastRun.request?.duration) + requested.put("rate", lastRun.request?.rate) + requested.put("temp", "absolute") + requested.put("smb", lastRun.request?.smb) + enacted?.put("requested", requested) + enacted?.put("smb", lastRun.tbrSetByPump?.bolusDelivered) + } + } else { + val calcIob = iobCobCalculatorPlugin.calculateIobArrayInDia(profile) + if (calcIob.isNotEmpty()) { + iob = calcIob[0].json() + iob.put("time", DateUtil.toISOString(dateUtil._now())) + } + } + return DeviceStatus( + timestamp = dateUtil._now(), + suggested = apsResult?.toString(), + iob = iob?.toString(), + enacted = enacted?.toString(), + device = "openaps://" + Build.MANUFACTURER + " " + Build.MODEL, + pump = pumpInterface.getJSONStatus(profile, profileName, version).toString(), + uploaderBattery = receiverStatusStore.batteryLevel, + configuration = runningConfiguration.configuration().toString() + ) +} /* { @@ -364,41 +440,3 @@ import info.nightscout.androidaps.logging.StacktraceLoggerWrapper; "created_at": "2016-06-24T09:27:49.230Z" } */ - -public class DeviceStatus { - private final AAPSLogger aapsLogger; - - public String device = null; - public JSONObject pump = null; - public JSONObject enacted = null; - public JSONObject suggested = null; - public JSONObject iob = null; - public int uploaderBattery = 0; - public String created_at = null; - public JSONObject configuration = null; - - public DeviceStatus(AAPSLogger aapsLogger) { - this.aapsLogger = aapsLogger; - } - - public JSONObject mongoRecord() { - JSONObject record = new JSONObject(); - - try { - if (device != null) record.put("device", device); - if (pump != null) record.put("pump", pump); - JSONObject openaps = new JSONObject(); - if (enacted != null) openaps.put("enacted", enacted); - if (suggested != null) openaps.put("suggested", suggested); - if (iob != null) openaps.put("iob", iob); - record.put("openaps", openaps); - if (uploaderBattery != 0) record.put("uploaderBattery", uploaderBattery); - if (created_at != null) record.put("created_at", created_at); - if (configuration != null) record.put("configuration", configuration); - } catch (JSONException e) { - aapsLogger.error("Unhandled exception", e); - } - return record; - } - -} diff --git a/database/schemas/info.nightscout.androidaps.database.AppDatabase/10.json b/database/schemas/info.nightscout.androidaps.database.AppDatabase/10.json new file mode 100644 index 0000000000..bf1c253a9c --- /dev/null +++ b/database/schemas/info.nightscout.androidaps.database.AppDatabase/10.json @@ -0,0 +1,2931 @@ +{ + "formatVersion": 1, + "database": { + "version": 10, + "identityHash": "e41836fe7fbd4aa439ec970af929ad7c", + "entities": [ + { + "tableName": "apsResults", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `version` INTEGER NOT NULL, `dateCreated` INTEGER NOT NULL, `isValid` INTEGER NOT NULL, `referenceId` INTEGER, `timestamp` INTEGER NOT NULL, `utcOffset` INTEGER NOT NULL, `algorithm` TEXT NOT NULL, `glucoseStatusJson` TEXT NOT NULL, `currentTempJson` TEXT NOT NULL, `iobDataJson` TEXT NOT NULL, `profileJson` TEXT NOT NULL, `autosensDataJson` TEXT, `mealDataJson` TEXT NOT NULL, `isMicroBolusAllowed` INTEGER, `resultJson` TEXT NOT NULL, `nightscoutSystemId` TEXT, `nightscoutId` TEXT, `pumpType` TEXT, `pumpSerial` TEXT, `temporaryId` INTEGER, `pumpId` INTEGER, `startId` INTEGER, `endId` INTEGER, FOREIGN KEY(`referenceId`) REFERENCES `apsResults`(`id`) ON UPDATE NO ACTION ON DELETE NO ACTION )", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "version", + "columnName": "version", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "dateCreated", + "columnName": "dateCreated", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "isValid", + "columnName": "isValid", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "referenceId", + "columnName": "referenceId", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "timestamp", + "columnName": "timestamp", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "utcOffset", + "columnName": "utcOffset", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "algorithm", + "columnName": "algorithm", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "glucoseStatusJson", + "columnName": "glucoseStatusJson", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "currentTempJson", + "columnName": "currentTempJson", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "iobDataJson", + "columnName": "iobDataJson", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "profileJson", + "columnName": "profileJson", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "autosensDataJson", + "columnName": "autosensDataJson", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "mealDataJson", + "columnName": "mealDataJson", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "isMicroBolusAllowed", + "columnName": "isMicroBolusAllowed", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "resultJson", + "columnName": "resultJson", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "interfaceIDs_backing.nightscoutSystemId", + "columnName": "nightscoutSystemId", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "interfaceIDs_backing.nightscoutId", + "columnName": "nightscoutId", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "interfaceIDs_backing.pumpType", + "columnName": "pumpType", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "interfaceIDs_backing.pumpSerial", + "columnName": "pumpSerial", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "interfaceIDs_backing.temporaryId", + "columnName": "temporaryId", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "interfaceIDs_backing.pumpId", + "columnName": "pumpId", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "interfaceIDs_backing.startId", + "columnName": "startId", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "interfaceIDs_backing.endId", + "columnName": "endId", + "affinity": "INTEGER", + "notNull": false + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [ + { + "name": "index_apsResults_referenceId", + "unique": false, + "columnNames": [ + "referenceId" + ], + "createSql": "CREATE INDEX IF NOT EXISTS `index_apsResults_referenceId` ON `${TABLE_NAME}` (`referenceId`)" + }, + { + "name": "index_apsResults_timestamp", + "unique": false, + "columnNames": [ + "timestamp" + ], + "createSql": "CREATE INDEX IF NOT EXISTS `index_apsResults_timestamp` ON `${TABLE_NAME}` (`timestamp`)" + } + ], + "foreignKeys": [ + { + "table": "apsResults", + "onDelete": "NO ACTION", + "onUpdate": "NO ACTION", + "columns": [ + "referenceId" + ], + "referencedColumns": [ + "id" + ] + } + ] + }, + { + "tableName": "boluses", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `version` INTEGER NOT NULL, `dateCreated` INTEGER NOT NULL, `isValid` INTEGER NOT NULL, `referenceId` INTEGER, `timestamp` INTEGER NOT NULL, `utcOffset` INTEGER NOT NULL, `amount` REAL NOT NULL, `type` TEXT NOT NULL, `isBasalInsulin` INTEGER NOT NULL, `nightscoutSystemId` TEXT, `nightscoutId` TEXT, `pumpType` TEXT, `pumpSerial` TEXT, `temporaryId` INTEGER, `pumpId` INTEGER, `startId` INTEGER, `endId` INTEGER, `insulinLabel` TEXT, `insulinEndTime` INTEGER, `peak` INTEGER, FOREIGN KEY(`referenceId`) REFERENCES `boluses`(`id`) ON UPDATE NO ACTION ON DELETE NO ACTION )", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "version", + "columnName": "version", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "dateCreated", + "columnName": "dateCreated", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "isValid", + "columnName": "isValid", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "referenceId", + "columnName": "referenceId", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "timestamp", + "columnName": "timestamp", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "utcOffset", + "columnName": "utcOffset", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "amount", + "columnName": "amount", + "affinity": "REAL", + "notNull": true + }, + { + "fieldPath": "type", + "columnName": "type", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "isBasalInsulin", + "columnName": "isBasalInsulin", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "interfaceIDs_backing.nightscoutSystemId", + "columnName": "nightscoutSystemId", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "interfaceIDs_backing.nightscoutId", + "columnName": "nightscoutId", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "interfaceIDs_backing.pumpType", + "columnName": "pumpType", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "interfaceIDs_backing.pumpSerial", + "columnName": "pumpSerial", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "interfaceIDs_backing.temporaryId", + "columnName": "temporaryId", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "interfaceIDs_backing.pumpId", + "columnName": "pumpId", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "interfaceIDs_backing.startId", + "columnName": "startId", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "interfaceIDs_backing.endId", + "columnName": "endId", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "insulinConfiguration.insulinLabel", + "columnName": "insulinLabel", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "insulinConfiguration.insulinEndTime", + "columnName": "insulinEndTime", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "insulinConfiguration.peak", + "columnName": "peak", + "affinity": "INTEGER", + "notNull": false + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [ + { + "name": "index_boluses_referenceId", + "unique": false, + "columnNames": [ + "referenceId" + ], + "createSql": "CREATE INDEX IF NOT EXISTS `index_boluses_referenceId` ON `${TABLE_NAME}` (`referenceId`)" + }, + { + "name": "index_boluses_timestamp", + "unique": false, + "columnNames": [ + "timestamp" + ], + "createSql": "CREATE INDEX IF NOT EXISTS `index_boluses_timestamp` ON `${TABLE_NAME}` (`timestamp`)" + } + ], + "foreignKeys": [ + { + "table": "boluses", + "onDelete": "NO ACTION", + "onUpdate": "NO ACTION", + "columns": [ + "referenceId" + ], + "referencedColumns": [ + "id" + ] + } + ] + }, + { + "tableName": "bolusCalculatorResults", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `version` INTEGER NOT NULL, `dateCreated` INTEGER NOT NULL, `isValid` INTEGER NOT NULL, `referenceId` INTEGER, `timestamp` INTEGER NOT NULL, `utcOffset` INTEGER NOT NULL, `targetBGLow` REAL NOT NULL, `targetBGHigh` REAL NOT NULL, `isf` REAL NOT NULL, `ic` REAL NOT NULL, `bolusIOB` REAL NOT NULL, `wasBolusIOBUsed` INTEGER NOT NULL, `basalIOB` REAL NOT NULL, `wasBasalIOBUsed` INTEGER NOT NULL, `glucoseValue` REAL NOT NULL, `wasGlucoseUsed` INTEGER NOT NULL, `glucoseDifference` REAL NOT NULL, `glucoseInsulin` REAL NOT NULL, `glucoseTrend` REAL NOT NULL, `wasTrendUsed` INTEGER NOT NULL, `trendInsulin` REAL NOT NULL, `cob` REAL NOT NULL, `wasCOBUsed` INTEGER NOT NULL, `cobInsulin` REAL NOT NULL, `carbs` REAL NOT NULL, `wereCarbsUsed` INTEGER NOT NULL, `carbsInsulin` REAL NOT NULL, `otherCorrection` REAL NOT NULL, `wasSuperbolusUsed` INTEGER NOT NULL, `superbolusInsulin` REAL NOT NULL, `wasTempTargetUsed` INTEGER NOT NULL, `totalInsulin` REAL NOT NULL, `percentageCorrection` INTEGER NOT NULL, `profileName` TEXT NOT NULL, `note` TEXT NOT NULL, `nightscoutSystemId` TEXT, `nightscoutId` TEXT, `pumpType` TEXT, `pumpSerial` TEXT, `temporaryId` INTEGER, `pumpId` INTEGER, `startId` INTEGER, `endId` INTEGER, FOREIGN KEY(`referenceId`) REFERENCES `bolusCalculatorResults`(`id`) ON UPDATE NO ACTION ON DELETE NO ACTION )", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "version", + "columnName": "version", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "dateCreated", + "columnName": "dateCreated", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "isValid", + "columnName": "isValid", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "referenceId", + "columnName": "referenceId", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "timestamp", + "columnName": "timestamp", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "utcOffset", + "columnName": "utcOffset", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "targetBGLow", + "columnName": "targetBGLow", + "affinity": "REAL", + "notNull": true + }, + { + "fieldPath": "targetBGHigh", + "columnName": "targetBGHigh", + "affinity": "REAL", + "notNull": true + }, + { + "fieldPath": "isf", + "columnName": "isf", + "affinity": "REAL", + "notNull": true + }, + { + "fieldPath": "ic", + "columnName": "ic", + "affinity": "REAL", + "notNull": true + }, + { + "fieldPath": "bolusIOB", + "columnName": "bolusIOB", + "affinity": "REAL", + "notNull": true + }, + { + "fieldPath": "wasBolusIOBUsed", + "columnName": "wasBolusIOBUsed", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "basalIOB", + "columnName": "basalIOB", + "affinity": "REAL", + "notNull": true + }, + { + "fieldPath": "wasBasalIOBUsed", + "columnName": "wasBasalIOBUsed", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "glucoseValue", + "columnName": "glucoseValue", + "affinity": "REAL", + "notNull": true + }, + { + "fieldPath": "wasGlucoseUsed", + "columnName": "wasGlucoseUsed", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "glucoseDifference", + "columnName": "glucoseDifference", + "affinity": "REAL", + "notNull": true + }, + { + "fieldPath": "glucoseInsulin", + "columnName": "glucoseInsulin", + "affinity": "REAL", + "notNull": true + }, + { + "fieldPath": "glucoseTrend", + "columnName": "glucoseTrend", + "affinity": "REAL", + "notNull": true + }, + { + "fieldPath": "wasTrendUsed", + "columnName": "wasTrendUsed", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "trendInsulin", + "columnName": "trendInsulin", + "affinity": "REAL", + "notNull": true + }, + { + "fieldPath": "cob", + "columnName": "cob", + "affinity": "REAL", + "notNull": true + }, + { + "fieldPath": "wasCOBUsed", + "columnName": "wasCOBUsed", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "cobInsulin", + "columnName": "cobInsulin", + "affinity": "REAL", + "notNull": true + }, + { + "fieldPath": "carbs", + "columnName": "carbs", + "affinity": "REAL", + "notNull": true + }, + { + "fieldPath": "wereCarbsUsed", + "columnName": "wereCarbsUsed", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "carbsInsulin", + "columnName": "carbsInsulin", + "affinity": "REAL", + "notNull": true + }, + { + "fieldPath": "otherCorrection", + "columnName": "otherCorrection", + "affinity": "REAL", + "notNull": true + }, + { + "fieldPath": "wasSuperbolusUsed", + "columnName": "wasSuperbolusUsed", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "superbolusInsulin", + "columnName": "superbolusInsulin", + "affinity": "REAL", + "notNull": true + }, + { + "fieldPath": "wasTempTargetUsed", + "columnName": "wasTempTargetUsed", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "totalInsulin", + "columnName": "totalInsulin", + "affinity": "REAL", + "notNull": true + }, + { + "fieldPath": "percentageCorrection", + "columnName": "percentageCorrection", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "profileName", + "columnName": "profileName", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "note", + "columnName": "note", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "interfaceIDs_backing.nightscoutSystemId", + "columnName": "nightscoutSystemId", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "interfaceIDs_backing.nightscoutId", + "columnName": "nightscoutId", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "interfaceIDs_backing.pumpType", + "columnName": "pumpType", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "interfaceIDs_backing.pumpSerial", + "columnName": "pumpSerial", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "interfaceIDs_backing.temporaryId", + "columnName": "temporaryId", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "interfaceIDs_backing.pumpId", + "columnName": "pumpId", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "interfaceIDs_backing.startId", + "columnName": "startId", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "interfaceIDs_backing.endId", + "columnName": "endId", + "affinity": "INTEGER", + "notNull": false + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [ + { + "name": "index_bolusCalculatorResults_referenceId", + "unique": false, + "columnNames": [ + "referenceId" + ], + "createSql": "CREATE INDEX IF NOT EXISTS `index_bolusCalculatorResults_referenceId` ON `${TABLE_NAME}` (`referenceId`)" + }, + { + "name": "index_bolusCalculatorResults_timestamp", + "unique": false, + "columnNames": [ + "timestamp" + ], + "createSql": "CREATE INDEX IF NOT EXISTS `index_bolusCalculatorResults_timestamp` ON `${TABLE_NAME}` (`timestamp`)" + } + ], + "foreignKeys": [ + { + "table": "bolusCalculatorResults", + "onDelete": "NO ACTION", + "onUpdate": "NO ACTION", + "columns": [ + "referenceId" + ], + "referencedColumns": [ + "id" + ] + } + ] + }, + { + "tableName": "carbs", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `version` INTEGER NOT NULL, `dateCreated` INTEGER NOT NULL, `isValid` INTEGER NOT NULL, `referenceId` INTEGER, `timestamp` INTEGER NOT NULL, `utcOffset` INTEGER NOT NULL, `duration` INTEGER NOT NULL, `amount` REAL NOT NULL, `nightscoutSystemId` TEXT, `nightscoutId` TEXT, `pumpType` TEXT, `pumpSerial` TEXT, `temporaryId` INTEGER, `pumpId` INTEGER, `startId` INTEGER, `endId` INTEGER, FOREIGN KEY(`referenceId`) REFERENCES `carbs`(`id`) ON UPDATE NO ACTION ON DELETE NO ACTION )", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "version", + "columnName": "version", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "dateCreated", + "columnName": "dateCreated", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "isValid", + "columnName": "isValid", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "referenceId", + "columnName": "referenceId", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "timestamp", + "columnName": "timestamp", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "utcOffset", + "columnName": "utcOffset", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "duration", + "columnName": "duration", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "amount", + "columnName": "amount", + "affinity": "REAL", + "notNull": true + }, + { + "fieldPath": "interfaceIDs_backing.nightscoutSystemId", + "columnName": "nightscoutSystemId", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "interfaceIDs_backing.nightscoutId", + "columnName": "nightscoutId", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "interfaceIDs_backing.pumpType", + "columnName": "pumpType", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "interfaceIDs_backing.pumpSerial", + "columnName": "pumpSerial", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "interfaceIDs_backing.temporaryId", + "columnName": "temporaryId", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "interfaceIDs_backing.pumpId", + "columnName": "pumpId", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "interfaceIDs_backing.startId", + "columnName": "startId", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "interfaceIDs_backing.endId", + "columnName": "endId", + "affinity": "INTEGER", + "notNull": false + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [ + { + "name": "index_carbs_referenceId", + "unique": false, + "columnNames": [ + "referenceId" + ], + "createSql": "CREATE INDEX IF NOT EXISTS `index_carbs_referenceId` ON `${TABLE_NAME}` (`referenceId`)" + }, + { + "name": "index_carbs_timestamp", + "unique": false, + "columnNames": [ + "timestamp" + ], + "createSql": "CREATE INDEX IF NOT EXISTS `index_carbs_timestamp` ON `${TABLE_NAME}` (`timestamp`)" + } + ], + "foreignKeys": [ + { + "table": "carbs", + "onDelete": "NO ACTION", + "onUpdate": "NO ACTION", + "columns": [ + "referenceId" + ], + "referencedColumns": [ + "id" + ] + } + ] + }, + { + "tableName": "effectiveProfileSwitches", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `version` INTEGER NOT NULL, `dateCreated` INTEGER NOT NULL, `isValid` INTEGER NOT NULL, `referenceId` INTEGER, `timestamp` INTEGER NOT NULL, `utcOffset` INTEGER NOT NULL, `duration` INTEGER NOT NULL, `basalBlocks` TEXT NOT NULL, `nightscoutSystemId` TEXT, `nightscoutId` TEXT, `pumpType` TEXT, `pumpSerial` TEXT, `temporaryId` INTEGER, `pumpId` INTEGER, `startId` INTEGER, `endId` INTEGER, FOREIGN KEY(`referenceId`) REFERENCES `effectiveProfileSwitches`(`id`) ON UPDATE NO ACTION ON DELETE NO ACTION )", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "version", + "columnName": "version", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "dateCreated", + "columnName": "dateCreated", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "isValid", + "columnName": "isValid", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "referenceId", + "columnName": "referenceId", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "timestamp", + "columnName": "timestamp", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "utcOffset", + "columnName": "utcOffset", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "duration", + "columnName": "duration", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "basalBlocks", + "columnName": "basalBlocks", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "interfaceIDs_backing.nightscoutSystemId", + "columnName": "nightscoutSystemId", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "interfaceIDs_backing.nightscoutId", + "columnName": "nightscoutId", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "interfaceIDs_backing.pumpType", + "columnName": "pumpType", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "interfaceIDs_backing.pumpSerial", + "columnName": "pumpSerial", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "interfaceIDs_backing.temporaryId", + "columnName": "temporaryId", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "interfaceIDs_backing.pumpId", + "columnName": "pumpId", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "interfaceIDs_backing.startId", + "columnName": "startId", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "interfaceIDs_backing.endId", + "columnName": "endId", + "affinity": "INTEGER", + "notNull": false + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [ + { + "name": "index_effectiveProfileSwitches_referenceId", + "unique": false, + "columnNames": [ + "referenceId" + ], + "createSql": "CREATE INDEX IF NOT EXISTS `index_effectiveProfileSwitches_referenceId` ON `${TABLE_NAME}` (`referenceId`)" + }, + { + "name": "index_effectiveProfileSwitches_timestamp", + "unique": false, + "columnNames": [ + "timestamp" + ], + "createSql": "CREATE INDEX IF NOT EXISTS `index_effectiveProfileSwitches_timestamp` ON `${TABLE_NAME}` (`timestamp`)" + } + ], + "foreignKeys": [ + { + "table": "effectiveProfileSwitches", + "onDelete": "NO ACTION", + "onUpdate": "NO ACTION", + "columns": [ + "referenceId" + ], + "referencedColumns": [ + "id" + ] + } + ] + }, + { + "tableName": "extendedBoluses", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `version` INTEGER NOT NULL, `dateCreated` INTEGER NOT NULL, `isValid` INTEGER NOT NULL, `referenceId` INTEGER, `timestamp` INTEGER NOT NULL, `utcOffset` INTEGER NOT NULL, `duration` INTEGER NOT NULL, `amount` REAL NOT NULL, `isEmulatingTempBasal` INTEGER NOT NULL, `nightscoutSystemId` TEXT, `nightscoutId` TEXT, `pumpType` TEXT, `pumpSerial` TEXT, `temporaryId` INTEGER, `pumpId` INTEGER, `startId` INTEGER, `endId` INTEGER, FOREIGN KEY(`referenceId`) REFERENCES `extendedBoluses`(`id`) ON UPDATE NO ACTION ON DELETE NO ACTION )", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "version", + "columnName": "version", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "dateCreated", + "columnName": "dateCreated", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "isValid", + "columnName": "isValid", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "referenceId", + "columnName": "referenceId", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "timestamp", + "columnName": "timestamp", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "utcOffset", + "columnName": "utcOffset", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "duration", + "columnName": "duration", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "amount", + "columnName": "amount", + "affinity": "REAL", + "notNull": true + }, + { + "fieldPath": "isEmulatingTempBasal", + "columnName": "isEmulatingTempBasal", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "interfaceIDs_backing.nightscoutSystemId", + "columnName": "nightscoutSystemId", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "interfaceIDs_backing.nightscoutId", + "columnName": "nightscoutId", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "interfaceIDs_backing.pumpType", + "columnName": "pumpType", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "interfaceIDs_backing.pumpSerial", + "columnName": "pumpSerial", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "interfaceIDs_backing.temporaryId", + "columnName": "temporaryId", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "interfaceIDs_backing.pumpId", + "columnName": "pumpId", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "interfaceIDs_backing.startId", + "columnName": "startId", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "interfaceIDs_backing.endId", + "columnName": "endId", + "affinity": "INTEGER", + "notNull": false + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [ + { + "name": "index_extendedBoluses_referenceId", + "unique": false, + "columnNames": [ + "referenceId" + ], + "createSql": "CREATE INDEX IF NOT EXISTS `index_extendedBoluses_referenceId` ON `${TABLE_NAME}` (`referenceId`)" + }, + { + "name": "index_extendedBoluses_timestamp", + "unique": false, + "columnNames": [ + "timestamp" + ], + "createSql": "CREATE INDEX IF NOT EXISTS `index_extendedBoluses_timestamp` ON `${TABLE_NAME}` (`timestamp`)" + } + ], + "foreignKeys": [ + { + "table": "extendedBoluses", + "onDelete": "NO ACTION", + "onUpdate": "NO ACTION", + "columns": [ + "referenceId" + ], + "referencedColumns": [ + "id" + ] + } + ] + }, + { + "tableName": "glucoseValues", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `version` INTEGER NOT NULL, `dateCreated` INTEGER NOT NULL, `isValid` INTEGER NOT NULL, `referenceId` INTEGER, `timestamp` INTEGER NOT NULL, `utcOffset` INTEGER NOT NULL, `raw` REAL, `value` REAL NOT NULL, `trendArrow` TEXT NOT NULL, `noise` REAL, `sourceSensor` TEXT NOT NULL, `nightscoutSystemId` TEXT, `nightscoutId` TEXT, `pumpType` TEXT, `pumpSerial` TEXT, `temporaryId` INTEGER, `pumpId` INTEGER, `startId` INTEGER, `endId` INTEGER, FOREIGN KEY(`referenceId`) REFERENCES `glucoseValues`(`id`) ON UPDATE NO ACTION ON DELETE NO ACTION )", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "version", + "columnName": "version", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "dateCreated", + "columnName": "dateCreated", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "isValid", + "columnName": "isValid", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "referenceId", + "columnName": "referenceId", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "timestamp", + "columnName": "timestamp", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "utcOffset", + "columnName": "utcOffset", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "raw", + "columnName": "raw", + "affinity": "REAL", + "notNull": false + }, + { + "fieldPath": "value", + "columnName": "value", + "affinity": "REAL", + "notNull": true + }, + { + "fieldPath": "trendArrow", + "columnName": "trendArrow", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "noise", + "columnName": "noise", + "affinity": "REAL", + "notNull": false + }, + { + "fieldPath": "sourceSensor", + "columnName": "sourceSensor", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "interfaceIDs_backing.nightscoutSystemId", + "columnName": "nightscoutSystemId", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "interfaceIDs_backing.nightscoutId", + "columnName": "nightscoutId", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "interfaceIDs_backing.pumpType", + "columnName": "pumpType", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "interfaceIDs_backing.pumpSerial", + "columnName": "pumpSerial", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "interfaceIDs_backing.temporaryId", + "columnName": "temporaryId", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "interfaceIDs_backing.pumpId", + "columnName": "pumpId", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "interfaceIDs_backing.startId", + "columnName": "startId", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "interfaceIDs_backing.endId", + "columnName": "endId", + "affinity": "INTEGER", + "notNull": false + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [ + { + "name": "index_glucoseValues_referenceId", + "unique": false, + "columnNames": [ + "referenceId" + ], + "createSql": "CREATE INDEX IF NOT EXISTS `index_glucoseValues_referenceId` ON `${TABLE_NAME}` (`referenceId`)" + }, + { + "name": "index_glucoseValues_timestamp", + "unique": false, + "columnNames": [ + "timestamp" + ], + "createSql": "CREATE INDEX IF NOT EXISTS `index_glucoseValues_timestamp` ON `${TABLE_NAME}` (`timestamp`)" + } + ], + "foreignKeys": [ + { + "table": "glucoseValues", + "onDelete": "NO ACTION", + "onUpdate": "NO ACTION", + "columns": [ + "referenceId" + ], + "referencedColumns": [ + "id" + ] + } + ] + }, + { + "tableName": "profileSwitches", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `version` INTEGER NOT NULL, `dateCreated` INTEGER NOT NULL, `isValid` INTEGER NOT NULL, `referenceId` INTEGER, `timestamp` INTEGER NOT NULL, `utcOffset` INTEGER NOT NULL, `profileName` TEXT NOT NULL, `glucoseUnit` TEXT NOT NULL, `basalBlocks` TEXT NOT NULL, `isfBlocks` TEXT NOT NULL, `icBlocks` TEXT NOT NULL, `targetBlocks` TEXT NOT NULL, `timeshift` INTEGER NOT NULL, `percentage` INTEGER NOT NULL, `duration` INTEGER NOT NULL, `nightscoutSystemId` TEXT, `nightscoutId` TEXT, `pumpType` TEXT, `pumpSerial` TEXT, `temporaryId` INTEGER, `pumpId` INTEGER, `startId` INTEGER, `endId` INTEGER, `insulinLabel` TEXT NOT NULL, `insulinEndTime` INTEGER NOT NULL, `peak` INTEGER NOT NULL, FOREIGN KEY(`referenceId`) REFERENCES `profileSwitches`(`id`) ON UPDATE NO ACTION ON DELETE NO ACTION )", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "version", + "columnName": "version", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "dateCreated", + "columnName": "dateCreated", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "isValid", + "columnName": "isValid", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "referenceId", + "columnName": "referenceId", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "timestamp", + "columnName": "timestamp", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "utcOffset", + "columnName": "utcOffset", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "profileName", + "columnName": "profileName", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "glucoseUnit", + "columnName": "glucoseUnit", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "basalBlocks", + "columnName": "basalBlocks", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "isfBlocks", + "columnName": "isfBlocks", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "icBlocks", + "columnName": "icBlocks", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "targetBlocks", + "columnName": "targetBlocks", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "timeshift", + "columnName": "timeshift", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "percentage", + "columnName": "percentage", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "duration", + "columnName": "duration", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "interfaceIDs_backing.nightscoutSystemId", + "columnName": "nightscoutSystemId", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "interfaceIDs_backing.nightscoutId", + "columnName": "nightscoutId", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "interfaceIDs_backing.pumpType", + "columnName": "pumpType", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "interfaceIDs_backing.pumpSerial", + "columnName": "pumpSerial", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "interfaceIDs_backing.temporaryId", + "columnName": "temporaryId", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "interfaceIDs_backing.pumpId", + "columnName": "pumpId", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "interfaceIDs_backing.startId", + "columnName": "startId", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "interfaceIDs_backing.endId", + "columnName": "endId", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "insulinConfiguration.insulinLabel", + "columnName": "insulinLabel", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "insulinConfiguration.insulinEndTime", + "columnName": "insulinEndTime", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "insulinConfiguration.peak", + "columnName": "peak", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [ + { + "name": "index_profileSwitches_referenceId", + "unique": false, + "columnNames": [ + "referenceId" + ], + "createSql": "CREATE INDEX IF NOT EXISTS `index_profileSwitches_referenceId` ON `${TABLE_NAME}` (`referenceId`)" + }, + { + "name": "index_profileSwitches_timestamp", + "unique": false, + "columnNames": [ + "timestamp" + ], + "createSql": "CREATE INDEX IF NOT EXISTS `index_profileSwitches_timestamp` ON `${TABLE_NAME}` (`timestamp`)" + } + ], + "foreignKeys": [ + { + "table": "profileSwitches", + "onDelete": "NO ACTION", + "onUpdate": "NO ACTION", + "columns": [ + "referenceId" + ], + "referencedColumns": [ + "id" + ] + } + ] + }, + { + "tableName": "temporaryBasals", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `version` INTEGER NOT NULL, `dateCreated` INTEGER NOT NULL, `isValid` INTEGER NOT NULL, `referenceId` INTEGER, `timestamp` INTEGER NOT NULL, `utcOffset` INTEGER NOT NULL, `type` TEXT NOT NULL, `isAbsolute` INTEGER NOT NULL, `rate` REAL NOT NULL, `duration` INTEGER NOT NULL, `nightscoutSystemId` TEXT, `nightscoutId` TEXT, `pumpType` TEXT, `pumpSerial` TEXT, `temporaryId` INTEGER, `pumpId` INTEGER, `startId` INTEGER, `endId` INTEGER, FOREIGN KEY(`referenceId`) REFERENCES `temporaryBasals`(`id`) ON UPDATE NO ACTION ON DELETE NO ACTION )", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "version", + "columnName": "version", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "dateCreated", + "columnName": "dateCreated", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "isValid", + "columnName": "isValid", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "referenceId", + "columnName": "referenceId", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "timestamp", + "columnName": "timestamp", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "utcOffset", + "columnName": "utcOffset", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "type", + "columnName": "type", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "isAbsolute", + "columnName": "isAbsolute", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "rate", + "columnName": "rate", + "affinity": "REAL", + "notNull": true + }, + { + "fieldPath": "duration", + "columnName": "duration", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "interfaceIDs_backing.nightscoutSystemId", + "columnName": "nightscoutSystemId", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "interfaceIDs_backing.nightscoutId", + "columnName": "nightscoutId", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "interfaceIDs_backing.pumpType", + "columnName": "pumpType", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "interfaceIDs_backing.pumpSerial", + "columnName": "pumpSerial", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "interfaceIDs_backing.temporaryId", + "columnName": "temporaryId", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "interfaceIDs_backing.pumpId", + "columnName": "pumpId", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "interfaceIDs_backing.startId", + "columnName": "startId", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "interfaceIDs_backing.endId", + "columnName": "endId", + "affinity": "INTEGER", + "notNull": false + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [ + { + "name": "index_temporaryBasals_referenceId", + "unique": false, + "columnNames": [ + "referenceId" + ], + "createSql": "CREATE INDEX IF NOT EXISTS `index_temporaryBasals_referenceId` ON `${TABLE_NAME}` (`referenceId`)" + }, + { + "name": "index_temporaryBasals_timestamp", + "unique": false, + "columnNames": [ + "timestamp" + ], + "createSql": "CREATE INDEX IF NOT EXISTS `index_temporaryBasals_timestamp` ON `${TABLE_NAME}` (`timestamp`)" + } + ], + "foreignKeys": [ + { + "table": "temporaryBasals", + "onDelete": "NO ACTION", + "onUpdate": "NO ACTION", + "columns": [ + "referenceId" + ], + "referencedColumns": [ + "id" + ] + } + ] + }, + { + "tableName": "temporaryTargets", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `version` INTEGER NOT NULL, `dateCreated` INTEGER NOT NULL, `isValid` INTEGER NOT NULL, `referenceId` INTEGER, `timestamp` INTEGER NOT NULL, `utcOffset` INTEGER NOT NULL, `reason` TEXT NOT NULL, `highTarget` REAL NOT NULL, `lowTarget` REAL NOT NULL, `duration` INTEGER NOT NULL, `nightscoutSystemId` TEXT, `nightscoutId` TEXT, `pumpType` TEXT, `pumpSerial` TEXT, `temporaryId` INTEGER, `pumpId` INTEGER, `startId` INTEGER, `endId` INTEGER, FOREIGN KEY(`referenceId`) REFERENCES `temporaryTargets`(`id`) ON UPDATE NO ACTION ON DELETE NO ACTION )", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "version", + "columnName": "version", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "dateCreated", + "columnName": "dateCreated", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "isValid", + "columnName": "isValid", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "referenceId", + "columnName": "referenceId", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "timestamp", + "columnName": "timestamp", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "utcOffset", + "columnName": "utcOffset", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "reason", + "columnName": "reason", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "highTarget", + "columnName": "highTarget", + "affinity": "REAL", + "notNull": true + }, + { + "fieldPath": "lowTarget", + "columnName": "lowTarget", + "affinity": "REAL", + "notNull": true + }, + { + "fieldPath": "duration", + "columnName": "duration", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "interfaceIDs_backing.nightscoutSystemId", + "columnName": "nightscoutSystemId", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "interfaceIDs_backing.nightscoutId", + "columnName": "nightscoutId", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "interfaceIDs_backing.pumpType", + "columnName": "pumpType", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "interfaceIDs_backing.pumpSerial", + "columnName": "pumpSerial", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "interfaceIDs_backing.temporaryId", + "columnName": "temporaryId", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "interfaceIDs_backing.pumpId", + "columnName": "pumpId", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "interfaceIDs_backing.startId", + "columnName": "startId", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "interfaceIDs_backing.endId", + "columnName": "endId", + "affinity": "INTEGER", + "notNull": false + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [ + { + "name": "index_temporaryTargets_referenceId", + "unique": false, + "columnNames": [ + "referenceId" + ], + "createSql": "CREATE INDEX IF NOT EXISTS `index_temporaryTargets_referenceId` ON `${TABLE_NAME}` (`referenceId`)" + }, + { + "name": "index_temporaryTargets_timestamp", + "unique": false, + "columnNames": [ + "timestamp" + ], + "createSql": "CREATE INDEX IF NOT EXISTS `index_temporaryTargets_timestamp` ON `${TABLE_NAME}` (`timestamp`)" + } + ], + "foreignKeys": [ + { + "table": "temporaryTargets", + "onDelete": "NO ACTION", + "onUpdate": "NO ACTION", + "columns": [ + "referenceId" + ], + "referencedColumns": [ + "id" + ] + } + ] + }, + { + "tableName": "therapyEvents", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `version` INTEGER NOT NULL, `dateCreated` INTEGER NOT NULL, `isValid` INTEGER NOT NULL, `referenceId` INTEGER, `timestamp` INTEGER NOT NULL, `utcOffset` INTEGER NOT NULL, `duration` INTEGER NOT NULL, `type` TEXT NOT NULL, `note` TEXT, `enteredBy` TEXT, `glucose` REAL, `glucoseType` TEXT, `glucoseUnit` TEXT NOT NULL, `nightscoutSystemId` TEXT, `nightscoutId` TEXT, `pumpType` TEXT, `pumpSerial` TEXT, `temporaryId` INTEGER, `pumpId` INTEGER, `startId` INTEGER, `endId` INTEGER, FOREIGN KEY(`referenceId`) REFERENCES `therapyEvents`(`id`) ON UPDATE NO ACTION ON DELETE NO ACTION )", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "version", + "columnName": "version", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "dateCreated", + "columnName": "dateCreated", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "isValid", + "columnName": "isValid", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "referenceId", + "columnName": "referenceId", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "timestamp", + "columnName": "timestamp", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "utcOffset", + "columnName": "utcOffset", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "duration", + "columnName": "duration", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "type", + "columnName": "type", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "note", + "columnName": "note", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "enteredBy", + "columnName": "enteredBy", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "glucose", + "columnName": "glucose", + "affinity": "REAL", + "notNull": false + }, + { + "fieldPath": "glucoseType", + "columnName": "glucoseType", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "glucoseUnit", + "columnName": "glucoseUnit", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "interfaceIDs_backing.nightscoutSystemId", + "columnName": "nightscoutSystemId", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "interfaceIDs_backing.nightscoutId", + "columnName": "nightscoutId", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "interfaceIDs_backing.pumpType", + "columnName": "pumpType", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "interfaceIDs_backing.pumpSerial", + "columnName": "pumpSerial", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "interfaceIDs_backing.temporaryId", + "columnName": "temporaryId", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "interfaceIDs_backing.pumpId", + "columnName": "pumpId", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "interfaceIDs_backing.startId", + "columnName": "startId", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "interfaceIDs_backing.endId", + "columnName": "endId", + "affinity": "INTEGER", + "notNull": false + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [ + { + "name": "index_therapyEvents_referenceId", + "unique": false, + "columnNames": [ + "referenceId" + ], + "createSql": "CREATE INDEX IF NOT EXISTS `index_therapyEvents_referenceId` ON `${TABLE_NAME}` (`referenceId`)" + }, + { + "name": "index_therapyEvents_timestamp", + "unique": false, + "columnNames": [ + "timestamp" + ], + "createSql": "CREATE INDEX IF NOT EXISTS `index_therapyEvents_timestamp` ON `${TABLE_NAME}` (`timestamp`)" + } + ], + "foreignKeys": [ + { + "table": "therapyEvents", + "onDelete": "NO ACTION", + "onUpdate": "NO ACTION", + "columns": [ + "referenceId" + ], + "referencedColumns": [ + "id" + ] + } + ] + }, + { + "tableName": "totalDailyDoses", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `version` INTEGER NOT NULL, `dateCreated` INTEGER NOT NULL, `isValid` INTEGER NOT NULL, `referenceId` INTEGER, `timestamp` INTEGER NOT NULL, `utcOffset` INTEGER NOT NULL, `basalAmount` REAL, `bolusAmount` REAL, `totalAmount` REAL, `nightscoutSystemId` TEXT, `nightscoutId` TEXT, `pumpType` TEXT, `pumpSerial` TEXT, `temporaryId` INTEGER, `pumpId` INTEGER, `startId` INTEGER, `endId` INTEGER, FOREIGN KEY(`referenceId`) REFERENCES `totalDailyDoses`(`id`) ON UPDATE NO ACTION ON DELETE NO ACTION )", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "version", + "columnName": "version", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "dateCreated", + "columnName": "dateCreated", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "isValid", + "columnName": "isValid", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "referenceId", + "columnName": "referenceId", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "timestamp", + "columnName": "timestamp", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "utcOffset", + "columnName": "utcOffset", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "basalAmount", + "columnName": "basalAmount", + "affinity": "REAL", + "notNull": false + }, + { + "fieldPath": "bolusAmount", + "columnName": "bolusAmount", + "affinity": "REAL", + "notNull": false + }, + { + "fieldPath": "totalAmount", + "columnName": "totalAmount", + "affinity": "REAL", + "notNull": false + }, + { + "fieldPath": "interfaceIDs_backing.nightscoutSystemId", + "columnName": "nightscoutSystemId", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "interfaceIDs_backing.nightscoutId", + "columnName": "nightscoutId", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "interfaceIDs_backing.pumpType", + "columnName": "pumpType", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "interfaceIDs_backing.pumpSerial", + "columnName": "pumpSerial", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "interfaceIDs_backing.temporaryId", + "columnName": "temporaryId", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "interfaceIDs_backing.pumpId", + "columnName": "pumpId", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "interfaceIDs_backing.startId", + "columnName": "startId", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "interfaceIDs_backing.endId", + "columnName": "endId", + "affinity": "INTEGER", + "notNull": false + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [ + { + "name": "index_totalDailyDoses_referenceId", + "unique": false, + "columnNames": [ + "referenceId" + ], + "createSql": "CREATE INDEX IF NOT EXISTS `index_totalDailyDoses_referenceId` ON `${TABLE_NAME}` (`referenceId`)" + }, + { + "name": "index_totalDailyDoses_timestamp", + "unique": false, + "columnNames": [ + "timestamp" + ], + "createSql": "CREATE INDEX IF NOT EXISTS `index_totalDailyDoses_timestamp` ON `${TABLE_NAME}` (`timestamp`)" + } + ], + "foreignKeys": [ + { + "table": "totalDailyDoses", + "onDelete": "NO ACTION", + "onUpdate": "NO ACTION", + "columns": [ + "referenceId" + ], + "referencedColumns": [ + "id" + ] + } + ] + }, + { + "tableName": "apsResultLinks", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `version` INTEGER NOT NULL, `dateCreated` INTEGER NOT NULL, `isValid` INTEGER NOT NULL, `referenceId` INTEGER, `apsResultId` INTEGER NOT NULL, `smbId` INTEGER, `tbrId` INTEGER, `nightscoutSystemId` TEXT, `nightscoutId` TEXT, `pumpType` TEXT, `pumpSerial` TEXT, `temporaryId` INTEGER, `pumpId` INTEGER, `startId` INTEGER, `endId` INTEGER, FOREIGN KEY(`apsResultId`) REFERENCES `apsResults`(`id`) ON UPDATE NO ACTION ON DELETE NO ACTION , FOREIGN KEY(`smbId`) REFERENCES `boluses`(`id`) ON UPDATE NO ACTION ON DELETE NO ACTION , FOREIGN KEY(`tbrId`) REFERENCES `temporaryBasals`(`id`) ON UPDATE NO ACTION ON DELETE NO ACTION , FOREIGN KEY(`referenceId`) REFERENCES `apsResultLinks`(`id`) ON UPDATE NO ACTION ON DELETE NO ACTION )", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "version", + "columnName": "version", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "dateCreated", + "columnName": "dateCreated", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "isValid", + "columnName": "isValid", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "referenceId", + "columnName": "referenceId", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "apsResultId", + "columnName": "apsResultId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "smbId", + "columnName": "smbId", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "tbrId", + "columnName": "tbrId", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "interfaceIDs_backing.nightscoutSystemId", + "columnName": "nightscoutSystemId", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "interfaceIDs_backing.nightscoutId", + "columnName": "nightscoutId", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "interfaceIDs_backing.pumpType", + "columnName": "pumpType", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "interfaceIDs_backing.pumpSerial", + "columnName": "pumpSerial", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "interfaceIDs_backing.temporaryId", + "columnName": "temporaryId", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "interfaceIDs_backing.pumpId", + "columnName": "pumpId", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "interfaceIDs_backing.startId", + "columnName": "startId", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "interfaceIDs_backing.endId", + "columnName": "endId", + "affinity": "INTEGER", + "notNull": false + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [ + { + "name": "index_apsResultLinks_referenceId", + "unique": false, + "columnNames": [ + "referenceId" + ], + "createSql": "CREATE INDEX IF NOT EXISTS `index_apsResultLinks_referenceId` ON `${TABLE_NAME}` (`referenceId`)" + }, + { + "name": "index_apsResultLinks_apsResultId", + "unique": false, + "columnNames": [ + "apsResultId" + ], + "createSql": "CREATE INDEX IF NOT EXISTS `index_apsResultLinks_apsResultId` ON `${TABLE_NAME}` (`apsResultId`)" + }, + { + "name": "index_apsResultLinks_smbId", + "unique": false, + "columnNames": [ + "smbId" + ], + "createSql": "CREATE INDEX IF NOT EXISTS `index_apsResultLinks_smbId` ON `${TABLE_NAME}` (`smbId`)" + }, + { + "name": "index_apsResultLinks_tbrId", + "unique": false, + "columnNames": [ + "tbrId" + ], + "createSql": "CREATE INDEX IF NOT EXISTS `index_apsResultLinks_tbrId` ON `${TABLE_NAME}` (`tbrId`)" + } + ], + "foreignKeys": [ + { + "table": "apsResults", + "onDelete": "NO ACTION", + "onUpdate": "NO ACTION", + "columns": [ + "apsResultId" + ], + "referencedColumns": [ + "id" + ] + }, + { + "table": "boluses", + "onDelete": "NO ACTION", + "onUpdate": "NO ACTION", + "columns": [ + "smbId" + ], + "referencedColumns": [ + "id" + ] + }, + { + "table": "temporaryBasals", + "onDelete": "NO ACTION", + "onUpdate": "NO ACTION", + "columns": [ + "tbrId" + ], + "referencedColumns": [ + "id" + ] + }, + { + "table": "apsResultLinks", + "onDelete": "NO ACTION", + "onUpdate": "NO ACTION", + "columns": [ + "referenceId" + ], + "referencedColumns": [ + "id" + ] + } + ] + }, + { + "tableName": "multiwaveBolusLinks", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `version` INTEGER NOT NULL, `dateCreated` INTEGER NOT NULL, `isValid` INTEGER NOT NULL, `referenceId` INTEGER, `bolusId` INTEGER NOT NULL, `extendedBolusId` INTEGER NOT NULL, `nightscoutSystemId` TEXT, `nightscoutId` TEXT, `pumpType` TEXT, `pumpSerial` TEXT, `temporaryId` INTEGER, `pumpId` INTEGER, `startId` INTEGER, `endId` INTEGER, FOREIGN KEY(`bolusId`) REFERENCES `boluses`(`id`) ON UPDATE NO ACTION ON DELETE NO ACTION , FOREIGN KEY(`extendedBolusId`) REFERENCES `extendedBoluses`(`id`) ON UPDATE NO ACTION ON DELETE NO ACTION , FOREIGN KEY(`referenceId`) REFERENCES `multiwaveBolusLinks`(`id`) ON UPDATE NO ACTION ON DELETE NO ACTION )", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "version", + "columnName": "version", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "dateCreated", + "columnName": "dateCreated", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "isValid", + "columnName": "isValid", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "referenceId", + "columnName": "referenceId", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "bolusId", + "columnName": "bolusId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "extendedBolusId", + "columnName": "extendedBolusId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "interfaceIDs_backing.nightscoutSystemId", + "columnName": "nightscoutSystemId", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "interfaceIDs_backing.nightscoutId", + "columnName": "nightscoutId", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "interfaceIDs_backing.pumpType", + "columnName": "pumpType", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "interfaceIDs_backing.pumpSerial", + "columnName": "pumpSerial", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "interfaceIDs_backing.temporaryId", + "columnName": "temporaryId", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "interfaceIDs_backing.pumpId", + "columnName": "pumpId", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "interfaceIDs_backing.startId", + "columnName": "startId", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "interfaceIDs_backing.endId", + "columnName": "endId", + "affinity": "INTEGER", + "notNull": false + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [ + { + "name": "index_multiwaveBolusLinks_referenceId", + "unique": false, + "columnNames": [ + "referenceId" + ], + "createSql": "CREATE INDEX IF NOT EXISTS `index_multiwaveBolusLinks_referenceId` ON `${TABLE_NAME}` (`referenceId`)" + }, + { + "name": "index_multiwaveBolusLinks_bolusId", + "unique": false, + "columnNames": [ + "bolusId" + ], + "createSql": "CREATE INDEX IF NOT EXISTS `index_multiwaveBolusLinks_bolusId` ON `${TABLE_NAME}` (`bolusId`)" + }, + { + "name": "index_multiwaveBolusLinks_extendedBolusId", + "unique": false, + "columnNames": [ + "extendedBolusId" + ], + "createSql": "CREATE INDEX IF NOT EXISTS `index_multiwaveBolusLinks_extendedBolusId` ON `${TABLE_NAME}` (`extendedBolusId`)" + } + ], + "foreignKeys": [ + { + "table": "boluses", + "onDelete": "NO ACTION", + "onUpdate": "NO ACTION", + "columns": [ + "bolusId" + ], + "referencedColumns": [ + "id" + ] + }, + { + "table": "extendedBoluses", + "onDelete": "NO ACTION", + "onUpdate": "NO ACTION", + "columns": [ + "extendedBolusId" + ], + "referencedColumns": [ + "id" + ] + }, + { + "table": "multiwaveBolusLinks", + "onDelete": "NO ACTION", + "onUpdate": "NO ACTION", + "columns": [ + "referenceId" + ], + "referencedColumns": [ + "id" + ] + } + ] + }, + { + "tableName": "preferenceChanges", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `timestamp` INTEGER NOT NULL, `utcOffset` INTEGER NOT NULL, `key` TEXT NOT NULL, `value` TEXT)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "timestamp", + "columnName": "timestamp", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "utcOffset", + "columnName": "utcOffset", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "key", + "columnName": "key", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "value", + "columnName": "value", + "affinity": "TEXT", + "notNull": false + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "versionChanges", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `timestamp` INTEGER NOT NULL, `utcOffset` INTEGER NOT NULL, `versionCode` INTEGER NOT NULL, `versionName` TEXT NOT NULL, `gitRemote` TEXT, `commitHash` TEXT)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "timestamp", + "columnName": "timestamp", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "utcOffset", + "columnName": "utcOffset", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "versionCode", + "columnName": "versionCode", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "versionName", + "columnName": "versionName", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "gitRemote", + "columnName": "gitRemote", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "commitHash", + "columnName": "commitHash", + "affinity": "TEXT", + "notNull": false + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "userEntry", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `timestamp` INTEGER NOT NULL, `utcOffset` INTEGER NOT NULL, `action` TEXT NOT NULL, `s` TEXT NOT NULL, `values` TEXT NOT NULL)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "timestamp", + "columnName": "timestamp", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "utcOffset", + "columnName": "utcOffset", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "action", + "columnName": "action", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "s", + "columnName": "s", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "values", + "columnName": "values", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "foods", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `version` INTEGER NOT NULL, `dateCreated` INTEGER NOT NULL, `isValid` INTEGER NOT NULL, `referenceId` INTEGER, `name` TEXT NOT NULL, `category` TEXT, `subCategory` TEXT, `portion` REAL NOT NULL, `carbs` INTEGER NOT NULL, `fat` INTEGER, `protein` INTEGER, `energy` INTEGER, `unit` TEXT NOT NULL, `gi` INTEGER, `nightscoutSystemId` TEXT, `nightscoutId` TEXT, `pumpType` TEXT, `pumpSerial` TEXT, `temporaryId` INTEGER, `pumpId` INTEGER, `startId` INTEGER, `endId` INTEGER, FOREIGN KEY(`referenceId`) REFERENCES `foods`(`id`) ON UPDATE NO ACTION ON DELETE NO ACTION )", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "version", + "columnName": "version", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "dateCreated", + "columnName": "dateCreated", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "isValid", + "columnName": "isValid", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "referenceId", + "columnName": "referenceId", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "name", + "columnName": "name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "category", + "columnName": "category", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "subCategory", + "columnName": "subCategory", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "portion", + "columnName": "portion", + "affinity": "REAL", + "notNull": true + }, + { + "fieldPath": "carbs", + "columnName": "carbs", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "fat", + "columnName": "fat", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "protein", + "columnName": "protein", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "energy", + "columnName": "energy", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "unit", + "columnName": "unit", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "gi", + "columnName": "gi", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "interfaceIDs_backing.nightscoutSystemId", + "columnName": "nightscoutSystemId", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "interfaceIDs_backing.nightscoutId", + "columnName": "nightscoutId", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "interfaceIDs_backing.pumpType", + "columnName": "pumpType", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "interfaceIDs_backing.pumpSerial", + "columnName": "pumpSerial", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "interfaceIDs_backing.temporaryId", + "columnName": "temporaryId", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "interfaceIDs_backing.pumpId", + "columnName": "pumpId", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "interfaceIDs_backing.startId", + "columnName": "startId", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "interfaceIDs_backing.endId", + "columnName": "endId", + "affinity": "INTEGER", + "notNull": false + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [ + { + "name": "index_foods_referenceId", + "unique": false, + "columnNames": [ + "referenceId" + ], + "createSql": "CREATE INDEX IF NOT EXISTS `index_foods_referenceId` ON `${TABLE_NAME}` (`referenceId`)" + } + ], + "foreignKeys": [ + { + "table": "foods", + "onDelete": "NO ACTION", + "onUpdate": "NO ACTION", + "columns": [ + "referenceId" + ], + "referencedColumns": [ + "id" + ] + } + ] + }, + { + "tableName": "deviceStatus", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `timestamp` INTEGER NOT NULL, `utcOffset` INTEGER NOT NULL, `device` TEXT, `pump` TEXT, `enacted` TEXT, `suggested` TEXT, `iob` TEXT, `uploaderBattery` INTEGER NOT NULL, `configuration` TEXT, `nightscoutSystemId` TEXT, `nightscoutId` TEXT, `pumpType` TEXT, `pumpSerial` TEXT, `temporaryId` INTEGER, `pumpId` INTEGER, `startId` INTEGER, `endId` INTEGER)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "timestamp", + "columnName": "timestamp", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "utcOffset", + "columnName": "utcOffset", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "device", + "columnName": "device", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "pump", + "columnName": "pump", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "enacted", + "columnName": "enacted", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "suggested", + "columnName": "suggested", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "iob", + "columnName": "iob", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "uploaderBattery", + "columnName": "uploaderBattery", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "configuration", + "columnName": "configuration", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "interfaceIDs_backing.nightscoutSystemId", + "columnName": "nightscoutSystemId", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "interfaceIDs_backing.nightscoutId", + "columnName": "nightscoutId", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "interfaceIDs_backing.pumpType", + "columnName": "pumpType", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "interfaceIDs_backing.pumpSerial", + "columnName": "pumpSerial", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "interfaceIDs_backing.temporaryId", + "columnName": "temporaryId", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "interfaceIDs_backing.pumpId", + "columnName": "pumpId", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "interfaceIDs_backing.startId", + "columnName": "startId", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "interfaceIDs_backing.endId", + "columnName": "endId", + "affinity": "INTEGER", + "notNull": false + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [ + { + "name": "index_deviceStatus_timestamp", + "unique": false, + "columnNames": [ + "timestamp" + ], + "createSql": "CREATE INDEX IF NOT EXISTS `index_deviceStatus_timestamp` ON `${TABLE_NAME}` (`timestamp`)" + } + ], + "foreignKeys": [] + } + ], + "views": [], + "setupQueries": [ + "CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)", + "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, 'e41836fe7fbd4aa439ec970af929ad7c')" + ] + } +} \ No newline at end of file diff --git a/database/src/main/java/info/nightscout/androidaps/database/AppDatabase.kt b/database/src/main/java/info/nightscout/androidaps/database/AppDatabase.kt index a4516b6982..2947bdfecd 100644 --- a/database/src/main/java/info/nightscout/androidaps/database/AppDatabase.kt +++ b/database/src/main/java/info/nightscout/androidaps/database/AppDatabase.kt @@ -6,14 +6,14 @@ import androidx.room.TypeConverters import info.nightscout.androidaps.database.daos.* import info.nightscout.androidaps.database.entities.* -const val DATABASE_VERSION = 9 +const val DATABASE_VERSION = 10 @Database(version = DATABASE_VERSION, entities = [APSResult::class, Bolus::class, BolusCalculatorResult::class, Carbs::class, EffectiveProfileSwitch::class, ExtendedBolus::class, GlucoseValue::class, ProfileSwitch::class, TemporaryBasal::class, TemporaryTarget::class, TherapyEvent::class, TotalDailyDose::class, APSResultLink::class, MultiwaveBolusLink::class, PreferenceChange::class, VersionChange::class, UserEntry::class, - Food::class], + Food::class, DeviceStatus::class], exportSchema = true) @TypeConverters(Converters::class) internal abstract class AppDatabase : RoomDatabase() { @@ -54,4 +54,6 @@ internal abstract class AppDatabase : RoomDatabase() { abstract val foodDao: FoodDao + abstract val deviceStatusDao: DeviceStatusDao + } \ No newline at end of file diff --git a/database/src/main/java/info/nightscout/androidaps/database/AppRepository.kt b/database/src/main/java/info/nightscout/androidaps/database/AppRepository.kt index 00c5e2c503..1e866dee24 100644 --- a/database/src/main/java/info/nightscout/androidaps/database/AppRepository.kt +++ b/database/src/main/java/info/nightscout/androidaps/database/AppRepository.kt @@ -455,6 +455,26 @@ open class AppRepository @Inject internal constructor( fun deleteAllBolusCalculatorResults() = database.bolusCalculatorResultDao.deleteAllEntries() + // DEVICE STATUS + fun insert(deviceStatus: DeviceStatus) : Long = + database.deviceStatusDao.insert(deviceStatus) + + /* + * returns a Pair of the next entity to sync and the ID of the "update". + * The update id might either be the entry id itself if it is a new entry - or the id + * of the update ("historic") entry. The sync counter should be incremented to that id if it was synced successfully. + * + * It is a Maybe as there might be no next element. + * */ + + fun getNextSyncElementDeviceStatus(id: Long): Maybe = + database.deviceStatusDao.getNextModifiedOrNewAfter(id) + .subscribeOn(Schedulers.io()) + + fun getModifiedDeviceStatusDataFromId(lastId: Long): Single> = + database.deviceStatusDao.getModifiedFrom(lastId) + .subscribeOn(Schedulers.io()) + } @Suppress("USELESS_CAST") diff --git a/database/src/main/java/info/nightscout/androidaps/database/DelegatedAppDatabase.kt b/database/src/main/java/info/nightscout/androidaps/database/DelegatedAppDatabase.kt index 9f29abfcd6..22ffbb4154 100644 --- a/database/src/main/java/info/nightscout/androidaps/database/DelegatedAppDatabase.kt +++ b/database/src/main/java/info/nightscout/androidaps/database/DelegatedAppDatabase.kt @@ -24,5 +24,6 @@ internal class DelegatedAppDatabase(val changes: MutableList, val datab val userEntryDao: UserEntryDao = DelegatedUserEntryDao(changes, database.userEntryDao) val preferenceChangeDao: PreferenceChangeDao = DelegatedPreferenceChangeDao(changes, database.preferenceChangeDao) val foodDao: FoodDao = DelegatedFoodDao(changes, database.foodDao) + val deviceStatusDao: DeviceStatusDao = DelegatedDeviceStatusDao(changes, database.deviceStatusDao) fun clearAllTables() = database.clearAllTables() } \ No newline at end of file diff --git a/database/src/main/java/info/nightscout/androidaps/database/TableNames.kt b/database/src/main/java/info/nightscout/androidaps/database/TableNames.kt index 9d3a06cc55..a22a280a2a 100644 --- a/database/src/main/java/info/nightscout/androidaps/database/TableNames.kt +++ b/database/src/main/java/info/nightscout/androidaps/database/TableNames.kt @@ -5,11 +5,11 @@ const val TABLE_APS_RESULT_LINKS = "apsResultLinks" const val TABLE_BOLUSES = "boluses" const val TABLE_BOLUS_CALCULATOR_RESULTS = "bolusCalculatorResults" const val TABLE_CARBS = "carbs" +const val TABLE_DEVICE_STATUS = "deviceStatus" const val TABLE_EFFECTIVE_PROFILE_SWITCHES = "effectiveProfileSwitches" const val TABLE_EXTENDED_BOLUSES = "extendedBoluses" const val TABLE_GLUCOSE_VALUES = "glucoseValues" const val TABLE_FOODS = "foods" -const val TABLE_MEAL_LINKS = "mealLinks" const val TABLE_MULTIWAVE_BOLUS_LINKS = "multiwaveBolusLinks" const val TABLE_PROFILE_SWITCHES = "profileSwitches" const val TABLE_TEMPORARY_BASALS = "temporaryBasals" @@ -18,4 +18,4 @@ const val TABLE_TOTAL_DAILY_DOSES = "totalDailyDoses" const val TABLE_THERAPY_EVENTS = "therapyEvents" const val TABLE_PREFERENCE_CHANGES = "preferenceChanges" const val TABLE_VERSION_CHANGES = "versionChanges" -const val TABLE_USER_ENTRY = "userEntry" \ No newline at end of file +const val TABLE_USER_ENTRY = "userEntry" diff --git a/database/src/main/java/info/nightscout/androidaps/database/daos/DeviceStatusDao.kt b/database/src/main/java/info/nightscout/androidaps/database/daos/DeviceStatusDao.kt new file mode 100644 index 0000000000..d34edc36d2 --- /dev/null +++ b/database/src/main/java/info/nightscout/androidaps/database/daos/DeviceStatusDao.kt @@ -0,0 +1,41 @@ +package info.nightscout.androidaps.database.daos + +import androidx.room.Dao +import androidx.room.Insert +import androidx.room.Query +import androidx.room.Update +import info.nightscout.androidaps.database.entities.DeviceStatus +import info.nightscout.androidaps.database.TABLE_DEVICE_STATUS +import io.reactivex.Maybe +import io.reactivex.Single + +@Suppress("FunctionName") +@Dao +internal interface DeviceStatusDao { + + @Insert + fun insert(entry: DeviceStatus): Long + + @Update + fun update(entry: DeviceStatus) + + @Query("SELECT * FROM $TABLE_DEVICE_STATUS WHERE id = :id") + fun findById(id: Long): DeviceStatus? + + @Query("DELETE FROM $TABLE_DEVICE_STATUS") + fun deleteAllEntries() + + @Query("DELETE FROM $TABLE_DEVICE_STATUS WHERE id NOT IN (SELECT MAX(id) FROM $TABLE_DEVICE_STATUS)") + fun deleteAllEntriesExceptLast() + + @Query("SELECT * FROM $TABLE_DEVICE_STATUS WHERE nightscoutId = :nsId") + fun findByNSId(nsId: String): DeviceStatus? + + // This query will be used with v3 to get all changed records + @Query("SELECT * FROM $TABLE_DEVICE_STATUS WHERE id > :id ORDER BY id ASC") + fun getModifiedFrom(id: Long): Single> + + // for WS we need 1 record only + @Query("SELECT * FROM $TABLE_DEVICE_STATUS WHERE id > :id ORDER BY id ASC limit 1") + fun getNextModifiedOrNewAfter(id: Long): Maybe +} \ No newline at end of file diff --git a/database/src/main/java/info/nightscout/androidaps/database/daos/delegated/DelegatedDeviceStatusDao.kt b/database/src/main/java/info/nightscout/androidaps/database/daos/delegated/DelegatedDeviceStatusDao.kt new file mode 100644 index 0000000000..1d798ef546 --- /dev/null +++ b/database/src/main/java/info/nightscout/androidaps/database/daos/delegated/DelegatedDeviceStatusDao.kt @@ -0,0 +1,6 @@ +package info.nightscout.androidaps.database.daos.delegated + +import info.nightscout.androidaps.database.daos.DeviceStatusDao +import info.nightscout.androidaps.database.interfaces.DBEntry + +internal class DelegatedDeviceStatusDao(changes: MutableList, private val dao: DeviceStatusDao) : DelegatedDao(changes), DeviceStatusDao by dao \ No newline at end of file diff --git a/database/src/main/java/info/nightscout/androidaps/database/entities/DeviceStatus.kt b/database/src/main/java/info/nightscout/androidaps/database/entities/DeviceStatus.kt new file mode 100644 index 0000000000..87763245fc --- /dev/null +++ b/database/src/main/java/info/nightscout/androidaps/database/entities/DeviceStatus.kt @@ -0,0 +1,44 @@ +package info.nightscout.androidaps.database.entities + +import androidx.room.Embedded +import androidx.room.Entity +import androidx.room.Index +import androidx.room.PrimaryKey +import info.nightscout.androidaps.database.TABLE_DEVICE_STATUS +import info.nightscout.androidaps.database.embedments.InterfaceIDs +import info.nightscout.androidaps.database.interfaces.DBEntryWithTime +import java.util.* + +@Entity(tableName = TABLE_DEVICE_STATUS, + foreignKeys = [], + indices = [Index("timestamp")]) +data class DeviceStatus( + @PrimaryKey(autoGenerate = true) + var id: Long = 0, + @Embedded + var interfaceIDs_backing: InterfaceIDs? = null, + override var timestamp: Long, + override var utcOffset: Long = TimeZone.getDefault().getOffset(timestamp).toLong(), + var device: String? = null, + var pump: String? = null, + var enacted: String? = null, + var suggested: String? = null, + var iob: String? = null, + var uploaderBattery: Int = 0, + var configuration: String? = null + +) : DBEntryWithTime { + + var interfaceIDs: InterfaceIDs + get() { + var value = this.interfaceIDs_backing + if (value == null) { + value = InterfaceIDs() + interfaceIDs_backing = value + } + return value + } + set(value) { + interfaceIDs_backing = value + } +} \ No newline at end of file diff --git a/database/src/main/java/info/nightscout/androidaps/database/transactions/UpdateNsIdDeviceStatusTransaction.kt b/database/src/main/java/info/nightscout/androidaps/database/transactions/UpdateNsIdDeviceStatusTransaction.kt new file mode 100644 index 0000000000..766f672877 --- /dev/null +++ b/database/src/main/java/info/nightscout/androidaps/database/transactions/UpdateNsIdDeviceStatusTransaction.kt @@ -0,0 +1,12 @@ +package info.nightscout.androidaps.database.transactions + +import info.nightscout.androidaps.database.entities.DeviceStatus + +class UpdateNsIdDeviceStatusTransaction(val deviceStatus: DeviceStatus) : Transaction() { + + override fun run() { + val current = database.deviceStatusDao.findById(deviceStatus.id) + if (current != null && current.interfaceIDs.nightscoutId != deviceStatus.interfaceIDs.nightscoutId) + database.deviceStatusDao.update(deviceStatus) + } +} \ No newline at end of file