diff --git a/.idea/dictionaries/project_dictionary.xml b/.idea/dictionaries/project_dictionary.xml index eb2cb8b9f3..3639be9c59 100644 --- a/.idea/dictionaries/project_dictionary.xml +++ b/.idea/dictionaries/project_dictionary.xml @@ -2,19 +2,24 @@ aaps + acked actionstring allowednumbers androidaps autosens autosensdata + autosense bage + basaliob basals bgcheck + bgsource bolusing carb carbs carbsreq careportal + cellnovo crashlytics danar danars @@ -23,6 +28,7 @@ dexcom dexdrip enteredby + enteredinsulin eveningoutpost eversense extendedbolus @@ -32,12 +38,15 @@ gson hmac iage + insulet iobtotal + libre listdelimiter localprofile medtronic mgdl mmol + multiwave netinsulin netratio nightscout @@ -45,6 +54,7 @@ nsclient okcancel omnipod + openaps oref passcode poctech @@ -56,7 +66,9 @@ refresheventsfromnightscout rileylink roboelectric + sitechange smscommunicator + sooil soundid splitted superbolus @@ -73,6 +85,9 @@ uart wizzardpage xdrip + ypso + ypsomed + ypsopump \ No newline at end of file diff --git a/app/build.gradle b/app/build.gradle index 31d430687c..e4d4c5be8b 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -111,7 +111,7 @@ android { defaultConfig { multiDexEnabled true versionCode 1500 - version "2.8.2.1-dev-e" + version "2.8.2.1-dev-e3" buildConfigField "String", "VERSION", '"' + version + '"' buildConfigField "String", "BUILDVERSION", '"' + generateGitBuild() + '-' + generateDate() + '"' buildConfigField "String", "REMOTE", '"' + generateGitRemote() + '"' diff --git a/app/src/androidTest/java/info/nightscout/androidaps/RealPumpTest.kt b/app/src/androidTest/java/info/nightscout/androidaps/RealPumpTest.kt index 656bdae255..75ae0caa20 100644 --- a/app/src/androidTest/java/info/nightscout/androidaps/RealPumpTest.kt +++ b/app/src/androidTest/java/info/nightscout/androidaps/RealPumpTest.kt @@ -1,35 +1,8 @@ package info.nightscout.androidaps -import android.os.SystemClock import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.LargeTest -import androidx.test.rule.ActivityTestRule -import androidx.test.rule.GrantPermissionRule -import info.nightscout.androidaps.data.Profile -import info.nightscout.androidaps.interfaces.PluginBase -import info.nightscout.androidaps.interfaces.PluginType -import info.nightscout.androidaps.plugins.aps.loop.LoopPlugin -import info.nightscout.androidaps.plugins.aps.openAPSSMB.OpenAPSSMBPlugin -import info.nightscout.androidaps.plugins.configBuilder.ConfigBuilderPlugin -import info.nightscout.androidaps.interfaces.ProfileFunction -import info.nightscout.androidaps.plugins.constraints.objectives.ObjectivesPlugin -import info.nightscout.androidaps.plugins.general.actions.ActionsPlugin -import info.nightscout.androidaps.plugins.insulin.InsulinOrefUltraRapidActingPlugin -import info.nightscout.androidaps.plugins.profile.local.LocalProfilePlugin -import info.nightscout.androidaps.danaRv2.DanaRv2Plugin -import info.nightscout.androidaps.plugins.sensitivity.SensitivityOref1Plugin -import info.nightscout.androidaps.plugins.source.RandomBgPlugin -import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin -import info.nightscout.androidaps.utils.DateUtil -import info.nightscout.androidaps.utils.extensions.isRunningTest -import info.nightscout.androidaps.utils.sharedPreferences.SP -import org.json.JSONObject -import org.junit.Assert -import org.junit.Before -import org.junit.Rule -import org.junit.Test import org.junit.runner.RunWith -import javax.inject.Inject @LargeTest @RunWith(AndroidJUnit4::class) @@ -89,7 +62,7 @@ class RealPumpTest { localProfilePlugin.numOfProfiles = 0 val singleProfile = LocalProfilePlugin.SingleProfile().copyFrom(localProfilePlugin.rawProfile, profile, "TestProfile") localProfilePlugin.addProfile(singleProfile) - val profileSwitch = profileFunction.prepareProfileSwitch(localProfilePlugin.createProfileStore(), "TestProfile", 0, 100, 0, DateUtil.now()) + val profileSwitch = profileFunction.prepareProfileSwitch(localProfilePlugin.createProfileStore(), "TestProfile", 0, 100, 0, dateUtil._now()) treatmentsPlugin.addToHistoryProfileSwitch(profileSwitch) // Insulin configBuilderPlugin.performPluginSwitch(insulinOrefUltraRapidActingPlugin, true, PluginType.INSULIN) diff --git a/app/src/main/java/info/nightscout/androidaps/ConfigImpl.kt b/app/src/main/java/info/nightscout/androidaps/ConfigImpl.kt new file mode 100644 index 0000000000..0371902901 --- /dev/null +++ b/app/src/main/java/info/nightscout/androidaps/ConfigImpl.kt @@ -0,0 +1,2 @@ +package info.nightscout.androidaps + diff --git a/app/src/main/java/info/nightscout/androidaps/MainActivity.kt b/app/src/main/java/info/nightscout/androidaps/MainActivity.kt index bccdbbcb1a..b5b5974fee 100644 --- a/app/src/main/java/info/nightscout/androidaps/MainActivity.kt +++ b/app/src/main/java/info/nightscout/androidaps/MainActivity.kt @@ -32,15 +32,20 @@ import info.nightscout.androidaps.activities.PreferencesActivity import info.nightscout.androidaps.activities.ProfileHelperActivity import info.nightscout.androidaps.activities.SingleFragmentActivity import info.nightscout.androidaps.activities.StatsActivity +import info.nightscout.androidaps.database.entities.UserEntry.Action +import info.nightscout.androidaps.database.entities.UserEntry.Sources import info.nightscout.androidaps.databinding.ActivityMainBinding import info.nightscout.androidaps.events.EventAppExit import info.nightscout.androidaps.events.EventPreferenceChange import info.nightscout.androidaps.events.EventRebuildTabs import info.nightscout.androidaps.historyBrowser.HistoryBrowseActivity -import info.nightscout.androidaps.interfaces.ActivePluginProvider +import info.nightscout.androidaps.interfaces.ActivePlugin +import info.nightscout.androidaps.interfaces.Config +import info.nightscout.androidaps.interfaces.IconsProvider import info.nightscout.androidaps.interfaces.PluginType import info.nightscout.androidaps.logging.AAPSLogger import info.nightscout.androidaps.logging.LTag +import info.nightscout.androidaps.logging.UserEntryLogger import info.nightscout.androidaps.plugins.aps.loop.LoopPlugin import info.nightscout.androidaps.plugins.bus.RxBusWrapper import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker @@ -56,7 +61,6 @@ import info.nightscout.androidaps.utils.buildHelper.BuildHelper import info.nightscout.androidaps.utils.extensions.isRunningRealPumpTest import info.nightscout.androidaps.utils.locale.LocaleHelper import info.nightscout.androidaps.utils.protection.ProtectionCheck -import info.nightscout.androidaps.utils.resources.IconsProvider import info.nightscout.androidaps.utils.rx.AapsSchedulers import info.nightscout.androidaps.utils.sharedPreferences.SP import info.nightscout.androidaps.utils.tabs.TabPageAdapter @@ -80,13 +84,14 @@ class MainActivity : NoSplashAppCompatActivity() { @Inject lateinit var loopPlugin: LoopPlugin @Inject lateinit var nsSettingsStatus: NSSettingsStatus @Inject lateinit var buildHelper: BuildHelper - @Inject lateinit var activePlugin: ActivePluginProvider + @Inject lateinit var activePlugin: ActivePlugin @Inject lateinit var fabricPrivacy: FabricPrivacy @Inject lateinit var protectionCheck: ProtectionCheck @Inject lateinit var iconsProvider: IconsProvider @Inject lateinit var constraintChecker: ConstraintChecker @Inject lateinit var signatureVerifierPlugin: SignatureVerifierPlugin @Inject lateinit var config: Config + @Inject lateinit var uel: UserEntryLogger private lateinit var actionBarDrawerToggle: ActionBarDrawerToggle private var pluginPreferencesMenuItem: MenuItem? = null @@ -316,6 +321,7 @@ class MainActivity : NoSplashAppCompatActivity() { R.id.nav_exit -> { aapsLogger.debug(LTag.CORE, "Exiting") + uel.log(Action.EXIT_AAPS, Sources.Aaps) rxBus.send(EventAppExit()) finish() System.runFinalization() @@ -375,7 +381,7 @@ class MainActivity : NoSplashAppCompatActivity() { if (!config.NSCLIENT && !config.PUMPCONTROL) activePlugin.activeAPS.let { fabricPrivacy.firebaseAnalytics.setUserProperty("Aps", it::class.java.simpleName) } activePlugin.activeBgSource.let { fabricPrivacy.firebaseAnalytics.setUserProperty("BgSource", it::class.java.simpleName) } - fabricPrivacy.firebaseAnalytics.setUserProperty("Profile", activePlugin.activeProfileInterface.javaClass.simpleName) + fabricPrivacy.firebaseAnalytics.setUserProperty("Profile", activePlugin.activeProfileSource.javaClass.simpleName) activePlugin.activeSensitivity.let { fabricPrivacy.firebaseAnalytics.setUserProperty("Sensitivity", it::class.java.simpleName) } activePlugin.activeInsulin.let { fabricPrivacy.firebaseAnalytics.setUserProperty("Insulin", it::class.java.simpleName) } // Add to crash log too diff --git a/app/src/main/java/info/nightscout/androidaps/MainApp.kt b/app/src/main/java/info/nightscout/androidaps/MainApp.kt index 4851452333..9731bf37d6 100644 --- a/app/src/main/java/info/nightscout/androidaps/MainApp.kt +++ b/app/src/main/java/info/nightscout/androidaps/MainApp.kt @@ -5,31 +5,38 @@ import android.content.Intent import android.content.IntentFilter import android.net.ConnectivityManager import android.net.wifi.WifiManager +import android.os.Build import com.j256.ormlite.android.apptools.OpenHelperManager import dagger.android.AndroidInjector import dagger.android.DaggerApplication import info.nightscout.androidaps.database.AppRepository +import info.nightscout.androidaps.database.entities.TherapyEvent +import info.nightscout.androidaps.database.entities.UserEntry +import info.nightscout.androidaps.database.transactions.InsertIfNewByTimestampTherapyEventTransaction import info.nightscout.androidaps.database.transactions.VersionChangeTransaction import info.nightscout.androidaps.db.CompatDBHelper import info.nightscout.androidaps.db.DatabaseHelper import info.nightscout.androidaps.db.StaticInjector import info.nightscout.androidaps.dependencyInjection.DaggerAppComponent +import info.nightscout.androidaps.interfaces.ConfigBuilder +import info.nightscout.androidaps.interfaces.Config import info.nightscout.androidaps.interfaces.PluginBase import info.nightscout.androidaps.logging.AAPSLogger import info.nightscout.androidaps.logging.LTag -import info.nightscout.androidaps.plugins.configBuilder.ConfigBuilderPlugin +import info.nightscout.androidaps.logging.UserEntryLogger import info.nightscout.androidaps.plugins.configBuilder.PluginStore import info.nightscout.androidaps.plugins.constraints.versionChecker.VersionCheckerUtils -import info.nightscout.androidaps.plugins.general.nsclient.NSUpload import info.nightscout.androidaps.receivers.BTReceiver import info.nightscout.androidaps.receivers.ChargingStateReceiver import info.nightscout.androidaps.receivers.KeepAliveReceiver.KeepAliveManager import info.nightscout.androidaps.receivers.NetworkChangeReceiver import info.nightscout.androidaps.receivers.TimeDateOrTZChangeReceiver import info.nightscout.androidaps.utils.ActivityMonitor +import info.nightscout.androidaps.utils.DateUtil import info.nightscout.androidaps.utils.locale.LocaleHelper.update import info.nightscout.androidaps.utils.sharedPreferences.SP import io.reactivex.disposables.CompositeDisposable +import io.reactivex.rxkotlin.plusAssign import net.danlew.android.joda.JodaTimeAndroid import javax.inject.Inject @@ -42,14 +49,15 @@ class MainApp : DaggerApplication() { @Inject lateinit var activityMonitor: ActivityMonitor @Inject lateinit var versionCheckersUtils: VersionCheckerUtils @Inject lateinit var sp: SP - @Inject lateinit var nsUpload: NSUpload @Inject lateinit var config: Config - @Inject lateinit var configBuilderPlugin: ConfigBuilderPlugin + @Inject lateinit var configBuilder: ConfigBuilder @Inject lateinit var keepAliveManager: KeepAliveManager @Inject lateinit var plugins: List<@JvmSuppressWildcards PluginBase> @Inject lateinit var compatDBHelper: CompatDBHelper @Inject lateinit var repository: AppRepository + @Inject lateinit var dateUtil: DateUtil @Inject lateinit var staticInjector: StaticInjector// TODO avoid , here fake only to initialize + @Inject lateinit var uel: UserEntryLogger override fun onCreate() { super.onCreate() @@ -63,8 +71,9 @@ class MainApp : DaggerApplication() { gitRemote = null commitHash = null } - disposable.add(repository.runTransaction(VersionChangeTransaction(BuildConfig.VERSION_NAME, BuildConfig.VERSION_CODE, gitRemote, commitHash)).subscribe()) - disposable.add(compatDBHelper.dbChangeDisposable()) + disposable += repository.runTransaction(VersionChangeTransaction(BuildConfig.VERSION_NAME, BuildConfig.VERSION_CODE, gitRemote, commitHash)).subscribe() + disposable += repository.runTransaction(InsertIfNewByTimestampTherapyEventTransaction(timestamp = dateUtil.now(), type = TherapyEvent.Type.NOTE, note = getString(info.nightscout.androidaps.core.R.string.androidaps_start).toString() + " - " + Build.MANUFACTURER + " " + Build.MODEL, glucoseUnit = TherapyEvent.GlucoseUnit.MGDL)).subscribe() + disposable += compatDBHelper.dbChangeDisposable() registerActivityLifecycleCallbacks(activityMonitor) JodaTimeAndroid.init(this) aapsLogger.debug("Version: " + BuildConfig.VERSION_NAME) @@ -77,10 +86,10 @@ class MainApp : DaggerApplication() { // Register all tabs in app here pluginStore.plugins = plugins - configBuilderPlugin.initialize() - nsUpload.uploadAppStart() - Thread { keepAliveManager.setAlarm(this) }.start() + configBuilder.initialize() + keepAliveManager.setAlarm(this) doMigrations() + uel.log(UserEntry.Action.START_AAPS, UserEntry.Sources.Aaps) } private fun doMigrations() { diff --git a/app/src/main/java/info/nightscout/androidaps/activities/MyPreferenceFragment.kt b/app/src/main/java/info/nightscout/androidaps/activities/MyPreferenceFragment.kt index aed679673b..8b1ad36b9d 100644 --- a/app/src/main/java/info/nightscout/androidaps/activities/MyPreferenceFragment.kt +++ b/app/src/main/java/info/nightscout/androidaps/activities/MyPreferenceFragment.kt @@ -8,7 +8,7 @@ import android.os.Bundle import androidx.annotation.XmlRes import androidx.preference.* import dagger.android.support.AndroidSupportInjection -import info.nightscout.androidaps.Config +import info.nightscout.androidaps.interfaces.Config import info.nightscout.androidaps.R import info.nightscout.androidaps.danaRKorean.DanaRKoreanPlugin import info.nightscout.androidaps.danaRv2.DanaRv2Plugin diff --git a/app/src/main/java/info/nightscout/androidaps/activities/ProfileHelperActivity.kt b/app/src/main/java/info/nightscout/androidaps/activities/ProfileHelperActivity.kt index 34978739b6..7ba6fc505f 100644 --- a/app/src/main/java/info/nightscout/androidaps/activities/ProfileHelperActivity.kt +++ b/app/src/main/java/info/nightscout/androidaps/activities/ProfileHelperActivity.kt @@ -13,7 +13,7 @@ import info.nightscout.androidaps.data.defaultProfile.DefaultProfileDPV import info.nightscout.androidaps.databinding.ActivityProfilehelperBinding import info.nightscout.androidaps.db.ProfileSwitch import info.nightscout.androidaps.dialogs.ProfileViewerDialog -import info.nightscout.androidaps.interfaces.ActivePluginProvider +import info.nightscout.androidaps.interfaces.ActivePlugin import info.nightscout.androidaps.interfaces.DatabaseHelperInterface import info.nightscout.androidaps.interfaces.ProfileFunction import info.nightscout.androidaps.logging.AAPSLogger @@ -24,7 +24,7 @@ import info.nightscout.androidaps.utils.DateUtil import info.nightscout.androidaps.utils.T import info.nightscout.androidaps.utils.ToastUtils import info.nightscout.androidaps.utils.alertDialogs.OKDialog -import info.nightscout.androidaps.utils.extensions.toVisibility +import info.nightscout.androidaps.extensions.toVisibility import info.nightscout.androidaps.utils.stats.TddCalculator import java.text.DecimalFormat import javax.inject.Inject @@ -39,7 +39,7 @@ class ProfileHelperActivity : NoSplashAppCompatActivity() { @Inject lateinit var localProfilePlugin: LocalProfilePlugin @Inject lateinit var rxBus: RxBusWrapper @Inject lateinit var dateUtil: DateUtil - @Inject lateinit var activePlugin: ActivePluginProvider + @Inject lateinit var activePlugin: ActivePlugin @Inject lateinit var databaseHelper: DatabaseHelperInterface enum class ProfileType { @@ -98,7 +98,7 @@ class ProfileHelperActivity : NoSplashAppCompatActivity() { } // Active profile - profileList = activePlugin.activeProfileInterface.profile?.getProfileList() ?: ArrayList() + profileList = activePlugin.activeProfileSource.profile?.getProfileList() ?: ArrayList() binding.availableProfileList.setOnClickListener { PopupMenu(this, binding.availableProfileList).apply { @@ -114,7 +114,7 @@ class ProfileHelperActivity : NoSplashAppCompatActivity() { } // Profile switch - profileSwitch = databaseHelper.getProfileSwitchData(dateUtil._now() - T.months(2).msecs(), true) + profileSwitch = databaseHelper.getProfileSwitchData(dateUtil.now() - T.months(2).msecs(), true) binding.profileswitchList.setOnClickListener { PopupMenu(this, binding.profileswitchList).apply { @@ -141,7 +141,7 @@ class ProfileHelperActivity : NoSplashAppCompatActivity() { profile?.let { OKDialog.showConfirmation(this, resourceHelper.gs(R.string.careportal_profileswitch), resourceHelper.gs(R.string.copytolocalprofile), Runnable { localProfilePlugin.addProfile(localProfilePlugin.copyFrom(it, "DefaultProfile " + - dateUtil.dateAndTimeAndSecondsString(dateUtil._now()) + dateUtil.dateAndTimeAndSecondsString(dateUtil.now()) .replace(".", "/") )) rxBus.send(EventLocalProfileChanged()) @@ -210,7 +210,7 @@ class ProfileHelperActivity : NoSplashAppCompatActivity() { getProfile(ageUsed[1], tddUsed[1], weightUsed[1], pctUsed[1] / 100.0, 1)?.let { profile1 -> ProfileViewerDialog().also { pvd -> pvd.arguments = Bundle().also { - it.putLong("time", DateUtil.now()) + it.putLong("time", dateUtil.now()) it.putInt("mode", ProfileViewerDialog.Mode.PROFILE_COMPARE.ordinal) it.putString("customProfile", profile0.data.toString()) it.putString("customProfile2", profile1.data.toString()) @@ -233,7 +233,7 @@ class ProfileHelperActivity : NoSplashAppCompatActivity() { ProfileType.MOTOL_DEFAULT -> defaultProfile.profile(age, tdd, weight, profileFunction.getUnits()) ProfileType.DPV_DEFAULT -> defaultProfileDPV.profile(age, tdd, basalPct, profileFunction.getUnits()) ProfileType.CURRENT -> profileFunction.getProfile()?.convertToNonCustomizedProfile() - ProfileType.AVAILABLE_PROFILE -> activePlugin.activeProfileInterface.profile?.getSpecificProfile(profileList[profileUsed[tab]].toString()) + ProfileType.AVAILABLE_PROFILE -> activePlugin.activeProfileSource.profile?.getSpecificProfile(profileList[profileUsed[tab]].toString()) ProfileType.PROFILE_SWITCH -> profileSwitch[profileSwitchUsed[tab]].profileObject?.convertToNonCustomizedProfile() } } catch (e: Exception) { diff --git a/app/src/main/java/info/nightscout/androidaps/activities/StatsActivity.kt b/app/src/main/java/info/nightscout/androidaps/activities/StatsActivity.kt index 896506b93f..8edeccfebd 100644 --- a/app/src/main/java/info/nightscout/androidaps/activities/StatsActivity.kt +++ b/app/src/main/java/info/nightscout/androidaps/activities/StatsActivity.kt @@ -2,7 +2,8 @@ package info.nightscout.androidaps.activities import android.os.Bundle import info.nightscout.androidaps.R -import info.nightscout.androidaps.database.entities.UserEntry.* +import info.nightscout.androidaps.database.entities.UserEntry.Action +import info.nightscout.androidaps.database.entities.UserEntry.Sources import info.nightscout.androidaps.databinding.ActivityStatsBinding import info.nightscout.androidaps.logging.UserEntryLogger import info.nightscout.androidaps.utils.ActivityMonitor @@ -32,7 +33,7 @@ class StatsActivity : NoSplashAppCompatActivity() { binding.ok.setOnClickListener { finish() } binding.reset.setOnClickListener { OKDialog.showConfirmation(this, resourceHelper.gs(R.string.doyouwantresetstats)) { - uel.log(Action.STAT_RESET) + uel.log(Action.STAT_RESET, Sources.Stats) activityMonitor.reset() recreate() } diff --git a/app/src/main/java/info/nightscout/androidaps/activities/SurveyActivity.kt b/app/src/main/java/info/nightscout/androidaps/activities/SurveyActivity.kt index 5286afc33d..88477fd19f 100644 --- a/app/src/main/java/info/nightscout/androidaps/activities/SurveyActivity.kt +++ b/app/src/main/java/info/nightscout/androidaps/activities/SurveyActivity.kt @@ -8,7 +8,7 @@ import info.nightscout.androidaps.R import info.nightscout.androidaps.data.defaultProfile.DefaultProfile import info.nightscout.androidaps.databinding.ActivitySurveyBinding import info.nightscout.androidaps.dialogs.ProfileViewerDialog -import info.nightscout.androidaps.interfaces.ActivePluginProvider +import info.nightscout.androidaps.interfaces.ActivePlugin import info.nightscout.androidaps.interfaces.ProfileFunction import info.nightscout.androidaps.logging.AAPSLogger import info.nightscout.androidaps.logging.LTag @@ -24,12 +24,13 @@ import javax.inject.Inject class SurveyActivity : NoSplashAppCompatActivity() { @Inject lateinit var aapsLogger: AAPSLogger - @Inject lateinit var activePlugin: ActivePluginProvider + @Inject lateinit var activePlugin: ActivePlugin @Inject lateinit var tddCalculator: TddCalculator @Inject lateinit var tirCalculator: TirCalculator @Inject lateinit var profileFunction: ProfileFunction @Inject lateinit var activityMonitor: ActivityMonitor @Inject lateinit var defaultProfile: DefaultProfile + @Inject lateinit var dateUtil: DateUtil private lateinit var binding: ActivitySurveyBinding @@ -40,7 +41,7 @@ class SurveyActivity : NoSplashAppCompatActivity() { binding.id.text = InstanceId.instanceId() - val profileStore = activePlugin.activeProfileInterface.profile + val profileStore = activePlugin.activeProfileSource.profile val profileList = profileStore?.getProfileList() ?: return binding.spinner.adapter = ArrayAdapter(this, R.layout.spinner_centered, profileList) @@ -68,7 +69,7 @@ class SurveyActivity : NoSplashAppCompatActivity() { defaultProfile.profile(age, tdd, weight, profileFunction.getUnits())?.let { profile -> ProfileViewerDialog().also { pvd -> pvd.arguments = Bundle().also { - it.putLong("time", DateUtil.now()) + it.putLong("time", dateUtil.now()) it.putInt("mode", ProfileViewerDialog.Mode.PROFILE_COMPARE.ordinal) it.putString("customProfile", runningProfile.data.toString()) it.putString("customProfile2", profile.data.toString()) diff --git a/core/src/main/java/info/nightscout/androidaps/data/defaultProfile/DefaultProfile.kt b/app/src/main/java/info/nightscout/androidaps/data/defaultProfile/DefaultProfile.kt similarity index 100% rename from core/src/main/java/info/nightscout/androidaps/data/defaultProfile/DefaultProfile.kt rename to app/src/main/java/info/nightscout/androidaps/data/defaultProfile/DefaultProfile.kt diff --git a/core/src/main/java/info/nightscout/androidaps/data/defaultProfile/DefaultProfileDPV.kt b/app/src/main/java/info/nightscout/androidaps/data/defaultProfile/DefaultProfileDPV.kt similarity index 100% rename from core/src/main/java/info/nightscout/androidaps/data/defaultProfile/DefaultProfileDPV.kt rename to app/src/main/java/info/nightscout/androidaps/data/defaultProfile/DefaultProfileDPV.kt diff --git a/app/src/main/java/info/nightscout/androidaps/db/CompatDBHelper.kt b/app/src/main/java/info/nightscout/androidaps/db/CompatDBHelper.kt index aef3c28a3b..6bf2763978 100644 --- a/app/src/main/java/info/nightscout/androidaps/db/CompatDBHelper.kt +++ b/app/src/main/java/info/nightscout/androidaps/db/CompatDBHelper.kt @@ -1,14 +1,10 @@ package info.nightscout.androidaps.db import info.nightscout.androidaps.database.AppRepository -import info.nightscout.androidaps.database.entities.Food -import info.nightscout.androidaps.database.entities.GlucoseValue -import info.nightscout.androidaps.database.entities.TemporaryTarget -import info.nightscout.androidaps.database.entities.TherapyEvent -import info.nightscout.androidaps.events.EventFoodDatabaseChanged -import info.nightscout.androidaps.events.EventNewBG -import info.nightscout.androidaps.events.EventTempTargetChange -import info.nightscout.androidaps.events.EventTherapyEventChange +import info.nightscout.androidaps.database.entities.* +import info.nightscout.androidaps.database.entities.ExtendedBolus +import info.nightscout.androidaps.database.entities.TemporaryBasal +import info.nightscout.androidaps.events.* import info.nightscout.androidaps.logging.AAPSLogger import info.nightscout.androidaps.logging.LTag import info.nightscout.androidaps.plugins.bus.RxBusWrapper @@ -30,13 +26,41 @@ class CompatDBHelper @Inject constructor( rxBus.send(EventNewBG(null)) } .subscribe { - it.filterIsInstance().firstOrNull()?.let { - aapsLogger.debug(LTag.DATABASE, "Firing EventNewHistoryData") - rxBus.send(EventNewHistoryData(it.timestamp)) - } - it.filterIsInstance().lastOrNull()?.let { + /** + * GlucoseValues can come in batch + * oldest one should be used for invalidation, newest one for for triggering Loop. + * Thus we need to collect both + * + */ + var newestGlucoseValue : GlucoseValue? = null + it.filterIsInstance().lastOrNull()?.let { gv -> aapsLogger.debug(LTag.DATABASE, "Firing EventNewBg") - rxBus.send(EventNewBG(it)) + rxBus.send(EventNewBG(gv)) + newestGlucoseValue = gv + } + it.filterIsInstance().map { gv -> gv.timestamp }.minOrNull()?.let { timestamp -> + aapsLogger.debug(LTag.DATABASE, "Firing EventNewHistoryData") + rxBus.send(EventNewHistoryData(timestamp, true, newestGlucoseValue)) + } + it.filterIsInstance().map { t -> t.timestamp }.minOrNull()?.let { timestamp -> + aapsLogger.debug(LTag.DATABASE, "Firing EventTreatmentChange") + rxBus.send(EventTreatmentChange()) + rxBus.send(EventNewHistoryData(timestamp, false)) + } + it.filterIsInstance().map { t -> t.timestamp }.minOrNull()?.let { timestamp -> + aapsLogger.debug(LTag.DATABASE, "Firing EventTreatmentChange") + rxBus.send(EventTreatmentChange()) + rxBus.send(EventNewHistoryData(timestamp, false)) + } + it.filterIsInstance().map { t -> t.timestamp }.minOrNull()?.let { timestamp -> + aapsLogger.debug(LTag.DATABASE, "Firing EventTempBasalChange") + rxBus.send(EventTempBasalChange()) + rxBus.send(EventNewHistoryData(timestamp, false)) + } + it.filterIsInstance().map { t -> t.timestamp }.minOrNull()?.let { timestamp -> + aapsLogger.debug(LTag.DATABASE, "Firing EventExtendedBolusChange") + rxBus.send(EventExtendedBolusChange()) + rxBus.send(EventNewHistoryData(timestamp, false)) } it.filterIsInstance().firstOrNull()?.let { aapsLogger.debug(LTag.DATABASE, "Firing EventTempTargetChange") diff --git a/app/src/main/java/info/nightscout/androidaps/db/DatabaseHelper.java b/app/src/main/java/info/nightscout/androidaps/db/DatabaseHelper.java index 3e4f21c330..2aaec095a0 100644 --- a/app/src/main/java/info/nightscout/androidaps/db/DatabaseHelper.java +++ b/app/src/main/java/info/nightscout/androidaps/db/DatabaseHelper.java @@ -34,24 +34,20 @@ import javax.inject.Inject; import info.nightscout.androidaps.dana.comm.RecordTypes; import info.nightscout.androidaps.data.Profile; -import info.nightscout.androidaps.events.EventExtendedBolusChange; import info.nightscout.androidaps.events.EventProfileNeedsUpdate; import info.nightscout.androidaps.events.EventRefreshOverview; import info.nightscout.androidaps.events.EventReloadProfileSwitchData; -import info.nightscout.androidaps.events.EventReloadTempBasalData; -import info.nightscout.androidaps.events.EventReloadTreatmentData; -import info.nightscout.androidaps.events.EventTempBasalChange; -import info.nightscout.androidaps.interfaces.ActivePluginProvider; +import info.nightscout.androidaps.interfaces.ActivePlugin; import info.nightscout.androidaps.interfaces.DatabaseHelperInterface; -import info.nightscout.androidaps.interfaces.ProfileInterface; +import info.nightscout.androidaps.interfaces.ProfileSource; import info.nightscout.androidaps.interfaces.ProfileStore; import info.nightscout.androidaps.logging.AAPSLogger; import info.nightscout.androidaps.logging.LTag; import info.nightscout.androidaps.plugins.bus.RxBusWrapper; import info.nightscout.androidaps.plugins.general.nsclient.NSUpload; import info.nightscout.androidaps.plugins.general.openhumans.OpenHumansUploader; -import info.nightscout.androidaps.plugins.iob.iobCobCalculator.events.EventNewHistoryData; import info.nightscout.androidaps.plugins.pump.virtual.VirtualPumpPlugin; +import info.nightscout.androidaps.utils.DateUtil; import info.nightscout.androidaps.utils.PercentageSplitter; /** @@ -67,25 +63,18 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper { @Inject RxBusWrapper rxBus; @Inject VirtualPumpPlugin virtualPumpPlugin; @Inject OpenHumansUploader openHumansUploader; - @Inject ActivePluginProvider activePlugin; + @Inject ActivePlugin activePlugin; @Inject NSUpload nsUpload; + @Inject DateUtil dateUtil; public static final String DATABASE_NAME = "AndroidAPSDb"; - public static final String DATABASE_EXTENDEDBOLUSES = "ExtendedBoluses"; public static final String DATABASE_DANARHISTORY = "DanaRHistory"; public static final String DATABASE_DBREQUESTS = "DBRequests"; - public static final String DATABASE_TDDS = "TDDs"; private static final int DATABASE_VERSION = 13; public static Long earliestDataChange = null; - private static final ScheduledExecutorService tempBasalsWorker = Executors.newSingleThreadScheduledExecutor(); - private static ScheduledFuture scheduledTemBasalsPost = null; - - private static final ScheduledExecutorService extendedBolusWorker = Executors.newSingleThreadScheduledExecutor(); - private static ScheduledFuture scheduledExtendedBolusPost = null; - private static final ScheduledExecutorService profileSwitchEventWorker = Executors.newSingleThreadScheduledExecutor(); private static ScheduledFuture scheduledProfileSwitchEventPost = null; @@ -198,8 +187,6 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper { aapsLogger.error("Unhandled exception", e); } virtualPumpPlugin.setFakingStatus(true); - scheduleTemporaryBasalChange(); - scheduleExtendedBolusChange(); scheduleProfileSwitchChange(); new java.util.Timer().schedule( new java.util.TimerTask() { @@ -212,29 +199,6 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper { ); } - public void resetTemporaryBasals() { - try { - TableUtils.dropTable(connectionSource, TemporaryBasal.class, true); - TableUtils.createTableIfNotExists(connectionSource, TemporaryBasal.class); - updateEarliestDataChange(0); - } catch (SQLException e) { - aapsLogger.error("Unhandled exception", e); - } - virtualPumpPlugin.setFakingStatus(false); - scheduleTemporaryBasalChange(); - } - - public void resetExtededBoluses() { - try { - TableUtils.dropTable(connectionSource, ExtendedBolus.class, true); - TableUtils.createTableIfNotExists(connectionSource, ExtendedBolus.class); - updateEarliestDataChange(0); - } catch (SQLException e) { - aapsLogger.error("Unhandled exception", e); - } - scheduleExtendedBolusChange(); - } - public void resetProfileSwitch() { try { TableUtils.dropTable(connectionSource, ProfileSwitch.class, true); @@ -507,7 +471,7 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper { openHumansUploader.enqueueTemporaryBasal(old); updateEarliestDataChange(tempBasal.date); - scheduleTemporaryBasalChange(); +// scheduleTemporaryBasalChange(); return false; } @@ -516,7 +480,7 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper { openHumansUploader.enqueueTemporaryBasal(tempBasal); aapsLogger.debug(LTag.DATABASE, "TEMPBASAL: New record from: " + Source.getString(tempBasal.source) + " " + tempBasal.toString()); updateEarliestDataChange(tempBasal.date); - scheduleTemporaryBasalChange(); +// scheduleTemporaryBasalChange(); return true; } if (tempBasal.source == Source.NIGHTSCOUT) { @@ -535,7 +499,7 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper { aapsLogger.debug(LTag.DATABASE, "TEMPBASAL: Updating record by date from: " + Source.getString(tempBasal.source) + " " + old.toString()); updateEarliestDataChange(oldDate); updateEarliestDataChange(old.date); - scheduleTemporaryBasalChange(); +// scheduleTemporaryBasalChange(); return true; } return false; @@ -558,7 +522,7 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper { aapsLogger.debug(LTag.DATABASE, "TEMPBASAL: Updating record by _id from: " + Source.getString(tempBasal.source) + " " + old.toString()); updateEarliestDataChange(oldDate); updateEarliestDataChange(old.date); - scheduleTemporaryBasalChange(); +// scheduleTemporaryBasalChange(); return true; } } @@ -567,7 +531,7 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper { openHumansUploader.enqueueTemporaryBasal(tempBasal); aapsLogger.debug(LTag.DATABASE, "TEMPBASAL: New record from: " + Source.getString(tempBasal.source) + " " + tempBasal.toString()); updateEarliestDataChange(tempBasal.date); - scheduleTemporaryBasalChange(); +// scheduleTemporaryBasalChange(); return true; } if (tempBasal.source == Source.USER) { @@ -575,7 +539,7 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper { openHumansUploader.enqueueTemporaryBasal(tempBasal); aapsLogger.debug(LTag.DATABASE, "TEMPBASAL: New record from: " + Source.getString(tempBasal.source) + " " + tempBasal.toString()); updateEarliestDataChange(tempBasal.date); - scheduleTemporaryBasalChange(); +// scheduleTemporaryBasalChange(); return true; } } catch (SQLException e) { @@ -592,16 +556,7 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper { } catch (SQLException e) { aapsLogger.error("Unhandled exception", e); } - scheduleTemporaryBasalChange(); - } - - public List getAllTemporaryBasals() { - try { - return getDaoTemporaryBasal().queryForAll(); - } catch (SQLException e) { - aapsLogger.error("Unhandled exception", e); - } - return Collections.emptyList(); +// scheduleTemporaryBasalChange(); } public List getTemporaryBasalsDataFromTime(long mills, boolean ascending) { @@ -620,44 +575,6 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper { return new ArrayList(); } - public List getTemporaryBasalsDataFromTime(long from, long to, boolean ascending) { - try { - List tempbasals; - QueryBuilder queryBuilder = getDaoTemporaryBasal().queryBuilder(); - queryBuilder.orderBy("date", ascending); - Where where = queryBuilder.where(); - where.between("date", from, to); - PreparedQuery preparedQuery = queryBuilder.prepare(); - tempbasals = getDaoTemporaryBasal().query(preparedQuery); - return tempbasals; - } catch (SQLException e) { - aapsLogger.error("Unhandled exception", e); - } - return new ArrayList(); - } - - private void scheduleTemporaryBasalChange() { - class PostRunnable implements Runnable { - public void run() { - aapsLogger.debug(LTag.DATABASE, "Firing EventTempBasalChange"); - rxBus.send(new EventReloadTempBasalData()); - rxBus.send(new EventTempBasalChange()); - if (earliestDataChange != null) - rxBus.send(new EventNewHistoryData(earliestDataChange)); - earliestDataChange = null; - scheduledTemBasalsPost = null; - } - } - // prepare task for execution in 1 sec - // cancel waiting task to prevent sending multiple posts - if (scheduledTemBasalsPost != null) - scheduledTemBasalsPost.cancel(false); - Runnable task = new PostRunnable(); - final int sec = 1; - scheduledTemBasalsPost = tempBasalsWorker.schedule(task, sec, TimeUnit.SECONDS); - - } - /* { "_id": "59232e1ddd032d04218dab00", @@ -674,93 +591,6 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper { } */ - public void createTempBasalFromJsonIfNotExists(JSONObject trJson) { - try { - if (trJson.has("originalExtendedAmount")) { // extended bolus uploaded as temp basal - ExtendedBolus extendedBolus = new ExtendedBolus(StaticInjector.Companion.getInstance()) - .source(Source.NIGHTSCOUT) - .date(trJson.getLong("mills")) - .pumpId(trJson.has("pumpId") ? trJson.getLong("pumpId") : 0) - .durationInMinutes(trJson.getInt("duration")) - .insulin(trJson.getDouble("originalExtendedAmount")) - ._id(trJson.getString("_id")); - // if faking found in NS, adapt AAPS to use it too - if (!virtualPumpPlugin.getFakingStatus()) { - virtualPumpPlugin.setFakingStatus(true); - updateEarliestDataChange(0); - scheduleTemporaryBasalChange(); - } - createOrUpdate(extendedBolus); - } else if (trJson.has("isFakedTempBasal")) { // extended bolus end uploaded as temp basal end - ExtendedBolus extendedBolus = new ExtendedBolus(StaticInjector.Companion.getInstance()); - extendedBolus.source = Source.NIGHTSCOUT; - extendedBolus.date = trJson.getLong("mills"); - extendedBolus.pumpId = trJson.has("pumpId") ? trJson.getLong("pumpId") : 0; - extendedBolus.durationInMinutes = 0; - extendedBolus.insulin = 0; - extendedBolus._id = trJson.getString("_id"); - // if faking found in NS, adapt AAPS to use it too - if (!virtualPumpPlugin.getFakingStatus()) { - virtualPumpPlugin.setFakingStatus(true); - updateEarliestDataChange(0); - scheduleTemporaryBasalChange(); - } - createOrUpdate(extendedBolus); - } else { - TemporaryBasal tempBasal = new TemporaryBasal(StaticInjector.Companion.getInstance()) - .date(trJson.getLong("mills")) - .source(Source.NIGHTSCOUT) - .pumpId(trJson.has("pumpId") ? trJson.getLong("pumpId") : 0); - if (trJson.has("duration")) { - tempBasal.durationInMinutes = trJson.getInt("duration"); - } - if (trJson.has("percent")) { - tempBasal.percentRate = trJson.getInt("percent") + 100; - tempBasal.isAbsolute = false; - } - if (trJson.has("absolute")) { - tempBasal.absoluteRate = trJson.getDouble("absolute"); - tempBasal.isAbsolute = true; - } - tempBasal._id = trJson.getString("_id"); - createOrUpdate(tempBasal); - } - } catch (JSONException e) { - aapsLogger.error("Unhandled exception: " + trJson.toString(), e); - } - } - - public void deleteTempBasalById(String _id) { - TemporaryBasal stored = findTempBasalById(_id); - if (stored != null) { - aapsLogger.debug(LTag.DATABASE, "TEMPBASAL: Removing TempBasal record from database: " + stored.toString()); - delete(stored); - updateEarliestDataChange(stored.date); - scheduleTemporaryBasalChange(); - } - } - - public TemporaryBasal findTempBasalById(String _id) { - try { - QueryBuilder queryBuilder = null; - queryBuilder = getDaoTemporaryBasal().queryBuilder(); - Where where = queryBuilder.where(); - where.eq("_id", _id); - PreparedQuery preparedQuery = queryBuilder.prepare(); - List list = getDaoTemporaryBasal().query(preparedQuery); - - if (list.size() != 1) { - return null; - } else { - return list.get(0); - } - } catch (SQLException e) { - aapsLogger.error("Unhandled exception", e); - } - return null; - } - - public TemporaryBasal findTempBasalByPumpId(Long pumpId) { try { QueryBuilder queryBuilder = null; @@ -785,109 +615,6 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper { // ------------ ExtendedBolus handling --------------- - public boolean createOrUpdate(ExtendedBolus extendedBolus) { - try { - aapsLogger.debug(LTag.DATABASE, "EXTENDEDBOLUS: createOrUpdate: " + Source.getString(extendedBolus.source) + " " + extendedBolus.log()); - - ExtendedBolus old; - extendedBolus.date = roundDateToSec(extendedBolus.date); - - if (extendedBolus.source == Source.PUMP) { - // if pumpId == 0 do not check for existing pumpId - // used with pumps without history - // and insight where record as added first without pumpId - // and then is record updated with pumpId - if (extendedBolus.pumpId == 0) { - getDaoExtendedBolus().createOrUpdate(extendedBolus); - openHumansUploader.enqueueExtendedBolus(extendedBolus); - } else { - QueryBuilder queryBuilder = getDaoExtendedBolus().queryBuilder(); - Where where = queryBuilder.where(); - where.eq("pumpId", extendedBolus.pumpId); - PreparedQuery preparedQuery = queryBuilder.prepare(); - List trList = getDaoExtendedBolus().query(preparedQuery); - if (trList.size() > 1) { - aapsLogger.error("EXTENDEDBOLUS: Multiple records found for pumpId: " + extendedBolus.pumpId); - return false; - } - getDaoExtendedBolus().createOrUpdate(extendedBolus); - openHumansUploader.enqueueExtendedBolus(extendedBolus); - } - aapsLogger.debug(LTag.DATABASE, "EXTENDEDBOLUS: New record from: " + Source.getString(extendedBolus.source) + " " + extendedBolus.log()); - updateEarliestDataChange(extendedBolus.date); - scheduleExtendedBolusChange(); - return true; - } - if (extendedBolus.source == Source.NIGHTSCOUT) { - old = getDaoExtendedBolus().queryForId(extendedBolus.date); - if (old != null) { - if (!old.isEqual(extendedBolus)) { - long oldDate = old.date; - getDaoExtendedBolus().delete(old); // need to delete/create because date may change too - old.copyFrom(extendedBolus); - getDaoExtendedBolus().create(old); - aapsLogger.debug(LTag.DATABASE, "EXTENDEDBOLUS: Updating record by date from: " + Source.getString(extendedBolus.source) + " " + old.log()); - openHumansUploader.enqueueExtendedBolus(old); - updateEarliestDataChange(oldDate); - updateEarliestDataChange(old.date); - scheduleExtendedBolusChange(); - return true; - } - return false; - } - // find by NS _id - if (extendedBolus._id != null) { - QueryBuilder queryBuilder = getDaoExtendedBolus().queryBuilder(); - Where where = queryBuilder.where(); - where.eq("_id", extendedBolus._id); - PreparedQuery preparedQuery = queryBuilder.prepare(); - List trList = getDaoExtendedBolus().query(preparedQuery); - if (trList.size() > 0) { - old = trList.get(0); - if (!old.isEqual(extendedBolus)) { - long oldDate = old.date; - getDaoExtendedBolus().delete(old); // need to delete/create because date may change too - old.copyFrom(extendedBolus); - getDaoExtendedBolus().create(old); - aapsLogger.debug(LTag.DATABASE, "EXTENDEDBOLUS: Updating record by _id from: " + Source.getString(extendedBolus.source) + " " + old.log()); - openHumansUploader.enqueueExtendedBolus(old); - updateEarliestDataChange(oldDate); - updateEarliestDataChange(old.date); - scheduleExtendedBolusChange(); - return true; - } - } - } - getDaoExtendedBolus().create(extendedBolus); - aapsLogger.debug(LTag.DATABASE, "EXTENDEDBOLUS: New record from: " + Source.getString(extendedBolus.source) + " " + extendedBolus.log()); - openHumansUploader.enqueueExtendedBolus(extendedBolus); - updateEarliestDataChange(extendedBolus.date); - scheduleExtendedBolusChange(); - return true; - } - if (extendedBolus.source == Source.USER) { - getDaoExtendedBolus().create(extendedBolus); - aapsLogger.debug(LTag.DATABASE, "EXTENDEDBOLUS: New record from: " + Source.getString(extendedBolus.source) + " " + extendedBolus.log()); - openHumansUploader.enqueueExtendedBolus(extendedBolus); - updateEarliestDataChange(extendedBolus.date); - scheduleExtendedBolusChange(); - return true; - } - } catch (SQLException e) { - aapsLogger.error("Unhandled exception", e); - } - return false; - } - - public List getAllExtendedBoluses() { - try { - return getDaoExtendedBolus().queryForAll(); - } catch (SQLException e) { - aapsLogger.error("Unhandled exception", e); - } - return Collections.emptyList(); - } - public ExtendedBolus getExtendedBolusByPumpId(long pumpId) { try { return getDaoExtendedBolus().queryBuilder() @@ -907,69 +634,7 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper { } catch (SQLException e) { aapsLogger.error("Unhandled exception", e); } - scheduleExtendedBolusChange(); - } - - public List getExtendedBolusDataFromTime(long mills, boolean ascending) { - try { - List extendedBoluses; - QueryBuilder queryBuilder = getDaoExtendedBolus().queryBuilder(); - queryBuilder.orderBy("date", ascending); - Where where = queryBuilder.where(); - where.ge("date", mills); - PreparedQuery preparedQuery = queryBuilder.prepare(); - extendedBoluses = getDaoExtendedBolus().query(preparedQuery); - return extendedBoluses; - } catch (SQLException e) { - aapsLogger.error("Unhandled exception", e); - } - return new ArrayList(); - } - - public List getExtendedBolusDataFromTime(long from, long to, boolean ascending) { - try { - List extendedBoluses; - QueryBuilder queryBuilder = getDaoExtendedBolus().queryBuilder(); - queryBuilder.orderBy("date", ascending); - Where where = queryBuilder.where(); - where.between("date", from, to); - PreparedQuery preparedQuery = queryBuilder.prepare(); - extendedBoluses = getDaoExtendedBolus().query(preparedQuery); - return extendedBoluses; - } catch (SQLException e) { - aapsLogger.error("Unhandled exception", e); - } - return new ArrayList(); - } - - public void deleteExtendedBolusById(String _id) { - ExtendedBolus stored = findExtendedBolusById(_id); - if (stored != null) { - aapsLogger.debug(LTag.DATABASE, "EXTENDEDBOLUS: Removing ExtendedBolus record from database: " + stored.toString()); - delete(stored); - updateEarliestDataChange(stored.date); - scheduleExtendedBolusChange(); - } - } - - public ExtendedBolus findExtendedBolusById(String _id) { - try { - QueryBuilder queryBuilder = null; - queryBuilder = getDaoExtendedBolus().queryBuilder(); - Where where = queryBuilder.where(); - where.eq("_id", _id); - PreparedQuery preparedQuery = queryBuilder.prepare(); - List list = getDaoExtendedBolus().query(preparedQuery); - - if (list.size() == 1) { - return list.get(0); - } else { - return null; - } - } catch (SQLException e) { - aapsLogger.error("Unhandled exception", e); - } - return null; +// scheduleExtendedBolusChange(); } /* @@ -989,33 +654,6 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper { } */ - public void createExtendedBolusFromJsonIfNotExists(JSONObject json) { - ExtendedBolus extendedBolus = ExtendedBolus.createFromJson(StaticInjector.Companion.getInstance(), json); - if (extendedBolus != null) - createOrUpdate(extendedBolus); - } - - private void scheduleExtendedBolusChange() { - class PostRunnable implements Runnable { - public void run() { - aapsLogger.debug(LTag.DATABASE, "Firing EventExtendedBolusChange"); - rxBus.send(new EventReloadTreatmentData(new EventExtendedBolusChange())); - if (earliestDataChange != null) - rxBus.send(new EventNewHistoryData(earliestDataChange)); - earliestDataChange = null; - scheduledExtendedBolusPost = null; - } - } - // prepare task for execution in 1 sec - // cancel waiting task to prevent sending multiple posts - if (scheduledExtendedBolusPost != null) - scheduledExtendedBolusPost.cancel(false); - Runnable task = new PostRunnable(); - final int sec = 1; - scheduledExtendedBolusPost = extendedBolusWorker.schedule(task, sec, TimeUnit.SECONDS); - - } - // ---------------- ProfileSwitch handling --------------- public List getProfileSwitchData(long from, boolean ascending) { @@ -1157,7 +795,7 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper { } } // look for already added percentage from NS - profileSwitch.profileName = PercentageSplitter.pureName(profileSwitch.profileName); + profileSwitch.profileName = PercentageSplitter.INSTANCE.pureName(profileSwitch.profileName); getDaoProfileSwitch().create(profileSwitch); aapsLogger.debug(LTag.DATABASE, "PROFILESWITCH: New record from: " + Source.getString(profileSwitch.source) + " " + profileSwitch.toString()); openHumansUploader.enqueueProfileSwitch(profileSwitch); @@ -1235,15 +873,15 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper { if (trJson.has("profileJson")) profileSwitch.profileJson = trJson.getString("profileJson"); else { - ProfileInterface profileInterface = activePlugin.getActiveProfileInterface(); - ProfileStore store = profileInterface.getProfile(); + ProfileSource profileSource = activePlugin.getActiveProfileSource(); + ProfileStore store = profileSource.getProfile(); if (store != null) { Profile profile = store.getSpecificProfile(profileSwitch.profileName); if (profile != null) { profileSwitch.profileJson = profile.getData().toString(); aapsLogger.debug(LTag.DATABASE, "Profile switch prefilled with JSON from local store"); // Update data in NS - nsUpload.updateProfileSwitch(profileSwitch); + nsUpload.updateProfileSwitch(profileSwitch, dateUtil); } else { aapsLogger.debug(LTag.DATABASE, "JSON for profile switch doesn't exist. Ignoring: " + trJson.toString()); return; diff --git a/app/src/main/java/info/nightscout/androidaps/db/DatabaseHelperProvider.java b/app/src/main/java/info/nightscout/androidaps/db/DatabaseHelperProvider.java index 6587fb6371..bdea090609 100644 --- a/app/src/main/java/info/nightscout/androidaps/db/DatabaseHelperProvider.java +++ b/app/src/main/java/info/nightscout/androidaps/db/DatabaseHelperProvider.java @@ -1,10 +1,10 @@ package info.nightscout.androidaps.db; import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import com.j256.ormlite.dao.CloseableIterator; -import org.jetbrains.annotations.Nullable; import org.json.JSONObject; import java.sql.SQLException; @@ -16,6 +16,7 @@ import javax.inject.Singleton; import info.nightscout.androidaps.MainApp; import info.nightscout.androidaps.interfaces.DatabaseHelperInterface; +@Deprecated @Singleton public class DatabaseHelperProvider implements DatabaseHelperInterface { @@ -78,10 +79,11 @@ public class DatabaseHelperProvider implements DatabaseHelperInterface { return MainApp.Companion.getDbHelper().createOrUpdate(tempBasal); } - @NonNull @Override public TemporaryBasal findTempBasalByPumpId(long id) { + @Nullable @Override public TemporaryBasal findTempBasalByPumpId(long id) { return MainApp.Companion.getDbHelper().findTempBasalByPumpId(id); } + @Deprecated @NonNull @Override public List getTemporaryBasalsDataFromTime(long mills, boolean ascending) { return MainApp.Companion.getDbHelper().getTemporaryBasalsDataFromTime(mills, ascending); } @@ -134,42 +136,14 @@ public class DatabaseHelperProvider implements DatabaseHelperInterface { return MainApp.Companion.getDbHelper().getPumpStoppedEvent(pumpSerial, before); } - @Override public boolean createOrUpdate(@NonNull ExtendedBolus extendedBolus) { - return MainApp.Companion.getDbHelper().createOrUpdate(extendedBolus); - } - @Override public void createOrUpdate(@NonNull ProfileSwitch profileSwitch) { MainApp.Companion.getDbHelper().createOrUpdate(profileSwitch); } - @Override public void delete(@NonNull TemporaryBasal tempBasal) { - MainApp.Companion.getDbHelper().delete(tempBasal); - } - - @NonNull @Override public List getExtendedBolusDataFromTime(long mills, boolean ascending) { - return MainApp.Companion.getDbHelper().getExtendedBolusDataFromTime(mills, ascending); - } - - @Override public void deleteTempBasalById(@NonNull String _id) { - MainApp.Companion.getDbHelper().deleteTempBasalById(_id); - } - - @Override public void deleteExtendedBolusById(@NonNull String _id) { - MainApp.Companion.getDbHelper().deleteExtendedBolusById(_id); - } - @Override public void deleteProfileSwitchById(@NonNull String _id) { MainApp.Companion.getDbHelper().deleteProfileSwitchById(_id); } - @Override public void createTempBasalFromJsonIfNotExists(@NonNull JSONObject json) { - MainApp.Companion.getDbHelper().createTempBasalFromJsonIfNotExists(json); - } - - @Override public void createExtendedBolusFromJsonIfNotExists(@NonNull JSONObject json) { - MainApp.Companion.getDbHelper().createExtendedBolusFromJsonIfNotExists(json); - } - @Override public void createProfileSwitchFromJsonIfNotExists(@NonNull JSONObject trJson) { MainApp.Companion.getDbHelper().createProfileSwitchFromJsonIfNotExists(trJson); } @@ -194,10 +168,6 @@ public class DatabaseHelperProvider implements DatabaseHelperInterface { return MainApp.Companion.getDbHelper().getProfileSwitchEventsFromTime(mills, ascending); } - @NonNull @Override public List getAllExtendedBoluses() { - return MainApp.Companion.getDbHelper().getAllExtendedBoluses(); - } - @NonNull @Override public List getAllProfileSwitches() { return MainApp.Companion.getDbHelper().getAllProfileSwitches(); } @@ -206,10 +176,6 @@ public class DatabaseHelperProvider implements DatabaseHelperInterface { return MainApp.Companion.getDbHelper().getAllTDDs(); } - @NonNull @Override public List getAllTemporaryBasals() { - return MainApp.Companion.getDbHelper().getAllTemporaryBasals(); - } - @NonNull @Override public List getAllOHQueueItems(long maxEntries) { return MainApp.Companion.getDbHelper().getAllOHQueueItems(maxEntries); } diff --git a/app/src/main/java/info/nightscout/androidaps/dependencyInjection/AppModule.kt b/app/src/main/java/info/nightscout/androidaps/dependencyInjection/AppModule.kt index c18c1128a3..740426792c 100644 --- a/app/src/main/java/info/nightscout/androidaps/dependencyInjection/AppModule.kt +++ b/app/src/main/java/info/nightscout/androidaps/dependencyInjection/AppModule.kt @@ -6,7 +6,7 @@ import dagger.Lazy import dagger.Module import dagger.Provides import dagger.android.HasAndroidInjector -import info.nightscout.androidaps.Config +import info.nightscout.androidaps.interfaces.Config import info.nightscout.androidaps.MainApp import info.nightscout.androidaps.db.DatabaseHelperProvider import info.nightscout.androidaps.interfaces.* @@ -15,36 +15,40 @@ import info.nightscout.androidaps.plugins.aps.loop.LoopPlugin import info.nightscout.androidaps.plugins.bus.RxBusWrapper import info.nightscout.androidaps.plugins.configBuilder.ConfigBuilderPlugin import info.nightscout.androidaps.plugins.configBuilder.PluginStore -import info.nightscout.androidaps.plugins.general.maintenance.ImportExportPrefs +import info.nightscout.androidaps.plugins.general.maintenance.ImportExportPrefsImpl +import info.nightscout.androidaps.plugins.general.nsclient.DataSyncSelectorImplementation import info.nightscout.androidaps.plugins.general.nsclient.UploadQueue import info.nightscout.androidaps.plugins.general.smsCommunicator.SmsCommunicatorPlugin import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorPlugin +import info.nightscout.androidaps.plugins.pump.PumpSyncImplementation import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin import info.nightscout.androidaps.queue.CommandQueue -import info.nightscout.androidaps.utils.androidNotification.NotificationHolder -import info.nightscout.androidaps.utils.resources.IconsProvider +import info.nightscout.androidaps.utils.androidNotification.NotificationHolderImpl +import info.nightscout.androidaps.utils.buildHelper.ConfigImpl +import info.nightscout.androidaps.utils.resources.IconsProviderImplementation import info.nightscout.androidaps.utils.rx.AapsSchedulers import info.nightscout.androidaps.utils.rx.DefaultAapsSchedulers import info.nightscout.androidaps.utils.sharedPreferences.SP import info.nightscout.androidaps.utils.storage.FileStorage import info.nightscout.androidaps.utils.storage.Storage import javax.inject.Singleton +@Suppress("unused") @Module(includes = [ AppModule.AppBindings::class ]) open class AppModule { @Provides - fun providesPlugins(configInterface: ConfigInterface, + fun providesPlugins(config: Config, @PluginsModule.AllConfigs allConfigs: Map<@JvmSuppressWildcards Int, @JvmSuppressWildcards PluginBase>, @PluginsModule.PumpDriver pumpDrivers: Lazy>, @PluginsModule.NotNSClient notNsClient: Lazy>, @PluginsModule.APS aps: Lazy>) : List<@JvmSuppressWildcards PluginBase> { val plugins = allConfigs.toMutableMap() - if (configInterface.PUMPDRIVERS) plugins += pumpDrivers.get() - if (configInterface.APS) plugins += aps.get() - if (!configInterface.NSCLIENT) plugins += notNsClient.get() + if (config.PUMPDRIVERS) plugins += pumpDrivers.get() + if (config.APS) plugins += aps.get() + if (!config.NSCLIENT) plugins += notNsClient.get() return plugins.toList().sortedBy { it.first }.map { it.second } } @@ -72,19 +76,22 @@ open class AppModule { interface AppBindings { @Binds fun bindContext(mainApp: MainApp): Context @Binds fun bindInjector(mainApp: MainApp): HasAndroidInjector - @Binds fun bindActivePluginProvider(pluginStore: PluginStore): ActivePluginProvider + @Binds fun bindActivePluginProvider(pluginStore: PluginStore): ActivePlugin @Binds fun bindCommandQueueProvider(commandQueue: CommandQueue): CommandQueueProvider - @Binds fun bindConfigInterface(config: Config): ConfigInterface - @Binds fun bindConfigBuilderInterface(configBuilderPlugin: ConfigBuilderPlugin): ConfigBuilderInterface - @Binds fun bindTreatmentInterface(treatmentsPlugin: TreatmentsPlugin): TreatmentsInterface + @Binds fun bindConfigInterface(config: ConfigImpl): Config + @Binds fun bindConfigBuilderInterface(configBuilderPlugin: ConfigBuilderPlugin): ConfigBuilder + @Binds fun bindTreatmentsInterface(treatmentsPlugin: TreatmentsPlugin): TreatmentsInterface @Binds fun bindDatabaseHelperInterface(databaseHelperProvider: DatabaseHelperProvider): DatabaseHelperInterface - @Binds fun bindNotificationHolderInterface(notificationHolder: NotificationHolder): NotificationHolderInterface - @Binds fun bindImportExportPrefsInterface(importExportPrefs: ImportExportPrefs): ImportExportPrefsInterface - @Binds fun bindIconsProviderInterface(iconsProvider: IconsProvider): IconsProviderInterface + @Binds fun bindNotificationHolderInterface(notificationHolder: NotificationHolderImpl): NotificationHolder + @Binds fun bindImportExportPrefsInterface(importExportPrefs: ImportExportPrefsImpl): ImportExportPrefs + @Binds fun bindIconsProviderInterface(iconsProvider: IconsProviderImplementation): IconsProvider @Binds fun bindLoopInterface(loopPlugin: LoopPlugin): LoopInterface - @Binds fun bindIobCobCalculatorInterface(iobCobCalculatorPlugin: IobCobCalculatorPlugin): IobCobCalculatorInterface - @Binds fun bindSmsCommunicatorInterface(smsCommunicatorPlugin: SmsCommunicatorPlugin): SmsCommunicatorInterface + @Binds fun bindIobCobCalculatorInterface(iobCobCalculatorPlugin: IobCobCalculatorPlugin): IobCobCalculator + @Binds fun bindSmsCommunicatorInterface(smsCommunicatorPlugin: SmsCommunicatorPlugin): SmsCommunicator @Binds fun bindUploadQueueAdminInterfaceToUploadQueue(uploadQueueAdminInterface: UploadQueueAdminInterface) : UploadQueueInterface + @Binds fun bindDataSyncSelector(dataSyncSelectorImplementation: DataSyncSelectorImplementation): DataSyncSelector + @Binds fun bindPumpSync(pumpSyncImplementation: PumpSyncImplementation): PumpSync + } } diff --git a/app/src/main/java/info/nightscout/androidaps/dependencyInjection/DataClassesModule.kt b/app/src/main/java/info/nightscout/androidaps/dependencyInjection/DataClassesModule.kt index de4df287a4..c222f2de55 100644 --- a/app/src/main/java/info/nightscout/androidaps/dependencyInjection/DataClassesModule.kt +++ b/app/src/main/java/info/nightscout/androidaps/dependencyInjection/DataClassesModule.kt @@ -14,7 +14,7 @@ abstract class DataClassesModule { @ContributesAndroidInjector abstract fun glucoseStatusInjector(): GlucoseStatus - @ContributesAndroidInjector abstract fun DatabaseHelperInjector(): DatabaseHelper + @ContributesAndroidInjector abstract fun databaseHelperInjector(): DatabaseHelper @ContributesAndroidInjector abstract fun treatmentServiceInjector(): TreatmentService @ContributesAndroidInjector abstract fun bolusWizardInjector(): BolusWizard diff --git a/app/src/main/java/info/nightscout/androidaps/dependencyInjection/FragmentsModule.kt b/app/src/main/java/info/nightscout/androidaps/dependencyInjection/FragmentsModule.kt index 4acdd1f0db..15298fb768 100644 --- a/app/src/main/java/info/nightscout/androidaps/dependencyInjection/FragmentsModule.kt +++ b/app/src/main/java/info/nightscout/androidaps/dependencyInjection/FragmentsModule.kt @@ -66,7 +66,7 @@ abstract class FragmentsModule { @ContributesAndroidInjector abstract fun contributesTidepoolFragment(): TidepoolFragment @ContributesAndroidInjector abstract fun contributesTreatmentsFragment(): TreatmentsFragment - @ContributesAndroidInjector abstract fun contributesTreatmentsBolusFragment(): TreatmentsBolusFragment + @ContributesAndroidInjector abstract fun contributesTreatmentsBolusFragment(): TreatmentsBolusCarbsFragment @ContributesAndroidInjector abstract fun contributesTreatmentsTemporaryBasalsFragment(): TreatmentsTemporaryBasalsFragment @ContributesAndroidInjector abstract fun contributesTreatmentsTempTargetFragment(): TreatmentsTempTargetFragment @ContributesAndroidInjector abstract fun contributesTreatmentsExtendedBolusesFragment(): TreatmentsExtendedBolusesFragment diff --git a/app/src/main/java/info/nightscout/androidaps/dependencyInjection/OverviewModule.kt b/app/src/main/java/info/nightscout/androidaps/dependencyInjection/OverviewModule.kt index 196e5b1203..42c55758ab 100644 --- a/app/src/main/java/info/nightscout/androidaps/dependencyInjection/OverviewModule.kt +++ b/app/src/main/java/info/nightscout/androidaps/dependencyInjection/OverviewModule.kt @@ -3,6 +3,8 @@ package info.nightscout.androidaps.dependencyInjection import dagger.Module import dagger.android.ContributesAndroidInjector import info.nightscout.androidaps.plugins.general.overview.graphData.GraphData +import info.nightscout.androidaps.plugins.general.overview.graphExtensions.GlucoseValueDataPoint +import info.nightscout.androidaps.plugins.general.overview.graphExtensions.TherapyEventDataPoint import info.nightscout.androidaps.plugins.general.overview.notifications.NotificationWithAction @Module 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/dependencyInjection/WorkersModule.kt b/app/src/main/java/info/nightscout/androidaps/dependencyInjection/WorkersModule.kt index a46b6b5264..0c67611761 100644 --- a/app/src/main/java/info/nightscout/androidaps/dependencyInjection/WorkersModule.kt +++ b/app/src/main/java/info/nightscout/androidaps/dependencyInjection/WorkersModule.kt @@ -3,9 +3,11 @@ package info.nightscout.androidaps.dependencyInjection import dagger.Module import dagger.android.ContributesAndroidInjector import info.nightscout.androidaps.plugins.general.food.FoodPlugin +import info.nightscout.androidaps.plugins.general.nsclient.NSClientAddAckWorker import info.nightscout.androidaps.plugins.general.nsclient.NSClientAddUpdateWorker import info.nightscout.androidaps.plugins.general.nsclient.NSClientMbgWorker import info.nightscout.androidaps.plugins.general.nsclient.NSClientRemoveWorker +import info.nightscout.androidaps.plugins.general.nsclient.NSClientUpdateRemoveAckWorker import info.nightscout.androidaps.plugins.general.smsCommunicator.SmsCommunicatorPlugin import info.nightscout.androidaps.plugins.profile.ns.NSProfilePlugin import info.nightscout.androidaps.plugins.source.* @@ -25,6 +27,8 @@ abstract class WorkersModule { @ContributesAndroidInjector abstract fun contributesNSProfileWorker(): NSProfilePlugin.NSProfileWorker @ContributesAndroidInjector abstract fun contributesSmsCommunicatorWorker(): SmsCommunicatorPlugin.SmsCommunicatorWorker @ContributesAndroidInjector abstract fun contributesNSClientWorker(): NSClientAddUpdateWorker + @ContributesAndroidInjector abstract fun contributesNSClientAddAckWorker(): NSClientAddAckWorker + @ContributesAndroidInjector abstract fun contributesNSClientUpdateRemoveAckWorker(): NSClientUpdateRemoveAckWorker @ContributesAndroidInjector abstract fun contributesNSClientRemoveWorker(): NSClientRemoveWorker @ContributesAndroidInjector abstract fun contributesNSClientMbgWorker(): NSClientMbgWorker @ContributesAndroidInjector abstract fun contributesFoodWorker(): FoodPlugin.FoodWorker diff --git a/app/src/main/java/info/nightscout/androidaps/dialogs/CalibrationDialog.kt b/app/src/main/java/info/nightscout/androidaps/dialogs/CalibrationDialog.kt index 52dea0d14e..8210b551ee 100644 --- a/app/src/main/java/info/nightscout/androidaps/dialogs/CalibrationDialog.kt +++ b/app/src/main/java/info/nightscout/androidaps/dialogs/CalibrationDialog.kt @@ -9,7 +9,9 @@ import dagger.android.HasAndroidInjector import info.nightscout.androidaps.Constants import info.nightscout.androidaps.R import info.nightscout.androidaps.data.Profile -import info.nightscout.androidaps.database.entities.UserEntry.* +import info.nightscout.androidaps.database.entities.ValueWithUnit +import info.nightscout.androidaps.database.entities.UserEntry.Action +import info.nightscout.androidaps.database.entities.UserEntry.Sources import info.nightscout.androidaps.databinding.DialogCalibrationBinding import info.nightscout.androidaps.interfaces.ProfileFunction import info.nightscout.androidaps.logging.UserEntryLogger @@ -79,7 +81,7 @@ class CalibrationDialog : DialogFragmentWithDate() { if (bg > 0) { activity?.let { activity -> OKDialog.showConfirmation(activity, resourceHelper.gs(R.string.overview_calibration), HtmlHelper.fromHtml(Joiner.on("
").join(actions)), { - uel.log(Action.CALIBRATION, ValueWithUnit(bg, units)) + uel.log(Action.CALIBRATION, Sources.CalibrationDialog, ValueWithUnit.fromGlucoseUnit(bg, units)) xdripCalibrations.sendIntent(bg) }) } diff --git a/app/src/main/java/info/nightscout/androidaps/dialogs/CarbsDialog.kt b/app/src/main/java/info/nightscout/androidaps/dialogs/CarbsDialog.kt index 56dfbae96c..1eed6ba5bd 100644 --- a/app/src/main/java/info/nightscout/androidaps/dialogs/CarbsDialog.kt +++ b/app/src/main/java/info/nightscout/androidaps/dialogs/CarbsDialog.kt @@ -1,5 +1,6 @@ package info.nightscout.androidaps.dialogs +import android.content.Context import android.os.Bundle import android.text.Editable import android.text.TextWatcher @@ -8,27 +9,29 @@ import android.view.View import android.view.ViewGroup import com.google.common.base.Joiner import info.nightscout.androidaps.Constants -import info.nightscout.androidaps.MainApp import info.nightscout.androidaps.R +import info.nightscout.androidaps.activities.ErrorHelperActivity +import info.nightscout.androidaps.data.DetailedBolusInfo import info.nightscout.androidaps.data.Profile import info.nightscout.androidaps.database.AppRepository import info.nightscout.androidaps.database.entities.TemporaryTarget -import info.nightscout.androidaps.database.entities.TherapyEvent -import info.nightscout.androidaps.database.entities.UserEntry.* +import info.nightscout.androidaps.database.entities.UserEntry.Action +import info.nightscout.androidaps.database.entities.UserEntry.Sources +import info.nightscout.androidaps.database.entities.ValueWithUnit import info.nightscout.androidaps.database.transactions.InsertTemporaryTargetAndCancelCurrentTransaction import info.nightscout.androidaps.databinding.DialogCarbsBinding +import info.nightscout.androidaps.extensions.formatColor import info.nightscout.androidaps.interfaces.Constraint +import info.nightscout.androidaps.interfaces.IobCobCalculator import info.nightscout.androidaps.interfaces.ProfileFunction import info.nightscout.androidaps.logging.LTag import info.nightscout.androidaps.logging.UserEntryLogger import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker -import info.nightscout.androidaps.plugins.general.nsclient.NSUpload -import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorPlugin -import info.nightscout.androidaps.plugins.treatments.CarbsGenerator import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin +import info.nightscout.androidaps.queue.Callback +import info.nightscout.androidaps.queue.CommandQueue import info.nightscout.androidaps.utils.* import info.nightscout.androidaps.utils.alertDialogs.OKDialog -import info.nightscout.androidaps.utils.extensions.formatColor import info.nightscout.androidaps.utils.resources.ResourceHelper import io.reactivex.disposables.CompositeDisposable import io.reactivex.rxkotlin.plusAssign @@ -40,17 +43,16 @@ import kotlin.math.max class CarbsDialog : DialogFragmentWithDate() { - @Inject lateinit var mainApp: MainApp + @Inject lateinit var ctx: Context @Inject lateinit var resourceHelper: ResourceHelper @Inject lateinit var constraintChecker: ConstraintChecker @Inject lateinit var defaultValueHelper: DefaultValueHelper @Inject lateinit var treatmentsPlugin: TreatmentsPlugin @Inject lateinit var profileFunction: ProfileFunction - @Inject lateinit var iobCobCalculatorPlugin: IobCobCalculatorPlugin - @Inject lateinit var nsUpload: NSUpload - @Inject lateinit var carbsGenerator: CarbsGenerator + @Inject lateinit var iobCobCalculator: IobCobCalculator @Inject lateinit var uel: UserEntryLogger @Inject lateinit var carbTimer: CarbTimer + @Inject lateinit var commandQueue: CommandQueue @Inject lateinit var repository: AppRepository companion object { @@ -76,15 +78,15 @@ class CarbsDialog : DialogFragmentWithDate() { val time = binding.time.value.toInt() if (time > 12 * 60 || time < -12 * 60) { binding.time.value = 0.0 - ToastUtils.showToastInUiThread(mainApp, resourceHelper.gs(R.string.constraintapllied)) + ToastUtils.showToastInUiThread(ctx, resourceHelper.gs(R.string.constraintapllied)) } if (binding.duration.value > 10) { binding.duration.value = 0.0 - ToastUtils.showToastInUiThread(mainApp, resourceHelper.gs(R.string.constraintapllied)) + ToastUtils.showToastInUiThread(ctx, resourceHelper.gs(R.string.constraintapllied)) } if (binding.carbs.value.toInt() > maxCarbs) { binding.carbs.value = 0.0 - ToastUtils.showToastInUiThread(mainApp, resourceHelper.gs(R.string.carbsconstraintapplied)) + ToastUtils.showToastInUiThread(ctx, resourceHelper.gs(R.string.carbsconstraintapplied)) } } @@ -142,7 +144,7 @@ class CarbsDialog : DialogFragmentWithDate() { validateInputs() } - iobCobCalculatorPlugin.actualBg()?.let { bgReading -> + iobCobCalculator.ads.actualBg()?.let { bgReading -> if (bgReading.value < 72) binding.hypoTt.isChecked = true } @@ -222,7 +224,10 @@ class CarbsDialog : DialogFragmentWithDate() { OKDialog.showConfirmation(activity, resourceHelper.gs(R.string.carbs), HtmlHelper.fromHtml(Joiner.on("
").join(actions)), { when { activitySelected -> { - uel.log(Action.TT, ValueWithUnit(TemporaryTarget.Reason.ACTIVITY.text, Units.TherapyEvent), ValueWithUnit(activityTT, units) , ValueWithUnit(activityTTDuration, Units.M)) + uel.log(Action.TT, Sources.CarbDialog, + ValueWithUnit.TherapyEventTTReason(TemporaryTarget.Reason.ACTIVITY), + ValueWithUnit.fromGlucoseUnit(activityTT, units), + ValueWithUnit.Minute(activityTTDuration)) disposable += repository.runTransactionForResult(InsertTemporaryTargetAndCancelCurrentTransaction( timestamp = System.currentTimeMillis(), duration = TimeUnit.MINUTES.toMillis(activityTTDuration.toLong()), @@ -230,15 +235,18 @@ class CarbsDialog : DialogFragmentWithDate() { lowTarget = Profile.toMgdl(activityTT, profileFunction.getUnits()), highTarget = Profile.toMgdl(activityTT, profileFunction.getUnits()) )).subscribe({ result -> - result.inserted.forEach { nsUpload.uploadTempTarget(it) } - result.updated.forEach { nsUpload.updateTempTarget(it) } + result.inserted.forEach { aapsLogger.debug(LTag.DATABASE, "Inserted temp target $it") } + result.updated.forEach { aapsLogger.debug(LTag.DATABASE, "Updated temp target $it") } }, { - aapsLogger.error(LTag.BGSOURCE, "Error while saving temporary target", it) + aapsLogger.error(LTag.DATABASE, "Error while saving temporary target", it) }) } eatingSoonSelected -> { - uel.log(Action.TT, ValueWithUnit(TemporaryTarget.Reason.EATING_SOON.text, Units.TherapyEvent), ValueWithUnit(eatingSoonTT, units) , ValueWithUnit(eatingSoonTTDuration, Units.M)) + uel.log(Action.TT, Sources.CarbDialog, + ValueWithUnit.TherapyEventTTReason(TemporaryTarget.Reason.EATING_SOON), + ValueWithUnit.fromGlucoseUnit(eatingSoonTT, units), + ValueWithUnit.Minute(eatingSoonTTDuration)) disposable += repository.runTransactionForResult(InsertTemporaryTargetAndCancelCurrentTransaction( timestamp = System.currentTimeMillis(), duration = TimeUnit.MINUTES.toMillis(eatingSoonTTDuration.toLong()), @@ -246,15 +254,18 @@ class CarbsDialog : DialogFragmentWithDate() { lowTarget = Profile.toMgdl(eatingSoonTT, profileFunction.getUnits()), highTarget = Profile.toMgdl(eatingSoonTT, profileFunction.getUnits()) )).subscribe({ result -> - result.inserted.forEach { nsUpload.uploadTempTarget(it) } - result.updated.forEach { nsUpload.updateTempTarget(it) } + result.inserted.forEach { aapsLogger.debug(LTag.DATABASE, "Inserted temp target $it") } + result.updated.forEach { aapsLogger.debug(LTag.DATABASE, "Updated temp target $it") } }, { - aapsLogger.error(LTag.BGSOURCE, "Error while saving temporary target", it) + aapsLogger.error(LTag.DATABASE, "Error while saving temporary target", it) }) } hypoSelected -> { - uel.log(Action.TT, ValueWithUnit(TemporaryTarget.Reason.HYPOGLYCEMIA.text, Units.TherapyEvent), ValueWithUnit(hypoTT, units) , ValueWithUnit(hypoTTDuration, Units.M)) + uel.log(Action.TT, Sources.CarbDialog, + ValueWithUnit.TherapyEventTTReason(TemporaryTarget.Reason.HYPOGLYCEMIA), + ValueWithUnit.fromGlucoseUnit(hypoTT, units), + ValueWithUnit.Minute(hypoTTDuration)) disposable += repository.runTransactionForResult(InsertTemporaryTargetAndCancelCurrentTransaction( timestamp = System.currentTimeMillis(), duration = TimeUnit.MINUTES.toMillis(hypoTTDuration.toLong()), @@ -262,24 +273,37 @@ class CarbsDialog : DialogFragmentWithDate() { lowTarget = Profile.toMgdl(hypoTT, profileFunction.getUnits()), highTarget = Profile.toMgdl(hypoTT, profileFunction.getUnits()) )).subscribe({ result -> - result.inserted.forEach { nsUpload.uploadTempTarget(it) } - result.updated.forEach { nsUpload.updateTempTarget(it) } + result.inserted.forEach { aapsLogger.debug(LTag.DATABASE, "Inserted temp target $it") } + result.updated.forEach { aapsLogger.debug(LTag.DATABASE, "Updated temp target $it") } }, { - aapsLogger.error(LTag.BGSOURCE, "Error while saving temporary target", it) + aapsLogger.error(LTag.DATABASE, "Error while saving temporary target", it) }) } } if (carbsAfterConstraints > 0) { - if (duration == 0) { - carbsGenerator.createCarb(carbsAfterConstraints, time, TherapyEvent.Type.CARBS_CORRECTION.text, notes) - } else { - carbsGenerator.generateCarbs(carbsAfterConstraints, time, duration, notes) - nsUpload.uploadEvent(TherapyEvent.Type.NOTE.text, DateUtil.now() - 2000, resourceHelper.gs(R.string.generated_ecarbs_note, carbsAfterConstraints, duration, timeOffset)) - } - uel.log(Action.CARBS, notes, ValueWithUnit(eventTime, Units.Timestamp, eventTimeChanged), ValueWithUnit(carbsAfterConstraints, Units.G), ValueWithUnit(timeOffset, Units.M, timeOffset != 0), ValueWithUnit(duration, Units.H, duration != 0)) + val detailedBolusInfo = DetailedBolusInfo() + detailedBolusInfo.eventType = DetailedBolusInfo.EventType.CORRECTION_BOLUS + detailedBolusInfo.carbs = carbsAfterConstraints.toDouble() + detailedBolusInfo.context = context + detailedBolusInfo.notes = notes + detailedBolusInfo.carbsDuration = T.hours(duration.toLong()).msecs() + detailedBolusInfo.carbsTimestamp = time + uel.log(if (duration == 0) Action.CARBS else Action.EXTENDED_CARBS, Sources.CarbDialog, + notes, + ValueWithUnit.Timestamp(eventTime).takeIf { eventTimeChanged }, + ValueWithUnit.Gram(carbsAfterConstraints), + ValueWithUnit.Minute(timeOffset).takeIf { timeOffset != 0 }, + ValueWithUnit.Hour(duration).takeIf { duration != 0 }) + commandQueue.bolus(detailedBolusInfo, object : Callback() { + override fun run() { + if (!result.success) { + ErrorHelperActivity.runAlarm(ctx, result.comment, resourceHelper.gs(R.string.treatmentdeliveryerror), R.raw.boluserror) + } + } + }) } if (useAlarm && carbs > 0 && timeOffset > 0) { - carbTimer.scheduleReminder(dateUtil._now() + T.mins(timeOffset.toLong()).msecs()) + carbTimer.scheduleReminder(dateUtil.now() + T.mins(timeOffset.toLong()).msecs()) } }, null) } diff --git a/app/src/main/java/info/nightscout/androidaps/dialogs/CareDialog.kt b/app/src/main/java/info/nightscout/androidaps/dialogs/CareDialog.kt index 122b38cd81..a667c03ccb 100644 --- a/app/src/main/java/info/nightscout/androidaps/dialogs/CareDialog.kt +++ b/app/src/main/java/info/nightscout/androidaps/dialogs/CareDialog.kt @@ -1,5 +1,6 @@ package info.nightscout.androidaps.dialogs +import android.content.Context import android.os.Bundle import android.text.Editable import android.text.TextWatcher @@ -10,24 +11,24 @@ import androidx.annotation.StringRes import com.google.common.base.Joiner import dagger.android.HasAndroidInjector import info.nightscout.androidaps.Constants -import info.nightscout.androidaps.MainApp import info.nightscout.androidaps.R import info.nightscout.androidaps.data.Profile import info.nightscout.androidaps.database.AppRepository +import info.nightscout.androidaps.database.entities.ValueWithUnit import info.nightscout.androidaps.database.entities.TherapyEvent -import info.nightscout.androidaps.database.transactions.InsertTherapyEventIfNewTransaction -import info.nightscout.androidaps.database.entities.UserEntry.* +import info.nightscout.androidaps.database.entities.UserEntry.Action +import info.nightscout.androidaps.database.entities.UserEntry.Sources +import info.nightscout.androidaps.database.transactions.InsertIfNewByTimestampTherapyEventTransaction import info.nightscout.androidaps.databinding.DialogCareBinding import info.nightscout.androidaps.interfaces.ProfileFunction import info.nightscout.androidaps.logging.LTag import info.nightscout.androidaps.logging.UserEntryLogger -import info.nightscout.androidaps.plugins.general.nsclient.NSUpload import info.nightscout.androidaps.plugins.iob.iobCobCalculator.GlucoseStatusProvider import info.nightscout.androidaps.utils.HtmlHelper import info.nightscout.androidaps.utils.T import info.nightscout.androidaps.utils.Translator import info.nightscout.androidaps.utils.alertDialogs.OKDialog -import info.nightscout.androidaps.utils.extensions.fromConstant +import info.nightscout.androidaps.extensions.fromConstant import info.nightscout.androidaps.utils.resources.ResourceHelper import io.reactivex.disposables.CompositeDisposable import io.reactivex.rxkotlin.plusAssign @@ -38,10 +39,9 @@ import javax.inject.Inject class CareDialog : DialogFragmentWithDate() { @Inject lateinit var injector: HasAndroidInjector - @Inject lateinit var mainApp: MainApp + @Inject lateinit var ctx: Context @Inject lateinit var resourceHelper: ResourceHelper @Inject lateinit var profileFunction: ProfileFunction - @Inject lateinit var nsUpload: NSUpload @Inject lateinit var translator: Translator @Inject lateinit var uel: UserEntryLogger @Inject lateinit var repository: AppRepository @@ -60,7 +60,8 @@ class CareDialog : DialogFragmentWithDate() { } private var options: EventType = EventType.BGCHECK - private var valuesWithUnit = mutableListOf() + //private var valuesWithUnit = mutableListOf() + private var valuesWithUnit = mutableListOf() @StringRes private var event: Int = R.string.none @@ -198,17 +199,17 @@ class CareDialog : DialogFragmentWithDate() { binding.sensor.isChecked -> TherapyEvent.MeterType.SENSOR else -> TherapyEvent.MeterType.MANUAL } - actions.add(resourceHelper.gs(R.string.careportal_newnstreatment_glucosetype) + ": " + translator.translate(meterType.text)) + actions.add(resourceHelper.gs(R.string.careportal_newnstreatment_glucosetype) + ": " + translator.translate(meterType)) actions.add(resourceHelper.gs(R.string.treatments_wizard_bg_label) + ": " + Profile.toCurrentUnitsString(profileFunction, binding.bg.value) + " " + resourceHelper.gs(unitResId)) therapyEvent.glucoseType = meterType therapyEvent.glucose = binding.bg.value - valuesWithUnit.add(ValueWithUnit(binding.bg.value.toDouble(), profileFunction.getUnits())) - valuesWithUnit.add(ValueWithUnit(meterType.text, Units.TherapyEvent)) + valuesWithUnit.add(ValueWithUnit.fromGlucoseUnit(binding.bg.value.toDouble(), profileFunction.getUnits())) + valuesWithUnit.add(ValueWithUnit.TherapyEventMeterType(meterType)) } if (options == EventType.NOTE || options == EventType.EXERCISE) { actions.add(resourceHelper.gs(R.string.careportal_newnstreatment_duration_label) + ": " + resourceHelper.gs(R.string.format_mins, binding.duration.value.toInt())) therapyEvent.duration = T.mins(binding.duration.value.toLong()).msecs() - valuesWithUnit.add(ValueWithUnit(binding.duration.value.toInt(), Units.M, !binding.duration.value.equals(0.0))) + valuesWithUnit.add(ValueWithUnit.Minute(binding.duration.value.toInt()).takeIf { !binding.duration.value.equals(0.0) } ) } val notes = binding.notesLayout.notes.text.toString() if (notes.isNotEmpty()) { @@ -220,16 +221,26 @@ class CareDialog : DialogFragmentWithDate() { therapyEvent.enteredBy = enteredBy + var source = when (options) { + EventType.BGCHECK -> Sources.BgCheck + EventType.SENSOR_INSERT -> Sources.SensorInsert + EventType.BATTERY_CHANGE -> Sources.BatteryChange + EventType.NOTE -> Sources.Note + EventType.EXERCISE -> Sources.Exercise + EventType.QUESTION -> Sources.Question + EventType.ANNOUNCEMENT -> Sources.Announcement + } + activity?.let { activity -> OKDialog.showConfirmation(activity, resourceHelper.gs(event), HtmlHelper.fromHtml(Joiner.on("
").join(actions)), { - disposable += repository.runTransactionForResult(InsertTherapyEventIfNewTransaction(therapyEvent)).subscribe({ result -> - result.inserted.forEach { nsUpload.uploadEvent(it) } - }, { - aapsLogger.error(LTag.BGSOURCE, "Error while saving therapy event", it) - }) - valuesWithUnit.add(0, ValueWithUnit(eventTime, Units.Timestamp, eventTimeChanged)) - valuesWithUnit.add(1, ValueWithUnit(therapyEvent.type.text, Units.TherapyEvent)) - uel.log(Action.CAREPORTAL, notes, valuesWithUnit) + disposable += repository.runTransactionForResult(InsertIfNewByTimestampTherapyEventTransaction(therapyEvent)) + .subscribe( + { result -> result.inserted.forEach { aapsLogger.debug(LTag.DATABASE, "Inserted therapy event $it") } }, + { aapsLogger.error(LTag.DATABASE, "Error while saving therapy event", it) } + ) + valuesWithUnit.add(0, ValueWithUnit.Timestamp(eventTime).takeIf { eventTimeChanged }) + valuesWithUnit.add(1, ValueWithUnit.TherapyEventType(therapyEvent.type)) + uel.log(Action.CAREPORTAL, source, notes, valuesWithUnit) }, null) } return true diff --git a/app/src/main/java/info/nightscout/androidaps/dialogs/ExtendedBolusDialog.kt b/app/src/main/java/info/nightscout/androidaps/dialogs/ExtendedBolusDialog.kt index 4116091eed..e3ed95451c 100644 --- a/app/src/main/java/info/nightscout/androidaps/dialogs/ExtendedBolusDialog.kt +++ b/app/src/main/java/info/nightscout/androidaps/dialogs/ExtendedBolusDialog.kt @@ -8,9 +8,11 @@ import android.view.ViewGroup import com.google.common.base.Joiner import info.nightscout.androidaps.R import info.nightscout.androidaps.activities.ErrorHelperActivity -import info.nightscout.androidaps.database.entities.UserEntry.* +import info.nightscout.androidaps.database.entities.ValueWithUnit +import info.nightscout.androidaps.database.entities.UserEntry.Action +import info.nightscout.androidaps.database.entities.UserEntry.Sources import info.nightscout.androidaps.databinding.DialogExtendedbolusBinding -import info.nightscout.androidaps.interfaces.ActivePluginProvider +import info.nightscout.androidaps.interfaces.ActivePlugin import info.nightscout.androidaps.interfaces.CommandQueueProvider import info.nightscout.androidaps.interfaces.Constraint import info.nightscout.androidaps.logging.UserEntryLogger @@ -19,7 +21,7 @@ import info.nightscout.androidaps.queue.Callback import info.nightscout.androidaps.utils.HtmlHelper import info.nightscout.androidaps.utils.SafeParse import info.nightscout.androidaps.utils.alertDialogs.OKDialog -import info.nightscout.androidaps.utils.extensions.formatColor +import info.nightscout.androidaps.extensions.formatColor import info.nightscout.androidaps.utils.resources.ResourceHelper import java.text.DecimalFormat import java.util.* @@ -32,7 +34,7 @@ class ExtendedBolusDialog : DialogFragmentWithDate() { @Inject lateinit var resourceHelper: ResourceHelper @Inject lateinit var constraintChecker: ConstraintChecker @Inject lateinit var commandQueue: CommandQueueProvider - @Inject lateinit var activePlugin: ActivePluginProvider + @Inject lateinit var activePlugin: ActivePlugin @Inject lateinit var uel: UserEntryLogger private var _binding: DialogExtendedbolusBinding? = null @@ -88,7 +90,9 @@ class ExtendedBolusDialog : DialogFragmentWithDate() { activity?.let { activity -> OKDialog.showConfirmation(activity, resourceHelper.gs(R.string.extended_bolus), HtmlHelper.fromHtml(Joiner.on("
").join(actions)), { - uel.log(Action.EXTENDED_BOLUS, ValueWithUnit(insulinAfterConstraint, Units.U), ValueWithUnit(durationInMinutes, Units.M)) + uel.log(Action.EXTENDED_BOLUS, Sources.ExtendedBolusDialog, + ValueWithUnit.Insulin(insulinAfterConstraint), + ValueWithUnit.Minute(durationInMinutes)) commandQueue.extendedBolus(insulinAfterConstraint, durationInMinutes, object : Callback() { override fun run() { if (!result.success) { diff --git a/app/src/main/java/info/nightscout/androidaps/dialogs/FillDialog.kt b/app/src/main/java/info/nightscout/androidaps/dialogs/FillDialog.kt index 09f9234937..f9cf203e5e 100644 --- a/app/src/main/java/info/nightscout/androidaps/dialogs/FillDialog.kt +++ b/app/src/main/java/info/nightscout/androidaps/dialogs/FillDialog.kt @@ -10,24 +10,24 @@ import info.nightscout.androidaps.R import info.nightscout.androidaps.activities.ErrorHelperActivity import info.nightscout.androidaps.data.DetailedBolusInfo import info.nightscout.androidaps.database.AppRepository +import info.nightscout.androidaps.database.entities.ValueWithUnit import info.nightscout.androidaps.database.entities.TherapyEvent -import info.nightscout.androidaps.database.transactions.InsertTherapyEventIfNewTransaction -import info.nightscout.androidaps.database.entities.UserEntry.* +import info.nightscout.androidaps.database.entities.UserEntry.Action +import info.nightscout.androidaps.database.entities.UserEntry.Sources +import info.nightscout.androidaps.database.transactions.InsertIfNewByTimestampTherapyEventTransaction import info.nightscout.androidaps.databinding.DialogFillBinding -import info.nightscout.androidaps.db.Source -import info.nightscout.androidaps.interfaces.ActivePluginProvider +import info.nightscout.androidaps.interfaces.ActivePlugin import info.nightscout.androidaps.interfaces.CommandQueueProvider import info.nightscout.androidaps.interfaces.Constraint import info.nightscout.androidaps.logging.LTag import info.nightscout.androidaps.logging.UserEntryLogger import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker -import info.nightscout.androidaps.plugins.general.nsclient.NSUpload import info.nightscout.androidaps.queue.Callback import info.nightscout.androidaps.utils.DecimalFormatter import info.nightscout.androidaps.utils.HtmlHelper import info.nightscout.androidaps.utils.SafeParse import info.nightscout.androidaps.utils.alertDialogs.OKDialog -import info.nightscout.androidaps.utils.extensions.formatColor +import info.nightscout.androidaps.extensions.formatColor import info.nightscout.androidaps.utils.resources.ResourceHelper import io.reactivex.disposables.CompositeDisposable import io.reactivex.rxkotlin.plusAssign @@ -40,9 +40,8 @@ class FillDialog : DialogFragmentWithDate() { @Inject lateinit var constraintChecker: ConstraintChecker @Inject lateinit var resourceHelper: ResourceHelper @Inject lateinit var ctx: Context - @Inject lateinit var nsUpload: NSUpload @Inject lateinit var commandQueue: CommandQueueProvider - @Inject lateinit var activePlugin: ActivePluginProvider + @Inject lateinit var activePlugin: ActivePlugin @Inject lateinit var uel: UserEntryLogger @Inject lateinit var repository: AppRepository @@ -124,7 +123,7 @@ class FillDialog : DialogFragmentWithDate() { val insulinChange = binding.fillCartridgeChange.isChecked if (insulinChange) actions.add(resourceHelper.gs(R.string.record_insulin_cartridge_change).formatColor(resourceHelper, R.color.actionsConfirm)) - val notes = binding.notesLayout.notes.text.toString() + val notes: String = binding.notesLayout.notes.text.toString() if (notes.isNotEmpty()) actions.add(resourceHelper.gs(R.string.notes_label) + ": " + notes) eventTime -= eventTime % 1000 @@ -136,35 +135,41 @@ class FillDialog : DialogFragmentWithDate() { activity?.let { activity -> OKDialog.showConfirmation(activity, resourceHelper.gs(R.string.primefill), HtmlHelper.fromHtml(Joiner.on("
").join(actions)), { if (insulinAfterConstraints > 0) { - uel.log(Action.PRIME_BOLUS, notes, ValueWithUnit(insulinAfterConstraints, Units.U, insulinAfterConstraints != 0.0)) + uel.log(Action.PRIME_BOLUS, Sources.FillDialog, + notes, + ValueWithUnit.Insulin(insulinAfterConstraints).takeIf { insulinAfterConstraints != 0.0 }) requestPrimeBolus(insulinAfterConstraints, notes) } if (siteChange) { - uel.log(Action.CAREPORTAL, notes, ValueWithUnit(TherapyEvent.Type.CANNULA_CHANGE.text, Units.TherapyEvent)) - disposable += repository.runTransactionForResult(InsertTherapyEventIfNewTransaction( + uel.log(Action.SITE_CHANGE, Sources.FillDialog, + notes, + ValueWithUnit.Timestamp(eventTime).takeIf { eventTimeChanged }, + ValueWithUnit.TherapyEventType(TherapyEvent.Type.CANNULA_CHANGE)) + disposable += repository.runTransactionForResult(InsertIfNewByTimestampTherapyEventTransaction( timestamp = eventTime, type = TherapyEvent.Type.CANNULA_CHANGE, note = notes, glucoseUnit = TherapyEvent.GlucoseUnit.MGDL - )).subscribe({ result -> - result.inserted.forEach { nsUpload.uploadEvent(it) } - }, { - aapsLogger.error(LTag.BGSOURCE, "Error while saving therapy event", it) - }) + )).subscribe( + { result -> result.inserted.forEach { aapsLogger.debug(LTag.DATABASE, "Inserted therapy event $it") } }, + { aapsLogger.error(LTag.DATABASE, "Error while saving therapy event", it) } + ) } if (insulinChange) { // add a second for case of both checked - uel.log(Action.CAREPORTAL, notes, ValueWithUnit(TherapyEvent.Type.INSULIN_CHANGE.text, Units.TherapyEvent)) - disposable += repository.runTransactionForResult(InsertTherapyEventIfNewTransaction( + uel.log(Action.RESERVOIR_CHANGE, Sources.FillDialog, + notes, + ValueWithUnit.Timestamp(eventTime).takeIf { eventTimeChanged }, + ValueWithUnit.TherapyEventType(TherapyEvent.Type.INSULIN_CHANGE)) + disposable += repository.runTransactionForResult(InsertIfNewByTimestampTherapyEventTransaction( timestamp = eventTime + 1000, type = TherapyEvent.Type.INSULIN_CHANGE, note = notes, glucoseUnit = TherapyEvent.GlucoseUnit.MGDL - )).subscribe({ result -> - result.inserted.forEach { nsUpload.uploadEvent(it) } - }, { - aapsLogger.error(LTag.BGSOURCE, "Error while saving therapy event", it) - }) + )).subscribe( + { result -> result.inserted.forEach { aapsLogger.debug(LTag.DATABASE, "Inserted therapy event $it") } }, + { aapsLogger.error(LTag.DATABASE, "Error while saving therapy event", it) } + ) } }, null) } @@ -181,8 +186,7 @@ class FillDialog : DialogFragmentWithDate() { val detailedBolusInfo = DetailedBolusInfo() detailedBolusInfo.insulin = insulin detailedBolusInfo.context = context - detailedBolusInfo.source = Source.USER - detailedBolusInfo.isValid = false // do not count it in IOB (for pump history) + detailedBolusInfo.bolusType = DetailedBolusInfo.BolusType.PRIMING detailedBolusInfo.notes = notes commandQueue.bolus(detailedBolusInfo, object : Callback() { override fun run() { diff --git a/app/src/main/java/info/nightscout/androidaps/dialogs/InsulinDialog.kt b/app/src/main/java/info/nightscout/androidaps/dialogs/InsulinDialog.kt index da3347485a..ff21e94308 100644 --- a/app/src/main/java/info/nightscout/androidaps/dialogs/InsulinDialog.kt +++ b/app/src/main/java/info/nightscout/androidaps/dialogs/InsulinDialog.kt @@ -8,33 +8,32 @@ import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import com.google.common.base.Joiner -import info.nightscout.androidaps.Config +import info.nightscout.androidaps.interfaces.Config import info.nightscout.androidaps.Constants import info.nightscout.androidaps.R import info.nightscout.androidaps.activities.ErrorHelperActivity import info.nightscout.androidaps.data.DetailedBolusInfo import info.nightscout.androidaps.data.Profile import info.nightscout.androidaps.database.AppRepository +import info.nightscout.androidaps.database.entities.ValueWithUnit import info.nightscout.androidaps.database.entities.TemporaryTarget -import info.nightscout.androidaps.database.entities.TherapyEvent -import info.nightscout.androidaps.database.entities.UserEntry.* +import info.nightscout.androidaps.database.entities.UserEntry.Action +import info.nightscout.androidaps.database.entities.UserEntry.Sources import info.nightscout.androidaps.database.transactions.InsertTemporaryTargetAndCancelCurrentTransaction import info.nightscout.androidaps.databinding.DialogInsulinBinding -import info.nightscout.androidaps.db.Source -import info.nightscout.androidaps.interfaces.ActivePluginProvider +import info.nightscout.androidaps.interfaces.ActivePlugin import info.nightscout.androidaps.interfaces.CommandQueueProvider import info.nightscout.androidaps.interfaces.Constraint import info.nightscout.androidaps.interfaces.ProfileFunction import info.nightscout.androidaps.logging.LTag import info.nightscout.androidaps.logging.UserEntryLogger import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker -import info.nightscout.androidaps.plugins.general.nsclient.NSUpload import info.nightscout.androidaps.queue.Callback import info.nightscout.androidaps.utils.* import info.nightscout.androidaps.utils.alertDialogs.OKDialog -import info.nightscout.androidaps.utils.extensions.formatColor +import info.nightscout.androidaps.extensions.formatColor import info.nightscout.androidaps.utils.extensions.toSignedString -import info.nightscout.androidaps.utils.extensions.toVisibility +import info.nightscout.androidaps.extensions.toVisibility import info.nightscout.androidaps.utils.resources.ResourceHelper import io.reactivex.disposables.CompositeDisposable import io.reactivex.rxkotlin.plusAssign @@ -52,12 +51,11 @@ class InsulinDialog : DialogFragmentWithDate() { @Inject lateinit var defaultValueHelper: DefaultValueHelper @Inject lateinit var profileFunction: ProfileFunction @Inject lateinit var commandQueue: CommandQueueProvider - @Inject lateinit var activePlugin: ActivePluginProvider + @Inject lateinit var activePlugin: ActivePlugin @Inject lateinit var ctx: Context @Inject lateinit var repository: AppRepository @Inject lateinit var config: Config @Inject lateinit var uel: UserEntryLogger - @Inject lateinit var nsUpload: NSUpload companion object { @@ -177,7 +175,7 @@ class InsulinDialog : DialogFragmentWithDate() { actions.add(resourceHelper.gs(R.string.temptargetshort) + ": " + (DecimalFormatter.to1Decimal(eatingSoonTT) + " " + unitLabel + " (" + resourceHelper.gs(R.string.format_mins, eatingSoonTTDuration) + ")").formatColor(resourceHelper, R.color.tempTargetConfirmation)) val timeOffset = binding.time.value.toInt() - val time = DateUtil.now() + T.mins(timeOffset.toLong()).msecs() + val time = dateUtil.now() + T.mins(timeOffset.toLong()).msecs() if (timeOffset != 0) actions.add(resourceHelper.gs(R.string.time) + ": " + dateUtil.dateAndTimeString(time)) @@ -189,7 +187,11 @@ class InsulinDialog : DialogFragmentWithDate() { activity?.let { activity -> OKDialog.showConfirmation(activity, resourceHelper.gs(R.string.bolus), HtmlHelper.fromHtml(Joiner.on("
").join(actions)), { if (eatingSoonChecked) { - uel.log(Action.TT, notes, ValueWithUnit(TemporaryTarget.Reason.EATING_SOON.text, Units.TherapyEvent), ValueWithUnit(eatingSoonTT, units), ValueWithUnit(eatingSoonTTDuration, Units.M)) + uel.log(Action.TT, Sources.InsulinDialog, + notes, + ValueWithUnit.TherapyEventTTReason(TemporaryTarget.Reason.EATING_SOON), + ValueWithUnit.fromGlucoseUnit(eatingSoonTT, units), + ValueWithUnit.Minute(eatingSoonTTDuration)) disposable += repository.runTransactionForResult(InsertTemporaryTargetAndCancelCurrentTransaction( timestamp = System.currentTimeMillis(), duration = TimeUnit.MINUTES.toMillis(eatingSoonTTDuration.toLong()), @@ -197,26 +199,34 @@ class InsulinDialog : DialogFragmentWithDate() { lowTarget = Profile.toMgdl(eatingSoonTT, profileFunction.getUnits()), highTarget = Profile.toMgdl(eatingSoonTT, profileFunction.getUnits()) )).subscribe({ result -> - result.inserted.forEach { nsUpload.uploadTempTarget(it) } - result.updated.forEach { nsUpload.updateTempTarget(it) } + result.inserted.forEach { aapsLogger.debug(LTag.DATABASE, "Inserted temp target $it") } + result.updated.forEach { aapsLogger.debug(LTag.DATABASE, "Updated temp target $it") } }, { - aapsLogger.error(LTag.BGSOURCE, "Error while saving temporary target", it) + aapsLogger.error(LTag.DATABASE, "Error while saving temporary target", it) }) } if (insulinAfterConstraints > 0) { val detailedBolusInfo = DetailedBolusInfo() - detailedBolusInfo.eventType = TherapyEvent.Type.CORRECTION_BOLUS.text + detailedBolusInfo.eventType = DetailedBolusInfo.EventType.CORRECTION_BOLUS detailedBolusInfo.insulin = insulinAfterConstraints detailedBolusInfo.context = context - detailedBolusInfo.source = Source.USER detailedBolusInfo.notes = notes + detailedBolusInfo.timestamp = time if (recordOnlyChecked) { - uel.log(Action.BOLUS_RECORD, notes, ValueWithUnit(insulinAfterConstraints, Units.U), ValueWithUnit(timeOffset, Units.M, timeOffset!= 0)) - detailedBolusInfo.date = time - activePlugin.activeTreatments.addToHistoryTreatment(detailedBolusInfo, false) + uel.log(Action.BOLUS, Sources.InsulinDialog, + resourceHelper.gs(R.string.record) + if (notes.isNotEmpty()) ": " + notes else "", + ValueWithUnit.SimpleString(resourceHelper.gsNotLocalised(R.string.record)), + ValueWithUnit.Insulin(insulinAfterConstraints), + ValueWithUnit.Minute(timeOffset).takeIf { timeOffset!= 0 }) + disposable += repository.runTransactionForResult(detailedBolusInfo.insertBolusTransaction()) + .subscribe( + { result -> result.inserted.forEach { aapsLogger.debug(LTag.DATABASE, "Inserted bolus $it") } }, + { aapsLogger.error(LTag.DATABASE, "Error while saving bolus", it) } + ) } else { - uel.log(Action.BOLUS, notes, ValueWithUnit(insulinAfterConstraints, Units.U)) - detailedBolusInfo.date = DateUtil.now() + uel.log(Action.BOLUS, Sources.InsulinDialog, + notes, + ValueWithUnit.Insulin(insulinAfterConstraints)) commandQueue.bolus(detailedBolusInfo, object : Callback() { override fun run() { if (!result.success) { diff --git a/app/src/main/java/info/nightscout/androidaps/dialogs/LoopDialog.kt b/app/src/main/java/info/nightscout/androidaps/dialogs/LoopDialog.kt index 9b10142c8c..c5dce440b9 100644 --- a/app/src/main/java/info/nightscout/androidaps/dialogs/LoopDialog.kt +++ b/app/src/main/java/info/nightscout/androidaps/dialogs/LoopDialog.kt @@ -12,7 +12,9 @@ import androidx.fragment.app.FragmentManager import dagger.android.support.DaggerDialogFragment import info.nightscout.androidaps.R import info.nightscout.androidaps.activities.ErrorHelperActivity -import info.nightscout.androidaps.database.entities.UserEntry.* +import info.nightscout.androidaps.database.entities.ValueWithUnit +import info.nightscout.androidaps.database.entities.UserEntry.Action +import info.nightscout.androidaps.database.entities.UserEntry.Sources import info.nightscout.androidaps.databinding.DialogLoopBinding import info.nightscout.androidaps.events.EventPreferenceChange import info.nightscout.androidaps.events.EventRefreshOverview @@ -21,13 +23,12 @@ import info.nightscout.androidaps.logging.AAPSLogger import info.nightscout.androidaps.logging.UserEntryLogger import info.nightscout.androidaps.plugins.aps.loop.LoopPlugin import info.nightscout.androidaps.plugins.bus.RxBusWrapper -import info.nightscout.androidaps.plugins.configBuilder.ConfigBuilderPlugin import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker import info.nightscout.androidaps.queue.Callback import info.nightscout.androidaps.utils.FabricPrivacy import info.nightscout.androidaps.utils.ToastUtils import info.nightscout.androidaps.utils.alertDialogs.OKDialog -import info.nightscout.androidaps.utils.extensions.toVisibility +import info.nightscout.androidaps.extensions.toVisibility import info.nightscout.androidaps.utils.resources.ResourceHelper import info.nightscout.androidaps.utils.sharedPreferences.SP import javax.inject.Inject @@ -42,10 +43,10 @@ class LoopDialog : DaggerDialogFragment() { @Inject lateinit var resourceHelper: ResourceHelper @Inject lateinit var profileFunction: ProfileFunction @Inject lateinit var loopPlugin: LoopPlugin - @Inject lateinit var activePlugin: ActivePluginProvider + @Inject lateinit var activePlugin: ActivePlugin @Inject lateinit var constraintChecker: ConstraintChecker @Inject lateinit var commandQueue: CommandQueueProvider - @Inject lateinit var configBuilderPlugin: ConfigBuilderPlugin + @Inject lateinit var configBuilder: ConfigBuilder @Inject lateinit var uel: UserEntryLogger private var showOkCancel: Boolean = true @@ -197,7 +198,7 @@ class LoopDialog : DaggerDialogFragment() { } } val profile = profileFunction.getProfile() - val profileStore = activePlugin.activeProfileInterface.profile + val profileStore = activePlugin.activeProfileSource.profile if (profile == null || profileStore == null) { ToastUtils.showToastInUiThread(ctx, resourceHelper.gs(R.string.noprofile)) @@ -239,31 +240,31 @@ class LoopDialog : DaggerDialogFragment() { val profile = profileFunction.getProfile() ?: return true when (v.id) { R.id.overview_closeloop -> { - uel.log(Action.CLOSED_LOOP_MODE) + uel.log(Action.CLOSED_LOOP_MODE, Sources.LoopDialog) sp.putString(R.string.key_aps_mode, "closed") rxBus.send(EventPreferenceChange(resourceHelper.gs(R.string.closedloop))) return true } R.id.overview_lgsloop -> { - uel.log(Action.LGS_LOOP_MODE) + uel.log(Action.LGS_LOOP_MODE, Sources.LoopDialog) sp.putString(R.string.key_aps_mode, "lgs") rxBus.send(EventPreferenceChange(resourceHelper.gs(R.string.lowglucosesuspend))) return true } R.id.overview_openloop -> { - uel.log(Action.OPEN_LOOP_MODE) + uel.log(Action.OPEN_LOOP_MODE, Sources.LoopDialog) sp.putString(R.string.key_aps_mode, "open") rxBus.send(EventPreferenceChange(resourceHelper.gs(R.string.lowglucosesuspend))) return true } R.id.overview_disable -> { - uel.log(Action.LOOP_DISABLED) + uel.log(Action.LOOP_DISABLED, Sources.LoopDialog) loopPlugin.setPluginEnabled(PluginType.LOOP, false) loopPlugin.setFragmentVisible(PluginType.LOOP, false) - configBuilderPlugin.storeSettings("DisablingLoop") + configBuilder.storeSettings("DisablingLoop") rxBus.send(EventRefreshOverview("suspendmenu")) commandQueue.cancelTempBasal(true, object : Callback() { override fun run() { @@ -277,17 +278,17 @@ class LoopDialog : DaggerDialogFragment() { } R.id.overview_enable -> { - uel.log(Action.LOOP_ENABLED) + uel.log(Action.LOOP_ENABLED, Sources.LoopDialog) loopPlugin.setPluginEnabled(PluginType.LOOP, true) loopPlugin.setFragmentVisible(PluginType.LOOP, true) - configBuilderPlugin.storeSettings("EnablingLoop") + configBuilder.storeSettings("EnablingLoop") rxBus.send(EventRefreshOverview("suspendmenu")) loopPlugin.createOfflineEvent(0) return true } R.id.overview_resume, R.id.overview_reconnect -> { - uel.log(if (v.id==R.id.overview_resume) Action.RESUME else Action.RECONNECT ) + uel.log(if (v.id==R.id.overview_resume) Action.RESUME else Action.RECONNECT, Sources.LoopDialog) loopPlugin.suspendTo(0L) rxBus.send(EventRefreshOverview("suspendmenu")) commandQueue.cancelTempBasal(true, object : Callback() { @@ -303,49 +304,49 @@ class LoopDialog : DaggerDialogFragment() { } R.id.overview_suspend_1h -> { - uel.log(Action.SUSPEND, ValueWithUnit(1, Units.H)) + uel.log(Action.SUSPEND, Sources.LoopDialog, ValueWithUnit.Hour(1)) loopPlugin.suspendLoop(60) rxBus.send(EventRefreshOverview("suspendmenu")) return true } R.id.overview_suspend_2h -> { - uel.log(Action.SUSPEND, ValueWithUnit(2, Units.H)) + uel.log(Action.SUSPEND, Sources.LoopDialog, ValueWithUnit.Hour(2)) loopPlugin.suspendLoop(120) rxBus.send(EventRefreshOverview("suspendmenu")) return true } R.id.overview_suspend_3h -> { - uel.log(Action.SUSPEND, ValueWithUnit(3, Units.H)) + uel.log(Action.SUSPEND, Sources.LoopDialog, ValueWithUnit.Hour(3)) loopPlugin.suspendLoop(180) rxBus.send(EventRefreshOverview("suspendmenu")) return true } R.id.overview_suspend_10h -> { - uel.log(Action.SUSPEND, ValueWithUnit(10, Units.H)) + uel.log(Action.SUSPEND, Sources.LoopDialog, ValueWithUnit.Hour(10)) loopPlugin.suspendLoop(600) rxBus.send(EventRefreshOverview("suspendmenu")) return true } R.id.overview_disconnect_15m -> { - uel.log(Action.DISCONNECT, ValueWithUnit(15, Units.M)) + uel.log(Action.DISCONNECT, Sources.LoopDialog, ValueWithUnit.Minute(15)) loopPlugin.disconnectPump(15, profile) rxBus.send(EventRefreshOverview("suspendmenu")) return true } R.id.overview_disconnect_30m -> { - uel.log(Action.DISCONNECT, ValueWithUnit(30, Units.M)) + uel.log(Action.DISCONNECT, Sources.LoopDialog, ValueWithUnit.Minute(30)) loopPlugin.disconnectPump(30, profile) rxBus.send(EventRefreshOverview("suspendmenu")) return true } R.id.overview_disconnect_1h -> { - uel.log(Action.DISCONNECT, ValueWithUnit(1, Units.H)) + uel.log(Action.DISCONNECT, Sources.LoopDialog, ValueWithUnit.Hour(1)) loopPlugin.disconnectPump(60, profile) sp.putBoolean(R.string.key_objectiveusedisconnect, true) rxBus.send(EventRefreshOverview("suspendmenu")) @@ -353,14 +354,14 @@ class LoopDialog : DaggerDialogFragment() { } R.id.overview_disconnect_2h -> { - uel.log(Action.DISCONNECT, ValueWithUnit(2, Units.H)) + uel.log(Action.DISCONNECT, Sources.LoopDialog, ValueWithUnit.Hour(2)) loopPlugin.disconnectPump(120, profile) rxBus.send(EventRefreshOverview("suspendmenu")) return true } R.id.overview_disconnect_3h -> { - uel.log(Action.DISCONNECT, ValueWithUnit(3, Units.H)) + uel.log(Action.DISCONNECT, Sources.LoopDialog, ValueWithUnit.Hour(3)) loopPlugin.disconnectPump(180, profile) rxBus.send(EventRefreshOverview("suspendmenu")) return true diff --git a/app/src/main/java/info/nightscout/androidaps/dialogs/ProfileSwitchDialog.kt b/app/src/main/java/info/nightscout/androidaps/dialogs/ProfileSwitchDialog.kt index 692f3ee431..591a5d92c6 100644 --- a/app/src/main/java/info/nightscout/androidaps/dialogs/ProfileSwitchDialog.kt +++ b/app/src/main/java/info/nightscout/androidaps/dialogs/ProfileSwitchDialog.kt @@ -8,13 +8,14 @@ import android.widget.ArrayAdapter import com.google.common.base.Joiner import info.nightscout.androidaps.Constants import info.nightscout.androidaps.R -import info.nightscout.androidaps.database.entities.UserEntry.* +import info.nightscout.androidaps.database.entities.ValueWithUnit +import info.nightscout.androidaps.database.entities.UserEntry.Action +import info.nightscout.androidaps.database.entities.UserEntry.Sources import info.nightscout.androidaps.databinding.DialogProfileswitchBinding -import info.nightscout.androidaps.interfaces.ActivePluginProvider +import info.nightscout.androidaps.interfaces.ActivePlugin import info.nightscout.androidaps.interfaces.ProfileFunction import info.nightscout.androidaps.logging.UserEntryLogger import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin -import info.nightscout.androidaps.utils.DateUtil import info.nightscout.androidaps.utils.HtmlHelper import info.nightscout.androidaps.utils.alertDialogs.OKDialog import info.nightscout.androidaps.utils.resources.ResourceHelper @@ -27,7 +28,7 @@ class ProfileSwitchDialog : DialogFragmentWithDate() { @Inject lateinit var resourceHelper: ResourceHelper @Inject lateinit var profileFunction: ProfileFunction @Inject lateinit var treatmentsPlugin: TreatmentsPlugin - @Inject lateinit var activePlugin: ActivePluginProvider + @Inject lateinit var activePlugin: ActivePlugin @Inject lateinit var uel: UserEntryLogger private var profileIndex: Int? = null @@ -67,7 +68,7 @@ class ProfileSwitchDialog : DialogFragmentWithDate() { // profile context?.let { context -> - val profileStore = activePlugin.activeProfileInterface.profile + val profileStore = activePlugin.activeProfileSource.profile ?: return val profileList = profileStore.getProfileList() val adapter = ArrayAdapter(context, R.layout.spinner_centered, profileList) @@ -81,7 +82,7 @@ class ProfileSwitchDialog : DialogFragmentWithDate() { binding.profile.setSelection(p) } ?: return - treatmentsPlugin.getProfileSwitchFromHistory(DateUtil.now())?.let { ps -> + treatmentsPlugin.getProfileSwitchFromHistory(dateUtil.now())?.let { ps -> if (ps.isCPP) { binding.reuselayout.visibility = View.VISIBLE binding.reusebutton.text = resourceHelper.gs(R.string.reuse_profile_pct_hours, ps.percentage, ps.timeshift) @@ -102,7 +103,7 @@ class ProfileSwitchDialog : DialogFragmentWithDate() { override fun submit(): Boolean { if (_binding == null) return false - val profileStore = activePlugin.activeProfileInterface.profile + val profileStore = activePlugin.activeProfileSource.profile ?: return false val actions: LinkedList = LinkedList() @@ -125,7 +126,14 @@ class ProfileSwitchDialog : DialogFragmentWithDate() { activity?.let { activity -> OKDialog.showConfirmation(activity, resourceHelper.gs(R.string.careportal_profileswitch), HtmlHelper.fromHtml(Joiner.on("
").join(actions)), { - uel.log(Action.PROFILE_SWITCH, notes, ValueWithUnit(eventTime, Units.Timestamp, eventTimeChanged), ValueWithUnit(profile, Units.None), ValueWithUnit(percent, Units.Percent), ValueWithUnit(timeShift, Units.H, timeShift != 0), ValueWithUnit(duration, Units.M, duration != 0)) + uel.log(Action.PROFILE_SWITCH, + Sources.ProfileSwitchDialog, + notes, + ValueWithUnit.Timestamp(eventTime).takeIf { eventTimeChanged }, + ValueWithUnit.SimpleString(profile), + ValueWithUnit.Percent(percent), + ValueWithUnit.Hour(timeShift).takeIf { timeShift != 0 }, + ValueWithUnit.Minute(duration).takeIf { duration != 0 }) treatmentsPlugin.doProfileSwitch(profileStore, profile, duration, percent, timeShift, eventTime) }) } diff --git a/app/src/main/java/info/nightscout/androidaps/dialogs/TempBasalDialog.kt b/app/src/main/java/info/nightscout/androidaps/dialogs/TempBasalDialog.kt index 01c9aa8d2a..03f7bc4aa7 100644 --- a/app/src/main/java/info/nightscout/androidaps/dialogs/TempBasalDialog.kt +++ b/app/src/main/java/info/nightscout/androidaps/dialogs/TempBasalDialog.kt @@ -8,20 +8,18 @@ import android.view.ViewGroup import com.google.common.base.Joiner import info.nightscout.androidaps.R import info.nightscout.androidaps.activities.ErrorHelperActivity -import info.nightscout.androidaps.database.entities.UserEntry.* +import info.nightscout.androidaps.database.entities.ValueWithUnit +import info.nightscout.androidaps.database.entities.UserEntry.Action +import info.nightscout.androidaps.database.entities.UserEntry.Sources import info.nightscout.androidaps.databinding.DialogTempbasalBinding -import info.nightscout.androidaps.interfaces.ActivePluginProvider -import info.nightscout.androidaps.interfaces.CommandQueueProvider -import info.nightscout.androidaps.interfaces.Constraint -import info.nightscout.androidaps.interfaces.ProfileFunction -import info.nightscout.androidaps.interfaces.PumpDescription +import info.nightscout.androidaps.interfaces.* import info.nightscout.androidaps.logging.UserEntryLogger import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker import info.nightscout.androidaps.queue.Callback import info.nightscout.androidaps.utils.HtmlHelper import info.nightscout.androidaps.utils.SafeParse import info.nightscout.androidaps.utils.alertDialogs.OKDialog -import info.nightscout.androidaps.utils.extensions.formatColor +import info.nightscout.androidaps.extensions.formatColor import info.nightscout.androidaps.utils.resources.ResourceHelper import java.text.DecimalFormat import java.util.* @@ -33,7 +31,7 @@ class TempBasalDialog : DialogFragmentWithDate() { @Inject lateinit var constraintChecker: ConstraintChecker @Inject lateinit var resourceHelper: ResourceHelper @Inject lateinit var profileFunction: ProfileFunction - @Inject lateinit var activePlugin: ActivePluginProvider + @Inject lateinit var activePlugin: ActivePlugin @Inject lateinit var commandQueue: CommandQueueProvider @Inject lateinit var ctx: Context @Inject lateinit var uel: UserEntryLogger @@ -126,11 +124,15 @@ class TempBasalDialog : DialogFragmentWithDate() { } } if (isPercentPump) { - uel.log(Action.TEMP_BASAL, ValueWithUnit(percent, Units.Percent), ValueWithUnit(durationInMinutes, Units.M)) - commandQueue.tempBasalPercent(percent, durationInMinutes, true, profile, callback) + uel.log(Action.TEMP_BASAL, Sources.TempBasalDialog, + ValueWithUnit.Percent(percent), + ValueWithUnit.Minute(durationInMinutes)) + commandQueue.tempBasalPercent(percent, durationInMinutes, true, profile, PumpSync.TemporaryBasalType.NORMAL, callback) } else { - uel.log(Action.TEMP_BASAL, ValueWithUnit(absolute, Units.U), ValueWithUnit(durationInMinutes, Units.M)) - commandQueue.tempBasalAbsolute(absolute, durationInMinutes, true, profile, callback) + uel.log(Action.TEMP_BASAL, Sources.TempBasalDialog, + ValueWithUnit.Insulin(absolute), + ValueWithUnit.Minute(durationInMinutes)) + commandQueue.tempBasalAbsolute(absolute, durationInMinutes, true, profile, PumpSync.TemporaryBasalType.NORMAL, callback) } }) } diff --git a/app/src/main/java/info/nightscout/androidaps/dialogs/TempTargetDialog.kt b/app/src/main/java/info/nightscout/androidaps/dialogs/TempTargetDialog.kt index 7cebd826f0..556617303d 100644 --- a/app/src/main/java/info/nightscout/androidaps/dialogs/TempTargetDialog.kt +++ b/app/src/main/java/info/nightscout/androidaps/dialogs/TempTargetDialog.kt @@ -12,8 +12,10 @@ import info.nightscout.androidaps.R import info.nightscout.androidaps.data.Profile import info.nightscout.androidaps.database.AppRepository import info.nightscout.androidaps.database.ValueWrapper +import info.nightscout.androidaps.database.entities.ValueWithUnit import info.nightscout.androidaps.database.entities.TemporaryTarget -import info.nightscout.androidaps.database.entities.UserEntry.* +import info.nightscout.androidaps.database.entities.UserEntry.Action +import info.nightscout.androidaps.database.entities.UserEntry.Sources import info.nightscout.androidaps.database.transactions.CancelCurrentTemporaryTargetIfAnyTransaction import info.nightscout.androidaps.database.transactions.InsertTemporaryTargetAndCancelCurrentTransaction import info.nightscout.androidaps.databinding.DialogTemptargetBinding @@ -21,7 +23,6 @@ import info.nightscout.androidaps.interfaces.ProfileFunction import info.nightscout.androidaps.logging.LTag import info.nightscout.androidaps.logging.UserEntryLogger import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker -import info.nightscout.androidaps.plugins.general.nsclient.NSUpload import info.nightscout.androidaps.utils.DefaultValueHelper import info.nightscout.androidaps.utils.HtmlHelper import info.nightscout.androidaps.utils.alertDialogs.OKDialog @@ -41,7 +42,6 @@ class TempTargetDialog : DialogFragmentWithDate() { @Inject lateinit var defaultValueHelper: DefaultValueHelper @Inject lateinit var uel: UserEntryLogger @Inject lateinit var repository: AppRepository - @Inject lateinit var nsUpload: NSUpload private lateinit var reasonList: List @@ -88,7 +88,7 @@ class TempTargetDialog : DialogFragmentWithDate() { // temp target context?.let { context -> - if (repository.getTemporaryTargetActiveAt(dateUtil._now()).blockingGet() is ValueWrapper.Existing) + if (repository.getTemporaryTargetActiveAt(dateUtil.now()).blockingGet() is ValueWrapper.Existing) binding.targetCancel.visibility = View.VISIBLE else binding.targetCancel.visibility = View.GONE @@ -135,19 +135,19 @@ class TempTargetDialog : DialogFragmentWithDate() { binding.reason.setSelection(reasonList.indexOf(resourceHelper.gs(R.string.eatingsoon))) } - R.id.activity -> { + R.id.activity -> { binding.temptarget.value = defaultValueHelper.determineActivityTT() binding.duration.value = defaultValueHelper.determineActivityTTDuration().toDouble() binding.reason.setSelection(reasonList.indexOf(resourceHelper.gs(R.string.activity))) } - R.id.hypo -> { + R.id.hypo -> { binding.temptarget.value = defaultValueHelper.determineHypoTT() binding.duration.value = defaultValueHelper.determineHypoTTDuration().toDouble() binding.reason.setSelection(reasonList.indexOf(resourceHelper.gs(R.string.hypo))) } - R.id.cancel -> { + R.id.cancel -> { binding.duration.value = 0.0 } } @@ -181,18 +181,18 @@ class TempTargetDialog : DialogFragmentWithDate() { OKDialog.showConfirmation(activity, resourceHelper.gs(R.string.careportal_temporarytarget), HtmlHelper.fromHtml(Joiner.on("
").join(actions)), { val units = profileFunction.getUnits() when(reason) { - resourceHelper.gs(R.string.eatingsoon) -> uel.log(Action.TT, ValueWithUnit(eventTime, Units.Timestamp, eventTimeChanged), ValueWithUnit(TemporaryTarget.Reason.EATING_SOON.text, Units.TherapyEvent), ValueWithUnit(target, units), ValueWithUnit(duration, Units.M)) - resourceHelper.gs(R.string.activity) -> uel.log(Action.TT, ValueWithUnit(eventTime, Units.Timestamp, eventTimeChanged), ValueWithUnit(TemporaryTarget.Reason.ACTIVITY.text, Units.TherapyEvent), ValueWithUnit(target, units), ValueWithUnit(duration, Units.M)) - resourceHelper.gs(R.string.hypo) -> uel.log(Action.TT, ValueWithUnit(eventTime, Units.Timestamp, eventTimeChanged), ValueWithUnit(TemporaryTarget.Reason.HYPOGLYCEMIA.text, Units.TherapyEvent), ValueWithUnit(target, units), ValueWithUnit(duration, Units.M)) - resourceHelper.gs(R.string.manual) -> uel.log(Action.TT, ValueWithUnit(eventTime, Units.Timestamp, eventTimeChanged), ValueWithUnit(TemporaryTarget.Reason.CUSTOM.text, Units.TherapyEvent), ValueWithUnit(target, units), ValueWithUnit(duration, Units.M)) - resourceHelper.gs(R.string.stoptemptarget) -> uel.log(Action.CANCEL_TT, ValueWithUnit(eventTime, Units.Timestamp, eventTimeChanged)) + resourceHelper.gs(R.string.eatingsoon) -> uel.log(Action.TT, Sources.TTDialog, ValueWithUnit.Timestamp(eventTime).takeIf { eventTimeChanged }, ValueWithUnit.TherapyEventTTReason(TemporaryTarget.Reason.EATING_SOON), ValueWithUnit.fromGlucoseUnit(target, units), ValueWithUnit.Minute(duration)) + resourceHelper.gs(R.string.activity) -> uel.log(Action.TT, Sources.TTDialog, ValueWithUnit.Timestamp(eventTime).takeIf { eventTimeChanged }, ValueWithUnit.TherapyEventTTReason(TemporaryTarget.Reason.ACTIVITY), ValueWithUnit.fromGlucoseUnit(target, units), ValueWithUnit.Minute(duration)) + resourceHelper.gs(R.string.hypo) -> uel.log(Action.TT, Sources.TTDialog, ValueWithUnit.Timestamp(eventTime).takeIf { eventTimeChanged }, ValueWithUnit.TherapyEventTTReason(TemporaryTarget.Reason.HYPOGLYCEMIA), ValueWithUnit.fromGlucoseUnit(target, units), ValueWithUnit.Minute(duration)) + resourceHelper.gs(R.string.manual) -> uel.log(Action.TT, Sources.TTDialog, ValueWithUnit.Timestamp(eventTime).takeIf { eventTimeChanged }, ValueWithUnit.TherapyEventTTReason(TemporaryTarget.Reason.CUSTOM), ValueWithUnit.fromGlucoseUnit(target, units), ValueWithUnit.Minute(duration)) + resourceHelper.gs(R.string.stoptemptarget) -> uel.log(Action.CANCEL_TT, Sources.TTDialog, ValueWithUnit.Timestamp(eventTime).takeIf { eventTimeChanged }) } if (target == 0.0 || duration == 0) { disposable += repository.runTransactionForResult(CancelCurrentTemporaryTargetIfAnyTransaction(eventTime)) .subscribe({ result -> - result.updated.forEach { nsUpload.updateTempTarget(it) } + result.updated.forEach { aapsLogger.debug(LTag.DATABASE, "Updated temp target $it") } }, { - aapsLogger.error(LTag.BGSOURCE, "Error while saving temporary target", it) + aapsLogger.error(LTag.DATABASE, "Error while saving temporary target", it) }) } else { disposable += repository.runTransactionForResult(InsertTemporaryTargetAndCancelCurrentTransaction( @@ -200,17 +200,17 @@ class TempTargetDialog : DialogFragmentWithDate() { duration = TimeUnit.MINUTES.toMillis(duration.toLong()), reason = when (reason) { resourceHelper.gs(R.string.eatingsoon) -> TemporaryTarget.Reason.EATING_SOON - resourceHelper.gs(R.string.activity) -> TemporaryTarget.Reason.ACTIVITY - resourceHelper.gs(R.string.hypo) -> TemporaryTarget.Reason.HYPOGLYCEMIA - else -> TemporaryTarget.Reason.CUSTOM + resourceHelper.gs(R.string.activity) -> TemporaryTarget.Reason.ACTIVITY + resourceHelper.gs(R.string.hypo) -> TemporaryTarget.Reason.HYPOGLYCEMIA + else -> TemporaryTarget.Reason.CUSTOM }, lowTarget = Profile.toMgdl(target, profileFunction.getUnits()), highTarget = Profile.toMgdl(target, profileFunction.getUnits()) )).subscribe({ result -> - result.inserted.forEach { nsUpload.uploadTempTarget(it) } - result.updated.forEach { nsUpload.updateTempTarget(it) } + result.inserted.forEach { aapsLogger.debug(LTag.DATABASE, "Inserted temp target $it") } + result.updated.forEach { aapsLogger.debug(LTag.DATABASE, "Updated temp target $it") } }, { - aapsLogger.error(LTag.BGSOURCE, "Error while saving temporary target", it) + aapsLogger.error(LTag.DATABASE, "Error while saving temporary target", it) }) } diff --git a/app/src/main/java/info/nightscout/androidaps/dialogs/TreatmentDialog.kt b/app/src/main/java/info/nightscout/androidaps/dialogs/TreatmentDialog.kt index 5f421134a3..a76863bce2 100644 --- a/app/src/main/java/info/nightscout/androidaps/dialogs/TreatmentDialog.kt +++ b/app/src/main/java/info/nightscout/androidaps/dialogs/TreatmentDialog.kt @@ -8,17 +8,19 @@ import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import com.google.common.base.Joiner -import info.nightscout.androidaps.Config +import info.nightscout.androidaps.interfaces.Config import info.nightscout.androidaps.R import info.nightscout.androidaps.activities.ErrorHelperActivity import info.nightscout.androidaps.data.DetailedBolusInfo -import info.nightscout.androidaps.database.entities.TherapyEvent -import info.nightscout.androidaps.database.entities.UserEntry.* +import info.nightscout.androidaps.database.AppRepository +import info.nightscout.androidaps.database.entities.ValueWithUnit +import info.nightscout.androidaps.database.entities.UserEntry.Action +import info.nightscout.androidaps.database.entities.UserEntry.Sources import info.nightscout.androidaps.databinding.DialogTreatmentBinding -import info.nightscout.androidaps.db.Source -import info.nightscout.androidaps.interfaces.ActivePluginProvider +import info.nightscout.androidaps.interfaces.ActivePlugin import info.nightscout.androidaps.interfaces.CommandQueueProvider import info.nightscout.androidaps.interfaces.Constraint +import info.nightscout.androidaps.logging.LTag import info.nightscout.androidaps.logging.UserEntryLogger import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker import info.nightscout.androidaps.queue.Callback @@ -27,8 +29,10 @@ import info.nightscout.androidaps.utils.HtmlHelper import info.nightscout.androidaps.utils.SafeParse import info.nightscout.androidaps.utils.ToastUtils import info.nightscout.androidaps.utils.alertDialogs.OKDialog -import info.nightscout.androidaps.utils.extensions.formatColor +import info.nightscout.androidaps.extensions.formatColor import info.nightscout.androidaps.utils.resources.ResourceHelper +import io.reactivex.disposables.CompositeDisposable +import io.reactivex.rxkotlin.plusAssign import java.text.DecimalFormat import java.util.* import javax.inject.Inject @@ -38,11 +42,14 @@ class TreatmentDialog : DialogFragmentWithDate() { @Inject lateinit var constraintChecker: ConstraintChecker @Inject lateinit var resourceHelper: ResourceHelper - @Inject lateinit var activePlugin: ActivePluginProvider + @Inject lateinit var activePlugin: ActivePlugin @Inject lateinit var commandQueue: CommandQueueProvider @Inject lateinit var ctx: Context @Inject lateinit var config: Config @Inject lateinit var uel: UserEntryLogger + @Inject lateinit var repository: AppRepository + + private val disposable = CompositeDisposable() private val textWatcher: TextWatcher = object : TextWatcher { override fun afterTextChanged(s: Editable) {} @@ -130,24 +137,51 @@ class TreatmentDialog : DialogFragmentWithDate() { if (insulinAfterConstraints > 0 || carbsAfterConstraints > 0) { activity?.let { activity -> OKDialog.showConfirmation(activity, resourceHelper.gs(R.string.overview_treatment_label), HtmlHelper.fromHtml(Joiner.on("
").join(actions)), { - uel.log(Action.TREATMENT, ValueWithUnit(insulin, Units.U, insulin != 0.0), ValueWithUnit(carbs, Units.G, carbs != 0)) + val action = when { + insulinAfterConstraints.equals(0.0) -> Action.CARBS + carbsAfterConstraints.equals(0) -> Action.BOLUS + else -> Action.TREATMENT + } val detailedBolusInfo = DetailedBolusInfo() - if (insulinAfterConstraints == 0.0) detailedBolusInfo.eventType = TherapyEvent.Type.CARBS_CORRECTION.text - if (carbsAfterConstraints == 0) detailedBolusInfo.eventType = TherapyEvent.Type.CORRECTION_BOLUS.text + if (insulinAfterConstraints == 0.0) detailedBolusInfo.eventType = DetailedBolusInfo.EventType.CARBS_CORRECTION + if (carbsAfterConstraints == 0) detailedBolusInfo.eventType = DetailedBolusInfo.EventType.CORRECTION_BOLUS detailedBolusInfo.insulin = insulinAfterConstraints detailedBolusInfo.carbs = carbsAfterConstraints.toDouble() detailedBolusInfo.context = context - detailedBolusInfo.source = Source.USER - if (!(recordOnlyChecked && (detailedBolusInfo.insulin > 0 || pumpDescription.storesCarbInfo))) { - commandQueue.bolus(detailedBolusInfo, object : Callback() { - override fun run() { - if (!result.success) { - ErrorHelperActivity.runAlarm(ctx, result.comment, resourceHelper.gs(R.string.treatmentdeliveryerror), info.nightscout.androidaps.dana.R.raw.boluserror) + if (recordOnlyChecked) { + uel.log(action, Sources.TreatmentDialog, if (insulinAfterConstraints != 0.0) resourceHelper.gs(R.string.record) else "", + ValueWithUnit.Timestamp(detailedBolusInfo.timestamp).takeIf { eventTimeChanged }, + ValueWithUnit.SimpleString(resourceHelper.gsNotLocalised(R.string.record)).takeIf { insulinAfterConstraints != 0.0 }, + ValueWithUnit.Insulin(insulinAfterConstraints).takeIf { insulinAfterConstraints != 0.0 }, + ValueWithUnit.Gram(carbsAfterConstraints).takeIf { carbsAfterConstraints != 0 }) + if (detailedBolusInfo.insulin > 0) + disposable += repository.runTransactionForResult(detailedBolusInfo.insertBolusTransaction()) + .subscribe( + { result -> result.inserted.forEach { aapsLogger.debug(LTag.DATABASE, "Inserted bolus $it") } }, + { aapsLogger.error(LTag.DATABASE, "Error while saving bolus", it) } + ) + if (detailedBolusInfo.carbs > 0) + disposable += repository.runTransactionForResult(detailedBolusInfo.insertCarbsTransaction()) + .subscribe( + { result -> result.inserted.forEach { aapsLogger.debug(LTag.DATABASE, "Inserted carbs $it") } }, + { aapsLogger.error(LTag.DATABASE, "Error while saving carbs", it) } + ) + } else { + if (detailedBolusInfo.insulin > 0) { + uel.log(action, Sources.TreatmentDialog, + ValueWithUnit.Insulin(insulinAfterConstraints), + ValueWithUnit.Gram(carbsAfterConstraints).takeIf { carbsAfterConstraints != 0 }) + commandQueue.bolus(detailedBolusInfo, object : Callback() { + override fun run() { + if (!result.success) { + ErrorHelperActivity.runAlarm(ctx, result.comment, resourceHelper.gs(R.string.treatmentdeliveryerror), info.nightscout.androidaps.dana.R.raw.boluserror) + } } - } - }) - } else - activePlugin.activeTreatments.addToHistoryTreatment(detailedBolusInfo, false) + }) + } else + uel.log(action, Sources.TreatmentDialog, + ValueWithUnit.Gram(carbsAfterConstraints).takeIf { carbs != 0 }) + } }) } } else diff --git a/app/src/main/java/info/nightscout/androidaps/dialogs/WizardDialog.kt b/app/src/main/java/info/nightscout/androidaps/dialogs/WizardDialog.kt index 4b4744e6ea..1c97bf0edc 100644 --- a/app/src/main/java/info/nightscout/androidaps/dialogs/WizardDialog.kt +++ b/app/src/main/java/info/nightscout/androidaps/dialogs/WizardDialog.kt @@ -1,5 +1,6 @@ package info.nightscout.androidaps.dialogs +import android.content.Context import android.os.Bundle import android.text.Editable import android.text.TextWatcher @@ -16,25 +17,27 @@ import androidx.fragment.app.FragmentManager import dagger.android.HasAndroidInjector import dagger.android.support.DaggerDialogFragment import info.nightscout.androidaps.Constants -import info.nightscout.androidaps.MainApp import info.nightscout.androidaps.R import info.nightscout.androidaps.data.Profile import info.nightscout.androidaps.database.AppRepository import info.nightscout.androidaps.database.ValueWrapper import info.nightscout.androidaps.databinding.DialogWizardBinding import info.nightscout.androidaps.events.EventAutosensCalculationFinished -import info.nightscout.androidaps.interfaces.ActivePluginProvider +import info.nightscout.androidaps.interfaces.ActivePlugin import info.nightscout.androidaps.interfaces.Constraint +import info.nightscout.androidaps.interfaces.IobCobCalculator import info.nightscout.androidaps.interfaces.ProfileFunction -import info.nightscout.androidaps.interfaces.TreatmentsInterface import info.nightscout.androidaps.logging.AAPSLogger import info.nightscout.androidaps.logging.LTag import info.nightscout.androidaps.plugins.bus.RxBusWrapper import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker -import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorPlugin -import info.nightscout.androidaps.utils.* -import info.nightscout.androidaps.utils.extensions.toVisibility -import info.nightscout.androidaps.utils.extensions.valueToUnits +import info.nightscout.androidaps.utils.DateUtil +import info.nightscout.androidaps.utils.DecimalFormatter +import info.nightscout.androidaps.utils.FabricPrivacy +import info.nightscout.androidaps.utils.SafeParse +import info.nightscout.androidaps.utils.ToastUtils +import info.nightscout.androidaps.extensions.toVisibility +import info.nightscout.androidaps.extensions.valueToUnits import info.nightscout.androidaps.utils.resources.ResourceHelper import info.nightscout.androidaps.utils.rx.AapsSchedulers import info.nightscout.androidaps.utils.sharedPreferences.SP @@ -51,16 +54,15 @@ class WizardDialog : DaggerDialogFragment() { @Inject lateinit var aapsLogger: AAPSLogger @Inject lateinit var aapsSchedulers: AapsSchedulers @Inject lateinit var constraintChecker: ConstraintChecker - @Inject lateinit var mainApp: MainApp + @Inject lateinit var ctx: Context @Inject lateinit var sp: SP @Inject lateinit var rxBus: RxBusWrapper @Inject lateinit var fabricPrivacy: FabricPrivacy @Inject lateinit var resourceHelper: ResourceHelper @Inject lateinit var profileFunction: ProfileFunction - @Inject lateinit var activePlugin: ActivePluginProvider - @Inject lateinit var iobCobCalculatorPlugin: IobCobCalculatorPlugin + @Inject lateinit var activePlugin: ActivePlugin + @Inject lateinit var iobCobCalculator: IobCobCalculator @Inject lateinit var repository: AppRepository - @Inject lateinit var treatmentsPlugin: TreatmentsInterface @Inject lateinit var dateUtil: DateUtil private var wizard: BolusWizard? = null @@ -180,7 +182,7 @@ class WizardDialog : DaggerDialogFragment() { // profile spinner binding.profile.onItemSelectedListener = object : OnItemSelectedListener { override fun onNothingSelected(parent: AdapterView<*>?) { - ToastUtils.showToastInUiThread(mainApp, resourceHelper.gs(R.string.noprofileselected)) + ToastUtils.showToastInUiThread(ctx, resourceHelper.gs(R.string.noprofileselected)) binding.ok.visibility = View.GONE } @@ -208,7 +210,7 @@ class WizardDialog : DaggerDialogFragment() { private fun onCheckedChanged(buttonView: CompoundButton, @Suppress("UNUSED_PARAMETER") state: Boolean) { saveCheckedStates() - binding.ttcheckbox.isEnabled = binding.bgcheckbox.isChecked && repository.getTemporaryTargetActiveAt(dateUtil._now()).blockingGet() is ValueWrapper.Existing + binding.ttcheckbox.isEnabled = binding.bgcheckbox.isChecked && repository.getTemporaryTargetActiveAt(dateUtil.now()).blockingGet() is ValueWrapper.Existing if (buttonView.id == binding.cobcheckbox.id) processCobCheckBox() calculateInsulin() @@ -242,10 +244,10 @@ class WizardDialog : DaggerDialogFragment() { private fun initDialog() { val profile = profileFunction.getProfile() - val profileStore = activePlugin.activeProfileInterface.profile + val profileStore = activePlugin.activeProfileSource.profile if (profile == null || profileStore == null) { - ToastUtils.showToastInUiThread(mainApp, resourceHelper.gs(R.string.noprofile)) + ToastUtils.showToastInUiThread(ctx, resourceHelper.gs(R.string.noprofile)) dismiss() return } @@ -265,20 +267,12 @@ class WizardDialog : DaggerDialogFragment() { binding.bgInput.setStep(0.1) // Set BG if not old - val lastBg = iobCobCalculatorPlugin.actualBg() - - if (lastBg != null) { - binding.bgInput.value = lastBg.valueToUnits(units) - } else { - binding.bgInput.value = 0.0 - } - binding.ttcheckbox.isEnabled = repository.getTemporaryTargetActiveAt(dateUtil._now()).blockingGet() is ValueWrapper.Existing + binding.bgInput.value = iobCobCalculator.ads.actualBg()?.valueToUnits(units) ?: 0.0 + binding.ttcheckbox.isEnabled = repository.getTemporaryTargetActiveAt(dateUtil.now()).blockingGet() is ValueWrapper.Existing // IOB calculation - treatmentsPlugin.updateTotalIOBTreatments() - val bolusIob = treatmentsPlugin.lastCalculationTreatments.round() - treatmentsPlugin.updateTotalIOBTempBasals() - val basalIob = treatmentsPlugin.lastCalculationTempBasals.round() + val bolusIob = iobCobCalculator.calculateIobFromBolus().round() + val basalIob = iobCobCalculator.calculateIobFromTempBasalsIncludingConvertedExtended().round() binding.bolusiobinsulin.text = resourceHelper.gs(R.string.formatinsulinunits, -bolusIob.iob) binding.basaliobinsulin.text = resourceHelper.gs(R.string.formatinsulinunits, -basalIob.basaliob) @@ -289,7 +283,7 @@ class WizardDialog : DaggerDialogFragment() { } private fun calculateInsulin() { - val profileStore = activePlugin.activeProfileInterface.profile + val profileStore = activePlugin.activeProfileSource.profile if (binding.profile.selectedItem == null || profileStore == null) return // not initialized yet var profileName = binding.profile.selectedItem.toString() @@ -309,25 +303,25 @@ class WizardDialog : DaggerDialogFragment() { val carbsAfterConstraint = constraintChecker.applyCarbsConstraints(Constraint(carbs)).value() if (abs(carbs - carbsAfterConstraint) > 0.01) { binding.carbsInput.value = 0.0 - ToastUtils.showToastInUiThread(mainApp, resourceHelper.gs(R.string.carbsconstraintapplied)) + ToastUtils.showToastInUiThread(ctx, resourceHelper.gs(R.string.carbsconstraintapplied)) return } bg = if (binding.bgcheckbox.isChecked) bg else 0.0 - val dbRecord = repository.getTemporaryTargetActiveAt(dateUtil._now()).blockingGet() + val dbRecord = repository.getTemporaryTargetActiveAt(dateUtil.now()).blockingGet() val tempTarget = if (binding.ttcheckbox.isChecked && dbRecord is ValueWrapper.Existing) dbRecord.value else null // COB var cob = 0.0 if (binding.cobcheckbox.isChecked) { - val cobInfo = iobCobCalculatorPlugin.getCobInfo(false, "Wizard COB") + val cobInfo = iobCobCalculator.getCobInfo(false, "Wizard COB") cobInfo.displayCob?.let { cob = it } } val carbTime = SafeParse.stringToInt(binding.carbTimeInput.text) - wizard = BolusWizard(mainApp).doCalc(specificProfile, profileName, tempTarget, carbsAfterConstraint, cob, bg, correction, - sp.getInt(R.string.key_boluswizard_percentage, 100).toDouble(), + wizard = BolusWizard(injector).doCalc(specificProfile, profileName, tempTarget, carbsAfterConstraint, cob, bg, correction, + sp.getInt(R.string.key_boluswizard_percentage, 100), binding.bgcheckbox.isChecked, binding.cobcheckbox.isChecked, binding.bolusiobcheckbox.isChecked, diff --git a/app/src/main/java/info/nightscout/androidaps/dialogs/WizardInfoDialog.kt b/app/src/main/java/info/nightscout/androidaps/dialogs/WizardInfoDialog.kt index aa76bde8c3..2ef57d940d 100644 --- a/app/src/main/java/info/nightscout/androidaps/dialogs/WizardInfoDialog.kt +++ b/app/src/main/java/info/nightscout/androidaps/dialogs/WizardInfoDialog.kt @@ -9,12 +9,12 @@ import android.view.WindowManager import dagger.android.support.DaggerDialogFragment import info.nightscout.androidaps.Constants import info.nightscout.androidaps.R +import info.nightscout.androidaps.data.Profile +import info.nightscout.androidaps.database.entities.BolusCalculatorResult import info.nightscout.androidaps.databinding.DialogWizardinfoBinding import info.nightscout.androidaps.interfaces.ProfileFunction import info.nightscout.androidaps.utils.DecimalFormatter -import info.nightscout.androidaps.utils.JsonHelper import info.nightscout.androidaps.utils.resources.ResourceHelper -import org.json.JSONObject import javax.inject.Inject class WizardInfoDialog : DaggerDialogFragment() { @@ -22,10 +22,10 @@ class WizardInfoDialog : DaggerDialogFragment() { @Inject lateinit var resourceHelper: ResourceHelper @Inject lateinit var profileFunction: ProfileFunction - private var json: JSONObject? = null + private lateinit var data: BolusCalculatorResult - fun setData(json: JSONObject) { - this.json = json + fun setData(bolusCalculatorResult: BolusCalculatorResult) { + this.data = bolusCalculatorResult } private var _binding: DialogWizardinfoBinding? = null @@ -49,44 +49,42 @@ class WizardInfoDialog : DaggerDialogFragment() { binding.close.setOnClickListener { dismiss() } val units = profileFunction.getUnits() - val bgString = - if (units == Constants.MGDL) DecimalFormatter.to0Decimal(JsonHelper.safeGetDouble(json, "bg")) - else DecimalFormatter.to1Decimal(JsonHelper.safeGetDouble(json, "bg")) + val bgString = Profile.toUnitsString(data.glucoseValue, data.glucoseValue * Constants.MGDL_TO_MMOLL, units) // BG - binding.bg.text = resourceHelper.gs(R.string.format_bg_isf, bgString, JsonHelper.safeGetDouble(json, "isf")) - binding.bginsulin.text = resourceHelper.gs(R.string.formatinsulinunits, JsonHelper.safeGetDouble(json, "insulinbg")) - binding.bgcheckbox.isChecked = JsonHelper.safeGetBoolean(json, "insulinbgused") - binding.ttcheckbox.isChecked = JsonHelper.safeGetBoolean(json, "ttused") + binding.bg.text = resourceHelper.gs(R.string.format_bg_isf, bgString, data.isf) + binding.bginsulin.text = resourceHelper.gs(R.string.formatinsulinunits, data.glucoseInsulin) + binding.bgcheckbox.isChecked = data.wasGlucoseUsed + binding.ttcheckbox.isChecked = data.wasTempTargetUsed // Trend - binding.bgtrend.text = JsonHelper.safeGetString(json, "trend") - binding.bgtrendinsulin.text = resourceHelper.gs(R.string.formatinsulinunits, JsonHelper.safeGetDouble(json, "insulintrend")) - binding.bgtrendcheckbox.isChecked = JsonHelper.safeGetBoolean(json, "trendused") + binding.bgtrend.text = DecimalFormatter.to1Decimal(data.glucoseTrend) + binding.bgtrendinsulin.text = resourceHelper.gs(R.string.formatinsulinunits, data.trendInsulin) + binding.bgtrendcheckbox.isChecked = data.wasTrendUsed // COB - binding.cob.text = resourceHelper.gs(R.string.format_cob_ic, JsonHelper.safeGetDouble(json, "cob"), JsonHelper.safeGetDouble(json, "ic")) - binding.cobinsulin.text = resourceHelper.gs(R.string.formatinsulinunits, JsonHelper.safeGetDouble(json, "insulincob")) - binding.cobcheckbox.isChecked = JsonHelper.safeGetBoolean(json, "cobused") + binding.cob.text = resourceHelper.gs(R.string.format_cob_ic, data.cob, data.ic) + binding.cobinsulin.text = resourceHelper.gs(R.string.formatinsulinunits, data.cobInsulin) + binding.cobcheckbox.isChecked = data.wasCOBUsed // Bolus IOB - binding.bolusiobinsulin.text = resourceHelper.gs(R.string.formatinsulinunits, JsonHelper.safeGetDouble(json, "bolusiob")) - binding.bolusiobcheckbox.isChecked = JsonHelper.safeGetBoolean(json, "bolusiobused") + binding.bolusiobinsulin.text = resourceHelper.gs(R.string.formatinsulinunits, data.bolusIOB) + binding.bolusiobcheckbox.isChecked = data.wasBolusIOBUsed // Basal IOB - binding.basaliobinsulin.text = resourceHelper.gs(R.string.formatinsulinunits, JsonHelper.safeGetDouble(json, "basaliob")) - binding.basaliobcheckbox.isChecked = JsonHelper.safeGetBoolean(json, "basaliobused") + binding.basaliobinsulin.text = resourceHelper.gs(R.string.formatinsulinunits, data.basalIOB) + binding.basaliobcheckbox.isChecked = data.wasBasalIOBUsed // Superbolus - binding.sbinsulin.text = resourceHelper.gs(R.string.formatinsulinunits, JsonHelper.safeGetDouble(json, "insulinsuperbolus")) - binding.sbcheckbox.isChecked = JsonHelper.safeGetBoolean(json, "superbolusused") + binding.sbinsulin.text = resourceHelper.gs(R.string.formatinsulinunits, data.superbolusInsulin) + binding.sbcheckbox.isChecked = data.wasSuperbolusUsed // Carbs - binding.carbs.text = resourceHelper.gs(R.string.format_carbs_ic, JsonHelper.safeGetDouble(json, "carbs"), JsonHelper.safeGetDouble(json, "ic")) - binding.carbsinsulin.text = resourceHelper.gs(R.string.formatinsulinunits, JsonHelper.safeGetDouble(json, "insulincarbs")) + binding.carbs.text = resourceHelper.gs(R.string.format_carbs_ic, data.carbs, data.ic) + binding.carbsinsulin.text = resourceHelper.gs(R.string.formatinsulinunits, data.carbsInsulin) // Correction - binding.correctioninsulin.text = resourceHelper.gs(R.string.formatinsulinunits, JsonHelper.safeGetDouble(json, "othercorrection")) + binding.correctioninsulin.text = resourceHelper.gs(R.string.formatinsulinunits, data.otherCorrection) // Profile - binding.profile.text = JsonHelper.safeGetString(json, "profile") + binding.profile.text = data.profileName // Notes - binding.notes.text = JsonHelper.safeGetString(json, "notes") + binding.notes.text = data.note // Percentage - binding.percentUsed.text = resourceHelper.gs(R.string.format_percent, (JsonHelper.safeGetInt(json, "percentageCorrection", 100))) + binding.percentUsed.text = resourceHelper.gs(R.string.format_percent, data.percentageCorrection) // Total - binding.totalinsulin.text = resourceHelper.gs(R.string.formatinsulinunits, JsonHelper.safeGetDouble(json, "insulin")) + binding.totalinsulin.text = resourceHelper.gs(R.string.formatinsulinunits, data.totalInsulin) } override fun onStart() { diff --git a/app/src/main/java/info/nightscout/androidaps/events/EventNsTreatment.kt b/app/src/main/java/info/nightscout/androidaps/events/EventNsTreatment.kt deleted file mode 100644 index 149894c221..0000000000 --- a/app/src/main/java/info/nightscout/androidaps/events/EventNsTreatment.kt +++ /dev/null @@ -1,21 +0,0 @@ -package info.nightscout.androidaps.events - -import org.json.JSONObject - - -/** - * Event which is published with data fetched from NightScout specific for the - * Treatment-class. - * - * - * Payload is the from NS retrieved JSON-String which should be handled by all - * subscriber. - */ - -class EventNsTreatment(val mode: Int, val payload: JSONObject) : Event() { - companion object { - val ADD = 0 - val UPDATE = 1 - val REMOVE = 2 - } -} diff --git a/app/src/main/java/info/nightscout/androidaps/events/EventReloadTempBasalData.kt b/app/src/main/java/info/nightscout/androidaps/events/EventReloadTempBasalData.kt deleted file mode 100644 index fa8f720896..0000000000 --- a/app/src/main/java/info/nightscout/androidaps/events/EventReloadTempBasalData.kt +++ /dev/null @@ -1,3 +0,0 @@ -package info.nightscout.androidaps.events - -class EventReloadTempBasalData : Event() diff --git a/app/src/main/java/info/nightscout/androidaps/events/EventReloadTreatmentData.kt b/app/src/main/java/info/nightscout/androidaps/events/EventReloadTreatmentData.kt deleted file mode 100644 index 1f8b2938b9..0000000000 --- a/app/src/main/java/info/nightscout/androidaps/events/EventReloadTreatmentData.kt +++ /dev/null @@ -1,3 +0,0 @@ -package info.nightscout.androidaps.events - -class EventReloadTreatmentData(var next: Event) : Event() diff --git a/app/src/main/java/info/nightscout/androidaps/events/EventTreatmentChange.kt b/app/src/main/java/info/nightscout/androidaps/events/EventTreatmentChange.kt index 679b62ee30..2f25231b00 100644 --- a/app/src/main/java/info/nightscout/androidaps/events/EventTreatmentChange.kt +++ b/app/src/main/java/info/nightscout/androidaps/events/EventTreatmentChange.kt @@ -1,5 +1,3 @@ package info.nightscout.androidaps.events -import info.nightscout.androidaps.db.Treatment - -class EventTreatmentChange(val treatment: Treatment?) : EventLoop() +class EventTreatmentChange : EventLoop() diff --git a/app/src/main/java/info/nightscout/androidaps/historyBrowser/HistoryBrowseActivity.kt b/app/src/main/java/info/nightscout/androidaps/historyBrowser/HistoryBrowseActivity.kt index 8ee346247e..144b62f6fa 100644 --- a/app/src/main/java/info/nightscout/androidaps/historyBrowser/HistoryBrowseActivity.kt +++ b/app/src/main/java/info/nightscout/androidaps/historyBrowser/HistoryBrowseActivity.kt @@ -16,14 +16,13 @@ import info.nightscout.androidaps.activities.NoSplashAppCompatActivity import info.nightscout.androidaps.databinding.ActivityHistorybrowseBinding import info.nightscout.androidaps.events.EventCustomCalculationFinished import info.nightscout.androidaps.events.EventRefreshOverview -import info.nightscout.androidaps.interfaces.ActivePluginProvider +import info.nightscout.androidaps.interfaces.ActivePlugin import info.nightscout.androidaps.interfaces.ProfileFunction import info.nightscout.androidaps.logging.AAPSLogger import info.nightscout.androidaps.logging.LTag import info.nightscout.androidaps.plugins.bus.RxBusWrapper import info.nightscout.androidaps.plugins.general.overview.OverviewMenus import info.nightscout.androidaps.plugins.general.overview.graphData.GraphData -import info.nightscout.androidaps.plugins.iob.iobCobCalculator.events.EventAutosensBgLoaded import info.nightscout.androidaps.events.EventAutosensCalculationFinished import info.nightscout.androidaps.plugins.iob.iobCobCalculator.events.EventIobCalculationProgress import info.nightscout.androidaps.utils.DateUtil @@ -31,7 +30,7 @@ import info.nightscout.androidaps.utils.DefaultValueHelper import info.nightscout.androidaps.utils.FabricPrivacy import info.nightscout.androidaps.utils.T import info.nightscout.androidaps.utils.buildHelper.BuildHelper -import info.nightscout.androidaps.utils.extensions.toVisibility +import info.nightscout.androidaps.extensions.toVisibility import info.nightscout.androidaps.utils.rx.AapsSchedulers import info.nightscout.androidaps.utils.sharedPreferences.SP import io.reactivex.disposables.CompositeDisposable @@ -52,7 +51,7 @@ class HistoryBrowseActivity : NoSplashAppCompatActivity() { @Inject lateinit var defaultValueHelper: DefaultValueHelper @Inject lateinit var iobCobCalculatorPluginHistory: IobCobCalculatorPluginHistory @Inject lateinit var treatmentsPluginHistory: TreatmentsPluginHistory - @Inject lateinit var activePlugin: ActivePluginProvider + @Inject lateinit var activePlugin: ActivePlugin @Inject lateinit var buildHelper: BuildHelper @Inject lateinit var fabricPrivacy: FabricPrivacy @Inject lateinit var overviewMenus: OverviewMenus @@ -181,16 +180,6 @@ class HistoryBrowseActivity : NoSplashAppCompatActivity() { } }, fabricPrivacy::logException) ) - disposable.add(rxBus - .toObservable(EventAutosensBgLoaded::class.java) - .observeOn(aapsSchedulers.io) - .subscribe({ - // catch only events from iobCobCalculatorPluginHistory - if (it.cause is EventCustomCalculationFinished) { - updateGUI("EventAutosensCalculationFinished", bgOnly = true) - } - }, fabricPrivacy::logException) - ) disposable.add(rxBus .toObservable(EventIobCalculationProgress::class.java) .observeOn(aapsSchedulers.main) @@ -306,7 +295,8 @@ class HistoryBrowseActivity : NoSplashAppCompatActivity() { graphData.addInRangeArea(fromTime, toTime, lowLine, highLine) // **** BG **** - graphData.addBgReadings(fromTime, toTime, lowLine, highLine, null) + graphData.addBgReadings(fromTime, toTime, highLine, null) + if (buildHelper.isDev()) graphData.addBucketedData(fromTime, toTime) // add target line graphData.addTargetLine(fromTime, toTime, profile, null) diff --git a/app/src/main/java/info/nightscout/androidaps/historyBrowser/IobCobCalculatorPluginHistory.kt b/app/src/main/java/info/nightscout/androidaps/historyBrowser/IobCobCalculatorPluginHistory.kt index 8dc1ebfb32..1dfc35f70a 100644 --- a/app/src/main/java/info/nightscout/androidaps/historyBrowser/IobCobCalculatorPluginHistory.kt +++ b/app/src/main/java/info/nightscout/androidaps/historyBrowser/IobCobCalculatorPluginHistory.kt @@ -2,7 +2,7 @@ package info.nightscout.androidaps.historyBrowser import dagger.android.HasAndroidInjector import info.nightscout.androidaps.database.AppRepository -import info.nightscout.androidaps.interfaces.ActivePluginProvider +import info.nightscout.androidaps.interfaces.ActivePlugin import info.nightscout.androidaps.interfaces.ProfileFunction import info.nightscout.androidaps.logging.AAPSLogger import info.nightscout.androidaps.plugins.bus.RxBusWrapper @@ -27,8 +27,7 @@ class IobCobCalculatorPluginHistory @Inject constructor( sp: SP, resourceHelper: ResourceHelper, profileFunction: ProfileFunction, - activePlugin: ActivePluginProvider, - treatmentsPluginHistory: TreatmentsPluginHistory, + activePlugin: ActivePlugin, sensitivityOref1Plugin: SensitivityOref1Plugin, sensitivityAAPSPlugin: SensitivityAAPSPlugin, sensitivityWeightedAveragePlugin: SensitivityWeightedAveragePlugin, @@ -36,7 +35,7 @@ class IobCobCalculatorPluginHistory @Inject constructor( dateUtil: DateUtil, repository: AppRepository ) : IobCobCalculatorPlugin(injector, aapsLogger, aapsSchedulers, rxBus, sp, resourceHelper, profileFunction, - activePlugin, treatmentsPluginHistory, sensitivityOref1Plugin, sensitivityAAPSPlugin, sensitivityWeightedAveragePlugin, fabricPrivacy, dateUtil, repository) { + activePlugin, sensitivityOref1Plugin, sensitivityAAPSPlugin, sensitivityWeightedAveragePlugin, fabricPrivacy, dateUtil, repository) { override fun onStart() { // do not attach to rxbus } diff --git a/app/src/main/java/info/nightscout/androidaps/historyBrowser/TreatmentsPluginHistory.kt b/app/src/main/java/info/nightscout/androidaps/historyBrowser/TreatmentsPluginHistory.kt index 4b003538b3..c1fe715abe 100644 --- a/app/src/main/java/info/nightscout/androidaps/historyBrowser/TreatmentsPluginHistory.kt +++ b/app/src/main/java/info/nightscout/androidaps/historyBrowser/TreatmentsPluginHistory.kt @@ -3,10 +3,9 @@ package info.nightscout.androidaps.historyBrowser import android.content.Context import dagger.android.HasAndroidInjector import info.nightscout.androidaps.database.AppRepository -import info.nightscout.androidaps.interfaces.ActivePluginProvider +import info.nightscout.androidaps.interfaces.ActivePlugin import info.nightscout.androidaps.interfaces.DatabaseHelperInterface import info.nightscout.androidaps.interfaces.ProfileFunction -import info.nightscout.androidaps.interfaces.UploadQueueInterface import info.nightscout.androidaps.logging.AAPSLogger import info.nightscout.androidaps.plugins.bus.RxBusWrapper import info.nightscout.androidaps.plugins.general.nsclient.NSUpload @@ -30,14 +29,13 @@ class TreatmentsPluginHistory @Inject constructor( context: Context, sp: SP, profileFunction: ProfileFunction, - activePlugin: ActivePluginProvider, + activePlugin: ActivePlugin, nsUpload: NSUpload, fabricPrivacy: FabricPrivacy, dateUtil: DateUtil, - uploadQueue: UploadQueueInterface, databaseHelper: DatabaseHelperInterface, repository: AppRepository -) : TreatmentsPlugin(injector, aapsLogger, rxBus, aapsSchedulers, resourceHelper, context, sp, profileFunction, activePlugin, nsUpload, fabricPrivacy, dateUtil, uploadQueue, databaseHelper, repository) { +) : TreatmentsPlugin(injector, aapsLogger, rxBus, aapsSchedulers, resourceHelper, context, sp, profileFunction, activePlugin, nsUpload, fabricPrivacy, dateUtil, databaseHelper, repository) { init { onStart() diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/aps/loop/LoopFragment.kt b/app/src/main/java/info/nightscout/androidaps/plugins/aps/loop/LoopFragment.kt index 74f581b298..0c0b592a30 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/aps/loop/LoopFragment.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/aps/loop/LoopFragment.kt @@ -98,7 +98,6 @@ class LoopFragment : DaggerFragment() { binding.constraintsprocessed.text = it.constraintsProcessed?.toSpanned() ?: "" binding.source.text = it.source ?: "" binding.lastrun.text = dateUtil.dateAndTimeString(it.lastAPSRun) - ?: "" binding.smbrequestTime.text = dateUtil.dateAndTimeAndSecondsString(it.lastSMBRequest) binding.smbexecutionTime.text = dateUtil.dateAndTimeAndSecondsString(it.lastSMBEnact) binding.tbrrequestTime.text = dateUtil.dateAndTimeAndSecondsString(it.lastTBRRequest) 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 6abeea43b0..6c7e8a3ac5 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 @@ -17,8 +17,11 @@ import info.nightscout.androidaps.data.Profile import info.nightscout.androidaps.data.PumpEnactResult import info.nightscout.androidaps.database.AppRepository import info.nightscout.androidaps.database.entities.TherapyEvent -import info.nightscout.androidaps.database.transactions.InsertTherapyEventIfNewTransaction -import info.nightscout.androidaps.db.Source +import info.nightscout.androidaps.database.entities.UserEntry.Action +import info.nightscout.androidaps.database.entities.UserEntry.Sources +import info.nightscout.androidaps.database.entities.ValueWithUnit +import info.nightscout.androidaps.database.transactions.InsertIfNewByTimestampTherapyEventTransaction +import info.nightscout.androidaps.database.transactions.InsertTherapyEventAnnouncementTransaction import info.nightscout.androidaps.events.EventAcceptOpenLoopChange import info.nightscout.androidaps.events.EventAutosensCalculationFinished import info.nightscout.androidaps.events.EventNewBG @@ -27,20 +30,19 @@ import info.nightscout.androidaps.interfaces.* import info.nightscout.androidaps.interfaces.LoopInterface.LastRun import info.nightscout.androidaps.logging.AAPSLogger import info.nightscout.androidaps.logging.LTag +import info.nightscout.androidaps.logging.UserEntryLogger import info.nightscout.androidaps.plugins.aps.loop.events.EventLoopSetLastRunGui 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.general.nsclient.NSUpload +import info.nightscout.androidaps.plugins.configBuilder.RunningConfiguration import info.nightscout.androidaps.plugins.general.overview.events.EventDismissNotification import info.nightscout.androidaps.plugins.general.overview.events.EventNewNotification import info.nightscout.androidaps.plugins.general.overview.notifications.Notification import info.nightscout.androidaps.plugins.general.wear.events.EventWearConfirmAction import info.nightscout.androidaps.plugins.general.wear.events.EventWearInitiateAction -import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorPlugin import info.nightscout.androidaps.plugins.pump.virtual.VirtualPumpPlugin -import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin import info.nightscout.androidaps.queue.Callback import info.nightscout.androidaps.queue.commands.Command import info.nightscout.androidaps.receivers.ReceiverStatusStore @@ -48,6 +50,10 @@ 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.extensions.buildDeviceStatus +import info.nightscout.androidaps.extensions.convertedToAbsolute +import info.nightscout.androidaps.extensions.convertedToPercent +import info.nightscout.androidaps.extensions.plannedRemainingMinutes import info.nightscout.androidaps.utils.resources.ResourceHelper import info.nightscout.androidaps.utils.rx.AapsSchedulers import info.nightscout.androidaps.utils.sharedPreferences.SP @@ -70,15 +76,15 @@ open class LoopPlugin @Inject constructor( private val profileFunction: ProfileFunction, private val context: Context, private val commandQueue: CommandQueueProvider, - private val activePlugin: ActivePluginProvider, - private val treatmentsPlugin: TreatmentsPlugin, + private val activePlugin: ActivePlugin, private val virtualPumpPlugin: VirtualPumpPlugin, - private val iobCobCalculatorPlugin: IobCobCalculatorPlugin, + private val iobCobCalculator: IobCobCalculator, private val receiverStatusStore: ReceiverStatusStore, private val fabricPrivacy: FabricPrivacy, - private val nsUpload: NSUpload, private val dateUtil: DateUtil, - private val repository: AppRepository + private val uel: UserEntryLogger, + private val repository: AppRepository, + private val runningConfiguration: RunningConfiguration ) : PluginBase(PluginDescription() .mainType(PluginType.LOOP) .fragmentClass(LoopFragment::class.java.name) @@ -96,6 +102,7 @@ open class LoopPlugin @Inject constructor( private var carbsSuggestionsSuspendedUntil: Long = 0 private var prevCarbsreq = 0 override var lastRun: LastRun? = null + override fun onStart() { createNotificationChannel() super.onStart() @@ -117,7 +124,7 @@ open class LoopPlugin @Inject constructor( .subscribe({ event: EventAutosensCalculationFinished -> // Autosens calculation not triggered by a new BG if (event.cause !is EventNewBG) return@subscribe - val glucoseValue = iobCobCalculatorPlugin.actualBg() ?: return@subscribe + val glucoseValue = iobCobCalculator.ads.actualBg() ?: return@subscribe // BG outdated // already looped with that value if (glucoseValue.timestamp <= lastBgTriggeredRun) return@subscribe @@ -233,7 +240,9 @@ open class LoopPlugin @Inject constructor( private fun treatmentTimeThreshold(durationMinutes: Int): Boolean { val threshold = System.currentTimeMillis() + durationMinutes * 60 * 1000 var bool = false - if (treatmentsPlugin.lastBolusTime > threshold || treatmentsPlugin.lastCarbTime > threshold) bool = true + val lastBolusTime = repository.getLastBolusRecord()?.timestamp ?: 0L + val lastCarbsTime = repository.getLastCarbsRecord()?.timestamp ?: 0L + if (lastBolusTime > threshold || lastCarbsTime > threshold) bool = true return bool } @@ -295,155 +304,162 @@ open class LoopPlugin @Inject constructor( resultAfterConstraints.smb = constraintChecker.applyBolusConstraints(resultAfterConstraints.smbConstraint!!).value() // safety check for multiple SMBs - val lastBolusTime = treatmentsPlugin.lastBolusTime + val lastBolusTime = repository.getLastBolusRecord()?.timestamp ?: 0L if (lastBolusTime != 0L && lastBolusTime + T.mins(3).msecs() > System.currentTimeMillis()) { aapsLogger.debug(LTag.APS, "SMB requested but still in 3 min interval") resultAfterConstraints.smb = 0.0 } - if (lastRun != null && lastRun!!.constraintsProcessed != null) { - prevCarbsreq = lastRun!!.constraintsProcessed!!.carbsReq - } - if (lastRun == null) lastRun = LastRun() - lastRun!!.request = apsResult - lastRun!!.constraintsProcessed = resultAfterConstraints - lastRun!!.lastAPSRun = DateUtil.now() - lastRun!!.source = (usedAPS as PluginBase).name - lastRun!!.tbrSetByPump = null - lastRun!!.smbSetByPump = null - lastRun!!.lastTBREnact = 0 - lastRun!!.lastTBRRequest = 0 - lastRun!!.lastSMBEnact = 0 - lastRun!!.lastSMBRequest = 0 - nsUpload.uploadDeviceStatus(this, iobCobCalculatorPlugin, profileFunction, activePlugin.activePump, receiverStatusStore, BuildConfig.VERSION_NAME + "-" + BuildConfig.BUILDVERSION) - if (isSuspended) { - aapsLogger.debug(LTag.APS, resourceHelper.gs(R.string.loopsuspended)) - rxBus.send(EventLoopSetLastRunGui(resourceHelper.gs(R.string.loopsuspended))) - return - } - if (pump.isSuspended()) { - aapsLogger.debug(LTag.APS, resourceHelper.gs(R.string.pumpsuspended)) - rxBus.send(EventLoopSetLastRunGui(resourceHelper.gs(R.string.pumpsuspended))) - return - } - val closedLoopEnabled = constraintChecker.isClosedLoopAllowed() - if (closedLoopEnabled.value()) { - if (allowNotification) { - if (resultAfterConstraints.isCarbsRequired - && resultAfterConstraints.carbsReq >= sp.getInt(R.string.key_smb_enable_carbs_suggestions_threshold, 0) && carbsSuggestionsSuspendedUntil < System.currentTimeMillis() && !treatmentTimeThreshold(-15)) { - if (sp.getBoolean(R.string.key_enable_carbs_required_alert_local, true) && !sp.getBoolean(R.string.key_raise_notifications_as_android_notifications, true)) { - val carbReqLocal = Notification(Notification.CARBS_REQUIRED, resultAfterConstraints.carbsRequiredText, Notification.NORMAL) - rxBus.send(EventNewNotification(carbReqLocal)) - } - if (sp.getBoolean(R.string.key_ns_create_announcements_from_carbs_req, false)) { - nsUpload.uploadError(resultAfterConstraints.carbsRequiredText) - } - if (sp.getBoolean(R.string.key_enable_carbs_required_alert_local, true) && sp.getBoolean(R.string.key_raise_notifications_as_android_notifications, true)) { - val intentAction5m = Intent(context, CarbSuggestionReceiver::class.java) - intentAction5m.putExtra("ignoreDuration", 5) - val pendingIntent5m = PendingIntent.getBroadcast(context, 1, intentAction5m, PendingIntent.FLAG_UPDATE_CURRENT) - val actionIgnore5m = NotificationCompat.Action(R.drawable.ic_notif_aaps, resourceHelper.gs(R.string.ignore5m, "Ignore 5m"), pendingIntent5m) - val intentAction15m = Intent(context, CarbSuggestionReceiver::class.java) - intentAction15m.putExtra("ignoreDuration", 15) - val pendingIntent15m = PendingIntent.getBroadcast(context, 1, intentAction15m, PendingIntent.FLAG_UPDATE_CURRENT) - val actionIgnore15m = NotificationCompat.Action(R.drawable.ic_notif_aaps, resourceHelper.gs(R.string.ignore15m, "Ignore 15m"), pendingIntent15m) - val intentAction30m = Intent(context, CarbSuggestionReceiver::class.java) - intentAction30m.putExtra("ignoreDuration", 30) - val pendingIntent30m = PendingIntent.getBroadcast(context, 1, intentAction30m, PendingIntent.FLAG_UPDATE_CURRENT) - val actionIgnore30m = NotificationCompat.Action(R.drawable.ic_notif_aaps, resourceHelper.gs(R.string.ignore30m, "Ignore 30m"), pendingIntent30m) - val builder = NotificationCompat.Builder(context, CHANNEL_ID) - builder.setSmallIcon(R.drawable.notif_icon) - .setContentTitle(resourceHelper.gs(R.string.carbssuggestion)) - .setContentText(resultAfterConstraints.carbsRequiredText) - .setAutoCancel(true) - .setPriority(Notification.IMPORTANCE_HIGH) - .setCategory(Notification.CATEGORY_ALARM) - .addAction(actionIgnore5m) - .addAction(actionIgnore15m) - .addAction(actionIgnore30m) - .setVisibility(NotificationCompat.VISIBILITY_PUBLIC) - .setVibrate(longArrayOf(1000, 1000, 1000, 1000, 1000)) - val mNotificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager + prevCarbsreq = lastRun?.constraintsProcessed?.carbsReq ?: prevCarbsreq + lastRun = (lastRun ?: LastRun()).also { lastRun -> + lastRun.request = apsResult + lastRun.constraintsProcessed = resultAfterConstraints + lastRun.lastAPSRun = dateUtil.now() + lastRun.source = (usedAPS as PluginBase).name + lastRun.tbrSetByPump = null + lastRun.smbSetByPump = null + lastRun.lastTBREnact = 0 + lastRun.lastTBRRequest = 0 + lastRun.lastSMBEnact = 0 + lastRun.lastSMBRequest = 0 + buildDeviceStatus(dateUtil, this, iobCobCalculator, profileFunction, + activePlugin.activePump, receiverStatusStore, runningConfiguration, + BuildConfig.VERSION_NAME + "-" + BuildConfig.BUILDVERSION)?.also { + repository.insert(it) + } - // mId allows you to update the notification later on. - mNotificationManager.notify(Constants.notificationID, builder.build()) - rxBus.send(EventNewOpenLoopNotification()) + if (isSuspended) { + aapsLogger.debug(LTag.APS, resourceHelper.gs(R.string.loopsuspended)) + rxBus.send(EventLoopSetLastRunGui(resourceHelper.gs(R.string.loopsuspended))) + return + } + if (pump.isSuspended()) { + aapsLogger.debug(LTag.APS, resourceHelper.gs(R.string.pumpsuspended)) + rxBus.send(EventLoopSetLastRunGui(resourceHelper.gs(R.string.pumpsuspended))) + return + } + val closedLoopEnabled = constraintChecker.isClosedLoopAllowed() + if (closedLoopEnabled.value()) { + if (allowNotification) { + if (resultAfterConstraints.isCarbsRequired + && resultAfterConstraints.carbsReq >= sp.getInt(R.string.key_smb_enable_carbs_suggestions_threshold, 0) && carbsSuggestionsSuspendedUntil < System.currentTimeMillis() && !treatmentTimeThreshold(-15)) { + if (sp.getBoolean(R.string.key_enable_carbs_required_alert_local, true) && !sp.getBoolean(R.string.key_raise_notifications_as_android_notifications, true)) { + val carbReqLocal = Notification(Notification.CARBS_REQUIRED, resultAfterConstraints.carbsRequiredText, Notification.NORMAL) + rxBus.send(EventNewNotification(carbReqLocal)) + } + if (sp.getBoolean(R.string.key_ns_create_announcements_from_carbs_req, false)) { + disposable += repository.runTransaction(InsertTherapyEventAnnouncementTransaction(resultAfterConstraints.carbsRequiredText)).subscribe() + } + if (sp.getBoolean(R.string.key_enable_carbs_required_alert_local, true) && sp.getBoolean(R.string.key_raise_notifications_as_android_notifications, true)) { + val intentAction5m = Intent(context, CarbSuggestionReceiver::class.java) + intentAction5m.putExtra("ignoreDuration", 5) + val pendingIntent5m = PendingIntent.getBroadcast(context, 1, intentAction5m, PendingIntent.FLAG_UPDATE_CURRENT) + val actionIgnore5m = NotificationCompat.Action(R.drawable.ic_notif_aaps, resourceHelper.gs(R.string.ignore5m, "Ignore 5m"), pendingIntent5m) + val intentAction15m = Intent(context, CarbSuggestionReceiver::class.java) + intentAction15m.putExtra("ignoreDuration", 15) + val pendingIntent15m = PendingIntent.getBroadcast(context, 1, intentAction15m, PendingIntent.FLAG_UPDATE_CURRENT) + val actionIgnore15m = NotificationCompat.Action(R.drawable.ic_notif_aaps, resourceHelper.gs(R.string.ignore15m, "Ignore 15m"), pendingIntent15m) + val intentAction30m = Intent(context, CarbSuggestionReceiver::class.java) + intentAction30m.putExtra("ignoreDuration", 30) + val pendingIntent30m = PendingIntent.getBroadcast(context, 1, intentAction30m, PendingIntent.FLAG_UPDATE_CURRENT) + val actionIgnore30m = NotificationCompat.Action(R.drawable.ic_notif_aaps, resourceHelper.gs(R.string.ignore30m, "Ignore 30m"), pendingIntent30m) + val builder = NotificationCompat.Builder(context, CHANNEL_ID) + builder.setSmallIcon(R.drawable.notif_icon) + .setContentTitle(resourceHelper.gs(R.string.carbssuggestion)) + .setContentText(resultAfterConstraints.carbsRequiredText) + .setAutoCancel(true) + .setPriority(Notification.IMPORTANCE_HIGH) + .setCategory(Notification.CATEGORY_ALARM) + .addAction(actionIgnore5m) + .addAction(actionIgnore15m) + .addAction(actionIgnore30m) + .setVisibility(NotificationCompat.VISIBILITY_PUBLIC) + .setVibrate(longArrayOf(1000, 1000, 1000, 1000, 1000)) + val mNotificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager - //only send to wear if Native notifications are turned off - if (!sp.getBoolean(R.string.key_raise_notifications_as_android_notifications, true)) { - // Send to Wear - rxBus.send(EventWearInitiateAction("changeRequest")) + // mId allows you to update the notification later on. + mNotificationManager.notify(Constants.notificationID, builder.build()) + uel.log(Action.CAREPORTAL, Sources.Loop, resourceHelper.gs(R.string.carbsreq, resultAfterConstraints.carbsReq, resultAfterConstraints.carbsReqWithin), + ValueWithUnit.Gram(resultAfterConstraints.carbsReq), + ValueWithUnit.Minute(resultAfterConstraints.carbsReqWithin)) + rxBus.send(EventNewOpenLoopNotification()) + + //only send to wear if Native notifications are turned off + if (!sp.getBoolean(R.string.key_raise_notifications_as_android_notifications, true)) { + // Send to Wear + rxBus.send(EventWearInitiateAction("changeRequest")) + } + } + } else { + //If carbs were required previously, but are no longer needed, dismiss notifications + if (prevCarbsreq > 0) { + dismissSuggestion() + rxBus.send(EventDismissNotification(Notification.CARBS_REQUIRED)) } } - } else { - //If carbs were required previously, but are no longer needed, dismiss notifications - if (prevCarbsreq > 0) { - dismissSuggestion() - rxBus.send(EventDismissNotification(Notification.CARBS_REQUIRED)) - } } - } - if (resultAfterConstraints.isChangeRequested - && !commandQueue.bolusInQueue() - && !commandQueue.isRunning(Command.CommandType.BOLUS)) { - val waiting = PumpEnactResult(injector) - waiting.queued = true - if (resultAfterConstraints.tempBasalRequested) lastRun!!.tbrSetByPump = waiting - if (resultAfterConstraints.bolusRequested) lastRun!!.smbSetByPump = waiting - rxBus.send(EventLoopUpdateGui()) - fabricPrivacy.logCustom("APSRequest") - applyTBRRequest(resultAfterConstraints, profile, object : Callback() { - override fun run() { - if (result.enacted || result.success) { - lastRun!!.tbrSetByPump = result - lastRun!!.lastTBRRequest = lastRun!!.lastAPSRun - lastRun!!.lastTBREnact = DateUtil.now() - rxBus.send(EventLoopUpdateGui()) - applySMBRequest(resultAfterConstraints, object : Callback() { - override fun run() { - // Callback is only called if a bolus was actually requested - if (result.enacted || result.success) { - lastRun!!.smbSetByPump = result - lastRun!!.lastSMBRequest = lastRun!!.lastAPSRun - lastRun!!.lastSMBEnact = DateUtil.now() - } else { - Thread { - SystemClock.sleep(1000) - invoke("tempBasalFallback", allowNotification, true) - }.start() + if (resultAfterConstraints.isChangeRequested + && !commandQueue.bolusInQueue() + && !commandQueue.isRunning(Command.CommandType.BOLUS)) { + val waiting = PumpEnactResult(injector) + waiting.queued = true + if (resultAfterConstraints.tempBasalRequested) lastRun.tbrSetByPump = waiting + if (resultAfterConstraints.bolusRequested) lastRun.smbSetByPump = waiting + rxBus.send(EventLoopUpdateGui()) + fabricPrivacy.logCustom("APSRequest") + applyTBRRequest(resultAfterConstraints, profile, object : Callback() { + override fun run() { + if (result.enacted || result.success) { + lastRun.tbrSetByPump = result + lastRun.lastTBRRequest = lastRun.lastAPSRun + lastRun.lastTBREnact = dateUtil.now() + rxBus.send(EventLoopUpdateGui()) + applySMBRequest(resultAfterConstraints, object : Callback() { + override fun run() { + // Callback is only called if a bolus was actually requested + if (result.enacted || result.success) { + lastRun.smbSetByPump = result + lastRun.lastSMBRequest = lastRun.lastAPSRun + lastRun.lastSMBEnact = dateUtil.now() + } else { + Thread { + SystemClock.sleep(1000) + invoke("tempBasalFallback", allowNotification, true) + }.start() + } + rxBus.send(EventLoopUpdateGui()) } - rxBus.send(EventLoopUpdateGui()) - } - }) - } else { - lastRun!!.tbrSetByPump = result - lastRun!!.lastTBRRequest = lastRun!!.lastAPSRun + }) + } else { + lastRun.tbrSetByPump = result + lastRun.lastTBRRequest = lastRun.lastAPSRun + } + rxBus.send(EventLoopUpdateGui()) } - rxBus.send(EventLoopUpdateGui()) - } - }) - } else { - lastRun!!.tbrSetByPump = null - lastRun!!.smbSetByPump = null - } - } else { - if (resultAfterConstraints.isChangeRequested && allowNotification) { - val builder = NotificationCompat.Builder(context, CHANNEL_ID) - builder.setSmallIcon(R.drawable.notif_icon) - .setContentTitle(resourceHelper.gs(R.string.openloop_newsuggestion)) - .setContentText(resultAfterConstraints.toString()) - .setAutoCancel(true) - .setPriority(Notification.IMPORTANCE_HIGH) - .setCategory(Notification.CATEGORY_ALARM) - .setVisibility(NotificationCompat.VISIBILITY_PUBLIC) - if (sp.getBoolean(R.string.key_wear_control, false)) { - builder.setLocalOnly(true) + }) + } else { + lastRun.tbrSetByPump = null + lastRun.smbSetByPump = null + } + } else { + if (resultAfterConstraints.isChangeRequested && allowNotification) { + val builder = NotificationCompat.Builder(context, CHANNEL_ID) + builder.setSmallIcon(R.drawable.notif_icon) + .setContentTitle(resourceHelper.gs(R.string.openloop_newsuggestion)) + .setContentText(resultAfterConstraints.toString()) + .setAutoCancel(true) + .setPriority(Notification.IMPORTANCE_HIGH) + .setCategory(Notification.CATEGORY_ALARM) + .setVisibility(NotificationCompat.VISIBILITY_PUBLIC) + if (sp.getBoolean(R.string.key_wear_control, false)) { + builder.setLocalOnly(true) + } + presentSuggestion(builder) + } else if (allowNotification) { + dismissSuggestion() } - presentSuggestion(builder) - } else if (allowNotification) { - dismissSuggestion() } + rxBus.send(EventLoopUpdateGui()) } - rxBus.send(EventLoopUpdateGui()) } finally { aapsLogger.debug(LTag.APS, "invoke end") } @@ -486,21 +502,28 @@ 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) { - lastRun!!.tbrSetByPump = result - 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) - sp.incInt(R.string.key_ObjectivesmanualEnacts) - } - rxBus.send(EventAcceptOpenLoopChange()) + val profile = profileFunction.getProfile() ?: return + lastRun?.let { lastRun -> + lastRun.constraintsProcessed?.let { constraintsProcessed -> + applyTBRRequest(constraintsProcessed, profile, object : Callback() { + override fun run() { + if (result.enacted) { + lastRun.tbrSetByPump = result + lastRun.lastTBRRequest = lastRun.lastAPSRun + lastRun.lastTBREnact = dateUtil.now() + lastRun.lastOpenModeAccept = dateUtil.now() + buildDeviceStatus(dateUtil, this@LoopPlugin, iobCobCalculator, profileFunction, + activePlugin.activePump, receiverStatusStore, runningConfiguration, + BuildConfig.VERSION_NAME + "-" + BuildConfig.BUILDVERSION)?.also { + repository.insert(it) + } + sp.incInt(R.string.key_ObjectivesmanualEnacts) + } + rxBus.send(EventAcceptOpenLoopChange()) + } + }) } - }) + } fabricPrivacy.logCustom("AcceptTemp") } @@ -508,8 +531,8 @@ open class LoopPlugin @Inject constructor( * expect absolute request and allow both absolute and percent response based on pump capabilities * TODO: update pump drivers to support APS request in % */ - private fun applyTBRRequest(request: APSResult?, profile: Profile?, callback: Callback?) { - if (!request!!.tempBasalRequested) { + private fun applyTBRRequest(request: APSResult, profile: Profile, callback: Callback?) { + if (!request.tempBasalRequested) { callback?.result(PumpEnactResult(injector).enacted(false).success(true).comment(R.string.nochangerequested))?.run() return } @@ -526,44 +549,52 @@ open class LoopPlugin @Inject constructor( } aapsLogger.debug(LTag.APS, "applyAPSRequest: $request") val now = System.currentTimeMillis() - val activeTemp = treatmentsPlugin.getTempBasalFromHistory(now) + val activeTemp = iobCobCalculator.getTempBasalIncludingConvertedExtended(now) if (request.usePercent && allowPercentage()) { if (request.percent == 100 && request.duration == 0) { if (activeTemp != null) { aapsLogger.debug(LTag.APS, "applyAPSRequest: cancelTempBasal()") + uel.log(Action.CANCEL_TEMP_BASAL, Sources.Loop) commandQueue.cancelTempBasal(false, callback) } else { aapsLogger.debug(LTag.APS, "applyAPSRequest: Basal set correctly") callback?.result(PumpEnactResult(injector).percent(request.percent).duration(0) .enacted(false).success(true).comment(R.string.basal_set_correctly))?.run() } - } else if (activeTemp != null && activeTemp.plannedRemainingMinutes > 5 && request.duration - activeTemp.plannedRemainingMinutes < 30 && request.percent == activeTemp.percentRate) { + } else if (activeTemp != null && activeTemp.plannedRemainingMinutes > 5 && request.duration - activeTemp.plannedRemainingMinutes < 30 && request.percent == activeTemp.convertedToPercent(now, profile)) { aapsLogger.debug(LTag.APS, "applyAPSRequest: Temp basal set correctly") callback?.result(PumpEnactResult(injector).percent(request.percent) .enacted(false).success(true).duration(activeTemp.plannedRemainingMinutes) .comment(R.string.let_temp_basal_run))?.run() } else { aapsLogger.debug(LTag.APS, "applyAPSRequest: tempBasalPercent()") - commandQueue.tempBasalPercent(request.percent, request.duration, false, profile!!, callback) + uel.log(Action.TEMP_BASAL, Sources.Loop, + ValueWithUnit.Percent(request.percent), + ValueWithUnit.Minute(request.duration)) + commandQueue.tempBasalPercent(request.percent, request.duration, false, profile, PumpSync.TemporaryBasalType.NORMAL, callback) } } else { if (request.rate == 0.0 && request.duration == 0 || abs(request.rate - pump.baseBasalRate) < pump.pumpDescription.basalStep) { if (activeTemp != null) { aapsLogger.debug(LTag.APS, "applyAPSRequest: cancelTempBasal()") + uel.log(Action.CANCEL_TEMP_BASAL, Sources.Loop) commandQueue.cancelTempBasal(false, callback) } else { aapsLogger.debug(LTag.APS, "applyAPSRequest: Basal set correctly") callback?.result(PumpEnactResult(injector).absolute(request.rate).duration(0) .enacted(false).success(true).comment(R.string.basal_set_correctly))?.run() } - } else if (activeTemp != null && activeTemp.plannedRemainingMinutes > 5 && request.duration - activeTemp.plannedRemainingMinutes < 30 && abs(request.rate - activeTemp.tempBasalConvertedToAbsolute(now, profile)) < pump.pumpDescription.basalStep) { + } else if (activeTemp != null && activeTemp.plannedRemainingMinutes > 5 && request.duration - activeTemp.plannedRemainingMinutes < 30 && abs(request.rate - activeTemp.convertedToAbsolute(now, profile)) < pump.pumpDescription.basalStep) { aapsLogger.debug(LTag.APS, "applyAPSRequest: Temp basal set correctly") - callback?.result(PumpEnactResult(injector).absolute(activeTemp.tempBasalConvertedToAbsolute(now, profile)) + callback?.result(PumpEnactResult(injector).absolute(activeTemp.convertedToAbsolute(now, profile)) .enacted(false).success(true).duration(activeTemp.plannedRemainingMinutes) .comment(R.string.let_temp_basal_run))?.run() } else { aapsLogger.debug(LTag.APS, "applyAPSRequest: setTempBasalAbsolute()") - commandQueue.tempBasalAbsolute(request.rate, request.duration, false, profile!!, callback) + uel.log(Action.TEMP_BASAL, Sources.Loop, + ValueWithUnit.UnitPerHour(request.rate), + ValueWithUnit.Minute(request.duration)) + commandQueue.tempBasalAbsolute(request.rate, request.duration, false, profile, PumpSync.TemporaryBasalType.NORMAL, callback) } } } @@ -573,7 +604,7 @@ open class LoopPlugin @Inject constructor( return } val pump = activePlugin.activePump - val lastBolusTime = treatmentsPlugin.lastBolusTime + val lastBolusTime = repository.getLastBolusRecord()?.timestamp ?: 0L if (lastBolusTime != 0L && lastBolusTime + 3 * 60 * 1000 > System.currentTimeMillis()) { aapsLogger.debug(LTag.APS, "SMB requested but still in 3 min interval") callback?.result(PumpEnactResult(injector) @@ -595,13 +626,14 @@ open class LoopPlugin @Inject constructor( // deliver SMB val detailedBolusInfo = DetailedBolusInfo() - detailedBolusInfo.lastKnownBolusTime = treatmentsPlugin.lastBolusTime - detailedBolusInfo.eventType = TherapyEvent.Type.CORRECTION_BOLUS.text + detailedBolusInfo.lastKnownBolusTime = repository.getLastBolusRecord()?.timestamp ?: 0L + detailedBolusInfo.eventType = DetailedBolusInfo.EventType.CORRECTION_BOLUS detailedBolusInfo.insulin = request.smb - detailedBolusInfo.isSMB = true - detailedBolusInfo.source = Source.USER - detailedBolusInfo.deliverAt = request.deliverAt + detailedBolusInfo.bolusType = DetailedBolusInfo.BolusType.SMB + detailedBolusInfo.deliverAtTheLatest = request.deliverAt aapsLogger.debug(LTag.APS, "applyAPSRequest: bolus()") + if (request.smb > 0.0) + uel.log(Action.SMB, Sources.Loop, ValueWithUnit.Insulin(detailedBolusInfo.insulin)) commandQueue.bolus(detailedBolusInfo, callback) } @@ -613,7 +645,7 @@ open class LoopPlugin @Inject constructor( val pump = activePlugin.activePump disconnectTo(System.currentTimeMillis() + durationInMinutes * 60 * 1000L) if (pump.pumpDescription.tempBasalStyle == PumpDescription.ABSOLUTE) { - commandQueue.tempBasalAbsolute(0.0, durationInMinutes, true, profile!!, object : Callback() { + commandQueue.tempBasalAbsolute(0.0, durationInMinutes, true, profile!!, PumpSync.TemporaryBasalType.EMULATED_PUMP_SUSPEND, object : Callback() { override fun run() { if (!result.success) { ErrorHelperActivity.runAlarm(context, result.comment, resourceHelper.gs(R.string.tempbasaldeliveryerror), info.nightscout.androidaps.dana.R.raw.boluserror) @@ -621,7 +653,7 @@ open class LoopPlugin @Inject constructor( } }) } else { - commandQueue.tempBasalPercent(0, durationInMinutes, true, profile!!, object : Callback() { + commandQueue.tempBasalPercent(0, durationInMinutes, true, profile!!, PumpSync.TemporaryBasalType.EMULATED_PUMP_SUSPEND, object : Callback() { override fun run() { if (!result.success) { ErrorHelperActivity.runAlarm(context, result.comment, resourceHelper.gs(R.string.tempbasaldeliveryerror), info.nightscout.androidaps.dana.R.raw.boluserror) @@ -629,7 +661,7 @@ open class LoopPlugin @Inject constructor( } }) } - if (pump.pumpDescription.isExtendedBolusCapable && treatmentsPlugin.isInHistoryExtendedBolusInProgress) { + if (pump.pumpDescription.isExtendedBolusCapable && iobCobCalculator.getExtendedBolus(dateUtil.now()) != null) { commandQueue.cancelExtended(object : Callback() { override fun run() { if (!result.success) { @@ -654,17 +686,16 @@ open class LoopPlugin @Inject constructor( } override fun createOfflineEvent(durationInMinutes: Int) { - disposable += repository.runTransactionForResult(InsertTherapyEventIfNewTransaction( - timestamp = dateUtil._now(), + disposable += repository.runTransactionForResult(InsertIfNewByTimestampTherapyEventTransaction( + timestamp = dateUtil.now(), type = TherapyEvent.Type.APS_OFFLINE, duration = T.mins(durationInMinutes.toLong()).msecs(), enteredBy = "openaps://" + "AndroidAPS", glucoseUnit = TherapyEvent.GlucoseUnit.MGDL - )).subscribe({ result -> - result.inserted.forEach { nsUpload.uploadEvent(it) } - }, { - aapsLogger.error(LTag.BGSOURCE, "Error while saving therapy event", it) - }) + )).subscribe( + { result -> result.inserted.forEach { aapsLogger.debug(LTag.DATABASE, "Inserted therapy event $it") } }, + { aapsLogger.error(LTag.DATABASE, "Error while saving therapy event", it) } + ) } companion object { diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/aps/openAPSAMA/DetermineBasalAdapterAMAJS.kt b/app/src/main/java/info/nightscout/androidaps/plugins/aps/openAPSAMA/DetermineBasalAdapterAMAJS.kt index a2334030ea..c4e858f76c 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/aps/openAPSAMA/DetermineBasalAdapterAMAJS.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/aps/openAPSAMA/DetermineBasalAdapterAMAJS.kt @@ -6,6 +6,10 @@ import info.nightscout.androidaps.R import info.nightscout.androidaps.data.IobTotal import info.nightscout.androidaps.data.MealData import info.nightscout.androidaps.data.Profile +import info.nightscout.androidaps.extensions.convertedToAbsolute +import info.nightscout.androidaps.extensions.getPassedDurationToTimeInMinutes +import info.nightscout.androidaps.extensions.plannedRemainingMinutes +import info.nightscout.androidaps.interfaces.IobCobCalculator import info.nightscout.androidaps.interfaces.ProfileFunction import info.nightscout.androidaps.logging.AAPSLogger import info.nightscout.androidaps.logging.LTag @@ -15,8 +19,6 @@ import info.nightscout.androidaps.plugins.aps.openAPSSMB.SMBDefaults import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker import info.nightscout.androidaps.plugins.general.openhumans.OpenHumansUploader import info.nightscout.androidaps.plugins.iob.iobCobCalculator.GlucoseStatus -import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorPlugin -import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin import info.nightscout.androidaps.utils.sharedPreferences.SP import org.json.JSONArray import org.json.JSONException @@ -37,7 +39,7 @@ class DetermineBasalAdapterAMAJS internal constructor(scriptReader: ScriptReader @Inject lateinit var constraintChecker: ConstraintChecker @Inject lateinit var sp: SP @Inject lateinit var profileFunction: ProfileFunction - @Inject lateinit var treatmentsPlugin: TreatmentsPlugin + @Inject lateinit var iobCobCalculator: IobCobCalculator @Inject lateinit var openHumansUploader: OpenHumansUploader private val mScriptReader: ScriptReader @@ -183,18 +185,15 @@ class DetermineBasalAdapterAMAJS internal constructor(scriptReader: ScriptReader this.profile.put("out_units", "mmol/L") } val now = System.currentTimeMillis() - val tb = treatmentsPlugin.getTempBasalFromHistory(now) + val tb = iobCobCalculator.getTempBasalIncludingConvertedExtended(now) currentTemp = JSONObject() currentTemp.put("temp", "absolute") currentTemp.put("duration", tb?.plannedRemainingMinutes ?: 0) - currentTemp.put("rate", tb?.tempBasalConvertedToAbsolute(now, profile) ?: 0.0) - + currentTemp.put("rate", tb?.convertedToAbsolute(now, profile) ?: 0.0) // as we have non default temps longer than 30 minutes - val tempBasal = treatmentsPlugin.getTempBasalFromHistory(System.currentTimeMillis()) - if (tempBasal != null) { - currentTemp.put("minutesrunning", tempBasal.realDuration) - } - iobData = IobCobCalculatorPlugin.convertToJSONArray(iobArray) + if (tb != null) currentTemp.put("minutesrunning", tb.getPassedDurationToTimeInMinutes(now)) + + iobData = iobCobCalculator.convertToJSONArray(iobArray) this.glucoseStatus = JSONObject() this.glucoseStatus.put("glucose", glucoseStatus.glucose) if (sp.getBoolean(R.string.key_always_use_shortavg, false)) { @@ -206,7 +205,6 @@ class DetermineBasalAdapterAMAJS internal constructor(scriptReader: ScriptReader this.glucoseStatus.put("long_avgdelta", glucoseStatus.longAvgDelta) this.mealData = JSONObject() this.mealData.put("carbs", mealData.carbs) - this.mealData.put("boluses", mealData.boluses) this.mealData.put("mealCOB", mealData.mealCOB) if (constraintChecker.isAutosensModeEnabled().value()) { autosensData.put("ratio", autosensDataRatio) diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/aps/openAPSAMA/DetermineBasalResultAMA.kt b/app/src/main/java/info/nightscout/androidaps/plugins/aps/openAPSAMA/DetermineBasalResultAMA.kt index 8f462b2f19..6f66dd235f 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/aps/openAPSAMA/DetermineBasalResultAMA.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/aps/openAPSAMA/DetermineBasalResultAMA.kt @@ -3,7 +3,6 @@ package info.nightscout.androidaps.plugins.aps.openAPSAMA import dagger.android.HasAndroidInjector import info.nightscout.androidaps.logging.LTag import info.nightscout.androidaps.plugins.aps.loop.APSResult -import info.nightscout.androidaps.utils.DateUtil import org.json.JSONException import org.json.JSONObject import org.mozilla.javascript.NativeObject @@ -14,7 +13,7 @@ class DetermineBasalResultAMA private constructor(injector: HasAndroidInjector) private var snoozeBG = 0.0 internal constructor(injector: HasAndroidInjector, result: NativeObject, j: JSONObject) : this(injector) { - date = DateUtil.now() + date = dateUtil.now() json = j if (result.containsKey("error")) { reason = result["error"].toString() diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/aps/openAPSAMA/OpenAPSAMAFragment.kt b/app/src/main/java/info/nightscout/androidaps/plugins/aps/openAPSAMA/OpenAPSAMAFragment.kt index 84bc71daf7..acbbf1191b 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/aps/openAPSAMA/OpenAPSAMAFragment.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/aps/openAPSAMA/OpenAPSAMAFragment.kt @@ -35,6 +35,7 @@ class OpenAPSAMAFragment : DaggerFragment() { @Inject lateinit var fabricPrivacy: FabricPrivacy @Inject lateinit var openAPSAMAPlugin: OpenAPSAMAPlugin @Inject lateinit var dateUtil: DateUtil + @Inject lateinit var jsonFormatter: JSONFormatter private var _binding: OpenapsamaFragmentBinding? = null @@ -92,30 +93,30 @@ class OpenAPSAMAFragment : DaggerFragment() { private fun updateGUI() { if (_binding == null) return openAPSAMAPlugin.lastAPSResult?.let { lastAPSResult -> - binding.result.text = JSONFormatter.format(lastAPSResult.json) + binding.result.text = jsonFormatter.format(lastAPSResult.json) binding.request.text = lastAPSResult.toSpanned() } openAPSAMAPlugin.lastDetermineBasalAdapterAMAJS?.let { determineBasalAdapterAMAJS -> - binding.glucosestatus.text = JSONFormatter.format(determineBasalAdapterAMAJS.glucoseStatusParam) - binding.currenttemp.text = JSONFormatter.format(determineBasalAdapterAMAJS.currentTempParam) + binding.glucosestatus.text = jsonFormatter.format(determineBasalAdapterAMAJS.glucoseStatusParam) + binding.currenttemp.text = jsonFormatter.format(determineBasalAdapterAMAJS.currentTempParam) try { val iobArray = JSONArray(determineBasalAdapterAMAJS.iobDataParam) - binding.iobdata.text = TextUtils.concat(resourceHelper.gs(R.string.array_of_elements, iobArray.length()) + "\n", JSONFormatter.format(iobArray.getString(0))) + binding.iobdata.text = TextUtils.concat(resourceHelper.gs(R.string.array_of_elements, iobArray.length()) + "\n", jsonFormatter.format(iobArray.getString(0))) } catch (e: JSONException) { aapsLogger.error(LTag.APS, "Unhandled exception", e) @Suppress("SetTextI18n") binding.iobdata.text = "JSONException see log for details" } - binding.profile.text = JSONFormatter.format(determineBasalAdapterAMAJS.profileParam) - binding.mealdata.text = JSONFormatter.format(determineBasalAdapterAMAJS.mealDataParam) + binding.profile.text = jsonFormatter.format(determineBasalAdapterAMAJS.profileParam) + binding.mealdata.text = jsonFormatter.format(determineBasalAdapterAMAJS.mealDataParam) binding.scriptdebugdata.text = determineBasalAdapterAMAJS.scriptDebug } if (openAPSAMAPlugin.lastAPSRun != 0L) { binding.lastrun.text = dateUtil.dateAndTimeString(openAPSAMAPlugin.lastAPSRun) } openAPSAMAPlugin.lastAutosensResult.let { - binding.autosensdata.text = JSONFormatter.format(it.json()) + binding.autosensdata.text = jsonFormatter.format(it.json()) } } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/aps/openAPSAMA/OpenAPSAMAPlugin.kt b/app/src/main/java/info/nightscout/androidaps/plugins/aps/openAPSAMA/OpenAPSAMAPlugin.kt index 0847f100ac..42af7bf765 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/aps/openAPSAMA/OpenAPSAMAPlugin.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/aps/openAPSAMA/OpenAPSAMAPlugin.kt @@ -15,15 +15,13 @@ import info.nightscout.androidaps.plugins.aps.loop.ScriptReader import info.nightscout.androidaps.plugins.bus.RxBusWrapper import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker import info.nightscout.androidaps.plugins.iob.iobCobCalculator.AutosensResult -import info.nightscout.androidaps.plugins.iob.iobCobCalculator.GlucoseStatus import info.nightscout.androidaps.plugins.iob.iobCobCalculator.GlucoseStatusProvider -import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorPlugin import info.nightscout.androidaps.utils.DateUtil import info.nightscout.androidaps.utils.FabricPrivacy import info.nightscout.androidaps.utils.HardLimits import info.nightscout.androidaps.utils.Profiler import info.nightscout.androidaps.utils.Round -import info.nightscout.androidaps.utils.extensions.target +import info.nightscout.androidaps.extensions.target import info.nightscout.androidaps.utils.resources.ResourceHelper import org.json.JSONException import javax.inject.Inject @@ -38,9 +36,8 @@ open class OpenAPSAMAPlugin @Inject constructor( resourceHelper: ResourceHelper, private val profileFunction: ProfileFunction, private val context: Context, - private val activePlugin: ActivePluginProvider, - private val treatmentsPlugin: TreatmentsInterface, - private val iobCobCalculatorPlugin: IobCobCalculatorPlugin, + private val activePlugin: ActivePlugin, + private val iobCobCalculator: IobCobCalculator, private val hardLimits: HardLimits, private val profiler: Profiler, private val fabricPrivacy: FabricPrivacy, @@ -56,7 +53,7 @@ open class OpenAPSAMAPlugin @Inject constructor( .preferencesId(R.xml.pref_openapsama) .description(R.string.description_ama), aapsLogger, resourceHelper, injector -), APSInterface { +), APS { // last values override var lastAPSRun: Long = 0 @@ -107,10 +104,10 @@ open class OpenAPSAMAPlugin @Inject constructor( }.value() var start = System.currentTimeMillis() var startPart = System.currentTimeMillis() - val iobArray = iobCobCalculatorPlugin.calculateIobArrayInDia(profile) + val iobArray = iobCobCalculator.calculateIobArrayInDia(profile) profiler.log(LTag.APS, "calculateIobArrayInDia()", startPart) startPart = System.currentTimeMillis() - val mealData = iobCobCalculatorPlugin.mealData + val mealData = iobCobCalculator.getMealDataWithWaitingForCalculationFinish() profiler.log(LTag.APS, "getMealData()", startPart) val maxIob = constraintChecker.getMaxIOBAllowed().also { maxIOBAllowedConstraint -> inputConstraints.copyReasons(maxIOBAllowedConstraint) @@ -119,7 +116,7 @@ open class OpenAPSAMAPlugin @Inject constructor( var maxBg = hardLimits.verifyHardLimits(Round.roundTo(profile.targetHighMgdl, 0.1), R.string.profile_high_target, HardLimits.VERY_HARD_LIMIT_MAX_BG[0].toDouble(), HardLimits.VERY_HARD_LIMIT_MAX_BG[1].toDouble()) var targetBg = hardLimits.verifyHardLimits(profile.targetMgdl, R.string.temp_target_value, HardLimits.VERY_HARD_LIMIT_TARGET_BG[0].toDouble(), HardLimits.VERY_HARD_LIMIT_TARGET_BG[1].toDouble()) var isTempTarget = false - val tempTarget = repository.getTemporaryTargetActiveAt(dateUtil._now()).blockingGet() + val tempTarget = repository.getTemporaryTargetActiveAt(dateUtil.now()).blockingGet() if (tempTarget is ValueWrapper.Existing) { isTempTarget = true minBg = hardLimits.verifyHardLimits(tempTarget.value.lowTarget, R.string.temp_target_low_target, HardLimits.VERY_HARD_LIMIT_TEMP_MIN_BG[0].toDouble(), HardLimits.VERY_HARD_LIMIT_TEMP_MIN_BG[1].toDouble()) @@ -133,7 +130,7 @@ open class OpenAPSAMAPlugin @Inject constructor( if (!hardLimits.checkOnlyHardLimits(pump.baseBasalRate, R.string.current_basal_value, 0.01, hardLimits.maxBasal())) return startPart = System.currentTimeMillis() if (constraintChecker.isAutosensModeEnabled().value()) { - val autosensData = iobCobCalculatorPlugin.getLastAutosensDataSynchronized("OpenAPSPlugin") + val autosensData = iobCobCalculator.getLastAutosensDataWithWaitForCalculationFinish("OpenAPSPlugin") if (autosensData == null) { rxBus.send(EventOpenAPSUpdateResultGui(resourceHelper.gs(R.string.openaps_noasdata))) return @@ -163,10 +160,10 @@ open class OpenAPSAMAPlugin @Inject constructor( lastAPSResult = null lastAPSRun = 0 } else { - if (determineBasalResultAMA.rate == 0.0 && determineBasalResultAMA.duration == 0 && !treatmentsPlugin.isTempBasalInProgress) determineBasalResultAMA.tempBasalRequested = false + if (determineBasalResultAMA.rate == 0.0 && determineBasalResultAMA.duration == 0 && iobCobCalculator.getTempBasalIncludingConvertedExtended(dateUtil.now()) == null) determineBasalResultAMA.tempBasalRequested = false determineBasalResultAMA.iob = iobArray[0] val now = System.currentTimeMillis() - determineBasalResultAMA.json?.put("timestamp", DateUtil.toISOString(now)) + determineBasalResultAMA.json?.put("timestamp", dateUtil.toISOString(now)) determineBasalResultAMA.inputConstraints = inputConstraints lastDetermineBasalAdapterAMAJS = determineBasalAdapterAMAJS lastAPSResult = determineBasalResultAMA diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/aps/openAPSSMB/DetermineBasalAdapterSMBJS.kt b/app/src/main/java/info/nightscout/androidaps/plugins/aps/openAPSSMB/DetermineBasalAdapterSMBJS.kt index a980bb1bd4..6f00336ed0 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/aps/openAPSSMB/DetermineBasalAdapterSMBJS.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/aps/openAPSSMB/DetermineBasalAdapterSMBJS.kt @@ -6,7 +6,8 @@ import info.nightscout.androidaps.R import info.nightscout.androidaps.data.IobTotal import info.nightscout.androidaps.data.MealData import info.nightscout.androidaps.data.Profile -import info.nightscout.androidaps.interfaces.ActivePluginProvider +import info.nightscout.androidaps.interfaces.ActivePlugin +import info.nightscout.androidaps.interfaces.IobCobCalculator import info.nightscout.androidaps.interfaces.ProfileFunction import info.nightscout.androidaps.logging.AAPSLogger import info.nightscout.androidaps.logging.LTag @@ -15,9 +16,10 @@ import info.nightscout.androidaps.plugins.aps.loop.ScriptReader import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker import info.nightscout.androidaps.plugins.general.openhumans.OpenHumansUploader import info.nightscout.androidaps.plugins.iob.iobCobCalculator.GlucoseStatus -import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorPlugin -import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin import info.nightscout.androidaps.utils.SafeParse +import info.nightscout.androidaps.extensions.convertedToAbsolute +import info.nightscout.androidaps.extensions.getPassedDurationToTimeInMinutes +import info.nightscout.androidaps.extensions.plannedRemainingMinutes import info.nightscout.androidaps.utils.resources.ResourceHelper import info.nightscout.androidaps.utils.sharedPreferences.SP import org.json.JSONArray @@ -37,8 +39,8 @@ class DetermineBasalAdapterSMBJS internal constructor(private val scriptReader: @Inject lateinit var sp: SP @Inject lateinit var resourceHelper: ResourceHelper @Inject lateinit var profileFunction: ProfileFunction - @Inject lateinit var treatmentsPlugin: TreatmentsPlugin - @Inject lateinit var activePluginProvider: ActivePluginProvider + @Inject lateinit var iobCobCalculator: IobCobCalculator + @Inject lateinit var activePlugin: ActivePlugin @Inject lateinit var openHumansUploader: OpenHumansUploader private var profile = JSONObject() @@ -173,7 +175,7 @@ class DetermineBasalAdapterSMBJS internal constructor(private val scriptReader: advancedFiltering: Boolean, isSaveCgmSource: Boolean ) { - val pump = activePluginProvider.activePump + val pump = activePlugin.activePump val pumpBolusStep = pump.pumpDescription.bolusStep this.profile.put("max_iob", maxIob) //mProfile.put("dia", profile.getDia()); @@ -227,17 +229,14 @@ class DetermineBasalAdapterSMBJS internal constructor(private val scriptReader: this.profile.put("out_units", "mmol/L") } val now = System.currentTimeMillis() - val tb = treatmentsPlugin.getTempBasalFromHistory(now) + val tb = iobCobCalculator.getTempBasalIncludingConvertedExtended(now) currentTemp.put("temp", "absolute") currentTemp.put("duration", tb?.plannedRemainingMinutes ?: 0) - currentTemp.put("rate", tb?.tempBasalConvertedToAbsolute(now, profile) ?: 0.0) - + currentTemp.put("rate", tb?.convertedToAbsolute(now, profile) ?: 0.0) // as we have non default temps longer than 30 mintues - val tempBasal = treatmentsPlugin.getTempBasalFromHistory(System.currentTimeMillis()) - if (tempBasal != null) { - currentTemp.put("minutesrunning", tempBasal.realDuration) - } - iobData = IobCobCalculatorPlugin.convertToJSONArray(iobArray) + if (tb != null) currentTemp.put("minutesrunning", tb.getPassedDurationToTimeInMinutes(now)) + + iobData = iobCobCalculator.convertToJSONArray(iobArray) mGlucoseStatus.put("glucose", glucoseStatus.glucose) mGlucoseStatus.put("noise", glucoseStatus.noise) if (sp.getBoolean(R.string.key_always_use_shortavg, false)) { @@ -249,7 +248,6 @@ class DetermineBasalAdapterSMBJS internal constructor(private val scriptReader: mGlucoseStatus.put("long_avgdelta", glucoseStatus.longAvgDelta) mGlucoseStatus.put("date", glucoseStatus.date) this.mealData.put("carbs", mealData.carbs) - this.mealData.put("boluses", mealData.boluses) this.mealData.put("mealCOB", mealData.mealCOB) this.mealData.put("slopeFromMaxDeviation", mealData.slopeFromMaxDeviation) this.mealData.put("slopeFromMinDeviation", mealData.slopeFromMinDeviation) diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/aps/openAPSSMB/DetermineBasalResultSMB.kt b/app/src/main/java/info/nightscout/androidaps/plugins/aps/openAPSSMB/DetermineBasalResultSMB.kt index 46b68bbd0a..996621b8db 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/aps/openAPSSMB/DetermineBasalResultSMB.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/aps/openAPSSMB/DetermineBasalResultSMB.kt @@ -3,7 +3,6 @@ package info.nightscout.androidaps.plugins.aps.openAPSSMB import dagger.android.HasAndroidInjector import info.nightscout.androidaps.logging.LTag import info.nightscout.androidaps.plugins.aps.loop.APSResult -import info.nightscout.androidaps.utils.DateUtil import org.json.JSONException import org.json.JSONObject @@ -13,7 +12,7 @@ class DetermineBasalResultSMB private constructor(injector: HasAndroidInjector) private var snoozeBG = 0.0 internal constructor(injector: HasAndroidInjector, result: JSONObject) : this(injector) { - date = DateUtil.now() + date = dateUtil.now() json = result try { if (result.has("error")) { @@ -47,7 +46,7 @@ class DetermineBasalResultSMB private constructor(injector: HasAndroidInjector) if (result.has("deliverAt")) { val date = result.getString("deliverAt") try { - deliverAt = DateUtil.fromISODateString(date).time + deliverAt = dateUtil.fromISODateString(date) } catch (e: Exception) { aapsLogger.error(LTag.APS, "Error parsing 'deliverAt' date: $date", e) } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/aps/openAPSSMB/OpenAPSSMBFragment.kt b/app/src/main/java/info/nightscout/androidaps/plugins/aps/openAPSSMB/OpenAPSSMBFragment.kt index be4e1015fa..61e52b0821 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/aps/openAPSSMB/OpenAPSSMBFragment.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/aps/openAPSSMB/OpenAPSSMBFragment.kt @@ -36,6 +36,7 @@ class OpenAPSSMBFragment : DaggerFragment() { @Inject lateinit var fabricPrivacy: FabricPrivacy @Inject lateinit var openAPSSMBPlugin: OpenAPSSMBPlugin @Inject lateinit var dateUtil: DateUtil + @Inject lateinit var jsonFormatter: JSONFormatter private var _binding: OpenapsamaFragmentBinding? = null @@ -92,23 +93,23 @@ class OpenAPSSMBFragment : DaggerFragment() { fun updateGUI() { if (_binding == null) return openAPSSMBPlugin.lastAPSResult?.let { lastAPSResult -> - binding.result.text = JSONFormatter.format(lastAPSResult.json) + binding.result.text = jsonFormatter.format(lastAPSResult.json) binding.request.text = lastAPSResult.toSpanned() } openAPSSMBPlugin.lastDetermineBasalAdapterSMBJS?.let { determineBasalAdapterSMBJS -> - binding.glucosestatus.text = JSONFormatter.format(determineBasalAdapterSMBJS.glucoseStatusParam) - binding.currenttemp.text = JSONFormatter.format(determineBasalAdapterSMBJS.currentTempParam) + binding.glucosestatus.text = jsonFormatter.format(determineBasalAdapterSMBJS.glucoseStatusParam) + binding.currenttemp.text = jsonFormatter.format(determineBasalAdapterSMBJS.currentTempParam) try { val iobArray = JSONArray(determineBasalAdapterSMBJS.iobDataParam) - binding.iobdata.text = TextUtils.concat(resourceHelper.gs(R.string.array_of_elements, iobArray.length()) + "\n", JSONFormatter.format(iobArray.getString(0))) + binding.iobdata.text = TextUtils.concat(resourceHelper.gs(R.string.array_of_elements, iobArray.length()) + "\n", jsonFormatter.format(iobArray.getString(0))) } catch (e: JSONException) { aapsLogger.error(LTag.APS, "Unhandled exception", e) @SuppressLint("SetTextI18n") binding.iobdata.text = "JSONException see log for details" } - binding.profile.text = JSONFormatter.format(determineBasalAdapterSMBJS.profileParam) - binding.mealdata.text = JSONFormatter.format(determineBasalAdapterSMBJS.mealDataParam) + binding.profile.text = jsonFormatter.format(determineBasalAdapterSMBJS.profileParam) + binding.mealdata.text = jsonFormatter.format(determineBasalAdapterSMBJS.mealDataParam) binding.scriptdebugdata.text = determineBasalAdapterSMBJS.scriptDebug openAPSSMBPlugin.lastAPSResult?.inputConstraints?.let { binding.constraints.text = it.getReasons(aapsLogger) @@ -118,7 +119,7 @@ class OpenAPSSMBFragment : DaggerFragment() { binding.lastrun.text = dateUtil.dateAndTimeString(openAPSSMBPlugin.lastAPSRun) } openAPSSMBPlugin.lastAutosensResult.let { - binding.autosensdata.text = JSONFormatter.format(it.json()) + binding.autosensdata.text = jsonFormatter.format(it.json()) } } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/aps/openAPSSMB/OpenAPSSMBPlugin.kt b/app/src/main/java/info/nightscout/androidaps/plugins/aps/openAPSSMB/OpenAPSSMBPlugin.kt index 29d071867d..9bf1fc3f37 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/aps/openAPSSMB/OpenAPSSMBPlugin.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/aps/openAPSSMB/OpenAPSSMBPlugin.kt @@ -17,14 +17,12 @@ import info.nightscout.androidaps.plugins.aps.loop.ScriptReader import info.nightscout.androidaps.plugins.bus.RxBusWrapper import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker import info.nightscout.androidaps.plugins.iob.iobCobCalculator.AutosensResult -import info.nightscout.androidaps.plugins.iob.iobCobCalculator.GlucoseStatus import info.nightscout.androidaps.plugins.iob.iobCobCalculator.GlucoseStatusProvider -import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorPlugin import info.nightscout.androidaps.utils.DateUtil import info.nightscout.androidaps.utils.HardLimits import info.nightscout.androidaps.utils.Profiler import info.nightscout.androidaps.utils.Round -import info.nightscout.androidaps.utils.extensions.target +import info.nightscout.androidaps.extensions.target import info.nightscout.androidaps.utils.resources.ResourceHelper import info.nightscout.androidaps.utils.sharedPreferences.SP import javax.inject.Inject @@ -39,9 +37,8 @@ open class OpenAPSSMBPlugin @Inject constructor( resourceHelper: ResourceHelper, private val profileFunction: ProfileFunction, private val context: Context, - private val activePlugin: ActivePluginProvider, - private val treatmentsPlugin: TreatmentsInterface, - private val iobCobCalculatorPlugin: IobCobCalculatorPlugin, + private val activePlugin: ActivePlugin, + private val iobCobCalculator: IobCobCalculator, private val hardLimits: HardLimits, private val profiler: Profiler, private val sp: SP, @@ -58,7 +55,7 @@ open class OpenAPSSMBPlugin @Inject constructor( .description(R.string.description_smb) .setDefault(), aapsLogger, resourceHelper, injector -), APSInterface, ConstraintsInterface { +), APS, Constraints { // last values override var lastAPSRun: Long = 0 @@ -125,7 +122,7 @@ open class OpenAPSSMBPlugin @Inject constructor( var maxBg = hardLimits.verifyHardLimits(Round.roundTo(profile.targetHighMgdl, 0.1), R.string.profile_high_target, HardLimits.VERY_HARD_LIMIT_MAX_BG[0].toDouble(), HardLimits.VERY_HARD_LIMIT_MAX_BG[1].toDouble()) var targetBg = hardLimits.verifyHardLimits(profile.targetMgdl, R.string.temp_target_value, HardLimits.VERY_HARD_LIMIT_TARGET_BG[0].toDouble(), HardLimits.VERY_HARD_LIMIT_TARGET_BG[1].toDouble()) var isTempTarget = false - val tempTarget = repository.getTemporaryTargetActiveAt(dateUtil._now()).blockingGet() + val tempTarget = repository.getTemporaryTargetActiveAt(dateUtil.now()).blockingGet() if (tempTarget is ValueWrapper.Existing) { isTempTarget = true minBg = hardLimits.verifyHardLimits(tempTarget.value.lowTarget, R.string.temp_target_low_target, HardLimits.VERY_HARD_LIMIT_TEMP_MIN_BG[0].toDouble(), HardLimits.VERY_HARD_LIMIT_TEMP_MIN_BG[1].toDouble()) @@ -139,7 +136,7 @@ open class OpenAPSSMBPlugin @Inject constructor( if (!hardLimits.checkOnlyHardLimits(pump.baseBasalRate, R.string.current_basal_value, 0.01, hardLimits.maxBasal())) return startPart = System.currentTimeMillis() if (constraintChecker.isAutosensModeEnabled().value()) { - val autosensData = iobCobCalculatorPlugin.getLastAutosensDataSynchronized("OpenAPSPlugin") + val autosensData = iobCobCalculator.getLastAutosensDataWithWaitForCalculationFinish("OpenAPSPlugin") if (autosensData == null) { rxBus.send(EventOpenAPSUpdateResultGui(resourceHelper.gs(R.string.openaps_noasdata))) return @@ -148,7 +145,7 @@ open class OpenAPSSMBPlugin @Inject constructor( } else { lastAutosensResult.sensResult = "autosens disabled" } - val iobArray = iobCobCalculatorPlugin.calculateIobArrayForSMB(lastAutosensResult, SMBDefaults.exercise_mode, SMBDefaults.half_basal_exercise_target, isTempTarget) + val iobArray = iobCobCalculator.calculateIobArrayForSMB(lastAutosensResult, SMBDefaults.exercise_mode, SMBDefaults.half_basal_exercise_target, isTempTarget) profiler.log(LTag.APS, "calculateIobArrayInDia()", startPart) startPart = System.currentTimeMillis() val smbAllowed = Constraint(!tempBasalFallback).also { @@ -172,7 +169,7 @@ open class OpenAPSSMBPlugin @Inject constructor( activePlugin.activePump.baseBasalRate, iobArray, glucoseStatus, - iobCobCalculatorPlugin.mealData, + iobCobCalculator.getMealDataWithWaitingForCalculationFinish(), lastAutosensResult.ratio, isTempTarget, smbAllowed.value(), @@ -190,9 +187,9 @@ open class OpenAPSSMBPlugin @Inject constructor( } else { // TODO still needed with oref1? // Fix bug determine basal - if (determineBasalResultSMB.rate == 0.0 && determineBasalResultSMB.duration == 0 && !treatmentsPlugin.isTempBasalInProgress) determineBasalResultSMB.tempBasalRequested = false + if (determineBasalResultSMB.rate == 0.0 && determineBasalResultSMB.duration == 0 && iobCobCalculator.getTempBasalIncludingConvertedExtended(dateUtil.now()) == null) determineBasalResultSMB.tempBasalRequested = false determineBasalResultSMB.iob = iobArray[0] - determineBasalResultSMB.json?.put("timestamp", DateUtil.toISOString(now)) + determineBasalResultSMB.json?.put("timestamp", dateUtil.toISOString(now)) determineBasalResultSMB.inputConstraints = inputConstraints lastDetermineBasalAdapterSMBJS = determineBasalAdapterSMBJS lastAPSResult = determineBasalResultSMB diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/configBuilder/ConfigBuilderFragment.kt b/app/src/main/java/info/nightscout/androidaps/plugins/configBuilder/ConfigBuilderFragment.kt index 8a19808833..36c00a74e6 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/configBuilder/ConfigBuilderFragment.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/configBuilder/ConfigBuilderFragment.kt @@ -9,7 +9,7 @@ import android.widget.* import androidx.annotation.StringRes import androidx.core.content.ContextCompat import dagger.android.support.DaggerFragment -import info.nightscout.androidaps.Config +import info.nightscout.androidaps.interfaces.Config import info.nightscout.androidaps.R import info.nightscout.androidaps.activities.PreferencesActivity import info.nightscout.androidaps.databinding.ConfigbuilderFragmentBinding @@ -19,7 +19,7 @@ import info.nightscout.androidaps.plugins.bus.RxBusWrapper import info.nightscout.androidaps.plugins.configBuilder.events.EventConfigBuilderUpdateGui import info.nightscout.androidaps.utils.FabricPrivacy import io.reactivex.rxkotlin.plusAssign -import info.nightscout.androidaps.utils.extensions.toVisibility +import info.nightscout.androidaps.extensions.toVisibility import info.nightscout.androidaps.utils.protection.ProtectionCheck import info.nightscout.androidaps.utils.resources.ResourceHelper import info.nightscout.androidaps.utils.rx.AapsSchedulers @@ -34,7 +34,7 @@ class ConfigBuilderFragment : DaggerFragment() { @Inject lateinit var resourceHelper: ResourceHelper @Inject lateinit var configBuilderPlugin: ConfigBuilderPlugin @Inject lateinit var fabricPrivacy: FabricPrivacy - @Inject lateinit var activePlugin: ActivePluginProvider + @Inject lateinit var activePlugin: ActivePlugin @Inject lateinit var protectionCheck: ProtectionCheck @Inject lateinit var config: Config @@ -101,18 +101,18 @@ class ConfigBuilderFragment : DaggerFragment() { private fun updateGUI() { binding.categories.removeAllViews() if (!config.NSCLIENT) { - createViewsForPlugins(R.string.configbuilder_profile, R.string.configbuilder_profile_description, PluginType.PROFILE, activePlugin.getSpecificPluginsVisibleInListByInterface(ProfileInterface::class.java, PluginType.PROFILE)) + createViewsForPlugins(R.string.configbuilder_profile, R.string.configbuilder_profile_description, PluginType.PROFILE, activePlugin.getSpecificPluginsVisibleInList(PluginType.PROFILE)) } - createViewsForPlugins(R.string.configbuilder_insulin, R.string.configbuilder_insulin_description, PluginType.INSULIN, activePlugin.getSpecificPluginsVisibleInListByInterface(InsulinInterface::class.java, PluginType.INSULIN)) + createViewsForPlugins(R.string.configbuilder_insulin, R.string.configbuilder_insulin_description, PluginType.INSULIN, activePlugin.getSpecificPluginsVisibleInList(PluginType.INSULIN)) if (!config.NSCLIENT) { - createViewsForPlugins(R.string.configbuilder_bgsource, R.string.configbuilder_bgsource_description, PluginType.BGSOURCE, activePlugin.getSpecificPluginsVisibleInListByInterface(BgSourceInterface::class.java, PluginType.BGSOURCE)) + createViewsForPlugins(R.string.configbuilder_bgsource, R.string.configbuilder_bgsource_description, PluginType.BGSOURCE, activePlugin.getSpecificPluginsVisibleInList(PluginType.BGSOURCE)) createViewsForPlugins(R.string.configbuilder_pump, R.string.configbuilder_pump_description, PluginType.PUMP, activePlugin.getSpecificPluginsVisibleInList(PluginType.PUMP)) } - createViewsForPlugins(R.string.configbuilder_sensitivity, R.string.configbuilder_sensitivity_description, PluginType.SENSITIVITY, activePlugin.getSpecificPluginsVisibleInListByInterface(SensitivityInterface::class.java, PluginType.SENSITIVITY)) + createViewsForPlugins(R.string.configbuilder_sensitivity, R.string.configbuilder_sensitivity_description, PluginType.SENSITIVITY, activePlugin.getSpecificPluginsVisibleInList(PluginType.SENSITIVITY)) if (config.APS) { createViewsForPlugins(R.string.configbuilder_aps, R.string.configbuilder_aps_description, PluginType.APS, activePlugin.getSpecificPluginsVisibleInList(PluginType.APS)) createViewsForPlugins(R.string.configbuilder_loop, R.string.configbuilder_loop_description, PluginType.LOOP, activePlugin.getSpecificPluginsVisibleInList(PluginType.LOOP)) - createViewsForPlugins(R.string.constraints, R.string.configbuilder_constraints_description, PluginType.CONSTRAINTS, activePlugin.getSpecificPluginsVisibleInListByInterface(ConstraintsInterface::class.java, PluginType.CONSTRAINTS)) + createViewsForPlugins(R.string.constraints, R.string.configbuilder_constraints_description, PluginType.CONSTRAINTS, activePlugin.getSpecificPluginsVisibleInList(PluginType.CONSTRAINTS)) } createViewsForPlugins(R.string.configbuilder_treatments, R.string.configbuilder_treatments_description, PluginType.TREATMENT, activePlugin.getSpecificPluginsVisibleInList(PluginType.TREATMENT)) createViewsForPlugins(R.string.configbuilder_general, R.string.configbuilder_general_description, PluginType.GENERAL, activePlugin.getSpecificPluginsVisibleInList(PluginType.GENERAL)) diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/configBuilder/ConfigBuilderPlugin.kt b/app/src/main/java/info/nightscout/androidaps/plugins/configBuilder/ConfigBuilderPlugin.kt index d2065c238c..3b0ab58075 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/configBuilder/ConfigBuilderPlugin.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/configBuilder/ConfigBuilderPlugin.kt @@ -3,7 +3,9 @@ package info.nightscout.androidaps.plugins.configBuilder import androidx.fragment.app.FragmentActivity import dagger.android.HasAndroidInjector import info.nightscout.androidaps.R -import info.nightscout.androidaps.database.entities.UserEntry.* +import info.nightscout.androidaps.database.entities.UserEntry.Action +import info.nightscout.androidaps.database.entities.UserEntry.Sources +import info.nightscout.androidaps.database.entities.ValueWithUnit import info.nightscout.androidaps.events.EventAppInitialized import info.nightscout.androidaps.events.EventConfigBuilderChange import info.nightscout.androidaps.events.EventRebuildTabs @@ -27,8 +29,9 @@ class ConfigBuilderPlugin @Inject constructor( resourceHelper: ResourceHelper, private val sp: SP, private val rxBus: RxBusWrapper, - private val activePlugin: ActivePluginProvider, - private val uel: UserEntryLogger + private val activePlugin: ActivePlugin, + private val uel: UserEntryLogger, + private val pumpSync: PumpSync ) : PluginBase(PluginDescription() .mainType(PluginType.GENERAL) .fragmentClass(ConfigBuilderFragment::class.java.name) @@ -40,9 +43,9 @@ class ConfigBuilderPlugin @Inject constructor( .shortName(R.string.configbuilder_shortname) .description(R.string.description_config_builder), aapsLogger, resourceHelper, injector -), ConfigBuilderInterface { +), ConfigBuilder { - fun initialize() { + override fun initialize() { (activePlugin as PluginStore).loadDefaults() loadSettings() setAlwaysEnabledPluginsEnabled() @@ -66,7 +69,7 @@ class ConfigBuilderPlugin @Inject constructor( if (p.pluginDescription.alwaysEnabled && p.pluginDescription.neverVisible) continue savePref(p, type, true) if (type == PluginType.PUMP) { - if (p is ProfileInterface) { // Store state of optional Profile interface + if (p is ProfileSource) { // Store state of optional Profile interface savePref(p, PluginType.PROFILE, false) } } @@ -90,7 +93,7 @@ class ConfigBuilderPlugin @Inject constructor( val type = p.getType() loadPref(p, type, true) if (p.getType() == PluginType.PUMP) { - if (p is ProfileInterface) { + if (p is ProfileSource) { loadPref(p, PluginType.PROFILE, false) } } @@ -139,13 +142,16 @@ class ConfigBuilderPlugin @Inject constructor( val allowHardwarePump = sp.getBoolean("allow_hardware_pump", false) if (allowHardwarePump || activity == null) { performPluginSwitch(changedPlugin, newState, type) + pumpSync.connectNewPump() } else { - OKDialog.showConfirmation(activity, resourceHelper.gs(R.string.allow_hardware_pump_text), Runnable { + OKDialog.showConfirmation(activity, resourceHelper.gs(R.string.allow_hardware_pump_text), { performPluginSwitch(changedPlugin, newState, type) + pumpSync.connectNewPump() sp.putBoolean("allow_hardware_pump", true) - uel.log(Action.HW_PUMP_ALLOWED) + uel.log(Action.HW_PUMP_ALLOWED, Sources.ConfigBuilder, resourceHelper.gs(changedPlugin.pluginDescription.pluginName), + ValueWithUnit.SimpleString(resourceHelper.gsNotLocalised(changedPlugin.pluginDescription.pluginName))) aapsLogger.debug(LTag.PUMP, "First time HW pump allowed!") - }, Runnable { + }, { rxBus.send(EventConfigBuilderUpdateGui()) aapsLogger.debug(LTag.PUMP, "User does not allow switching to HW pump!") }) @@ -153,6 +159,14 @@ class ConfigBuilderPlugin @Inject constructor( } override fun performPluginSwitch(changedPlugin: PluginBase, enabled: Boolean, type: PluginType) { + if(enabled && !changedPlugin.isEnabled()) { + uel.log(Action.PLUGIN_ENABLED, Sources.ConfigBuilder, resourceHelper.gs(changedPlugin.pluginDescription.pluginName), + ValueWithUnit.SimpleString(resourceHelper.gsNotLocalised(changedPlugin.pluginDescription.pluginName))) + } + else if(!enabled) { + uel.log(Action.PLUGIN_DISABLED, Sources.ConfigBuilder, resourceHelper.gs(changedPlugin.pluginDescription.pluginName), + ValueWithUnit.SimpleString(resourceHelper.gsNotLocalised(changedPlugin.pluginDescription.pluginName))) + } changedPlugin.setPluginEnabled(type, enabled) changedPlugin.setFragmentVisible(type, enabled) processOnEnabledCategoryChanged(changedPlugin, type) @@ -166,13 +180,13 @@ class ConfigBuilderPlugin @Inject constructor( fun processOnEnabledCategoryChanged(changedPlugin: PluginBase, type: PluginType?) { var pluginsInCategory: ArrayList? = null when (type) { - PluginType.INSULIN -> pluginsInCategory = activePlugin.getSpecificPluginsListByInterface(InsulinInterface::class.java) - PluginType.SENSITIVITY -> pluginsInCategory = activePlugin.getSpecificPluginsListByInterface(SensitivityInterface::class.java) - PluginType.APS -> pluginsInCategory = activePlugin.getSpecificPluginsListByInterface(APSInterface::class.java) - PluginType.PROFILE -> pluginsInCategory = activePlugin.getSpecificPluginsListByInterface(ProfileInterface::class.java) - PluginType.BGSOURCE -> pluginsInCategory = activePlugin.getSpecificPluginsListByInterface(BgSourceInterface::class.java) + PluginType.INSULIN -> pluginsInCategory = activePlugin.getSpecificPluginsListByInterface(Insulin::class.java) + PluginType.SENSITIVITY -> pluginsInCategory = activePlugin.getSpecificPluginsListByInterface(Sensitivity::class.java) + PluginType.APS -> pluginsInCategory = activePlugin.getSpecificPluginsListByInterface(APS::class.java) + PluginType.PROFILE -> pluginsInCategory = activePlugin.getSpecificPluginsListByInterface(ProfileSource::class.java) + PluginType.BGSOURCE -> pluginsInCategory = activePlugin.getSpecificPluginsListByInterface(BgSource::class.java) PluginType.TREATMENT -> pluginsInCategory = activePlugin.getSpecificPluginsListByInterface(TreatmentsInterface::class.java) - PluginType.PUMP -> pluginsInCategory = activePlugin.getSpecificPluginsListByInterface(PumpInterface::class.java) + PluginType.PUMP -> pluginsInCategory = activePlugin.getSpecificPluginsListByInterface(Pump::class.java) else -> { } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/configBuilder/PluginStore.kt b/app/src/main/java/info/nightscout/androidaps/plugins/configBuilder/PluginStore.kt index f0945429c5..a459b9c00c 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/configBuilder/PluginStore.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/configBuilder/PluginStore.kt @@ -1,6 +1,6 @@ package info.nightscout.androidaps.plugins.configBuilder -import info.nightscout.androidaps.Config +import info.nightscout.androidaps.interfaces.Config import info.nightscout.androidaps.interfaces.* import info.nightscout.androidaps.logging.AAPSLogger import info.nightscout.androidaps.logging.LTag @@ -11,23 +11,23 @@ import javax.inject.Singleton class PluginStore @Inject constructor( private val aapsLogger: AAPSLogger, private val config: Config -) : ActivePluginProvider { +) : ActivePlugin { lateinit var plugins: List<@JvmSuppressWildcards PluginBase> - private var activeBgSourceStore: BgSourceInterface? = null - private var activePumpStore: PumpInterface? = null - private var activeProfile: ProfileInterface? = null - private var activeAPSStore: APSInterface? = null - private var activeInsulinStore: InsulinInterface? = null - private var activeSensitivityStore: SensitivityInterface? = null + private var activeBgSourceStore: BgSource? = null + private var activePumpStore: Pump? = null + private var activeProfile: ProfileSource? = null + private var activeAPSStore: APS? = null + private var activeInsulinStore: Insulin? = null + private var activeSensitivityStore: Sensitivity? = null private var activeTreatmentsStore: TreatmentsInterface? = null fun loadDefaults() { verifySelectionInCategories() } - fun getDefaultPlugin(type: PluginType): PluginBase { + private fun getDefaultPlugin(type: PluginType): PluginBase { for (p in plugins) if (p.getType() == type && p.isDefault()) return p throw IllegalStateException("Default plugin not found") @@ -41,14 +41,6 @@ class PluginStore @Inject constructor( return newList } - override fun getSpecificPluginsVisibleInList(type: PluginType): ArrayList { - val newList = ArrayList() - for (p in plugins) { - if (p.getType() == type) if (p.showInList(type)) newList.add(p) - } - return newList - } - override fun getSpecificPluginsListByInterface(interfaceClass: Class<*>): ArrayList { val newList = ArrayList() for (p in plugins) { @@ -57,10 +49,10 @@ class PluginStore @Inject constructor( return newList } - override fun getSpecificPluginsVisibleInListByInterface(interfaceClass: Class<*>, type: PluginType): ArrayList { + override fun getSpecificPluginsVisibleInList(type: PluginType): ArrayList { val newList = ArrayList() for (p in plugins) { - if (p.javaClass != ConfigBuilderPlugin::class.java && interfaceClass.isAssignableFrom(p.javaClass)) if (p.showInList(type)) newList.add(p) + if (p.getType() == type) if (p.showInList(type)) newList.add(p) } return newList } @@ -71,64 +63,64 @@ class PluginStore @Inject constructor( // PluginType.APS if (!config.NSCLIENT && !config.PUMPCONTROL) { pluginsInCategory = getSpecificPluginsList(PluginType.APS) - activeAPSStore = getTheOneEnabledInArray(pluginsInCategory, PluginType.APS) as APSInterface? + activeAPSStore = getTheOneEnabledInArray(pluginsInCategory, PluginType.APS) as APS? if (activeAPSStore == null) { - activeAPSStore = getDefaultPlugin(PluginType.APS) as APSInterface + activeAPSStore = getDefaultPlugin(PluginType.APS) as APS (activeAPSStore as PluginBase).setPluginEnabled(PluginType.APS, true) aapsLogger.debug(LTag.CONFIGBUILDER, "Defaulting APSInterface") } - setFragmentVisiblities((activeAPSStore as PluginBase).name, pluginsInCategory, PluginType.APS) + setFragmentVisibilities((activeAPSStore as PluginBase).name, pluginsInCategory, PluginType.APS) } // PluginType.INSULIN pluginsInCategory = getSpecificPluginsList(PluginType.INSULIN) - activeInsulinStore = getTheOneEnabledInArray(pluginsInCategory, PluginType.INSULIN) as InsulinInterface? + activeInsulinStore = getTheOneEnabledInArray(pluginsInCategory, PluginType.INSULIN) as Insulin? if (activeInsulinStore == null) { - activeInsulinStore = getDefaultPlugin(PluginType.INSULIN) as InsulinInterface + activeInsulinStore = getDefaultPlugin(PluginType.INSULIN) as Insulin (activeInsulinStore as PluginBase).setPluginEnabled(PluginType.INSULIN, true) aapsLogger.debug(LTag.CONFIGBUILDER, "Defaulting InsulinInterface") } - setFragmentVisiblities((activeInsulinStore as PluginBase).name, pluginsInCategory, PluginType.INSULIN) + setFragmentVisibilities((activeInsulinStore as PluginBase).name, pluginsInCategory, PluginType.INSULIN) // PluginType.SENSITIVITY pluginsInCategory = getSpecificPluginsList(PluginType.SENSITIVITY) - activeSensitivityStore = getTheOneEnabledInArray(pluginsInCategory, PluginType.SENSITIVITY) as SensitivityInterface? + activeSensitivityStore = getTheOneEnabledInArray(pluginsInCategory, PluginType.SENSITIVITY) as Sensitivity? if (activeSensitivityStore == null) { - activeSensitivityStore = getDefaultPlugin(PluginType.SENSITIVITY) as SensitivityInterface + activeSensitivityStore = getDefaultPlugin(PluginType.SENSITIVITY) as Sensitivity (activeSensitivityStore as PluginBase).setPluginEnabled(PluginType.SENSITIVITY, true) aapsLogger.debug(LTag.CONFIGBUILDER, "Defaulting SensitivityInterface") } - setFragmentVisiblities((activeSensitivityStore as PluginBase).name, pluginsInCategory, PluginType.SENSITIVITY) + setFragmentVisibilities((activeSensitivityStore as PluginBase).name, pluginsInCategory, PluginType.SENSITIVITY) // PluginType.PROFILE pluginsInCategory = getSpecificPluginsList(PluginType.PROFILE) - activeProfile = getTheOneEnabledInArray(pluginsInCategory, PluginType.PROFILE) as ProfileInterface? + activeProfile = getTheOneEnabledInArray(pluginsInCategory, PluginType.PROFILE) as ProfileSource? if (activeProfile == null) { - activeProfile = getDefaultPlugin(PluginType.PROFILE) as ProfileInterface + activeProfile = getDefaultPlugin(PluginType.PROFILE) as ProfileSource (activeProfile as PluginBase).setPluginEnabled(PluginType.PROFILE, true) aapsLogger.debug(LTag.CONFIGBUILDER, "Defaulting ProfileInterface") } - setFragmentVisiblities((activeProfile as PluginBase).name, pluginsInCategory, PluginType.PROFILE) + setFragmentVisibilities((activeProfile as PluginBase).name, pluginsInCategory, PluginType.PROFILE) // PluginType.BGSOURCE pluginsInCategory = getSpecificPluginsList(PluginType.BGSOURCE) - activeBgSourceStore = getTheOneEnabledInArray(pluginsInCategory, PluginType.BGSOURCE) as BgSourceInterface? + activeBgSourceStore = getTheOneEnabledInArray(pluginsInCategory, PluginType.BGSOURCE) as BgSource? if (activeBgSourceStore == null) { - activeBgSourceStore = getDefaultPlugin(PluginType.BGSOURCE) as BgSourceInterface + activeBgSourceStore = getDefaultPlugin(PluginType.BGSOURCE) as BgSource (activeBgSourceStore as PluginBase).setPluginEnabled(PluginType.BGSOURCE, true) aapsLogger.debug(LTag.CONFIGBUILDER, "Defaulting BgInterface") } - setFragmentVisiblities((activeBgSourceStore as PluginBase).name, pluginsInCategory, PluginType.BGSOURCE) + setFragmentVisibilities((activeBgSourceStore as PluginBase).name, pluginsInCategory, PluginType.PUMP) // PluginType.PUMP pluginsInCategory = getSpecificPluginsList(PluginType.PUMP) - activePumpStore = getTheOneEnabledInArray(pluginsInCategory, PluginType.PUMP) as PumpInterface? + activePumpStore = getTheOneEnabledInArray(pluginsInCategory, PluginType.PUMP) as Pump? if (activePumpStore == null) { - activePumpStore = getDefaultPlugin(PluginType.PUMP) as PumpInterface + activePumpStore = getDefaultPlugin(PluginType.PUMP) as Pump (activePumpStore as PluginBase).setPluginEnabled(PluginType.PUMP, true) aapsLogger.debug(LTag.CONFIGBUILDER, "Defaulting PumpInterface") } - setFragmentVisiblities((activePumpStore as PluginBase).name, pluginsInCategory, PluginType.PUMP) + setFragmentVisibilities((activePumpStore as PluginBase).name, pluginsInCategory, PluginType.PUMP) // PluginType.TREATMENT pluginsInCategory = getSpecificPluginsList(PluginType.TREATMENT) @@ -138,50 +130,11 @@ class PluginStore @Inject constructor( (activeTreatmentsStore as PluginBase).setPluginEnabled(PluginType.TREATMENT, true) aapsLogger.debug(LTag.CONFIGBUILDER, "Defaulting PumpInterface") } - setFragmentVisiblities((activeTreatmentsStore as PluginBase).name, pluginsInCategory, PluginType.TREATMENT) + setFragmentVisibilities((activeTreatmentsStore as PluginBase).name, pluginsInCategory, PluginType.TREATMENT) } - /** - * disables the visibility for all fragments of Plugins with the given PluginType - * which are not equally named to the Plugin implementing the given Plugin Interface. - * - * @param pluginInterface - * @param pluginType - * @param - * @return - */ - private fun determineActivePlugin(pluginInterface: Class, pluginType: PluginType): T? { - val pluginsInCategory: ArrayList = getSpecificPluginsListByInterface(pluginInterface) - return determineActivePlugin(pluginsInCategory, pluginType) - } - - /** - * disables the visibility for all fragments of Plugins in the given pluginsInCategory - * with the given PluginType which are not equally named to the Plugin implementing the - * given Plugin Interface. - * - * - * TODO we are casting an interface to PluginBase, which seems to be rather odd, since - * TODO the interface is not implementing PluginBase (this is just avoiding errors through - * TODO conventions. - * - * @param pluginsInCategory - * @param pluginType - * @param - * @return - */ - private fun determineActivePlugin(pluginsInCategory: ArrayList, - pluginType: PluginType): T? { - @Suppress("UNCHECKED_CAST") - val activePlugin = getTheOneEnabledInArray(pluginsInCategory, pluginType) as T? - if (activePlugin != null) { - setFragmentVisiblities((activePlugin as PluginBase).name, pluginsInCategory, pluginType) - } - return activePlugin - } - - private fun setFragmentVisiblities(activePluginName: String, pluginsInCategory: ArrayList, - pluginType: PluginType) { + private fun setFragmentVisibilities(activePluginName: String, pluginsInCategory: ArrayList, + pluginType: PluginType) { aapsLogger.debug(LTag.CONFIGBUILDER, "Selected interface: $activePluginName") for (p in pluginsInCategory) if (p.name != activePluginName) @@ -203,22 +156,22 @@ class PluginStore @Inject constructor( // ***** Interface ***** - override val activeBgSource: BgSourceInterface + override val activeBgSource: BgSource get() = activeBgSourceStore ?: checkNotNull(activeBgSourceStore) { "No bg source selected" } - override val activeProfileInterface: ProfileInterface + override val activeProfileSource: ProfileSource get() = activeProfile ?: checkNotNull(activeProfile) { "No profile selected" } - override val activeInsulin: InsulinInterface + override val activeInsulin: Insulin get() = activeInsulinStore ?: checkNotNull(activeInsulinStore) { "No insulin selected" } - override val activeAPS: APSInterface + override val activeAPS: APS get() = activeAPSStore ?: checkNotNull(activeAPSStore) { "No APS selected" } - override val activePump: PumpInterface + override val activePump: Pump get() = activePumpStore ?: checkNotNull(activePumpStore) { "No pump selected" } - override val activeSensitivity: SensitivityInterface + override val activeSensitivity: Sensitivity get() = activeSensitivityStore ?: checkNotNull(activeSensitivityStore) { "No sensitivity selected" } @@ -226,9 +179,9 @@ class PluginStore @Inject constructor( get() = activeTreatmentsStore ?: checkNotNull(activeTreatmentsStore) { "No treatments selected" } - override val activeOverview: OverviewInterface - get() = getSpecificPluginsListByInterface(OverviewInterface::class.java).first() as OverviewInterface + override val activeOverview: Overview + get() = getSpecificPluginsListByInterface(Overview::class.java).first() as Overview override fun getPluginsList(): ArrayList = ArrayList(plugins) -} \ No newline at end of file +} diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/constraints/dstHelper/DstHelperPlugin.kt b/app/src/main/java/info/nightscout/androidaps/plugins/constraints/dstHelper/DstHelperPlugin.kt index 8292346a11..42ff9ea765 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/constraints/dstHelper/DstHelperPlugin.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/constraints/dstHelper/DstHelperPlugin.kt @@ -24,7 +24,7 @@ class DstHelperPlugin @Inject constructor( private var rxBus: RxBusWrapper, resourceHelper: ResourceHelper, private var sp: SP, - private var activePlugin: ActivePluginProvider, + private var activePlugin: ActivePlugin, private var loopPlugin: LoopPlugin ) : PluginBase(PluginDescription() .mainType(PluginType.CONSTRAINTS) @@ -33,7 +33,7 @@ class DstHelperPlugin @Inject constructor( .showInList(false) .pluginName(R.string.dst_plugin_name), aapsLogger, resourceHelper, injector -), ConstraintsInterface { +), Constraints { companion object { private const val DISABLE_TIME_FRAME_HOURS = -3 diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/constraints/objectives/ObjectivesFragment.kt b/app/src/main/java/info/nightscout/androidaps/plugins/constraints/objectives/ObjectivesFragment.kt index 22fcb7052f..8f161e6ae2 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/constraints/objectives/ObjectivesFragment.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/constraints/objectives/ObjectivesFragment.kt @@ -17,7 +17,9 @@ import androidx.recyclerview.widget.LinearSmoothScroller import androidx.recyclerview.widget.RecyclerView import dagger.android.support.DaggerFragment import info.nightscout.androidaps.R -import info.nightscout.androidaps.database.entities.UserEntry.* +import info.nightscout.androidaps.database.entities.UserEntry.Action +import info.nightscout.androidaps.database.entities.UserEntry.Sources +import info.nightscout.androidaps.database.entities.ValueWithUnit import info.nightscout.androidaps.databinding.ObjectivesFragmentBinding import info.nightscout.androidaps.databinding.ObjectivesItemBinding import info.nightscout.androidaps.dialogs.NtpProgressDialog @@ -235,7 +237,7 @@ class ObjectivesFragment : DaggerFragment() { holder.binding.verify.setOnClickListener { receiverStatusStore.updateNetworkStatus() if (binding.fake.isChecked) { - objective.accomplishedOn = DateUtil.now() + objective.accomplishedOn = dateUtil.now() scrollToCurrentObjective() startUpdateTimer() rxBus.send(EventObjectivesUpdateGui()) @@ -247,7 +249,7 @@ class ObjectivesFragment : DaggerFragment() { rxBus.send(EventNtpStatus(resourceHelper.gs(R.string.timedetection), 0)) sntpClient.ntpTime(object : SntpClient.Callback() { override fun run() { - aapsLogger.debug("NTP time: $time System time: ${DateUtil.now()}") + aapsLogger.debug("NTP time: $time System time: ${dateUtil.now()}") SystemClock.sleep(300) if (!networkConnected) { rxBus.send(EventNtpStatus(resourceHelper.gs(R.string.notconnected), 99)) @@ -274,7 +276,7 @@ class ObjectivesFragment : DaggerFragment() { holder.binding.start.setOnClickListener { receiverStatusStore.updateNetworkStatus() if (binding.fake.isChecked) { - objective.startedOn = DateUtil.now() + objective.startedOn = dateUtil.now() scrollToCurrentObjective() startUpdateTimer() rxBus.send(EventObjectivesUpdateGui()) @@ -286,7 +288,7 @@ class ObjectivesFragment : DaggerFragment() { rxBus.send(EventNtpStatus(resourceHelper.gs(R.string.timedetection), 0)) sntpClient.ntpTime(object : SntpClient.Callback() { override fun run() { - aapsLogger.debug("NTP time: $time System time: ${DateUtil.now()}") + aapsLogger.debug("NTP time: $time System time: ${dateUtil.now()}") SystemClock.sleep(300) if (!networkConnected) { rxBus.send(EventNtpStatus(resourceHelper.gs(R.string.notconnected), 99)) @@ -308,7 +310,8 @@ class ObjectivesFragment : DaggerFragment() { holder.binding.unstart.setOnClickListener { activity?.let { activity -> OKDialog.showConfirmation(activity, resourceHelper.gs(R.string.objectives), resourceHelper.gs(R.string.doyouwantresetstart), Runnable { - uel.log(Action.OBJECTIVE_UNSTARTED, ValueWithUnit(position + 1, Units.None)) + uel.log(Action.OBJECTIVE_UNSTARTED, Sources.Objectives, + ValueWithUnit.SimpleInt(position + 1)) objective.startedOn = 0 scrollToCurrentObjective() rxBus.send(EventObjectivesUpdateGui()) diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/constraints/objectives/ObjectivesPlugin.kt b/app/src/main/java/info/nightscout/androidaps/plugins/constraints/objectives/ObjectivesPlugin.kt index 93090c7533..0f3fe5e7e5 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/constraints/objectives/ObjectivesPlugin.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/constraints/objectives/ObjectivesPlugin.kt @@ -5,15 +5,16 @@ import com.google.common.base.Charsets import com.google.common.hash.Hashing import dagger.android.HasAndroidInjector import info.nightscout.androidaps.BuildConfig -import info.nightscout.androidaps.Config import info.nightscout.androidaps.R -import info.nightscout.androidaps.database.entities.UserEntry.* +import info.nightscout.androidaps.database.entities.UserEntry.Action +import info.nightscout.androidaps.database.entities.UserEntry.Sources import info.nightscout.androidaps.interfaces.* import info.nightscout.androidaps.logging.AAPSLogger import info.nightscout.androidaps.logging.UserEntryLogger import info.nightscout.androidaps.plugins.constraints.objectives.objectives.* import info.nightscout.androidaps.utils.DateUtil import info.nightscout.androidaps.utils.alertDialogs.OKDialog +import info.nightscout.androidaps.utils.buildHelper.ConfigImpl import info.nightscout.androidaps.utils.resources.ResourceHelper import info.nightscout.androidaps.utils.sharedPreferences.SP import java.util.* @@ -25,9 +26,10 @@ class ObjectivesPlugin @Inject constructor( injector: HasAndroidInjector, aapsLogger: AAPSLogger, resourceHelper: ResourceHelper, - private val activePlugin: ActivePluginProvider, + private val activePlugin: ActivePlugin, private val sp: SP, - config: Config, + config: ConfigImpl, + private val dateUtil: DateUtil, private val uel: UserEntryLogger ) : PluginBase(PluginDescription() .mainType(PluginType.CONSTRAINTS) @@ -39,7 +41,7 @@ class ObjectivesPlugin @Inject constructor( .shortName(R.string.objectives_shortname) .description(R.string.description_objectives), aapsLogger, resourceHelper, injector -), ConstraintsInterface { +), Constraints { var objectives: MutableList = ArrayList() @@ -125,25 +127,25 @@ class ObjectivesPlugin @Inject constructor( if (!url.endsWith("/")) url = "$url/" @Suppress("DEPRECATION") val hashNS = Hashing.sha1().hashString(url + BuildConfig.APPLICATION_ID + "/" + requestCode, Charsets.UTF_8).toString() if (request.equals(hashNS.substring(0, 10), ignoreCase = true)) { - sp.putLong("Objectives_" + "openloop" + "_started", DateUtil.now()) - sp.putLong("Objectives_" + "openloop" + "_accomplished", DateUtil.now()) - sp.putLong("Objectives_" + "maxbasal" + "_started", DateUtil.now()) - sp.putLong("Objectives_" + "maxbasal" + "_accomplished", DateUtil.now()) - sp.putLong("Objectives_" + "maxiobzero" + "_started", DateUtil.now()) - sp.putLong("Objectives_" + "maxiobzero" + "_accomplished", DateUtil.now()) - sp.putLong("Objectives_" + "maxiob" + "_started", DateUtil.now()) - sp.putLong("Objectives_" + "maxiob" + "_accomplished", DateUtil.now()) - sp.putLong("Objectives_" + "autosens" + "_started", DateUtil.now()) - sp.putLong("Objectives_" + "autosens" + "_accomplished", DateUtil.now()) - sp.putLong("Objectives_" + "ama" + "_started", DateUtil.now()) - sp.putLong("Objectives_" + "ama" + "_accomplished", DateUtil.now()) - sp.putLong("Objectives_" + "smb" + "_started", DateUtil.now()) - sp.putLong("Objectives_" + "smb" + "_accomplished", DateUtil.now()) - sp.putLong("Objectives_" + "auto" + "_started", DateUtil.now()) - sp.putLong("Objectives_" + "auto" + "_accomplished", DateUtil.now()) + sp.putLong("Objectives_" + "openloop" + "_started", dateUtil.now()) + sp.putLong("Objectives_" + "openloop" + "_accomplished", dateUtil.now()) + sp.putLong("Objectives_" + "maxbasal" + "_started", dateUtil.now()) + sp.putLong("Objectives_" + "maxbasal" + "_accomplished", dateUtil.now()) + sp.putLong("Objectives_" + "maxiobzero" + "_started", dateUtil.now()) + sp.putLong("Objectives_" + "maxiobzero" + "_accomplished", dateUtil.now()) + sp.putLong("Objectives_" + "maxiob" + "_started", dateUtil.now()) + sp.putLong("Objectives_" + "maxiob" + "_accomplished", dateUtil.now()) + sp.putLong("Objectives_" + "autosens" + "_started", dateUtil.now()) + sp.putLong("Objectives_" + "autosens" + "_accomplished", dateUtil.now()) + sp.putLong("Objectives_" + "ama" + "_started", dateUtil.now()) + sp.putLong("Objectives_" + "ama" + "_accomplished", dateUtil.now()) + sp.putLong("Objectives_" + "smb" + "_started", dateUtil.now()) + sp.putLong("Objectives_" + "smb" + "_accomplished", dateUtil.now()) + sp.putLong("Objectives_" + "auto" + "_started", dateUtil.now()) + sp.putLong("Objectives_" + "auto" + "_accomplished", dateUtil.now()) setupObjectives() OKDialog.show(activity, resourceHelper.gs(R.string.objectives), resourceHelper.gs(R.string.codeaccepted)) - uel.log(Action.OBJECTIVES_SKIPPED) + uel.log(Action.OBJECTIVES_SKIPPED, Sources.Objectives) } else { OKDialog.show(activity, resourceHelper.gs(R.string.objectives), resourceHelper.gs(R.string.codeinvalid)) } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/constraints/objectives/activities/ObjectivesExamDialog.kt b/app/src/main/java/info/nightscout/androidaps/plugins/constraints/objectives/activities/ObjectivesExamDialog.kt index c45d61bfd4..50c91dd6b9 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/constraints/objectives/activities/ObjectivesExamDialog.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/constraints/objectives/activities/ObjectivesExamDialog.kt @@ -108,7 +108,7 @@ class ObjectivesExamDialog : DaggerDialogFragment() { } task.answered = result if (!result) { - task.disabledTo = DateUtil.now() + T.hours(1).msecs() + task.disabledTo = dateUtil.now() + T.hours(1).msecs() ToastUtils.showToastInUiThread(context, R.string.wronganswer) } else task.disabledTo = 0 updateGui() diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/constraints/objectives/objectives/Objective.kt b/app/src/main/java/info/nightscout/androidaps/plugins/constraints/objectives/objectives/Objective.kt index 876fb881db..71f258781d 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/constraints/objectives/objectives/Objective.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/constraints/objectives/objectives/Objective.kt @@ -21,6 +21,7 @@ abstract class Objective(injector: HasAndroidInjector, spName: String, @StringRe @Inject lateinit var sp: SP @Inject lateinit var resourceHelper: ResourceHelper + @Inject lateinit var dateUtil: DateUtil private val spName: String @StringRes val objective: Int @@ -55,7 +56,7 @@ abstract class Objective(injector: HasAndroidInjector, spName: String, @StringRe this.gate = gate startedOn = sp.getLong("Objectives_" + spName + "_started", 0L) accomplishedOn = sp.getLong("Objectives_" + spName + "_accomplished", 0L) - if (accomplishedOn - DateUtil.now() > T.hours(3).msecs() || startedOn - DateUtil.now() > T.hours(3).msecs()) { // more than 3 hours in the future + if (accomplishedOn - dateUtil.now() > T.hours(3).msecs() || startedOn - dateUtil.now() > T.hours(3).msecs()) { // more than 3 hours in the future startedOn = 0 accomplishedOn = 0 } @@ -69,7 +70,7 @@ abstract class Objective(injector: HasAndroidInjector, spName: String, @StringRe } val isAccomplished: Boolean - get() = accomplishedOn != 0L && accomplishedOn < DateUtil.now() + get() = accomplishedOn != 0L && accomplishedOn < dateUtil.now() val isStarted: Boolean get() = startedOn != 0L @@ -144,7 +145,7 @@ abstract class Objective(injector: HasAndroidInjector, spName: String, @StringRe override fun isCompleted(): Boolean = answered - fun isEnabledAnswer(): Boolean = disabledTo < DateUtil.now() + fun isEnabledAnswer(): Boolean = disabledTo < dateUtil.now() fun option(option: Option): ExamTask { options.add(option) diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/constraints/objectives/objectives/Objective0.kt b/app/src/main/java/info/nightscout/androidaps/plugins/constraints/objectives/objectives/Objective0.kt index 63eaa326fc..172d88c024 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/constraints/objectives/objectives/Objective0.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/constraints/objectives/objectives/Objective0.kt @@ -2,25 +2,24 @@ package info.nightscout.androidaps.plugins.constraints.objectives.objectives import dagger.android.HasAndroidInjector import info.nightscout.androidaps.R -import info.nightscout.androidaps.interfaces.ActivePluginProvider +import info.nightscout.androidaps.interfaces.ActivePlugin +import info.nightscout.androidaps.interfaces.IobCobCalculator import info.nightscout.androidaps.interfaces.PluginBase import info.nightscout.androidaps.interfaces.PluginType import info.nightscout.androidaps.plugins.aps.loop.LoopPlugin import info.nightscout.androidaps.plugins.general.nsclient.NSClientPlugin -import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorPlugin import info.nightscout.androidaps.plugins.pump.virtual.VirtualPumpPlugin import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin -import info.nightscout.androidaps.utils.DateUtil import javax.inject.Inject class Objective0(injector: HasAndroidInjector) : Objective(injector, "config", R.string.objectives_0_objective, R.string.objectives_0_gate) { - @Inject lateinit var activePlugin: ActivePluginProvider + @Inject lateinit var activePlugin: ActivePlugin @Inject lateinit var virtualPumpPlugin: VirtualPumpPlugin @Inject lateinit var treatmentsPlugin: TreatmentsPlugin @Inject lateinit var loopPlugin: LoopPlugin @Inject lateinit var nsClientPlugin: NSClientPlugin - @Inject lateinit var iobCobCalculatorPlugin: IobCobCalculatorPlugin + @Inject lateinit var iobCobCalculator: IobCobCalculator init { tasks.add(object : Task(this, R.string.objectives_bgavailableinns) { @@ -49,7 +48,7 @@ class Objective0(injector: HasAndroidInjector) : Objective(injector, "config", R }) tasks.add(object : Task(this, R.string.hasbgdata) { override fun isCompleted(): Boolean { - return iobCobCalculatorPlugin.lastBg() != null + return iobCobCalculator.ads.lastBg() != null } }) tasks.add(object : Task(this, R.string.loopenabled) { @@ -65,7 +64,7 @@ class Objective0(injector: HasAndroidInjector) : Objective(injector, "config", R }) tasks.add(object : Task(this, R.string.activate_profile) { override fun isCompleted(): Boolean { - return treatmentsPlugin.getProfileSwitchFromHistory(DateUtil.now()) != null + return treatmentsPlugin.getProfileSwitchFromHistory(dateUtil.now()) != null } }) } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/constraints/phoneChecker/PhoneCheckerPlugin.kt b/app/src/main/java/info/nightscout/androidaps/plugins/constraints/phoneChecker/PhoneCheckerPlugin.kt index 44466da5af..19dcb7d9fd 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/constraints/phoneChecker/PhoneCheckerPlugin.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/constraints/phoneChecker/PhoneCheckerPlugin.kt @@ -5,7 +5,7 @@ import android.os.Build import com.scottyab.rootbeer.RootBeer import dagger.android.HasAndroidInjector import info.nightscout.androidaps.R -import info.nightscout.androidaps.interfaces.ConstraintsInterface +import info.nightscout.androidaps.interfaces.Constraints import info.nightscout.androidaps.interfaces.PluginBase import info.nightscout.androidaps.interfaces.PluginDescription import info.nightscout.androidaps.interfaces.PluginType @@ -27,7 +27,7 @@ class PhoneCheckerPlugin @Inject constructor( .showInList(false) .pluginName(R.string.phonechecker), aapsLogger, resourceHelper, injector -), ConstraintsInterface { +), Constraints { var phoneRooted: Boolean = false var devMode: Boolean = false diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/constraints/safety/SafetyPlugin.kt b/app/src/main/java/info/nightscout/androidaps/plugins/constraints/safety/SafetyPlugin.kt index 0a5e1927e9..1034ee46ce 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/constraints/safety/SafetyPlugin.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/constraints/safety/SafetyPlugin.kt @@ -1,7 +1,7 @@ package info.nightscout.androidaps.plugins.constraints.safety import dagger.android.HasAndroidInjector -import info.nightscout.androidaps.Config +import info.nightscout.androidaps.interfaces.Config import info.nightscout.androidaps.R import info.nightscout.androidaps.data.Profile import info.nightscout.androidaps.interfaces.* @@ -13,6 +13,7 @@ import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker import info.nightscout.androidaps.plugins.general.overview.events.EventNewNotification import info.nightscout.androidaps.plugins.general.overview.notifications.Notification import info.nightscout.androidaps.plugins.sensitivity.SensitivityOref1Plugin +import info.nightscout.androidaps.utils.DateUtil import info.nightscout.androidaps.utils.DecimalFormatter import info.nightscout.androidaps.utils.HardLimits import info.nightscout.androidaps.utils.Round @@ -34,11 +35,12 @@ class SafetyPlugin @Inject constructor( private val openAPSAMAPlugin: OpenAPSAMAPlugin, private val openAPSSMBPlugin: OpenAPSSMBPlugin, private val sensitivityOref1Plugin: SensitivityOref1Plugin, - private val activePlugin: ActivePluginProvider, + private val activePlugin: ActivePlugin, private val hardLimits: HardLimits, private val buildHelper: BuildHelper, - private val treatmentsPlugin: TreatmentsInterface, - private val config: Config + private val iobCobCalculator: IobCobCalculator, + private val config: Config, + private val dateUtil: DateUtil ) : PluginBase(PluginDescription() .mainType(PluginType.CONSTRAINTS) .neverVisible(true) @@ -47,7 +49,7 @@ class SafetyPlugin @Inject constructor( .pluginName(R.string.safety) .preferencesId(R.xml.pref_safety), aapsLogger, resourceHelper, injector -), ConstraintsInterface { +), Constraints { /** * Constraints interface @@ -68,7 +70,7 @@ class SafetyPlugin @Inject constructor( value[aapsLogger, false, resourceHelper.gs(R.string.closed_loop_disabled_on_dev_branch)] = this } val pump = activePlugin.activePump - if (!pump.isFakingTempsByExtendedBoluses && treatmentsPlugin.isInHistoryExtendedBolusInProgress) { + if (!pump.isFakingTempsByExtendedBoluses && iobCobCalculator.getExtendedBolus(dateUtil.now()) != null) { value[aapsLogger, false, resourceHelper.gs(R.string.closed_loop_disabled_with_eb)] = this } return value @@ -124,7 +126,7 @@ class SafetyPlugin @Inject constructor( val pump = activePlugin.activePump // check for pump max if (pump.pumpDescription.tempBasalStyle == PumpDescription.ABSOLUTE) { - val pumpLimit = pump.pumpDescription.pumpType.tbrSettings.maxDose + val pumpLimit = pump.pumpDescription.pumpType.tbrSettings?.maxDose ?: 0.0 absoluteRate.setIfSmaller(aapsLogger, pumpLimit, String.format(resourceHelper.gs(R.string.limitingbasalratio), pumpLimit, resourceHelper.gs(R.string.pumplimit)), this) } @@ -147,7 +149,7 @@ class SafetyPlugin @Inject constructor( percentRateAfterConst = if (percentRateAfterConst < 100) Round.ceilTo(percentRateAfterConst.toDouble(), pump.pumpDescription.tempPercentStep.toDouble()).toInt() else Round.floorTo(percentRateAfterConst.toDouble(), pump.pumpDescription.tempPercentStep.toDouble()).toInt() percentRate[aapsLogger, percentRateAfterConst, String.format(resourceHelper.gs(R.string.limitingpercentrate), percentRateAfterConst, resourceHelper.gs(R.string.pumplimit))] = this if (pump.pumpDescription.tempBasalStyle == PumpDescription.PERCENT) { - val pumpLimit = pump.pumpDescription.pumpType.tbrSettings.maxDose + val pumpLimit = pump.pumpDescription.pumpType.tbrSettings?.maxDose ?: 0.0 percentRate.setIfSmaller(aapsLogger, pumpLimit.toInt(), String.format(resourceHelper.gs(R.string.limitingbasalratio), pumpLimit, resourceHelper.gs(R.string.pumplimit)), this) } return percentRate diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/constraints/signatureVerifier/SignatureVerifierPlugin.kt b/app/src/main/java/info/nightscout/androidaps/plugins/constraints/signatureVerifier/SignatureVerifierPlugin.kt index b67def6ec7..dd7245601c 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/constraints/signatureVerifier/SignatureVerifierPlugin.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/constraints/signatureVerifier/SignatureVerifierPlugin.kt @@ -5,7 +5,7 @@ import android.content.pm.PackageManager import dagger.android.HasAndroidInjector import info.nightscout.androidaps.R import info.nightscout.androidaps.interfaces.Constraint -import info.nightscout.androidaps.interfaces.ConstraintsInterface +import info.nightscout.androidaps.interfaces.Constraints import info.nightscout.androidaps.interfaces.PluginBase import info.nightscout.androidaps.interfaces.PluginDescription import info.nightscout.androidaps.interfaces.PluginType @@ -46,7 +46,7 @@ class SignatureVerifierPlugin @Inject constructor( .showInList(false) .pluginName(R.string.signature_verifier), aapsLogger, resourceHelper, injector -), ConstraintsInterface { +), Constraints { private val REVOKED_CERTS_URL = "https://raw.githubusercontent.com/nightscout/AndroidAPS/master/app/src/main/assets/revoked_certs.txt" private val UPDATE_INTERVAL = TimeUnit.DAYS.toMillis(1) diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/constraints/storage/StorageConstraintPlugin.kt b/app/src/main/java/info/nightscout/androidaps/plugins/constraints/storage/StorageConstraintPlugin.kt index 2824fbc101..cebf039967 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/constraints/storage/StorageConstraintPlugin.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/constraints/storage/StorageConstraintPlugin.kt @@ -6,7 +6,7 @@ import dagger.android.HasAndroidInjector import info.nightscout.androidaps.Constants import info.nightscout.androidaps.R import info.nightscout.androidaps.interfaces.Constraint -import info.nightscout.androidaps.interfaces.ConstraintsInterface +import info.nightscout.androidaps.interfaces.Constraints import info.nightscout.androidaps.interfaces.PluginBase import info.nightscout.androidaps.interfaces.PluginDescription import info.nightscout.androidaps.interfaces.PluginType @@ -33,7 +33,7 @@ open class StorageConstraintPlugin @Inject constructor( .showInList(false) .pluginName(R.string.storage), aapsLogger, resourceHelper, injector -), ConstraintsInterface { +), Constraints { override fun isClosedLoopAllowed(value: Constraint): Constraint { val diskFree = availableInternalMemorySize() diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/constraints/versionChecker/VersionCheckerPlugin.kt b/app/src/main/java/info/nightscout/androidaps/plugins/constraints/versionChecker/VersionCheckerPlugin.kt index 2eb4b34612..19e92e5015 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/constraints/versionChecker/VersionCheckerPlugin.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/constraints/versionChecker/VersionCheckerPlugin.kt @@ -4,7 +4,7 @@ import dagger.android.HasAndroidInjector import info.nightscout.androidaps.BuildConfig import info.nightscout.androidaps.R import info.nightscout.androidaps.interfaces.Constraint -import info.nightscout.androidaps.interfaces.ConstraintsInterface +import info.nightscout.androidaps.interfaces.Constraints import info.nightscout.androidaps.interfaces.PluginBase import info.nightscout.androidaps.interfaces.PluginDescription import info.nightscout.androidaps.interfaces.PluginType @@ -35,7 +35,7 @@ class VersionCheckerPlugin @Inject constructor( .showInList(false) .pluginName(R.string.versionChecker), aapsLogger, resourceHelper, injector -), ConstraintsInterface { +), Constraints { enum class GracePeriod(val warning: Long, val old: Long, val veryOld: Long) { RELEASE(30, 60, 90), diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/actions/ActionsFragment.kt b/app/src/main/java/info/nightscout/androidaps/plugins/general/actions/ActionsFragment.kt index 6f735ba04b..3d0eb423cb 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/actions/ActionsFragment.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/actions/ActionsFragment.kt @@ -11,17 +11,24 @@ import android.widget.LinearLayout import android.widget.TextView import androidx.core.content.ContextCompat import dagger.android.support.DaggerFragment -import info.nightscout.androidaps.Config +import info.nightscout.androidaps.interfaces.Config import info.nightscout.androidaps.Constants import info.nightscout.androidaps.R import info.nightscout.androidaps.activities.ErrorHelperActivity import info.nightscout.androidaps.activities.TDDStatsActivity -import info.nightscout.androidaps.database.entities.UserEntry.* +import info.nightscout.androidaps.database.AppRepository +import info.nightscout.androidaps.database.ValueWrapper +import info.nightscout.androidaps.database.entities.UserEntry.Action +import info.nightscout.androidaps.database.entities.UserEntry.Sources import info.nightscout.androidaps.dialogs.* import info.nightscout.androidaps.events.* +import info.nightscout.androidaps.extensions.toStringMedium +import info.nightscout.androidaps.extensions.toStringShort +import info.nightscout.androidaps.extensions.toVisibility import info.nightscout.androidaps.historyBrowser.HistoryBrowseActivity -import info.nightscout.androidaps.interfaces.ActivePluginProvider +import info.nightscout.androidaps.interfaces.ActivePlugin import info.nightscout.androidaps.interfaces.CommandQueueProvider +import info.nightscout.androidaps.interfaces.IobCobCalculator import info.nightscout.androidaps.interfaces.ProfileFunction import info.nightscout.androidaps.logging.AAPSLogger import info.nightscout.androidaps.logging.UserEntryLogger @@ -31,10 +38,10 @@ import info.nightscout.androidaps.plugins.general.overview.StatusLightHandler import info.nightscout.androidaps.plugins.pump.omnipod.eros.OmnipodErosPumpPlugin import info.nightscout.androidaps.queue.Callback import info.nightscout.androidaps.skins.SkinProvider +import info.nightscout.androidaps.utils.DateUtil import info.nightscout.androidaps.utils.FabricPrivacy import info.nightscout.androidaps.utils.alertDialogs.OKDialog import info.nightscout.androidaps.utils.buildHelper.BuildHelper -import info.nightscout.androidaps.utils.extensions.toVisibility import info.nightscout.androidaps.utils.protection.ProtectionCheck import info.nightscout.androidaps.utils.resources.ResourceHelper import info.nightscout.androidaps.utils.rx.AapsSchedulers @@ -52,18 +59,21 @@ class ActionsFragment : DaggerFragment() { @Inject lateinit var aapsSchedulers: AapsSchedulers @Inject lateinit var rxBus: RxBusWrapper @Inject lateinit var sp: SP + @Inject lateinit var dateUtil: DateUtil @Inject lateinit var profileFunction: ProfileFunction @Inject lateinit var ctx: Context @Inject lateinit var resourceHelper: ResourceHelper @Inject lateinit var statusLightHandler: StatusLightHandler @Inject lateinit var fabricPrivacy: FabricPrivacy - @Inject lateinit var activePlugin: ActivePluginProvider + @Inject lateinit var activePlugin: ActivePlugin + @Inject lateinit var iobCobCalculator: IobCobCalculator @Inject lateinit var commandQueue: CommandQueueProvider @Inject lateinit var buildHelper: BuildHelper @Inject lateinit var protectionCheck: ProtectionCheck @Inject lateinit var skinProvider: SkinProvider @Inject lateinit var config: Config @Inject lateinit var uel: UserEntryLogger + @Inject lateinit var repository: AppRepository private var disposable: CompositeDisposable = CompositeDisposable() @@ -154,8 +164,8 @@ class ActionsFragment : DaggerFragment() { } } extendedBolusCancel?.setOnClickListener { - if (activePlugin.activeTreatments.isInHistoryExtendedBolusInProgress) { - uel.log(Action.CANCEL_EXTENDED_BOLUS) + if (iobCobCalculator.getExtendedBolus(dateUtil.now()) != null) { + uel.log(Action.CANCEL_EXTENDED_BOLUS, Sources.Actions) commandQueue.cancelExtended(object : Callback() { override fun run() { if (!result.success) { @@ -169,8 +179,8 @@ class ActionsFragment : DaggerFragment() { TempBasalDialog().show(childFragmentManager, "Actions") } cancelTempBasal?.setOnClickListener { - if (activePlugin.activeTreatments.isTempBasalInProgress) { - uel.log(Action.CANCEL_TEMP_BASAL) + if (iobCobCalculator.getTempBasalIncludingConvertedExtended(dateUtil.now()) != null) { + uel.log(Action.CANCEL_TEMP_BASAL, Sources.Actions) commandQueue.cancelTempBasal(true, object : Callback() { override fun run() { if (!result.success) { @@ -255,7 +265,7 @@ class ActionsFragment : DaggerFragment() { val pump = activePlugin.activePump profileSwitch?.visibility = ( - activePlugin.activeProfileInterface.profile != null && + activePlugin.activeProfileSource.profile != null && pump.pumpDescription.isSetBasalProfileCapable && pump.isInitialized() && !pump.isSuspended()).toVisibility() @@ -264,12 +274,12 @@ class ActionsFragment : DaggerFragment() { extendedBolus?.visibility = View.GONE extendedBolusCancel?.visibility = View.GONE } else { - val activeExtendedBolus = activePlugin.activeTreatments.getExtendedBolusFromHistory(System.currentTimeMillis()) - if (activeExtendedBolus != null) { + val activeExtendedBolus = repository.getExtendedBolusActiveAt(dateUtil.now()).blockingGet() + if (activeExtendedBolus is ValueWrapper.Existing) { extendedBolus?.visibility = View.GONE extendedBolusCancel?.visibility = View.VISIBLE @Suppress("SetTextI18n") - extendedBolusCancel?.text = resourceHelper.gs(R.string.cancel) + " " + activeExtendedBolus.toStringMedium() + extendedBolusCancel?.text = resourceHelper.gs(R.string.cancel) + " " + activeExtendedBolus.value.toStringMedium(dateUtil) } else { extendedBolus?.visibility = View.VISIBLE extendedBolusCancel?.visibility = View.GONE @@ -280,7 +290,7 @@ class ActionsFragment : DaggerFragment() { setTempBasal?.visibility = View.GONE cancelTempBasal?.visibility = View.GONE } else { - val activeTemp = activePlugin.activeTreatments.getTempBasalFromHistory(System.currentTimeMillis()) + val activeTemp = iobCobCalculator.getTempBasalIncludingConvertedExtended(System.currentTimeMillis()) if (activeTemp != null) { setTempBasal?.visibility = View.GONE cancelTempBasal?.visibility = View.VISIBLE diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/actions/ActionsPlugin.kt b/app/src/main/java/info/nightscout/androidaps/plugins/general/actions/ActionsPlugin.kt index 9b4e4478b7..3fadf5be53 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/actions/ActionsPlugin.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/actions/ActionsPlugin.kt @@ -1,7 +1,7 @@ package info.nightscout.androidaps.plugins.general.actions import dagger.android.HasAndroidInjector -import info.nightscout.androidaps.Config +import info.nightscout.androidaps.interfaces.Config import info.nightscout.androidaps.R import info.nightscout.androidaps.interfaces.PluginBase import info.nightscout.androidaps.interfaces.PluginDescription diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/dataBroadcaster/DataBroadcastPlugin.kt b/app/src/main/java/info/nightscout/androidaps/plugins/general/dataBroadcaster/DataBroadcastPlugin.kt index 4ff7ce4d14..b231e253a6 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/dataBroadcaster/DataBroadcastPlugin.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/dataBroadcaster/DataBroadcastPlugin.kt @@ -5,15 +5,10 @@ import android.content.Intent import android.content.pm.ResolveInfo import android.os.Bundle import dagger.android.HasAndroidInjector -import info.nightscout.androidaps.Config +import info.nightscout.androidaps.interfaces.Config import info.nightscout.androidaps.R -import info.nightscout.androidaps.data.IobTotal import info.nightscout.androidaps.events.* -import info.nightscout.androidaps.interfaces.ActivePluginProvider -import info.nightscout.androidaps.interfaces.PluginBase -import info.nightscout.androidaps.interfaces.PluginDescription -import info.nightscout.androidaps.interfaces.PluginType -import info.nightscout.androidaps.interfaces.ProfileFunction +import info.nightscout.androidaps.interfaces.* import info.nightscout.androidaps.logging.AAPSLogger import info.nightscout.androidaps.logging.LTag import info.nightscout.androidaps.plugins.aps.events.EventOpenAPSUpdateGui @@ -22,11 +17,13 @@ import info.nightscout.androidaps.plugins.bus.RxBusWrapper import info.nightscout.androidaps.plugins.general.nsclient.data.NSDeviceStatus import info.nightscout.androidaps.plugins.general.overview.events.EventOverviewBolusProgress import info.nightscout.androidaps.plugins.iob.iobCobCalculator.GlucoseStatusProvider -import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorPlugin import info.nightscout.androidaps.receivers.ReceiverStatusStore import info.nightscout.androidaps.services.Intents +import info.nightscout.androidaps.utils.DateUtil import info.nightscout.androidaps.utils.DefaultValueHelper import info.nightscout.androidaps.utils.FabricPrivacy +import info.nightscout.androidaps.extensions.durationInMinutes +import info.nightscout.androidaps.extensions.toStringFull import info.nightscout.androidaps.utils.resources.ResourceHelper import info.nightscout.androidaps.utils.rx.AapsSchedulers import io.reactivex.disposables.CompositeDisposable @@ -40,14 +37,15 @@ class DataBroadcastPlugin @Inject constructor( resourceHelper: ResourceHelper, private val aapsSchedulers: AapsSchedulers, private val context: Context, + private val dateUtil: DateUtil, private val fabricPrivacy: FabricPrivacy, private val rxBus: RxBusWrapper, - private val iobCobCalculatorPlugin: IobCobCalculatorPlugin, + private val iobCobCalculator: IobCobCalculator, private val profileFunction: ProfileFunction, private val defaultValueHelper: DefaultValueHelper, private val nsDeviceStatus: NSDeviceStatus, private val loopPlugin: LoopPlugin, - private val activePlugin: ActivePluginProvider, + private val activePlugin: ActivePlugin, private var receiverStatusStore: ReceiverStatusStore, private val config: Config, private val glucoseStatusProvider: GlucoseStatusProvider @@ -121,7 +119,7 @@ class DataBroadcastPlugin @Inject constructor( } private fun bgStatus(bundle: Bundle) { - val lastBG = iobCobCalculatorPlugin.lastBg() ?: return + val lastBG = iobCobCalculator.ads.lastBg() ?: return val glucoseStatus = glucoseStatusProvider.glucoseStatusData ?: return bundle.putDouble("glucoseMgdl", lastBG.value) // last BG in mgdl @@ -136,15 +134,13 @@ class DataBroadcastPlugin @Inject constructor( private fun iobCob(bundle: Bundle) { profileFunction.getProfile() ?: return - activePlugin.activeTreatments.updateTotalIOBTreatments() - val bolusIob: IobTotal = activePlugin.activeTreatments.lastCalculationTreatments.round() - activePlugin.activeTreatments.updateTotalIOBTempBasals() - val basalIob: IobTotal = activePlugin.activeTreatments.lastCalculationTempBasals.round() + val bolusIob = iobCobCalculator.calculateIobFromBolus().round() + val basalIob = iobCobCalculator.calculateIobFromTempBasalsIncludingConvertedExtended().round() bundle.putDouble("bolusIob", bolusIob.iob) bundle.putDouble("basalIob", basalIob.basaliob) bundle.putDouble("iob", bolusIob.iob + basalIob.basaliob) // total IOB - val cob = iobCobCalculatorPlugin.getCobInfo(false, "broadcast") + val cob = iobCobCalculator.getCobInfo(false, "broadcast") bundle.putDouble("cob", cob.displayCob ?: -1.0) // COB [g] or -1 if N/A bundle.putDouble("futureCarbs", cob.futureCarbs) // future scheduled carbs } @@ -181,12 +177,12 @@ class DataBroadcastPlugin @Inject constructor( bundle.putLong("basalTimeStamp", now) bundle.putDouble("baseBasal", profile.basal) bundle.putString("profile", profileFunction.getProfileName()) - activePlugin.activeTreatments.getTempBasalFromHistory(now)?.let { - bundle.putLong("tempBasalStart", it.date) - bundle.putInt("tempBasalDurationInMinutes", it.durationInMinutes) - if (it.isAbsolute) bundle.putDouble("tempBasalAbsolute", it.absoluteRate) // U/h for absolute TBR - else bundle.putInt("tempBasalPercent", it.percentRate) // % for percent type TBR - bundle.putString("tempBasalString", it.toStringFull()) // user friendly string + iobCobCalculator.getTempBasalIncludingConvertedExtended(now)?.let { + bundle.putLong("tempBasalStart", it.timestamp) + bundle.putLong("tempBasalDurationInMinutes", it.durationInMinutes) + if (it.isAbsolute) bundle.putDouble("tempBasalAbsolute", it.rate) // U/h for absolute TBR + else bundle.putInt("tempBasalPercent", it.rate.toInt()) // % for percent type TBR + bundle.putString("tempBasalString", it.toStringFull(profile, dateUtil)) // user friendly string } } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/food/FoodFragment.kt b/app/src/main/java/info/nightscout/androidaps/plugins/general/food/FoodFragment.kt index ceb0855819..4d8105a655 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/food/FoodFragment.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/food/FoodFragment.kt @@ -17,6 +17,8 @@ import info.nightscout.androidaps.R import info.nightscout.androidaps.database.AppRepository import info.nightscout.androidaps.database.entities.Food import info.nightscout.androidaps.database.entities.UserEntry.Action +import info.nightscout.androidaps.database.entities.UserEntry.Sources +import info.nightscout.androidaps.database.entities.ValueWithUnit import info.nightscout.androidaps.database.transactions.InvalidateFoodTransaction import info.nightscout.androidaps.databinding.FoodFragmentBinding import info.nightscout.androidaps.databinding.FoodItemBinding @@ -25,11 +27,10 @@ import info.nightscout.androidaps.logging.AAPSLogger import info.nightscout.androidaps.logging.LTag import info.nightscout.androidaps.logging.UserEntryLogger import info.nightscout.androidaps.plugins.bus.RxBusWrapper -import info.nightscout.androidaps.plugins.general.nsclient.NSUpload import info.nightscout.androidaps.plugins.general.nsclient.events.EventNSClientRestart import info.nightscout.androidaps.utils.FabricPrivacy import info.nightscout.androidaps.utils.alertDialogs.OKDialog -import info.nightscout.androidaps.utils.extensions.toVisibility +import info.nightscout.androidaps.extensions.toVisibility import info.nightscout.androidaps.utils.resources.ResourceHelper import info.nightscout.androidaps.utils.rx.AapsSchedulers import io.reactivex.Completable @@ -48,13 +49,12 @@ class FoodFragment : DaggerFragment() { @Inject lateinit var aapsLogger: AAPSLogger @Inject lateinit var resourceHelper: ResourceHelper @Inject lateinit var fabricPrivacy: FabricPrivacy - @Inject lateinit var nsUpload: NSUpload @Inject lateinit var repository: AppRepository @Inject lateinit var uel: UserEntryLogger private val disposable = CompositeDisposable() - private lateinit var unfiltered: List - private lateinit var filtered: MutableList + private var unfiltered: List = arrayListOf() + private var filtered: MutableList = arrayListOf() private var _binding: FoodFragmentBinding? = null @@ -76,7 +76,8 @@ class FoodFragment : DaggerFragment() { binding.refreshFromNightscout.setOnClickListener { context?.let { context -> OKDialog.showConfirmation(context, resourceHelper.gs(R.string.refresheventsfromnightscout) + " ?", { - uel.log(Action.FOOD_FROM_NS) + uel.log(Action.FOOD, Sources.Food, resourceHelper.gs(R.string.refresheventsfromnightscout), + ValueWithUnit.SimpleString(resourceHelper.gsNotLocalised(R.string.refresheventsfromnightscout))) disposable += Completable.fromAction { repository.deleteAllFoods() } .subscribeOn(aapsSchedulers.io) .observeOn(aapsSchedulers.main) @@ -200,8 +201,10 @@ class FoodFragment : DaggerFragment() { private fun filterData() { val textFilter = binding.filter.text.toString() - val categoryFilter = binding.category.selectedItem?.toString() ?: resourceHelper.gs(R.string.none) - val subcategoryFilter = binding.subcategory.selectedItem?.toString() ?: resourceHelper.gs(R.string.none) + val categoryFilter = binding.category.selectedItem?.toString() + ?: resourceHelper.gs(R.string.none) + val subcategoryFilter = binding.subcategory.selectedItem?.toString() + ?: resourceHelper.gs(R.string.none) val newFiltered = ArrayList() for (f in unfiltered) { if (f.category == null || f.subCategory == null) continue @@ -250,16 +253,12 @@ class FoodFragment : DaggerFragment() { val food = v.tag as Food activity?.let { activity -> OKDialog.showConfirmation(activity, resourceHelper.gs(R.string.removerecord) + "\n" + food.name, { - uel.log(Action.FOOD_REMOVED, food.name) + uel.log(Action.FOOD_REMOVED, Sources.Food, food.name) disposable += repository.runTransactionForResult(InvalidateFoodTransaction(food.id)) - .subscribe({ - val id = food.interfaceIDs.nightscoutId - if (NSUpload.isIdValid(id)) nsUpload.removeFoodFromNS(id) - // no create at the moment - // else uploadQueue.removeID("dbAdd", food.timestamp.toString()) - }, { - aapsLogger.error(LTag.BGSOURCE, "Error while invalidating food", it) - }) + .subscribe( + { aapsLogger.error(LTag.DATABASE, "Invalidated food $it") }, + { aapsLogger.error(LTag.DATABASE, "Error while invalidating food", it) } + ) }, null) } } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/food/FoodPlugin.kt b/app/src/main/java/info/nightscout/androidaps/plugins/general/food/FoodPlugin.kt index f0f78a8577..fefc9009c1 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/food/FoodPlugin.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/food/FoodPlugin.kt @@ -3,11 +3,13 @@ package info.nightscout.androidaps.plugins.general.food import android.content.Context import androidx.work.Worker import androidx.work.WorkerParameters +import androidx.work.workDataOf import dagger.android.HasAndroidInjector import info.nightscout.androidaps.R import info.nightscout.androidaps.database.AppRepository import info.nightscout.androidaps.database.entities.Food -import info.nightscout.androidaps.database.transactions.SyncFoodTransaction +import info.nightscout.androidaps.database.transactions.SyncNsFoodTransaction +import info.nightscout.androidaps.extensions.foodFromJson import info.nightscout.androidaps.interfaces.PluginBase import info.nightscout.androidaps.interfaces.PluginDescription import info.nightscout.androidaps.interfaces.PluginType @@ -15,10 +17,8 @@ import info.nightscout.androidaps.logging.AAPSLogger import info.nightscout.androidaps.logging.LTag import info.nightscout.androidaps.receivers.DataWorker import info.nightscout.androidaps.utils.JsonHelper -import info.nightscout.androidaps.utils.extensions.foodFromJson import info.nightscout.androidaps.utils.resources.ResourceHelper import info.nightscout.androidaps.utils.sharedPreferences.SP -import org.json.JSONArray import org.json.JSONObject import javax.inject.Inject import javax.inject.Singleton @@ -56,8 +56,8 @@ class FoodPlugin @Inject constructor( override fun doWork(): Result { val foods = dataWorker.pickupJSONArray(inputData.getLong(DataWorker.STORE_KEY, -1)) - ?: return Result.failure() - aapsLogger.debug(LTag.DATAFOOD, "Received Food Data: $foods") + ?: return Result.failure(workDataOf("Error" to "missing input data")) + aapsLogger.debug(LTag.DATABASE, "Received Food Data: $foods") var ret = Result.success() @@ -75,34 +75,34 @@ class FoodPlugin @Inject constructor( isValid = false ).also { it.interfaceIDs.nightscoutId = JsonHelper.safeGetString(jsonFood, "_id") } - repository.runTransactionForResult(SyncFoodTransaction(delFood)) + repository.runTransactionForResult(SyncNsFoodTransaction(delFood, true)) .doOnError { - aapsLogger.error(LTag.DATAFOOD, "Error while removing food", it) - ret = Result.failure() + aapsLogger.error(LTag.DATABASE, "Error while removing food", it) + ret = Result.failure(workDataOf("Error" to it)) } .blockingGet() .also { - it.invalidated.forEach { f -> aapsLogger.debug(LTag.DATAFOOD, "Invalidated food ${f.interfaceIDs.nightscoutId}") } + it.invalidated.forEach { f -> aapsLogger.debug(LTag.DATABASE, "Invalidated food ${f.interfaceIDs.nightscoutId}") } } } else -> { val food = foodFromJson(jsonFood) if (food != null) { - repository.runTransactionForResult(SyncFoodTransaction(food)) + repository.runTransactionForResult(SyncNsFoodTransaction(food, false)) .doOnError { - aapsLogger.error(LTag.DATAFOOD, "Error while adding/updating food", it) - ret = Result.failure() + aapsLogger.error(LTag.DATABASE, "Error while adding/updating food", it) + ret = Result.failure(workDataOf("Error" to it)) } .blockingGet() .also { result -> - result.inserted.forEach { aapsLogger.debug(LTag.DATAFOOD, "Inserted food $it") } - result.updated.forEach { aapsLogger.debug(LTag.DATAFOOD, "Updated food $it") } - result.invalidated.forEach { aapsLogger.debug(LTag.DATAFOOD, "Invalidated food $it") } + result.inserted.forEach { aapsLogger.debug(LTag.DATABASE, "Inserted food $it") } + result.updated.forEach { aapsLogger.debug(LTag.DATABASE, "Updated food $it") } + result.invalidated.forEach { aapsLogger.debug(LTag.DATABASE, "Invalidated food $it") } } } else { - aapsLogger.error(LTag.DATAFOOD, "Error parsing food", jsonFood.toString()) - ret = Result.failure() + aapsLogger.error(LTag.DATABASE, "Error parsing food", jsonFood.toString()) + ret = Result.failure(workDataOf("Error" to "Error parsing food")) } } } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/maintenance/ImportExportPrefs.kt b/app/src/main/java/info/nightscout/androidaps/plugins/general/maintenance/ImportExportPrefsImpl.kt similarity index 96% rename from app/src/main/java/info/nightscout/androidaps/plugins/general/maintenance/ImportExportPrefs.kt rename to app/src/main/java/info/nightscout/androidaps/plugins/general/maintenance/ImportExportPrefsImpl.kt index 9acdf53e8a..bf83f2c5bc 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/maintenance/ImportExportPrefs.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/maintenance/ImportExportPrefsImpl.kt @@ -16,10 +16,11 @@ import info.nightscout.androidaps.R import info.nightscout.androidaps.activities.DaggerAppCompatActivityWithResult import info.nightscout.androidaps.activities.PreferencesActivity import info.nightscout.androidaps.database.entities.UserEntry -import info.nightscout.androidaps.database.entities.UserEntry.* +import info.nightscout.androidaps.database.entities.UserEntry.Action +import info.nightscout.androidaps.database.entities.UserEntry.Sources import info.nightscout.androidaps.events.EventAppExit -import info.nightscout.androidaps.interfaces.ConfigInterface -import info.nightscout.androidaps.interfaces.ImportExportPrefsInterface +import info.nightscout.androidaps.interfaces.Config +import info.nightscout.androidaps.interfaces.ImportExportPrefs import info.nightscout.androidaps.logging.AAPSLogger import info.nightscout.androidaps.logging.LTag import info.nightscout.androidaps.logging.UserEntryLogger @@ -40,7 +41,6 @@ import io.reactivex.Single import java.io.File import java.io.FileNotFoundException import java.io.IOException -import java.util.* import javax.inject.Inject import javax.inject.Singleton import kotlin.system.exitProcess @@ -50,20 +50,21 @@ import kotlin.system.exitProcess */ @Singleton -class ImportExportPrefs @Inject constructor( +class ImportExportPrefsImpl @Inject constructor( private var log: AAPSLogger, private val resourceHelper: ResourceHelper, private val sp: SP, private val buildHelper: BuildHelper, private val rxBus: RxBusWrapper, private val passwordCheck: PasswordCheck, - private val config: ConfigInterface, + private val config: Config, private val androidPermission: AndroidPermission, private val classicPrefsFormat: ClassicPrefsFormat, private val encryptedPrefsFormat: EncryptedPrefsFormat, private val prefFileList: PrefFileListProvider, - private val uel: UserEntryLogger -) : ImportExportPrefsInterface { + private val uel: UserEntryLogger, + private val dateUtil: DateUtil +) : ImportExportPrefs { override fun prefsFileExists(): Boolean { return prefFileList.listPreferenceFiles().size > 0 @@ -94,7 +95,7 @@ class ImportExportPrefs @Inject constructor( val metadata: MutableMap = mutableMapOf() metadata[PrefsMetadataKey.DEVICE_NAME] = PrefMetadata(detectUserName(context), PrefsStatus.OK) - metadata[PrefsMetadataKey.CREATED_AT] = PrefMetadata(DateUtil.toISOString(Date()), PrefsStatus.OK) + metadata[PrefsMetadataKey.CREATED_AT] = PrefMetadata(dateUtil.toISOString(dateUtil.now()), PrefsStatus.OK) metadata[PrefsMetadataKey.AAPS_VERSION] = PrefMetadata(BuildConfig.VERSION_NAME, PrefsStatus.OK) metadata[PrefsMetadataKey.AAPS_FLAVOUR] = PrefMetadata(BuildConfig.FLAVOR, PrefsStatus.OK) metadata[PrefsMetadataKey.DEVICE_MODEL] = PrefMetadata(config.currentDeviceModelString, PrefsStatus.OK) @@ -348,7 +349,7 @@ class ImportExportPrefs @Inject constructor( private fun restartAppAfterImport(context: Context) { sp.putBoolean(R.string.key_setupwizard_processed, true) OKDialog.show(context, resourceHelper.gs(R.string.setting_imported), resourceHelper.gs(R.string.restartingapp)) { - uel.log(Action.IMPORT_SETTINGS) + uel.log(Action.IMPORT_SETTINGS, Sources.Maintenance) log.debug(LTag.CORE, "Exiting") rxBus.send(EventAppExit()) if (context is AppCompatActivity) { 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 32b3001911..4337808106 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 @@ -8,16 +8,19 @@ import android.view.ViewGroup import dagger.android.support.DaggerFragment import info.nightscout.androidaps.R import info.nightscout.androidaps.database.AppRepository -import info.nightscout.androidaps.database.entities.UserEntry.* +import info.nightscout.androidaps.database.entities.UserEntry.Action +import info.nightscout.androidaps.database.entities.UserEntry.Sources 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.interfaces.ImportExportPrefs +import info.nightscout.androidaps.interfaces.PumpSync import info.nightscout.androidaps.logging.AAPSLogger import info.nightscout.androidaps.logging.UserEntryLogger import info.nightscout.androidaps.plugins.bus.RxBusWrapper import info.nightscout.androidaps.plugins.general.maintenance.activities.LogSettingActivity -import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin +import info.nightscout.androidaps.plugins.iob.iobCobCalculator.events.EventNewHistoryData import info.nightscout.androidaps.utils.alertDialogs.OKDialog import info.nightscout.androidaps.utils.resources.ResourceHelper import info.nightscout.androidaps.utils.rx.AapsSchedulers @@ -32,12 +35,13 @@ class MaintenanceFragment : DaggerFragment() { @Inject lateinit var maintenancePlugin: MaintenancePlugin @Inject lateinit var rxBus: RxBusWrapper @Inject lateinit var resourceHelper: ResourceHelper - @Inject lateinit var treatmentsPlugin: TreatmentsPlugin - @Inject lateinit var importExportPrefs: ImportExportPrefsInterface + @Inject lateinit var importExportPrefs: ImportExportPrefs @Inject lateinit var aapsSchedulers: AapsSchedulers @Inject lateinit var repository: AppRepository @Inject lateinit var databaseHelper: DatabaseHelperInterface @Inject lateinit var uel: UserEntryLogger + @Inject lateinit var dataSyncSelector: DataSyncSelector + @Inject lateinit var pumpSync: PumpSync private val compositeDisposable = CompositeDisposable() @@ -56,40 +60,42 @@ class MaintenanceFragment : DaggerFragment() { super.onViewCreated(view, savedInstanceState) binding.logSend.setOnClickListener { maintenancePlugin.sendLogs() } binding.logDelete.setOnClickListener { - uel.log(Action.DELETE_LOGS) + uel.log(Action.DELETE_LOGS, Sources.Maintenance) maintenancePlugin.deleteLogs() } binding.navResetdb.setOnClickListener { activity?.let { activity -> OKDialog.showConfirmation(activity, resourceHelper.gs(R.string.maintenance), resourceHelper.gs(R.string.reset_db_confirm), Runnable { - uel.log(Action.RESET_DATABASES) compositeDisposable.add( fromAction { databaseHelper.resetDatabases() - // should be handled by Plugin-Interface and - // additional service interface and plugin registry - treatmentsPlugin.service.resetTreatments() repository.clearDatabases() + dataSyncSelector.resetToNextFullSync() + pumpSync.connectNewPump() } .subscribeOn(aapsSchedulers.io) .observeOn(aapsSchedulers.main) .subscribeBy( onError = { aapsLogger.error("Error clearing databases", it) }, - onComplete = { rxBus.send(EventNewBG(null)) } + onComplete = { + rxBus.send(EventNewBG(null)) + rxBus.send(EventNewHistoryData(0, true)) + } ) ) + uel.log(Action.RESET_DATABASES, Sources.Maintenance) }) } } binding.navExport.setOnClickListener { - uel.log(Action.EXPORT_SETTINGS) + uel.log(Action.EXPORT_SETTINGS, Sources.Maintenance) // start activity for checking permissions... importExportPrefs.verifyStoragePermissions(this) { importExportPrefs.exportSharedPreferences(this) } } binding.navImport.setOnClickListener { - uel.log(Action.IMPORT_SETTINGS) + uel.log(Action.IMPORT_SETTINGS, Sources.Maintenance) // start activity for checking permissions... importExportPrefs.verifyStoragePermissions(this) { importExportPrefs.importSharedPreferences(this) @@ -99,7 +105,7 @@ class MaintenanceFragment : DaggerFragment() { binding.exportCsv.setOnClickListener { activity?.let { activity -> OKDialog.showConfirmation(activity, resourceHelper.gs(R.string.ue_export_to_csv) + "?") { - uel.log(Action.EXPORT_CSV) + uel.log(Action.EXPORT_CSV, Sources.Maintenance) importExportPrefs.exportUserEntriesCsv(activity, repository.getAllUserEntries()) } } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/maintenance/MaintenancePlugin.kt b/app/src/main/java/info/nightscout/androidaps/plugins/general/maintenance/MaintenancePlugin.kt index a193b73030..20bdfa269a 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/maintenance/MaintenancePlugin.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/maintenance/MaintenancePlugin.kt @@ -8,7 +8,7 @@ import androidx.preference.PreferenceFragmentCompat import androidx.preference.SwitchPreference import dagger.android.HasAndroidInjector import info.nightscout.androidaps.BuildConfig -import info.nightscout.androidaps.Config +import info.nightscout.androidaps.interfaces.Config import info.nightscout.androidaps.R import info.nightscout.androidaps.interfaces.PluginBase import info.nightscout.androidaps.interfaces.PluginDescription 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 new file mode 100644 index 0000000000..8776dceef0 --- /dev/null +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/nsclient/DataSyncSelectorImplementation.kt @@ -0,0 +1,411 @@ +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.ActivePlugin +import info.nightscout.androidaps.interfaces.DataSyncSelector +import info.nightscout.androidaps.interfaces.ProfileFunction +import info.nightscout.androidaps.logging.AAPSLogger +import info.nightscout.androidaps.logging.LTag +import info.nightscout.androidaps.extensions.toJson +import info.nightscout.androidaps.utils.DateUtil +import info.nightscout.androidaps.utils.sharedPreferences.SP +import javax.inject.Inject + +class DataSyncSelectorImplementation @Inject constructor( + private val sp: SP, + private val aapsLogger: AAPSLogger, + private val dateUtil: DateUtil, + private val profileFunction: ProfileFunction, + private val nsClientPlugin: NSClientPlugin, + private val activePlugin: ActivePlugin, + private val appRepository: AppRepository +) : DataSyncSelector { + + override fun resetToNextFullSync() { + sp.remove(R.string.key_ns_temporary_target_last_synced_id) + sp.remove(R.string.key_ns_glucose_value_last_synced_id) + sp.remove(R.string.key_ns_food_last_synced_id) + 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) + sp.remove(R.string.key_ns_temporary_basal_last_synced_id) + sp.remove(R.string.key_ns_extended_bolus_last_synced_id) + sp.remove(R.string.key_ns_therapy_event_last_synced_id) + } + + override fun confirmLastBolusIdIfGreater(lastSynced: Long) { + if (lastSynced > sp.getLong(R.string.key_ns_bolus_last_synced_id, 0)) { + aapsLogger.debug(LTag.NSCLIENT, "Setting Bolus data sync from $lastSynced") + sp.putLong(R.string.key_ns_bolus_last_synced_id, lastSynced) + } + } + + // Prepared for v3 (returns all modified after) + override fun changedBoluses(): List { + val startId = sp.getLong(R.string.key_ns_bolus_last_synced_id, 0) + return appRepository.getModifiedBolusesDataFromId(startId) + .blockingGet() + .filter { it.type != Bolus.Type.PRIMING } + .also { + aapsLogger.debug(LTag.NSCLIENT, "Loading Bolus data for sync from $startId. Records ${it.size}") + } + } + + override fun processChangedBolusesCompat(): Boolean { + val startId = sp.getLong(R.string.key_ns_bolus_last_synced_id, 0) + appRepository.getNextSyncElementBolus(startId).blockingGet()?.let { bolus -> + aapsLogger.info(LTag.DATABASE, "Loading Bolus data Start: $startId ID: ${bolus.first.id} HistoryID: ${bolus.second} ") + when { + // removed and not uploaded yet = ignore + !bolus.first.isValid && bolus.first.interfaceIDs.nightscoutId == null -> Any() + // removed and already uploaded = send for removal + !bolus.first.isValid && bolus.first.interfaceIDs.nightscoutId != null -> + nsClientPlugin.nsClientService?.dbRemove("treatments", bolus.first.interfaceIDs.nightscoutId, DataSyncSelector.PairBolus(bolus.first, bolus.second)) + // existing without nsId = create new + bolus.first.isValid && bolus.first.interfaceIDs.nightscoutId == null -> + nsClientPlugin.nsClientService?.dbAdd("treatments", bolus.first.toJson(dateUtil), DataSyncSelector.PairBolus(bolus.first, bolus.second)) + // existing with nsId = update + bolus.first.isValid && bolus.first.interfaceIDs.nightscoutId != null -> + nsClientPlugin.nsClientService?.dbUpdate("treatments", bolus.first.interfaceIDs.nightscoutId, bolus.first.toJson(dateUtil), DataSyncSelector.PairBolus(bolus.first, bolus.second)) + } + return true + } + return false + } + + override fun confirmLastCarbsIdIfGreater(lastSynced: Long) { + if (lastSynced > sp.getLong(R.string.key_ns_carbs_last_synced_id, 0)) { + aapsLogger.debug(LTag.NSCLIENT, "Setting Carbs data sync from $lastSynced") + sp.putLong(R.string.key_ns_carbs_last_synced_id, lastSynced) + } + } + + // Prepared for v3 (returns all modified after) + override fun changedCarbs(): List { + val startId = sp.getLong(R.string.key_ns_carbs_last_synced_id, 0) + return appRepository.getModifiedCarbsDataFromId(startId).blockingGet().also { + aapsLogger.debug(LTag.NSCLIENT, "Loading Carbs data for sync from $startId. Records ${it.size}") + } + } + + override fun processChangedCarbsCompat(): Boolean { + val startId = sp.getLong(R.string.key_ns_carbs_last_synced_id, 0) + appRepository.getNextSyncElementCarbs(startId).blockingGet()?.let { carb -> + aapsLogger.info(LTag.DATABASE, "Loading Carbs data Start: $startId ID: ${carb.first.id} HistoryID: ${carb.second} ") + when { + // removed and not uploaded yet = ignore + !carb.first.isValid && carb.first.interfaceIDs.nightscoutId == null -> Any() + // removed and already uploaded = send for removal + !carb.first.isValid && carb.first.interfaceIDs.nightscoutId != null -> + nsClientPlugin.nsClientService?.dbRemove("treatments", carb.first.interfaceIDs.nightscoutId, DataSyncSelector.PairCarbs(carb.first, carb.second)) + // existing without nsId = create new + carb.first.isValid && carb.first.interfaceIDs.nightscoutId == null -> + nsClientPlugin.nsClientService?.dbAdd("treatments", carb.first.toJson(dateUtil), DataSyncSelector.PairCarbs(carb.first, carb.second)) + // existing with nsId = update + carb.first.isValid && carb.first.interfaceIDs.nightscoutId != null -> + nsClientPlugin.nsClientService?.dbUpdate("treatments", carb.first.interfaceIDs.nightscoutId, carb.first.toJson(dateUtil), DataSyncSelector.PairCarbs(carb.first, carb.second)) + } + return true + } + return false + } + + override fun confirmLastBolusCalculatorResultsIdIfGreater(lastSynced: Long) { + if (lastSynced > sp.getLong(R.string.key_ns_bolus_calculator_result_last_synced_id, 0)) { + aapsLogger.debug(LTag.NSCLIENT, "Setting BolusCalculatorResult data sync from $lastSynced") + sp.putLong(R.string.key_ns_bolus_calculator_result_last_synced_id, lastSynced) + } + } + + // Prepared for v3 (returns all modified after) + override fun changedBolusCalculatorResults(): List { + val startId = sp.getLong(R.string.key_ns_bolus_calculator_result_last_synced_id, 0) + return appRepository.getModifiedBolusCalculatorResultsDataFromId(startId).blockingGet().also { + aapsLogger.debug(LTag.NSCLIENT, "Loading BolusCalculatorResult data for sync from $startId. Records ${it.size}") + } + } + + override fun processChangedBolusCalculatorResultsCompat(): Boolean { + val startId = sp.getLong(R.string.key_ns_bolus_calculator_result_last_synced_id, 0) + appRepository.getNextSyncElementBolusCalculatorResult(startId).blockingGet()?.let { bolusCalculatorResult -> + aapsLogger.info(LTag.DATABASE, "Loading BolusCalculatorResult data Start: $startId ID: ${bolusCalculatorResult.first.id} HistoryID: ${bolusCalculatorResult.second} ") + when { + // removed and not uploaded yet = ignore + !bolusCalculatorResult.first.isValid && bolusCalculatorResult.first.interfaceIDs.nightscoutId == null -> Any() + // removed and already uploaded = send for removal + !bolusCalculatorResult.first.isValid && bolusCalculatorResult.first.interfaceIDs.nightscoutId != null -> + nsClientPlugin.nsClientService?.dbRemove("treatments", bolusCalculatorResult.first.interfaceIDs.nightscoutId, DataSyncSelector.PairBolusCalculatorResult(bolusCalculatorResult.first, bolusCalculatorResult.second)) + // existing without nsId = create new + bolusCalculatorResult.first.isValid && bolusCalculatorResult.first.interfaceIDs.nightscoutId == null -> + nsClientPlugin.nsClientService?.dbAdd("treatments", bolusCalculatorResult.first.toJson(dateUtil), DataSyncSelector.PairBolusCalculatorResult(bolusCalculatorResult.first, bolusCalculatorResult.second)) + // existing with nsId = update + bolusCalculatorResult.first.isValid && bolusCalculatorResult.first.interfaceIDs.nightscoutId != null -> + nsClientPlugin.nsClientService?.dbUpdate("treatments", bolusCalculatorResult.first.interfaceIDs.nightscoutId, bolusCalculatorResult.first.toJson(dateUtil), DataSyncSelector.PairBolusCalculatorResult(bolusCalculatorResult.first, bolusCalculatorResult.second)) + } + return true + } + return false + } + + override fun confirmLastTempTargetsIdIfGreater(lastSynced: Long) { + if (lastSynced > sp.getLong(R.string.key_ns_temporary_target_last_synced_id, 0)) { + aapsLogger.debug(LTag.NSCLIENT, "Setting TemporaryTarget data sync from $lastSynced") + sp.putLong(R.string.key_ns_temporary_target_last_synced_id, lastSynced) + } + } + + // Prepared for v3 (returns all modified after) + override fun changedTempTargets(): List { + val startId = sp.getLong(R.string.key_ns_temporary_target_last_synced_id, 0) + return appRepository.getModifiedTemporaryTargetsDataFromId(startId).blockingGet().also { + aapsLogger.debug(LTag.NSCLIENT, "Loading TemporaryTarget data for sync from $startId. Records ${it.size}") + } + } + + override fun processChangedTempTargetsCompat(): Boolean { + val startId = sp.getLong(R.string.key_ns_temporary_target_last_synced_id, 0) + appRepository.getNextSyncElementTemporaryTarget(startId).blockingGet()?.let { tt -> + aapsLogger.info(LTag.DATABASE, "Loading TemporaryTarget data Start: $startId ID: ${tt.first.id} HistoryID: ${tt.second} ") + when { + // removed and not uploaded yet = ignore + !tt.first.isValid && tt.first.interfaceIDs.nightscoutId == null -> Any() + // removed and already uploaded = send for removal + !tt.first.isValid && tt.first.interfaceIDs.nightscoutId != null -> + nsClientPlugin.nsClientService?.dbRemove("treatments", tt.first.interfaceIDs.nightscoutId, DataSyncSelector.PairTemporaryTarget(tt.first, tt.second)) + // existing without nsId = create new + tt.first.isValid && tt.first.interfaceIDs.nightscoutId == null -> + nsClientPlugin.nsClientService?.dbAdd("treatments", tt.first.toJson(profileFunction.getUnits(), dateUtil), DataSyncSelector.PairTemporaryTarget(tt.first, tt.second)) + // existing with nsId = update + tt.first.isValid && tt.first.interfaceIDs.nightscoutId != null -> + nsClientPlugin.nsClientService?.dbUpdate("treatments", tt.first.interfaceIDs.nightscoutId, tt.first.toJson(profileFunction.getUnits(), dateUtil), DataSyncSelector.PairTemporaryTarget(tt.first, tt.second)) + } + return true + } + return false + } + + override fun confirmLastFoodIdIfGreater(lastSynced: Long) { + if (lastSynced > sp.getLong(R.string.key_ns_food_last_synced_id, 0)) { + aapsLogger.debug(LTag.NSCLIENT, "Setting Food data sync from $lastSynced") + sp.putLong(R.string.key_ns_food_last_synced_id, lastSynced) + } + } + + // Prepared for v3 (returns all modified after) + override fun changedFoods(): List { + val startId = sp.getLong(R.string.key_ns_food_last_synced_id, 0) + return appRepository.getModifiedFoodDataFromId(startId).blockingGet().also { + aapsLogger.debug(LTag.NSCLIENT, "Loading Food data for sync from $startId. Records ${it.size}") + } + } + + override fun processChangedFoodsCompat(): Boolean { + val startId = sp.getLong(R.string.key_ns_food_last_synced_id, 0) + appRepository.getNextSyncElementFood(startId).blockingGet()?.let { tt -> + aapsLogger.info(LTag.DATABASE, "Loading Food data Start: $startId ID: ${tt.first.id} HistoryID: ${tt.second} ") + when { + // removed and not uploaded yet = ignore + !tt.first.isValid && tt.first.interfaceIDs.nightscoutId == null -> Any() + // removed and already uploaded = send for removal + !tt.first.isValid && tt.first.interfaceIDs.nightscoutId != null -> + nsClientPlugin.nsClientService?.dbRemove("food", tt.first.interfaceIDs.nightscoutId, DataSyncSelector.PairFood(tt.first, tt.second)) + // existing without nsId = create new + tt.first.isValid && tt.first.interfaceIDs.nightscoutId == null -> + nsClientPlugin.nsClientService?.dbAdd("food", tt.first.toJson(), DataSyncSelector.PairFood(tt.first, tt.second)) + // existing with nsId = update + tt.first.isValid && tt.first.interfaceIDs.nightscoutId != null -> + nsClientPlugin.nsClientService?.dbUpdate("food", tt.first.interfaceIDs.nightscoutId, tt.first.toJson(), DataSyncSelector.PairFood(tt.first, tt.second)) + } + return true + } + return false + } + + override fun confirmLastGlucoseValueIdIfGreater(lastSynced: Long) { + if (lastSynced > sp.getLong(R.string.key_ns_glucose_value_last_synced_id, 0)) { + aapsLogger.debug(LTag.NSCLIENT, "Setting GlucoseValue data sync from $lastSynced") + sp.putLong(R.string.key_ns_glucose_value_last_synced_id, lastSynced) + } + } + + // Prepared for v3 (returns all modified after) + override fun changedGlucoseValues(): List { + val startId = sp.getLong(R.string.key_ns_glucose_value_last_synced_id, 0) + return appRepository.getModifiedBgReadingsDataFromId(startId).blockingGet().also { + aapsLogger.debug(LTag.NSCLIENT, "Loading GlucoseValue data for sync from $startId . Records ${it.size}") + } + } + + override fun processChangedGlucoseValuesCompat(): Boolean { + val startId = sp.getLong(R.string.key_ns_glucose_value_last_synced_id, 0) + appRepository.getNextSyncElementGlucoseValue(startId).blockingGet()?.let { gv -> + aapsLogger.info(LTag.DATABASE, "Loading GlucoseValue data Start: $startId ID: ${gv.first.id} HistoryID: ${gv.second} ") + if (activePlugin.activeBgSource.shouldUploadToNs(gv.first)) { + when { + // removed and not uploaded yet = ignore + !gv.first.isValid && gv.first.interfaceIDs.nightscoutId == null -> Any() + // removed and already uploaded = send for removal + !gv.first.isValid && gv.first.interfaceIDs.nightscoutId != null -> + nsClientPlugin.nsClientService?.dbRemove("entries", gv.first.interfaceIDs.nightscoutId, DataSyncSelector.PairGlucoseValue(gv.first, gv.second)) + // existing without nsId = create new + gv.first.isValid && gv.first.interfaceIDs.nightscoutId == null -> + nsClientPlugin.nsClientService?.dbAdd("entries", gv.first.toJson(dateUtil), DataSyncSelector.PairGlucoseValue(gv.first, gv.second)) + // existing with nsId = update + gv.first.isValid && gv.first.interfaceIDs.nightscoutId != null -> + nsClientPlugin.nsClientService?.dbUpdate("entries", gv.first.interfaceIDs.nightscoutId, gv.first.toJson(dateUtil), DataSyncSelector.PairGlucoseValue(gv.first, gv.second)) + } + return true + } + } + return false + } + + override fun confirmLastTherapyEventIdIfGreater(lastSynced: Long) { + if (lastSynced > sp.getLong(R.string.key_ns_therapy_event_last_synced_id, 0)) { + aapsLogger.debug(LTag.NSCLIENT, "Setting TherapyEvents data sync from $lastSynced") + sp.putLong(R.string.key_ns_therapy_event_last_synced_id, lastSynced) + } + } + + // Prepared for v3 (returns all modified after) + override fun changedTherapyEvents(): List { + val startId = sp.getLong(R.string.key_ns_therapy_event_last_synced_id, 0) + return appRepository.getModifiedTherapyEventDataFromId(startId).blockingGet().also { + aapsLogger.debug(LTag.NSCLIENT, "Loading TherapyEvents data for sync from $startId. Records ${it.size}") + } + } + + override fun processChangedTherapyEventsCompat(): Boolean { + val startId = sp.getLong(R.string.key_ns_therapy_event_last_synced_id, 0) + appRepository.getNextSyncElementTherapyEvent(startId).blockingGet()?.let { tt -> + aapsLogger.info(LTag.DATABASE, "Loading TherapyEvents data Start: $startId ID: ${tt.first.id} HistoryID: ${tt.second} ") + when { + // removed and not uploaded yet = ignore + !tt.first.isValid && tt.first.interfaceIDs.nightscoutId == null -> Any() + // removed and already uploaded = send for removal + !tt.first.isValid && tt.first.interfaceIDs.nightscoutId != null -> + nsClientPlugin.nsClientService?.dbRemove("treatments", tt.first.interfaceIDs.nightscoutId, DataSyncSelector.PairTherapyEvent(tt.first, tt.second)) + // existing without nsId = create new + tt.first.isValid && tt.first.interfaceIDs.nightscoutId == null -> + nsClientPlugin.nsClientService?.dbAdd("treatments", tt.first.toJson(), DataSyncSelector.PairTherapyEvent(tt.first, tt.second)) + // existing with nsId = update + tt.first.isValid && tt.first.interfaceIDs.nightscoutId != null -> + nsClientPlugin.nsClientService?.dbUpdate("treatments", tt.first.interfaceIDs.nightscoutId, tt.first.toJson(), DataSyncSelector.PairTherapyEvent(tt.first, tt.second)) + } + return true + } + 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(dateUtil), deviceStatus) + // with nsId = ignore + deviceStatus.interfaceIDs.nightscoutId != null -> Any() + } + return true + } + return false + } + + override fun confirmLastTemporaryBasalIdIfGreater(lastSynced: Long) { + if (lastSynced > sp.getLong(R.string.key_ns_temporary_basal_last_synced_id, 0)) { + aapsLogger.debug(LTag.NSCLIENT, "Setting TemporaryBasal data sync from $lastSynced") + sp.putLong(R.string.key_ns_temporary_basal_last_synced_id, lastSynced) + } + } + + // Prepared for v3 (returns all modified after) + override fun changedTemporaryBasals(): List { + val startId = sp.getLong(R.string.key_ns_temporary_basal_last_synced_id, 0) + return appRepository.getModifiedTemporaryBasalDataFromId(startId).blockingGet().also { + aapsLogger.debug(LTag.NSCLIENT, "Loading TemporaryBasal data for sync from $startId. Records ${it.size}") + } + } + + override fun processChangedTemporaryBasalsCompat(): Boolean { + val startId = sp.getLong(R.string.key_ns_temporary_basal_last_synced_id, 0) + appRepository.getNextSyncElementTemporaryBasal(startId).blockingGet()?.let { tb -> + aapsLogger.info(LTag.DATABASE, "Loading TemporaryBasal data Start: $startId ID: ${tb.first.id} HistoryID: ${tb.second} ") + profileFunction.getProfile(tb.first.timestamp)?.let { profile -> + when { + // removed and not uploaded yet = ignore + !tb.first.isValid && tb.first.interfaceIDs.nightscoutId == null -> Any() + // removed and already uploaded = send for removal + !tb.first.isValid && tb.first.interfaceIDs.nightscoutId != null -> + nsClientPlugin.nsClientService?.dbRemove("treatments", tb.first.interfaceIDs.nightscoutId, DataSyncSelector.PairTemporaryBasal(tb.first, tb.second)) + // existing without nsId = create new + tb.first.isValid && tb.first.interfaceIDs.nightscoutId == null -> + nsClientPlugin.nsClientService?.dbAdd("treatments", tb.first.toJson(profile, dateUtil), DataSyncSelector.PairTemporaryBasal(tb.first, tb.second)) + // existing with nsId = update + tb.first.isValid && tb.first.interfaceIDs.nightscoutId != null -> + nsClientPlugin.nsClientService?.dbUpdate("treatments", tb.first.interfaceIDs.nightscoutId, tb.first.toJson(profile, dateUtil), DataSyncSelector.PairTemporaryBasal(tb.first, tb.second)) + } + return true + } + } + return false + } + + override fun confirmLastExtendedBolusIdIfGreater(lastSynced: Long) { + if (lastSynced > sp.getLong(R.string.key_ns_extended_bolus_last_synced_id, 0)) { + aapsLogger.debug(LTag.NSCLIENT, "Setting ExtendedBolus data sync from $lastSynced") + sp.putLong(R.string.key_ns_extended_bolus_last_synced_id, lastSynced) + } + } + + // Prepared for v3 (returns all modified after) + override fun changedExtendedBoluses(): List { + val startId = sp.getLong(R.string.key_ns_extended_bolus_last_synced_id, 0) + return appRepository.getModifiedExtendedBolusDataFromId(startId).blockingGet().also { + aapsLogger.debug(LTag.NSCLIENT, "Loading ExtendedBolus data for sync from $startId. Records ${it.size}") + } + } + + override fun processChangedExtendedBolusesCompat(): Boolean { + val startId = sp.getLong(R.string.key_ns_extended_bolus_last_synced_id, 0) + appRepository.getNextSyncElementExtendedBolus(startId).blockingGet()?.let { eb -> + aapsLogger.info(LTag.DATABASE, "Loading ExtendedBolus data Start: $startId ID: ${eb.first.id} HistoryID: ${eb.second} ") + profileFunction.getProfile(eb.first.timestamp)?.let { profile -> + when { + // removed and not uploaded yet = ignore + !eb.first.isValid && eb.first.interfaceIDs.nightscoutId == null -> Any() + // removed and already uploaded = send for removal + !eb.first.isValid && eb.first.interfaceIDs.nightscoutId != null -> + nsClientPlugin.nsClientService?.dbRemove("treatments", eb.first.interfaceIDs.nightscoutId, DataSyncSelector.PairExtendedBolus(eb.first, eb.second)) + // existing without nsId = create new + eb.first.isValid && eb.first.interfaceIDs.nightscoutId == null -> + nsClientPlugin.nsClientService?.dbAdd("treatments", eb.first.toJson(profile, dateUtil), DataSyncSelector.PairExtendedBolus(eb.first, eb.second)) + // existing with nsId = update + eb.first.isValid && eb.first.interfaceIDs.nightscoutId != null -> + nsClientPlugin.nsClientService?.dbUpdate("treatments", eb.first.interfaceIDs.nightscoutId, eb.first.toJson(profile, dateUtil), DataSyncSelector.PairExtendedBolus(eb.first, eb.second)) + } + return true + } + } + return false + } +} diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/nsclient/NSClientAddAckWorker.kt b/app/src/main/java/info/nightscout/androidaps/plugins/general/nsclient/NSClientAddAckWorker.kt new file mode 100644 index 0000000000..e07346e85b --- /dev/null +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/nsclient/NSClientAddAckWorker.kt @@ -0,0 +1,237 @@ +package info.nightscout.androidaps.plugins.general.nsclient + +import android.content.Context +import androidx.work.Worker +import androidx.work.WorkerParameters +import androidx.work.workDataOf +import dagger.android.HasAndroidInjector +import info.nightscout.androidaps.database.AppRepository +import info.nightscout.androidaps.database.entities.DeviceStatus +import info.nightscout.androidaps.database.transactions.* +import info.nightscout.androidaps.interfaces.DataSyncSelector +import info.nightscout.androidaps.interfaces.DataSyncSelector.* +import info.nightscout.androidaps.logging.AAPSLogger +import info.nightscout.androidaps.logging.LTag +import info.nightscout.androidaps.plugins.bus.RxBusWrapper +import info.nightscout.androidaps.plugins.general.nsclient.acks.NSAddAck +import info.nightscout.androidaps.plugins.general.nsclient.events.EventNSClientNewLog +import info.nightscout.androidaps.receivers.DataWorker +import info.nightscout.androidaps.utils.rx.AapsSchedulers +import javax.inject.Inject + +class NSClientAddAckWorker( + context: Context, + params: WorkerParameters +) : Worker(context, params) { + + @Inject lateinit var dataWorker: DataWorker + @Inject lateinit var aapsLogger: AAPSLogger + @Inject lateinit var repository: AppRepository + @Inject lateinit var rxBus: RxBusWrapper + @Inject lateinit var dataSyncSelector: DataSyncSelector + @Inject lateinit var aapsSchedulers: AapsSchedulers + + override fun doWork(): Result { + var ret = Result.success() + + val ack = dataWorker.pickupObject(inputData.getLong(DataWorker.STORE_KEY, -1)) as NSAddAck? + ?: return Result.failure(workDataOf("Error" to "missing input data")) + + when (ack.originalObject) { + is PairTemporaryTarget -> { + val pair = ack.originalObject + pair.value.interfaceIDs.nightscoutId = ack.id + repository.runTransactionForResult(UpdateNsIdTemporaryTargetTransaction(pair.value)) + .doOnError { error -> + aapsLogger.error(LTag.DATABASE, "Updated ns id of TemporaryTarget failed", error) + ret = Result.failure((workDataOf("Error" to error))) + } + .doOnSuccess { + ret = Result.success(workDataOf("ProcessedData" to pair.toString())) + aapsLogger.debug(LTag.DATABASE, "Updated ns id of TemporaryTarget " + pair.value) + dataSyncSelector.confirmLastTempTargetsIdIfGreater(pair.updateRecordId) + } + .blockingGet() + rxBus.send(EventNSClientNewLog("DBADD", "Acked TemporaryTarget " + pair.value.interfaceIDs.nightscoutId)) + // Send new if waiting + dataSyncSelector.processChangedTempTargetsCompat() + } + + is PairGlucoseValue -> { + val pair = ack.originalObject + pair.value.interfaceIDs.nightscoutId = ack.id + repository.runTransactionForResult(UpdateNsIdGlucoseValueTransaction(pair.value)) + .doOnError { error -> + aapsLogger.error(LTag.DATABASE, "Updated ns id of GlucoseValue failed", error) + ret = Result.failure((workDataOf("Error" to error))) + } + .doOnSuccess { + ret = Result.success(workDataOf("ProcessedData" to pair.toString())) + aapsLogger.debug(LTag.DATABASE, "Updated ns id of GlucoseValue " + pair.value) + dataSyncSelector.confirmLastGlucoseValueIdIfGreater(pair.updateRecordId) + } + .blockingGet() + rxBus.send(EventNSClientNewLog("DBADD", "Acked GlucoseValue " + pair.value.interfaceIDs.nightscoutId)) + // Send new if waiting + dataSyncSelector.processChangedGlucoseValuesCompat() + } + + is PairFood -> { + val pair = ack.originalObject + pair.value.interfaceIDs.nightscoutId = ack.id + repository.runTransactionForResult(UpdateNsIdFoodTransaction(pair.value)) + .doOnError { error -> + aapsLogger.error(LTag.DATABASE, "Updated ns id of Food failed", error) + ret = Result.failure((workDataOf("Error" to error))) + } + .doOnSuccess { + ret = Result.success(workDataOf("ProcessedData" to pair.toString())) + aapsLogger.debug(LTag.DATABASE, "Updated ns id of Food " + pair.value) + dataSyncSelector.confirmLastFoodIdIfGreater(pair.updateRecordId) + } + .blockingGet() + rxBus.send(EventNSClientNewLog("DBADD", "Acked Food " + pair.value.interfaceIDs.nightscoutId)) + // Send new if waiting + dataSyncSelector.processChangedFoodsCompat() + } + + is PairTherapyEvent -> { + val pair = ack.originalObject + pair.value.interfaceIDs.nightscoutId = ack.id + repository.runTransactionForResult(UpdateNsIdTherapyEventTransaction(pair.value)) + .doOnError { error -> + aapsLogger.error(LTag.DATABASE, "Updated ns id of TherapyEvent failed", error) + ret = Result.failure((workDataOf("Error" to error))) + } + .doOnSuccess { + ret = Result.success(workDataOf("ProcessedData" to pair.toString())) + aapsLogger.debug(LTag.DATABASE, "Updated ns id of TherapyEvent " + pair.value) + dataSyncSelector.confirmLastTherapyEventIdIfGreater(pair.updateRecordId) + } + .blockingGet() + rxBus.send(EventNSClientNewLog("DBADD", "Acked TherapyEvent " + pair.value.interfaceIDs.nightscoutId)) + // Send new if waiting + dataSyncSelector.processChangedTherapyEventsCompat() + } + + is PairBolus -> { + val pair = ack.originalObject + pair.value.interfaceIDs.nightscoutId = ack.id + repository.runTransactionForResult(UpdateNsIdBolusTransaction(pair.value)) + .doOnError { error -> + aapsLogger.error(LTag.DATABASE, "Updated ns id of Bolus failed", error) + ret = Result.failure((workDataOf("Error" to error))) + } + .doOnSuccess { + ret = Result.success(workDataOf("ProcessedData" to pair.toString())) + aapsLogger.debug(LTag.DATABASE, "Updated ns id of Bolus " + pair.value) + dataSyncSelector.confirmLastBolusIdIfGreater(pair.updateRecordId) + } + .blockingGet() + rxBus.send(EventNSClientNewLog("DBADD", "Acked Bolus " + pair.value.interfaceIDs.nightscoutId)) + // Send new if waiting + dataSyncSelector.processChangedBolusesCompat() + } + + is PairCarbs -> { + val pair = ack.originalObject + pair.value.interfaceIDs.nightscoutId = ack.id + repository.runTransactionForResult(UpdateNsIdCarbsTransaction(pair.value)) + .doOnError { error -> + aapsLogger.error(LTag.DATABASE, "Updated ns id of Carbs failed", error) + ret = Result.failure((workDataOf("Error" to error))) + } + .doOnSuccess { + ret = Result.success(workDataOf("ProcessedData" to pair.toString())) + aapsLogger.debug(LTag.DATABASE, "Updated ns id of Carbs " + pair.value) + dataSyncSelector.confirmLastCarbsIdIfGreater(pair.updateRecordId) + } + .blockingGet() + rxBus.send(EventNSClientNewLog("DBADD", "Acked Carbs" + pair.value.interfaceIDs.nightscoutId)) + // Send new if waiting + dataSyncSelector.processChangedCarbsCompat() + } + + is PairBolusCalculatorResult -> { + val pair = ack.originalObject + pair.value.interfaceIDs.nightscoutId = ack.id + repository.runTransactionForResult(UpdateNsIdBolusCalculatorResultTransaction(pair.value)) + .doOnError { error -> + aapsLogger.error(LTag.DATABASE, "Updated ns id of BolusCalculatorResult failed", error) + ret = Result.failure((workDataOf("Error" to error))) + } + .doOnSuccess { + ret = Result.success(workDataOf("ProcessedData" to pair.toString())) + aapsLogger.debug(LTag.DATABASE, "Updated ns id of BolusCalculatorResult " + pair.value) + dataSyncSelector.confirmLastBolusCalculatorResultsIdIfGreater(pair.updateRecordId) + } + .blockingGet() + rxBus.send(EventNSClientNewLog("DBADD", "Acked BolusCalculatorResult" + pair.value.interfaceIDs.nightscoutId)) + // Send new if waiting + dataSyncSelector.processChangedBolusCalculatorResultsCompat() + } + + is PairTemporaryBasal -> { + val pair = ack.originalObject + pair.value.interfaceIDs.nightscoutId = ack.id + repository.runTransactionForResult(UpdateNsIdTemporaryBasalTransaction(pair.value)) + .doOnError { error -> + aapsLogger.error(LTag.DATABASE, "Updated ns id of TemporaryBasal failed", error) + ret = Result.failure((workDataOf("Error" to error))) + } + .doOnSuccess { + ret = Result.success(workDataOf("ProcessedData" to pair.toString())) + aapsLogger.debug(LTag.DATABASE, "Updated ns id of TemporaryBasal " + pair.value) + dataSyncSelector.confirmLastTemporaryBasalIdIfGreater(pair.updateRecordId) + } + .blockingGet() + rxBus.send(EventNSClientNewLog("DBADD", "Acked TemporaryBasal" + pair.value.interfaceIDs.nightscoutId)) + // Send new if waiting + dataSyncSelector.processChangedTemporaryBasalsCompat() + } + + is PairExtendedBolus -> { + val pair = ack.originalObject + pair.value.interfaceIDs.nightscoutId = ack.id + repository.runTransactionForResult(UpdateNsIdExtendedBolusTransaction(pair.value)) + .doOnError { error -> + aapsLogger.error(LTag.DATABASE, "Updated ns id of ExtendedBolus failed", error) + ret = Result.failure((workDataOf("Error" to error))) + } + .doOnSuccess { + ret = Result.success(workDataOf("ProcessedData" to pair.toString())) + aapsLogger.debug(LTag.DATABASE, "Updated ns id of ExtendedBolus " + pair.value) + dataSyncSelector.confirmLastExtendedBolusIdIfGreater(pair.updateRecordId) + } + .blockingGet() + rxBus.send(EventNSClientNewLog("DBADD", "Acked ExtendedBolus" + pair.value.interfaceIDs.nightscoutId)) + // Send new if waiting + dataSyncSelector.processChangedTemporaryBasalsCompat() + } + + is DeviceStatus -> { + val deviceStatus = ack.originalObject + deviceStatus.interfaceIDs.nightscoutId = ack.id + repository.runTransactionForResult(UpdateNsIdDeviceStatusTransaction(deviceStatus)) + .doOnError { error -> + aapsLogger.error(LTag.DATABASE, "Updated ns id of DeviceStatus failed", error) + ret = Result.failure((workDataOf("Error" to error))) + } + .doOnSuccess { + ret = Result.success(workDataOf("ProcessedData" to deviceStatus)) + aapsLogger.debug(LTag.DATABASE, "Updated ns id of DeviceStatus $deviceStatus") + dataSyncSelector.confirmLastDeviceStatusIdIfGreater(deviceStatus.id) + } + .blockingGet() + rxBus.send(EventNSClientNewLog("DBADD", "Acked DeviceStatus" + deviceStatus.interfaceIDs.nightscoutId)) + // Send new if waiting + dataSyncSelector.processChangedBolusCalculatorResultsCompat() + } + } + return ret + } + + init { + (context.applicationContext as HasAndroidInjector).androidInjector().inject(this) + } +} \ No newline at end of file diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/nsclient/NSClientAddUpdateWorker.kt b/app/src/main/java/info/nightscout/androidaps/plugins/general/nsclient/NSClientAddUpdateWorker.kt index 868993ddc8..89b30d8b8e 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/nsclient/NSClientAddUpdateWorker.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/nsclient/NSClientAddUpdateWorker.kt @@ -3,16 +3,18 @@ package info.nightscout.androidaps.plugins.general.nsclient import android.content.Context import androidx.work.Worker import androidx.work.WorkerParameters +import androidx.work.workDataOf import dagger.android.HasAndroidInjector +import info.nightscout.androidaps.Constants import info.nightscout.androidaps.R import info.nightscout.androidaps.database.AppRepository import info.nightscout.androidaps.database.entities.TherapyEvent -import info.nightscout.androidaps.database.entities.UserEntry -import info.nightscout.androidaps.database.entities.UserEntry.ValueWithUnit -import info.nightscout.androidaps.database.transactions.SyncTemporaryTargetTransaction -import info.nightscout.androidaps.database.transactions.SyncTherapyEventTransaction -import info.nightscout.androidaps.events.EventNsTreatment -import info.nightscout.androidaps.interfaces.ConfigInterface +import info.nightscout.androidaps.database.entities.UserEntry.Action +import info.nightscout.androidaps.database.entities.UserEntry.Sources +import info.nightscout.androidaps.database.entities.ValueWithUnit +import info.nightscout.androidaps.database.transactions.* +import info.nightscout.androidaps.extensions.* +import info.nightscout.androidaps.interfaces.Config import info.nightscout.androidaps.interfaces.DatabaseHelperInterface import info.nightscout.androidaps.logging.AAPSLogger import info.nightscout.androidaps.logging.LTag @@ -25,9 +27,8 @@ import info.nightscout.androidaps.utils.DateUtil import info.nightscout.androidaps.utils.JsonHelper import info.nightscout.androidaps.utils.JsonHelper.safeGetLong import info.nightscout.androidaps.utils.buildHelper.BuildHelper -import info.nightscout.androidaps.utils.extensions.temporaryTargetFromJson -import info.nightscout.androidaps.utils.extensions.therapyEventFromJson import info.nightscout.androidaps.utils.sharedPreferences.SP +import java.util.concurrent.TimeUnit import javax.inject.Inject class NSClientAddUpdateWorker( @@ -40,8 +41,8 @@ class NSClientAddUpdateWorker( @Inject lateinit var aapsLogger: AAPSLogger @Inject lateinit var buildHelper: BuildHelper @Inject lateinit var sp: SP - @Inject lateinit var dateutil: DateUtil - @Inject lateinit var config: ConfigInterface + @Inject lateinit var dateUtil: DateUtil + @Inject lateinit var config: Config @Inject lateinit var repository: AppRepository @Inject lateinit var databaseHelper: DatabaseHelperInterface @Inject lateinit var rxBus: RxBusWrapper @@ -49,65 +50,135 @@ class NSClientAddUpdateWorker( override fun doWork(): Result { val acceptNSData = !sp.getBoolean(R.string.key_ns_upload_only, true) && buildHelper.isEngineeringMode() || config.NSCLIENT - if (!acceptNSData) return Result.failure() + if (!acceptNSData) return Result.success() val treatments = dataWorker.pickupJSONArray(inputData.getLong(DataWorker.STORE_KEY, -1)) - ?: return Result.failure() + ?: return Result.failure(workDataOf("Error" to "missing input data")) var ret = Result.success() var latestDateInReceivedData = 0L for (i in 0 until treatments.length()) { - val json = treatments.getJSONObject(i) + var json = treatments.getJSONObject(i) // new DB model val insulin = JsonHelper.safeGetDouble(json, "insulin") val carbs = JsonHelper.safeGetDouble(json, "carbs") val eventType = JsonHelper.safeGetString(json, "eventType") if (eventType == null) { - aapsLogger.debug(LTag.DATASERVICE, "Wrong treatment. Ignoring : $json") + aapsLogger.debug(LTag.NSCLIENT, "Wrong treatment. Ignoring : $json") continue } //Find latest date in treatment val mills = safeGetLong(json, "mills") - if (mills != 0L && mills < dateutil._now()) + if (mills != 0L && mills < dateUtil.now()) if (mills > latestDateInReceivedData) latestDateInReceivedData = mills + if (insulin > 0) { + bolusFromJson(json)?.let { bolus -> + repository.runTransactionForResult(SyncNsBolusTransaction(bolus, invalidateByNsOnly = false)) + .doOnError { + aapsLogger.error(LTag.DATABASE, "Error while saving bolus", it) + ret = Result.failure(workDataOf("Error" to it)) + } + .blockingGet() + .also { result -> + result.inserted.forEach { + uel.log(Action.BOLUS, Sources.NSClient, + ValueWithUnit.Timestamp(it.timestamp), + ValueWithUnit.Insulin(it.amount) + ) + aapsLogger.debug(LTag.DATABASE, "Inserted bolus $it") + } + result.invalidated.forEach { + uel.log(Action.BOLUS_REMOVED, Sources.NSClient, + ValueWithUnit.Timestamp(it.timestamp), + ValueWithUnit.Insulin(it.amount) + ) + aapsLogger.debug(LTag.DATABASE, "Invalidated bolus $it") + } + result.updatedNsId.forEach { + aapsLogger.debug(LTag.DATABASE, "Updated nsId bolus $it") + } + } + } ?: aapsLogger.error("Error parsing bolus json $json") + } + if (carbs > 0) { + carbsFromJson(json)?.let { carb -> + repository.runTransactionForResult(SyncNsCarbsTransaction(carb, invalidateByNsOnly = false)) + .doOnError { + aapsLogger.error(LTag.DATABASE, "Error while saving carbs", it) + ret = Result.failure(workDataOf("Error" to it)) + } + .blockingGet() + .also { result -> + result.inserted.forEach { + uel.log(Action.CARBS, Sources.NSClient, + ValueWithUnit.Timestamp(it.timestamp), + ValueWithUnit.Gram(it.amount.toInt()) + ) + aapsLogger.debug(LTag.DATABASE, "Inserted carbs $it") + } + result.invalidated.forEach { + uel.log(Action.CARBS_REMOVED, Sources.NSClient, + ValueWithUnit.Timestamp(it.timestamp), + ValueWithUnit.Gram(it.amount.toInt()) + ) + aapsLogger.debug(LTag.DATABASE, "Invalidated carbs $it") + } + result.updatedNsId.forEach { + aapsLogger.debug(LTag.DATABASE, "Updated nsId carbs $it") + } + } + } ?: aapsLogger.error("Error parsing bolus json $json") + } + // Convert back emulated TBR -> EB + if (eventType == TherapyEvent.Type.TEMPORARY_BASAL.text && json.has("extendedEmulated")) { + val ebJson = json.getJSONObject("extendedEmulated") + ebJson.put("_id", json.getString("_id")) + ebJson.put("isValid", json.getBoolean("isValid")) + json = ebJson + } when { - insulin > 0 || carbs > 0 -> - rxBus.send(EventNsTreatment(EventNsTreatment.ADD, json)) + insulin > 0 || carbs > 0 -> Any() eventType == TherapyEvent.Type.TEMPORARY_TARGET.text -> temporaryTargetFromJson(json)?.let { temporaryTarget -> - repository.runTransactionForResult(SyncTemporaryTargetTransaction(temporaryTarget)) + repository.runTransactionForResult(SyncNsTemporaryTargetTransaction(temporaryTarget, invalidateByNsOnly = false)) .doOnError { aapsLogger.error(LTag.DATABASE, "Error while saving temporary target", it) - ret = Result.failure() + ret = Result.failure(workDataOf("Error" to it)) } .blockingGet() .also { result -> - result.inserted.forEach { - uel.log(UserEntry.Action.TT_FROM_NS, - ValueWithUnit(it.reason.text, UserEntry.Units.TherapyEvent), - ValueWithUnit(it.lowTarget, UserEntry.Units.Mg_Dl, true), - ValueWithUnit(it.highTarget, UserEntry.Units.Mg_Dl, it.lowTarget != it.highTarget), - ValueWithUnit(it.duration.toInt() / 60000, UserEntry.Units.M, true) + result.inserted.forEach { tt -> + uel.log(Action.TT, Sources.NSClient, + ValueWithUnit.TherapyEventTTReason(tt.reason), + ValueWithUnit.fromGlucoseUnit(tt.lowTarget, Constants.MGDL), + ValueWithUnit.fromGlucoseUnit(tt.highTarget, Constants.MGDL).takeIf { tt.lowTarget != tt.highTarget }, + ValueWithUnit.Minute(TimeUnit.MILLISECONDS.toMinutes(tt.duration).toInt()) ) + aapsLogger.debug(LTag.DATABASE, "Inserted TemporaryTarget $tt") } - result.invalidated.forEach { - uel.log(UserEntry.Action.TT_DELETED_FROM_NS, - ValueWithUnit(it.reason.text, UserEntry.Units.TherapyEvent), - ValueWithUnit(it.lowTarget, UserEntry.Units.Mg_Dl, true), - ValueWithUnit(it.highTarget, UserEntry.Units.Mg_Dl, it.lowTarget != it.highTarget), - ValueWithUnit(it.duration.toInt() / 60000, UserEntry.Units.M, true) + result.invalidated.forEach { tt -> + uel.log(Action.TT_REMOVED, Sources.NSClient, + ValueWithUnit.TherapyEventTTReason(tt.reason), + ValueWithUnit.Mgdl(tt.lowTarget), + ValueWithUnit.Mgdl(tt.highTarget).takeIf { tt.lowTarget != tt.highTarget }, + ValueWithUnit.Minute(TimeUnit.MILLISECONDS.toMinutes(tt.duration).toInt()) ) + aapsLogger.debug(LTag.DATABASE, "Invalidated TemporaryTarget $tt") } - result.ended.forEach { - uel.log(UserEntry.Action.TT_CANCELED_FROM_NS, - ValueWithUnit(it.reason.text, UserEntry.Units.TherapyEvent), - ValueWithUnit(it.lowTarget, UserEntry.Units.Mg_Dl, true), - ValueWithUnit(it.highTarget, UserEntry.Units.Mg_Dl, it.lowTarget != it.highTarget), - ValueWithUnit(it.duration.toInt() / 60000, UserEntry.Units.M, true) + result.ended.forEach { tt -> + uel.log(Action.CANCEL_TT, Sources.NSClient, + ValueWithUnit.TherapyEventTTReason(tt.reason), + ValueWithUnit.Mgdl(tt.lowTarget), + ValueWithUnit.Mgdl(tt.highTarget).takeIf { tt.lowTarget != tt.highTarget }, + ValueWithUnit.Minute(TimeUnit.MILLISECONDS.toMinutes(tt.duration).toInt()) ) + aapsLogger.debug(LTag.DATABASE, "Updated TemporaryTarget $tt") + } + result.updatedNsId.forEach { + aapsLogger.debug(LTag.DATABASE, "Updated nsId TemporaryTarget $it") } } } ?: aapsLogger.error("Error parsing TT json $json") @@ -115,7 +186,6 @@ class NSClientAddUpdateWorker( eventType == TherapyEvent.Type.INSULIN_CHANGE.text || eventType == TherapyEvent.Type.SENSOR_CHANGE.text || eventType == TherapyEvent.Type.FINGER_STICK_BG_VALUE.text || - eventType == TherapyEvent.Type.NOTE.text || eventType == TherapyEvent.Type.NONE.text || eventType == TherapyEvent.Type.ANNOUNCEMENT.text || eventType == TherapyEvent.Type.QUESTION.text || @@ -123,33 +193,118 @@ class NSClientAddUpdateWorker( eventType == TherapyEvent.Type.APS_OFFLINE.text || eventType == TherapyEvent.Type.PUMP_BATTERY_CHANGE.text -> therapyEventFromJson(json)?.let { therapyEvent -> - repository.runTransactionForResult(SyncTherapyEventTransaction(therapyEvent)) + repository.runTransactionForResult(SyncNsTherapyEventTransaction(therapyEvent, invalidateByNsOnly = false)) .doOnError { aapsLogger.error(LTag.DATABASE, "Error while saving therapy event", it) - ret = Result.failure() + ret = Result.failure(workDataOf("Error" to it)) + } + .blockingGet() + .also { result -> + val action = when (eventType) { + TherapyEvent.Type.CANNULA_CHANGE.text -> Action.SITE_CHANGE + TherapyEvent.Type.INSULIN_CHANGE.text -> Action.RESERVOIR_CHANGE + else -> Action.CAREPORTAL + } + result.inserted.forEach { + uel.log(action, Sources.NSClient, + it.note ?: "", + ValueWithUnit.Timestamp(it.timestamp), + ValueWithUnit.TherapyEventType(it.type) + ) + aapsLogger.debug(LTag.DATABASE, "Inserted TherapyEvent $it") + } + result.invalidated.forEach { + uel.log(Action.CAREPORTAL_REMOVED, Sources.NSClient, + it.note ?: "", + ValueWithUnit.Timestamp(it.timestamp), + ValueWithUnit.TherapyEventType(it.type) + ) + aapsLogger.debug(LTag.DATABASE, "Invalidated TherapyEvent $it") + } + result.updatedNsId.forEach { + aapsLogger.debug(LTag.DATABASE, "Updated nsId TherapyEvent $it") + } + } + } ?: aapsLogger.error("Error parsing TherapyEvent json $json") + eventType == TherapyEvent.Type.COMBO_BOLUS.text -> + extendedBolusFromJson(json)?.let { extendedBolus -> + repository.runTransactionForResult(SyncNsExtendedBolusTransaction(extendedBolus, invalidateByNsOnly = false)) + .doOnError { + aapsLogger.error(LTag.DATABASE, "Error while saving extended bolus", it) + ret = Result.failure(workDataOf("Error" to it)) } .blockingGet() .also { result -> result.inserted.forEach { - uel.log(UserEntry.Action.CAREPORTAL_FROM_NS, - it.note ?: "", - ValueWithUnit(it.timestamp, UserEntry.Units.Timestamp, true), - ValueWithUnit(it.type.text, UserEntry.Units.TherapyEvent) + uel.log(Action.EXTENDED_BOLUS, Sources.NSClient, + ValueWithUnit.Timestamp(it.timestamp), + ValueWithUnit.Insulin(it.amount), + ValueWithUnit.UnitPerHour(it.rate), + ValueWithUnit.Minute(TimeUnit.MILLISECONDS.toMinutes(it.duration).toInt()) ) + aapsLogger.debug(LTag.DATABASE, "Inserted ExtendedBolus $it") } result.invalidated.forEach { - uel.log(UserEntry.Action.CAREPORTAL_DELETED_FROM_NS, - it.note ?: "", - ValueWithUnit(it.timestamp, UserEntry.Units.Timestamp, true), - ValueWithUnit(it.type.text, UserEntry.Units.TherapyEvent) + uel.log(Action.EXTENDED_BOLUS_REMOVED, Sources.NSClient, + ValueWithUnit.Timestamp(it.timestamp), + ValueWithUnit.Insulin(it.amount), + ValueWithUnit.UnitPerHour(it.rate), + ValueWithUnit.Minute(TimeUnit.MILLISECONDS.toMinutes(it.duration).toInt()) ) + aapsLogger.debug(LTag.DATABASE, "Invalidated ExtendedBolus $it") + } + result.ended.forEach { + uel.log(Action.CANCEL_EXTENDED_BOLUS, Sources.NSClient, + ValueWithUnit.Timestamp(it.timestamp), + ValueWithUnit.Insulin(it.amount), + ValueWithUnit.UnitPerHour(it.rate), + ValueWithUnit.Minute(TimeUnit.MILLISECONDS.toMinutes(it.duration).toInt()) + ) + aapsLogger.debug(LTag.DATABASE, "Updated ExtendedBolus $it") + } + result.updatedNsId.forEach { + aapsLogger.debug(LTag.DATABASE, "Updated nsId ExtendedBolus $it") } } - } ?: aapsLogger.error("Error parsing TherapyEvent json $json") + } ?: aapsLogger.error("Error parsing ExtendedBolus json $json") eventType == TherapyEvent.Type.TEMPORARY_BASAL.text -> - databaseHelper.createTempBasalFromJsonIfNotExists(json) - eventType == TherapyEvent.Type.COMBO_BOLUS.text -> - databaseHelper.createExtendedBolusFromJsonIfNotExists(json) + temporaryBasalFromJson(json)?.let { temporaryBasal -> + repository.runTransactionForResult(SyncNsTemporaryBasalTransaction(temporaryBasal, invalidateByNsOnly = false)) + .doOnError { + aapsLogger.error(LTag.DATABASE, "Error while saving temporary basal", it) + ret = Result.failure(workDataOf("Error" to it)) + } + .blockingGet() + .also { result -> + result.inserted.forEach { + uel.log(Action.TEMP_BASAL, Sources.NSClient, + ValueWithUnit.Timestamp(it.timestamp), + ValueWithUnit.UnitPerHour(it.rate), + ValueWithUnit.Minute(TimeUnit.MILLISECONDS.toMinutes(it.duration).toInt()) + ) + aapsLogger.debug(LTag.DATABASE, "Inserted TemporaryBasal $it") + } + result.invalidated.forEach { + uel.log(Action.TEMP_BASAL_REMOVED, Sources.NSClient, + ValueWithUnit.Timestamp(it.timestamp), + ValueWithUnit.UnitPerHour(it.rate), + ValueWithUnit.Minute(TimeUnit.MILLISECONDS.toMinutes(it.duration).toInt()) + ) + aapsLogger.debug(LTag.DATABASE, "Invalidated TemporaryBasal $it") + } + result.ended.forEach { + uel.log(Action.CANCEL_TEMP_BASAL, Sources.NSClient, + ValueWithUnit.Timestamp(it.timestamp), + ValueWithUnit.UnitPerHour(it.rate), + ValueWithUnit.Minute(TimeUnit.MILLISECONDS.toMinutes(it.duration).toInt()) + ) + aapsLogger.debug(LTag.DATABASE, "Ended TemporaryBasal $it") + } + result.updatedNsId.forEach { + aapsLogger.debug(LTag.DATABASE, "Updated nsId TemporaryBasal $it") + } + } + } ?: aapsLogger.error("Error parsing TemporaryBasal json $json") eventType == TherapyEvent.Type.PROFILE_SWITCH.text -> databaseHelper.createProfileSwitchFromJsonIfNotExists(json) } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/nsclient/NSClientFragment.java b/app/src/main/java/info/nightscout/androidaps/plugins/general/nsclient/NSClientFragment.java deleted file mode 100644 index 333c510309..0000000000 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/nsclient/NSClientFragment.java +++ /dev/null @@ -1,171 +0,0 @@ -package info.nightscout.androidaps.plugins.general.nsclient; - - -import android.graphics.Paint; -import android.os.Bundle; -import android.text.Spanned; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.CheckBox; -import android.widget.CompoundButton; -import android.widget.ScrollView; -import android.widget.TextView; - -import javax.inject.Inject; - -import dagger.android.support.DaggerFragment; -import info.nightscout.androidaps.R; -import info.nightscout.androidaps.interfaces.UploadQueueAdminInterface; -import info.nightscout.androidaps.database.entities.UserEntry; -import info.nightscout.androidaps.database.entities.UserEntry.*; -import info.nightscout.androidaps.logging.UserEntryLogger; -import info.nightscout.androidaps.plugins.bus.RxBusWrapper; -import info.nightscout.androidaps.plugins.general.nsclient.events.EventNSClientNewLog; -import info.nightscout.androidaps.plugins.general.nsclient.events.EventNSClientRestart; -import info.nightscout.androidaps.plugins.general.nsclient.events.EventNSClientUpdateGUI; -import info.nightscout.androidaps.utils.FabricPrivacy; -import info.nightscout.androidaps.utils.HtmlHelper; -import info.nightscout.androidaps.utils.alertDialogs.OKDialog; -import info.nightscout.androidaps.utils.resources.ResourceHelper; -import info.nightscout.androidaps.utils.rx.AapsSchedulers; -import info.nightscout.androidaps.utils.sharedPreferences.SP; -import io.reactivex.disposables.CompositeDisposable; - -public class NSClientFragment extends DaggerFragment implements View.OnClickListener, CompoundButton.OnCheckedChangeListener { - @Inject NSClientPlugin nsClientPlugin; - @Inject SP sp; - @Inject ResourceHelper resourceHelper; - @Inject RxBusWrapper rxBus; - @Inject UploadQueueAdminInterface uploadQueue; - @Inject FabricPrivacy fabricPrivacy; - @Inject AapsSchedulers aapsSchedulers; - @Inject UserEntryLogger uel; - - private final CompositeDisposable disposable = new CompositeDisposable(); - - private TextView logTextView; - private TextView queueTextView; - private TextView urlTextView; - private TextView statusTextView; - private TextView clearlog; - private TextView restart; - private TextView delivernow; - private TextView clearqueue; - private TextView showqueue; - private ScrollView logScrollview; - private CheckBox autoscrollCheckbox; - private CheckBox pausedCheckbox; - - @Override - public View onCreateView(LayoutInflater inflater, ViewGroup container, - Bundle savedInstanceState) { - View view = inflater.inflate(R.layout.nsclientinternal_fragment, container, false); - - logScrollview = view.findViewById(R.id.nsclientinternal_logscrollview); - autoscrollCheckbox = view.findViewById(R.id.nsclientinternal_autoscroll); - autoscrollCheckbox.setChecked(nsClientPlugin.autoscroll); - autoscrollCheckbox.setOnCheckedChangeListener(this); - pausedCheckbox = view.findViewById(R.id.nsclientinternal_paused); - pausedCheckbox.setChecked(nsClientPlugin.paused); - pausedCheckbox.setOnCheckedChangeListener(this); - logTextView = view.findViewById(R.id.nsclientinternal_log); - queueTextView = view.findViewById(R.id.nsclientinternal_queue); - urlTextView = view.findViewById(R.id.nsclientinternal_url); - statusTextView = view.findViewById(R.id.nsclientinternal_status); - - clearlog = view.findViewById(R.id.nsclientinternal_clearlog); - clearlog.setOnClickListener(this); - clearlog.setPaintFlags(clearlog.getPaintFlags() | Paint.UNDERLINE_TEXT_FLAG); - restart = view.findViewById(R.id.nsclientinternal_restart); - restart.setOnClickListener(this); - restart.setPaintFlags(restart.getPaintFlags() | Paint.UNDERLINE_TEXT_FLAG); - delivernow = view.findViewById(R.id.nsclientinternal_delivernow); - delivernow.setOnClickListener(this); - delivernow.setPaintFlags(delivernow.getPaintFlags() | Paint.UNDERLINE_TEXT_FLAG); - clearqueue = view.findViewById(R.id.nsclientinternal_clearqueue); - clearqueue.setOnClickListener(this); - clearqueue.setPaintFlags(clearqueue.getPaintFlags() | Paint.UNDERLINE_TEXT_FLAG); - showqueue = view.findViewById(R.id.nsclientinternal_showqueue); - showqueue.setOnClickListener(this); - showqueue.setPaintFlags(showqueue.getPaintFlags() | Paint.UNDERLINE_TEXT_FLAG); - - return view; - } - - @Override - public synchronized void onResume() { - super.onResume(); - disposable.add(rxBus - .toObservable(EventNSClientUpdateGUI.class) - .observeOn(aapsSchedulers.getMain()) - .subscribe(event -> updateGui(), fabricPrivacy::logException) - ); - updateGui(); - } - - @Override - public synchronized void onPause() { - super.onPause(); - disposable.clear(); - } - - @Override - public void onClick(View view) { - switch (view.getId()) { - case R.id.nsclientinternal_restart: - rxBus.send(new EventNSClientRestart()); - fabricPrivacy.logCustom("NSClientRestart"); - break; - case R.id.nsclientinternal_delivernow: - nsClientPlugin.resend("GUI"); - fabricPrivacy.logCustom("NSClientDeliverNow"); - break; - case R.id.nsclientinternal_clearlog: - nsClientPlugin.clearLog(); - break; - case R.id.nsclientinternal_clearqueue: - OKDialog.showConfirmation(getContext(), resourceHelper.gs(R.string.nsclientinternal), resourceHelper.gs(R.string.clearqueueconfirm), () -> { - uel.log(Action.NS_QUEUE_CLEARED); - uploadQueue.clearQueue(); - updateGui(); - fabricPrivacy.logCustom("NSClientClearQueue"); - }); - break; - case R.id.nsclientinternal_showqueue: - rxBus.send(new EventNSClientNewLog("QUEUE", uploadQueue.textList())); - break; - } - } - - @Override - public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { - switch (buttonView.getId()) { - case R.id.nsclientinternal_paused: - uel.log(isChecked ? Action.NS_PAUSED : Action.NS_RESUME); - nsClientPlugin.pause(isChecked); - updateGui(); - fabricPrivacy.logCustom("NSClientPause"); - break; - case R.id.nsclientinternal_autoscroll: - sp.putBoolean(R.string.key_nsclientinternal_autoscroll, isChecked); - nsClientPlugin.autoscroll = isChecked; - updateGui(); - break; - } - } - - protected void updateGui() { - nsClientPlugin.updateLog(); - pausedCheckbox.setChecked(sp.getBoolean(R.string.key_nsclientinternal_paused, false)); - logTextView.setText(nsClientPlugin.textLog); - if (nsClientPlugin.autoscroll) { - logScrollview.fullScroll(ScrollView.FOCUS_DOWN); - } - urlTextView.setText(nsClientPlugin.url()); - Spanned queuetext = HtmlHelper.INSTANCE.fromHtml(resourceHelper.gs(R.string.queue) + " " + uploadQueue.size() + ""); - queueTextView.setText(queuetext); - statusTextView.setText(nsClientPlugin.status); - } - -} diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/nsclient/NSClientFragment.kt b/app/src/main/java/info/nightscout/androidaps/plugins/general/nsclient/NSClientFragment.kt new file mode 100644 index 0000000000..d2e77a4f95 --- /dev/null +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/nsclient/NSClientFragment.kt @@ -0,0 +1,122 @@ +package info.nightscout.androidaps.plugins.general.nsclient + +import android.graphics.Paint +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.ScrollView +import dagger.android.support.DaggerFragment +import info.nightscout.androidaps.R +import info.nightscout.androidaps.database.entities.UserEntry.Action +import info.nightscout.androidaps.database.entities.UserEntry.Sources +import info.nightscout.androidaps.databinding.NsClientFragmentBinding +import info.nightscout.androidaps.interfaces.DataSyncSelector +import info.nightscout.androidaps.interfaces.UploadQueueAdminInterface +import info.nightscout.androidaps.logging.UserEntryLogger +import info.nightscout.androidaps.plugins.bus.RxBusWrapper +import info.nightscout.androidaps.plugins.general.nsclient.events.EventNSClientNewLog +import info.nightscout.androidaps.plugins.general.nsclient.events.EventNSClientRestart +import info.nightscout.androidaps.plugins.general.nsclient.events.EventNSClientUpdateGUI +import info.nightscout.androidaps.utils.FabricPrivacy +import info.nightscout.androidaps.utils.HtmlHelper.fromHtml +import info.nightscout.androidaps.utils.alertDialogs.OKDialog +import info.nightscout.androidaps.utils.resources.ResourceHelper +import info.nightscout.androidaps.utils.rx.AapsSchedulers +import info.nightscout.androidaps.utils.sharedPreferences.SP +import io.reactivex.disposables.CompositeDisposable +import javax.inject.Inject + +class NSClientFragment : DaggerFragment() { + + @Inject lateinit var nsClientPlugin: NSClientPlugin + @Inject lateinit var sp: SP + @Inject lateinit var resourceHelper: ResourceHelper + @Inject lateinit var rxBus: RxBusWrapper + @Inject lateinit var uploadQueue: UploadQueueAdminInterface + @Inject lateinit var fabricPrivacy: FabricPrivacy + @Inject lateinit var aapsSchedulers: AapsSchedulers + @Inject lateinit var dataSyncSelector: DataSyncSelector + @Inject lateinit var uel: UserEntryLogger + + private val disposable = CompositeDisposable() + + private var _binding: NsClientFragmentBinding? = null + + // This property is only valid between onCreateView and + // onDestroyView. + private val binding get() = _binding!! + + override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View = + NsClientFragmentBinding.inflate(inflater, container, false).also { _binding = it }.root + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + + binding.autoscroll.isChecked = nsClientPlugin.autoscroll + binding.autoscroll.setOnCheckedChangeListener { _, isChecked -> + sp.putBoolean(R.string.key_nsclientinternal_autoscroll, isChecked) + nsClientPlugin.autoscroll = isChecked + updateGui() + } + + binding.paused.isChecked = nsClientPlugin.paused + binding.paused.setOnCheckedChangeListener { _, isChecked -> + uel.log(if (isChecked) Action.NS_PAUSED else Action.NS_RESUME, Sources.NSClient) + nsClientPlugin.pause(isChecked) + updateGui() + } + binding.clearLog.setOnClickListener { nsClientPlugin.clearLog() } + binding.clearLog.paintFlags = binding.clearLog.paintFlags or Paint.UNDERLINE_TEXT_FLAG + binding.restart.setOnClickListener { rxBus.send(EventNSClientRestart()) } + binding.restart.paintFlags = binding.restart.paintFlags or Paint.UNDERLINE_TEXT_FLAG + binding.deliverNow.setOnClickListener { nsClientPlugin.resend("GUI") } + binding.deliverNow.paintFlags = binding.deliverNow.paintFlags or Paint.UNDERLINE_TEXT_FLAG + binding.clearQueue.setOnClickListener { + context?.let { context -> + OKDialog.showConfirmation(context, resourceHelper.gs(R.string.nsclientinternal), resourceHelper.gs(R.string.clearqueueconfirm), Runnable { + uel.log(Action.NS_QUEUE_CLEARED, Sources.NSClient) + uploadQueue.clearQueue() + updateGui() + }) + } + } + binding.clearQueue.paintFlags = binding.clearQueue.paintFlags or Paint.UNDERLINE_TEXT_FLAG + binding.showQueue.setOnClickListener { rxBus.send(EventNSClientNewLog("QUEUE", uploadQueue.textList())) } + binding.showQueue.paintFlags = binding.showQueue.paintFlags or Paint.UNDERLINE_TEXT_FLAG + binding.fullSync.setOnClickListener { + context?.let { context -> + OKDialog.showConfirmation(context, resourceHelper.gs(R.string.nsclientinternal), resourceHelper.gs(R.string.full_sync), Runnable { + dataSyncSelector.resetToNextFullSync() + }) + } + } + binding.fullSync.paintFlags = binding.fullSync.paintFlags or Paint.UNDERLINE_TEXT_FLAG + } + + @Synchronized override fun onResume() { + super.onResume() + disposable.add(rxBus + .toObservable(EventNSClientUpdateGUI::class.java) + .observeOn(aapsSchedulers.main) + .subscribe({ updateGui() }, fabricPrivacy::logException) + ) + updateGui() + } + + @Synchronized override fun onPause() { + super.onPause() + disposable.clear() + } + + private fun updateGui() { + if (_binding == null) return + nsClientPlugin.updateLog() + binding.paused.isChecked = sp.getBoolean(R.string.key_nsclientinternal_paused, false) + binding.log.text = nsClientPlugin.textLog + if (nsClientPlugin.autoscroll) binding.logScrollview.fullScroll(ScrollView.FOCUS_DOWN) + binding.url.text = nsClientPlugin.url() + binding.queue.text = fromHtml(resourceHelper.gs(R.string.queue) + " " + uploadQueue.size() + "") + binding.status.text = nsClientPlugin.status + } +} \ No newline at end of file diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/nsclient/NSClientMbgWorker.kt b/app/src/main/java/info/nightscout/androidaps/plugins/general/nsclient/NSClientMbgWorker.kt index 7c05af0fc8..9f61cf6092 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/nsclient/NSClientMbgWorker.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/nsclient/NSClientMbgWorker.kt @@ -3,17 +3,18 @@ package info.nightscout.androidaps.plugins.general.nsclient import android.content.Context import androidx.work.Worker import androidx.work.WorkerParameters +import androidx.work.workDataOf import dagger.android.HasAndroidInjector import info.nightscout.androidaps.R import info.nightscout.androidaps.database.AppRepository -import info.nightscout.androidaps.database.transactions.SyncTherapyEventTransaction -import info.nightscout.androidaps.interfaces.ConfigInterface +import info.nightscout.androidaps.database.transactions.SyncNsTherapyEventTransaction +import info.nightscout.androidaps.interfaces.Config import info.nightscout.androidaps.logging.AAPSLogger import info.nightscout.androidaps.logging.LTag import info.nightscout.androidaps.plugins.general.nsclient.data.NSMbg import info.nightscout.androidaps.receivers.DataWorker import info.nightscout.androidaps.utils.buildHelper.BuildHelper -import info.nightscout.androidaps.utils.extensions.therapyEventFromNsMbg +import info.nightscout.androidaps.extensions.therapyEventFromNsMbg import info.nightscout.androidaps.utils.sharedPreferences.SP import javax.inject.Inject @@ -27,7 +28,7 @@ class NSClientMbgWorker( @Inject lateinit var aapsLogger: AAPSLogger @Inject lateinit var sp: SP @Inject lateinit var buildHelper: BuildHelper - @Inject lateinit var config: ConfigInterface + @Inject lateinit var config: Config override fun doWork(): Result { var ret = Result.success() @@ -36,14 +37,14 @@ class NSClientMbgWorker( if (!acceptNSData) return ret val mbgArray = dataWorker.pickupJSONArray(inputData.getLong(DataWorker.STORE_KEY, -1)) - ?: return Result.failure() + ?: return Result.failure(workDataOf("Error" to "missing input data")) for (i in 0 until mbgArray.length()) { val nsMbg = NSMbg(mbgArray.getJSONObject(i)) if (!nsMbg.isValid()) continue - repository.runTransactionForResult(SyncTherapyEventTransaction(therapyEventFromNsMbg(nsMbg))) + repository.runTransactionForResult(SyncNsTherapyEventTransaction(therapyEventFromNsMbg(nsMbg), false)) .doOnError { aapsLogger.error("Error while saving therapy event", it) - ret = Result.failure() + ret = Result.failure(workDataOf("Error" to it)) } .blockingGet() .also { diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/nsclient/NSClientPlugin.java b/app/src/main/java/info/nightscout/androidaps/plugins/general/nsclient/NSClientPlugin.java index 48257ee342..ae28f50b36 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/nsclient/NSClientPlugin.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/nsclient/NSClientPlugin.java @@ -4,20 +4,16 @@ import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.ServiceConnection; -import android.os.Bundle; import android.os.Handler; import android.os.HandlerThread; import android.os.IBinder; import android.text.Spanned; import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import androidx.preference.PreferenceFragmentCompat; import androidx.preference.SwitchPreference; -import org.json.JSONArray; -import org.json.JSONException; -import org.json.JSONObject; - import java.util.ArrayList; import java.util.List; @@ -25,30 +21,18 @@ import javax.inject.Inject; import javax.inject.Singleton; import dagger.android.HasAndroidInjector; -import info.nightscout.androidaps.Config; +import info.nightscout.androidaps.interfaces.Config; import info.nightscout.androidaps.Constants; import info.nightscout.androidaps.R; -import info.nightscout.androidaps.database.AppRepository; -import info.nightscout.androidaps.database.entities.TemporaryTarget; -import info.nightscout.androidaps.database.entities.TherapyEvent; -import info.nightscout.androidaps.database.entities.UserEntry.Action; -import info.nightscout.androidaps.database.entities.UserEntry.Units; -import info.nightscout.androidaps.database.entities.UserEntry.ValueWithUnit; -import info.nightscout.androidaps.database.transactions.SyncTemporaryTargetTransaction; -import info.nightscout.androidaps.database.transactions.SyncTherapyEventTransaction; import info.nightscout.androidaps.events.EventAppExit; import info.nightscout.androidaps.events.EventChargingState; import info.nightscout.androidaps.events.EventNetworkChange; -import info.nightscout.androidaps.events.EventNsTreatment; import info.nightscout.androidaps.events.EventPreferenceChange; -import info.nightscout.androidaps.interfaces.ActivePluginProvider; -import info.nightscout.androidaps.interfaces.DatabaseHelperInterface; import info.nightscout.androidaps.interfaces.PluginBase; import info.nightscout.androidaps.interfaces.PluginDescription; import info.nightscout.androidaps.interfaces.PluginType; import info.nightscout.androidaps.logging.AAPSLogger; import info.nightscout.androidaps.logging.LTag; -import info.nightscout.androidaps.logging.UserEntryLogger; import info.nightscout.androidaps.plugins.bus.RxBusWrapper; import info.nightscout.androidaps.plugins.general.nsclient.data.AlarmAck; import info.nightscout.androidaps.plugins.general.nsclient.data.NSAlarm; @@ -57,12 +41,8 @@ import info.nightscout.androidaps.plugins.general.nsclient.events.EventNSClientR import info.nightscout.androidaps.plugins.general.nsclient.events.EventNSClientStatus; import info.nightscout.androidaps.plugins.general.nsclient.events.EventNSClientUpdateGUI; import info.nightscout.androidaps.plugins.general.nsclient.services.NSClientService; -import info.nightscout.androidaps.plugins.general.overview.events.EventNewNotification; -import info.nightscout.androidaps.plugins.general.overview.notifications.Notification; -import info.nightscout.androidaps.services.Intents; import info.nightscout.androidaps.utils.FabricPrivacy; import info.nightscout.androidaps.utils.HtmlHelper; -import info.nightscout.androidaps.utils.JsonHelper; import info.nightscout.androidaps.utils.ToastUtils; import info.nightscout.androidaps.utils.buildHelper.BuildHelper; import info.nightscout.androidaps.utils.resources.ResourceHelper; @@ -70,11 +50,6 @@ import info.nightscout.androidaps.utils.rx.AapsSchedulers; import info.nightscout.androidaps.utils.sharedPreferences.SP; import io.reactivex.disposables.CompositeDisposable; -import static info.nightscout.androidaps.utils.extensions.TemporaryTargetExtensionKt.temporaryTargetFromJson; -import static info.nightscout.androidaps.utils.extensions.TemporaryTargetExtensionKt.temporaryTargetFromNsIdForInvalidating; -import static info.nightscout.androidaps.utils.extensions.TherapyEventExtensionKt.therapyEventFromJson; -import static info.nightscout.androidaps.utils.extensions.TherapyEventExtensionKt.therapyEventFromNsIdForInvalidating; - @Singleton public class NSClientPlugin extends PluginBase { private final CompositeDisposable disposable = new CompositeDisposable(); @@ -86,13 +61,9 @@ public class NSClientPlugin extends PluginBase { private final AapsSchedulers aapsSchedulers; private final FabricPrivacy fabricPrivacy; private final SP sp; + private final NsClientReceiverDelegate nsClientReceiverDelegate; private final Config config; private final BuildHelper buildHelper; - private final ActivePluginProvider activePlugin; - private final NSUpload nsUpload; - private final AppRepository repository; - private final DatabaseHelperInterface databaseHelper; - private final UserEntryLogger uel; public Handler handler; @@ -104,9 +75,8 @@ public class NSClientPlugin extends PluginBase { public String status = ""; - public NSClientService nsClientService = null; + public @Nullable NSClientService nsClientService = null; - private final NsClientReceiverDelegate nsClientReceiverDelegate; @Inject public NSClientPlugin( @@ -120,12 +90,7 @@ public class NSClientPlugin extends PluginBase { SP sp, NsClientReceiverDelegate nsClientReceiverDelegate, Config config, - BuildHelper buildHelper, - ActivePluginProvider activePlugin, - NSUpload nsUpload, - DatabaseHelperInterface databaseHelper, - AppRepository repository, - UserEntryLogger uel + BuildHelper buildHelper ) { super(new PluginDescription() .mainType(PluginType.GENERAL) @@ -148,11 +113,6 @@ public class NSClientPlugin extends PluginBase { this.nsClientReceiverDelegate = nsClientReceiverDelegate; this.config = config; this.buildHelper = buildHelper; - this.activePlugin = activePlugin; - this.nsUpload = nsUpload; - this.databaseHelper = databaseHelper; - this.repository = repository; - this.uel = uel; if (config.getNSCLIENT()) { getPluginDescription().alwaysEnabled(true).visibleByDefault(true); @@ -354,7 +314,7 @@ public class NSClientPlugin extends PluginBase { } public void updateLatestDateReceivedIfNewer(long latestReceived) { - if (latestReceived > nsClientService.latestDateInReceivedData) + if (nsClientService != null && latestReceived > nsClientService.latestDateInReceivedData) nsClientService.latestDateInReceivedData = latestReceived; } } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/nsclient/NSClientRemoveWorker.kt b/app/src/main/java/info/nightscout/androidaps/plugins/general/nsclient/NSClientRemoveWorker.kt index a80c71c803..e18708f7a0 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/nsclient/NSClientRemoveWorker.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/nsclient/NSClientRemoveWorker.kt @@ -3,16 +3,16 @@ package info.nightscout.androidaps.plugins.general.nsclient import android.content.Context import androidx.work.Worker import androidx.work.WorkerParameters +import androidx.work.workDataOf import dagger.android.HasAndroidInjector import info.nightscout.androidaps.R import info.nightscout.androidaps.database.AppRepository -import info.nightscout.androidaps.database.entities.UserEntry -import info.nightscout.androidaps.database.entities.UserEntry.ValueWithUnit -import info.nightscout.androidaps.database.transactions.SyncTemporaryTargetTransaction -import info.nightscout.androidaps.database.transactions.SyncTherapyEventTransaction -import info.nightscout.androidaps.events.EventNsTreatment -import info.nightscout.androidaps.events.EventNsTreatment.Companion.REMOVE -import info.nightscout.androidaps.interfaces.ConfigInterface +import info.nightscout.androidaps.database.entities.UserEntry.Action +import info.nightscout.androidaps.database.entities.UserEntry.Sources +import info.nightscout.androidaps.database.entities.ValueWithUnit +import info.nightscout.androidaps.database.transactions.* +import info.nightscout.androidaps.extensions.* +import info.nightscout.androidaps.interfaces.Config import info.nightscout.androidaps.interfaces.DatabaseHelperInterface import info.nightscout.androidaps.logging.AAPSLogger import info.nightscout.androidaps.logging.LTag @@ -21,9 +21,8 @@ import info.nightscout.androidaps.plugins.bus.RxBusWrapper import info.nightscout.androidaps.receivers.DataWorker import info.nightscout.androidaps.utils.JsonHelper import info.nightscout.androidaps.utils.buildHelper.BuildHelper -import info.nightscout.androidaps.utils.extensions.temporaryTargetFromNsIdForInvalidating -import info.nightscout.androidaps.utils.extensions.therapyEventFromNsIdForInvalidating import info.nightscout.androidaps.utils.sharedPreferences.SP +import java.util.concurrent.TimeUnit import javax.inject.Inject // This will not be needed fpr NS v3 @@ -38,7 +37,7 @@ class NSClientRemoveWorker( @Inject lateinit var aapsLogger: AAPSLogger @Inject lateinit var buildHelper: BuildHelper @Inject lateinit var sp: SP - @Inject lateinit var config: ConfigInterface + @Inject lateinit var config: Config @Inject lateinit var repository: AppRepository @Inject lateinit var databaseHelper: DatabaseHelperInterface @Inject lateinit var rxBus: RxBusWrapper @@ -46,12 +45,12 @@ class NSClientRemoveWorker( override fun doWork(): Result { val acceptNSData = !sp.getBoolean(R.string.key_ns_upload_only, true) && buildHelper.isEngineeringMode() || config.NSCLIENT - if (!acceptNSData) return Result.failure() + if (!acceptNSData) return Result.success() var ret = Result.success() val treatments = dataWorker.pickupJSONArray(inputData.getLong(DataWorker.STORE_KEY, -1)) - ?: return Result.failure() + ?: return Result.failure(workDataOf("Error" to "missing input data")) for (i in 0 until treatments.length()) { val json = treatments.getJSONObject(i) @@ -59,46 +58,107 @@ class NSClientRemoveWorker( // room Temporary target val temporaryTarget = temporaryTargetFromNsIdForInvalidating(nsId) - repository.runTransactionForResult(SyncTemporaryTargetTransaction(temporaryTarget)) + repository.runTransactionForResult(SyncNsTemporaryTargetTransaction(temporaryTarget, invalidateByNsOnly = true)) .doOnError { - aapsLogger.error(LTag.DATABASE, "Error while removing temporary target", it) - ret = Result.failure() + aapsLogger.error(LTag.DATABASE, "Error while invalidating temporary target", it) + ret = Result.failure(workDataOf("Error" to it)) } .blockingGet() .also { result -> - result.invalidated.forEach { + result.invalidated.forEach { tt -> uel.log( - UserEntry.Action.TT_DELETED_FROM_NS, - ValueWithUnit(it.reason.text, UserEntry.Units.TherapyEvent), - ValueWithUnit(it.lowTarget, UserEntry.Units.Mg_Dl, true), - ValueWithUnit(it.highTarget, UserEntry.Units.Mg_Dl, it.lowTarget != it.highTarget), - ValueWithUnit(it.duration.toInt() / 60000, UserEntry.Units.M, it.duration != 0L) + Action.TT_REMOVED, Sources.NSClient, + ValueWithUnit.TherapyEventTTReason(tt.reason), + ValueWithUnit.Mgdl(tt.lowTarget), + ValueWithUnit.Mgdl(tt.highTarget).takeIf { tt.lowTarget != tt.highTarget }, + ValueWithUnit.Minute(TimeUnit.MILLISECONDS.toMinutes(tt.duration).toInt()).takeIf { tt.duration != 0L } ) } } // room Therapy Event val therapyEvent = therapyEventFromNsIdForInvalidating(nsId) - repository.runTransactionForResult(SyncTherapyEventTransaction(therapyEvent)) + repository.runTransactionForResult(SyncNsTherapyEventTransaction(therapyEvent, invalidateByNsOnly = true)) .doOnError { - aapsLogger.error(LTag.DATABASE, "Error while removing therapy event", it) - ret = Result.failure() + aapsLogger.error(LTag.DATABASE, "Error while invalidating therapy event", it) + ret = Result.failure(workDataOf("Error" to it)) + } + .blockingGet() + .also { result -> + result.invalidated.forEach { + uel.log(Action.CAREPORTAL_REMOVED, Sources.NSClient, + (it.note ?: ""), + ValueWithUnit.Timestamp(it.timestamp), + ValueWithUnit.TherapyEventType(it.type)) + } + } + + // room Bolus + val bolus = bolusFromNsIdForInvalidating(nsId) + repository.runTransactionForResult(SyncNsBolusTransaction(bolus, invalidateByNsOnly = true)) + .doOnError { + aapsLogger.error(LTag.DATABASE, "Error while invalidating bolus", it) + ret = Result.failure(workDataOf("Error" to it)) + } + .blockingGet() + .also { result -> + result.invalidated.forEach { + uel.log(Action.CAREPORTAL_REMOVED, Sources.NSClient, + ValueWithUnit.Timestamp(it.timestamp), + ValueWithUnit.Insulin(it.amount)) + } + } + + // room Carbs + val carbs = carbsFromNsIdForInvalidating(nsId) + repository.runTransactionForResult(SyncNsCarbsTransaction(carbs, invalidateByNsOnly = true)) + .doOnError { + aapsLogger.error(LTag.DATABASE, "Error while invalidating carbs", it) + ret = Result.failure(workDataOf("Error" to it)) + } + .blockingGet() + .also { result -> + result.invalidated.forEach { + uel.log(Action.CAREPORTAL_REMOVED, Sources.NSClient, + ValueWithUnit.Timestamp(it.timestamp), + ValueWithUnit.Gram(it.amount.toInt())) + } + } + + // room TemporaryBasal + val temporaryBasal = temporaryBasalFromNsIdForInvalidating(nsId) + repository.runTransactionForResult(SyncNsTemporaryBasalTransaction(temporaryBasal, invalidateByNsOnly = true)) + .doOnError { + aapsLogger.error(LTag.DATABASE, "Error while invalidating temporary basal", it) + ret = Result.failure(workDataOf("Error" to it)) } .blockingGet() .also { result -> result.invalidated.forEach { uel.log( - UserEntry.Action.CAREPORTAL_DELETED_FROM_NS, (it.note ?: ""), - ValueWithUnit(it.timestamp, UserEntry.Units.Timestamp, true), - ValueWithUnit(it.type.text, UserEntry.Units.TherapyEvent)) + Action.CAREPORTAL_REMOVED, Sources.NSClient, + ValueWithUnit.Timestamp(it.timestamp), + ValueWithUnit.UnitPerHour(it.rate)) + } + } + // room ExtendedBolus + val extendedBolus = extendedBolusFromNsIdForInvalidating(nsId) + repository.runTransactionForResult(SyncNsExtendedBolusTransaction(extendedBolus, invalidateByNsOnly = true)) + .doOnError { + aapsLogger.error(LTag.DATABASE, "Error while invalidating extended bolus", it) + ret = Result.failure(workDataOf("Error" to it)) + } + .blockingGet() + .also { result -> + result.invalidated.forEach { + uel.log( + Action.CAREPORTAL_REMOVED, Sources.NSClient, + ValueWithUnit.Timestamp(it.timestamp), + ValueWithUnit.UnitPerHour(it.rate)) } } - // Insulin, carbs - rxBus.send(EventNsTreatment(REMOVE, json)) // old DB model - databaseHelper.deleteTempBasalById(nsId) - databaseHelper.deleteExtendedBolusById(nsId) databaseHelper.deleteProfileSwitchById(nsId) } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/nsclient/NSClientUpdateRemoveAckWorker.kt b/app/src/main/java/info/nightscout/androidaps/plugins/general/nsclient/NSClientUpdateRemoveAckWorker.kt new file mode 100644 index 0000000000..b061350786 --- /dev/null +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/nsclient/NSClientUpdateRemoveAckWorker.kt @@ -0,0 +1,126 @@ +package info.nightscout.androidaps.plugins.general.nsclient + +import android.content.Context +import androidx.work.Worker +import androidx.work.WorkerParameters +import androidx.work.workDataOf +import dagger.android.HasAndroidInjector +import info.nightscout.androidaps.database.AppRepository +import info.nightscout.androidaps.interfaces.DataSyncSelector +import info.nightscout.androidaps.interfaces.DataSyncSelector.* +import info.nightscout.androidaps.logging.AAPSLogger +import info.nightscout.androidaps.plugins.bus.RxBusWrapper +import info.nightscout.androidaps.plugins.general.nsclient.acks.NSUpdateAck +import info.nightscout.androidaps.plugins.general.nsclient.events.EventNSClientNewLog +import info.nightscout.androidaps.receivers.DataWorker +import info.nightscout.androidaps.utils.rx.AapsSchedulers +import javax.inject.Inject + +class NSClientUpdateRemoveAckWorker( + context: Context, + params: WorkerParameters +) : Worker(context, params) { + + @Inject lateinit var dataWorker: DataWorker + @Inject lateinit var aapsLogger: AAPSLogger + @Inject lateinit var repository: AppRepository + @Inject lateinit var rxBus: RxBusWrapper + @Inject lateinit var dataSyncSelector: DataSyncSelector + @Inject lateinit var aapsSchedulers: AapsSchedulers + + override fun doWork(): Result { + var ret = Result.success() + + val ack = dataWorker.pickupObject(inputData.getLong(DataWorker.STORE_KEY, -1)) as NSUpdateAck? + ?: return Result.failure(workDataOf("Error" to "missing input data")) + + // new room way + when (ack.originalObject) { + is PairTemporaryTarget -> { + val pair = ack.originalObject + dataSyncSelector.confirmLastTempTargetsIdIfGreater(pair.updateRecordId) + rxBus.send(EventNSClientNewLog("DBUPDATE/DBREMOVE", "Acked TemporaryTarget" + ack._id)) + // Send new if waiting + dataSyncSelector.processChangedTempTargetsCompat() + ret = Result.success(workDataOf("ProcessedData" to pair.toString())) + } + + is PairGlucoseValue -> { + val pair = ack.originalObject + dataSyncSelector.confirmLastGlucoseValueIdIfGreater(pair.updateRecordId) + rxBus.send(EventNSClientNewLog("DBUPDATE/DBREMOVE", "Acked GlucoseValue " + ack._id)) + // Send new if waiting + dataSyncSelector.processChangedGlucoseValuesCompat() + ret = Result.success(workDataOf("ProcessedData" to pair.toString())) + } + + is PairFood -> { + val pair = ack.originalObject + dataSyncSelector.confirmLastFoodIdIfGreater(pair.updateRecordId) + rxBus.send(EventNSClientNewLog("DBUPDATE/DBREMOVE", "Acked Food " + ack._id)) + // Send new if waiting + dataSyncSelector.processChangedFoodsCompat() + ret = Result.success(workDataOf("ProcessedData" to pair.toString())) + } + + is PairTherapyEvent -> { + val pair = ack.originalObject + dataSyncSelector.confirmLastTherapyEventIdIfGreater(pair.updateRecordId) + rxBus.send(EventNSClientNewLog("DBUPDATE/DBREMOVE", "Acked TherapyEvent " + ack._id)) + // Send new if waiting + dataSyncSelector.processChangedTherapyEventsCompat() + ret = Result.success(workDataOf("ProcessedData" to pair.toString())) + } + + is PairBolus -> { + val pair = ack.originalObject + dataSyncSelector.confirmLastBolusIdIfGreater(pair.updateRecordId) + rxBus.send(EventNSClientNewLog("DBUPDATE/DBREMOVE", "Acked Bolus " + ack._id)) + // Send new if waiting + dataSyncSelector.processChangedBolusesCompat() + ret = Result.success(workDataOf("ProcessedData" to pair.toString())) + } + + is PairCarbs -> { + val pair = ack.originalObject + dataSyncSelector.confirmLastCarbsIdIfGreater(pair.updateRecordId) + rxBus.send(EventNSClientNewLog("DBUPDATE/DBREMOVE", "Acked Carbs " + ack._id)) + // Send new if waiting + dataSyncSelector.processChangedCarbsCompat() + ret = Result.success(workDataOf("ProcessedData" to pair.toString())) + } + + is PairBolusCalculatorResult -> { + val pair = ack.originalObject + dataSyncSelector.confirmLastBolusCalculatorResultsIdIfGreater(pair.updateRecordId) + rxBus.send(EventNSClientNewLog("DBUPDATE/DBREMOVE", "Acked BolusCalculatorResult " + ack._id)) + // Send new if waiting + dataSyncSelector.processChangedBolusCalculatorResultsCompat() + ret = Result.success(workDataOf("ProcessedData" to pair.toString())) + } + + is PairTemporaryBasal -> { + val pair = ack.originalObject + dataSyncSelector.confirmLastTemporaryBasalIdIfGreater(pair.updateRecordId) + rxBus.send(EventNSClientNewLog("DBUPDATE/DBREMOVE", "Acked TemporaryBasal " + ack._id)) + // Send new if waiting + dataSyncSelector.processChangedTemporaryBasalsCompat() + ret = Result.success(workDataOf("ProcessedData" to pair.toString())) + } + + is PairExtendedBolus -> { + val pair = ack.originalObject + dataSyncSelector.confirmLastExtendedBolusIdIfGreater(pair.updateRecordId) + rxBus.send(EventNSClientNewLog("DBUPDATE/DBREMOVE", "Acked ExtendedBolus " + ack._id)) + // Send new if waiting + dataSyncSelector.processChangedExtendedBolusesCompat() + ret = Result.success(workDataOf("ProcessedData" to pair.toString())) + } + } + return ret + } + + init { + (context.applicationContext as HasAndroidInjector).androidInjector().inject(this) + } +} \ No newline at end of file diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/nsclient/acks/NSAddAck.java b/app/src/main/java/info/nightscout/androidaps/plugins/general/nsclient/acks/NSAddAck.java deleted file mode 100644 index dbd9151938..0000000000 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/nsclient/acks/NSAddAck.java +++ /dev/null @@ -1,62 +0,0 @@ -package info.nightscout.androidaps.plugins.general.nsclient.acks; - -import org.json.JSONArray; -import org.json.JSONObject; - -import info.nightscout.androidaps.events.Event; -import info.nightscout.androidaps.logging.AAPSLogger; -import info.nightscout.androidaps.logging.LTag; -import info.nightscout.androidaps.plugins.bus.RxBusWrapper; -import info.nightscout.androidaps.plugins.general.nsclient.events.EventNSClientRestart; -import io.socket.client.Ack; - -/** - * Created by mike on 29.12.2015. - */ -public class NSAddAck extends Event implements Ack { - private final AAPSLogger aapsLogger; - private final RxBusWrapper rxBus; - - public String _id = null; - public String nsClientID = null; - public JSONObject json = null; - - public NSAddAck(AAPSLogger aapsLogger, RxBusWrapper rxBus) { - this.aapsLogger = aapsLogger; - this.rxBus = rxBus; - } - - public void call(Object... args) { - // Regular response - try { - JSONArray responsearray = (JSONArray) (args[0]); - JSONObject response; - if (responsearray.length() > 0) { - response = responsearray.getJSONObject(0); - _id = response.getString("_id"); - json = response; - if (response.has("NSCLIENT_ID")) { - nsClientID = response.getString("NSCLIENT_ID"); - } - } - rxBus.send(this); - return; - } catch (Exception e) { - aapsLogger.error("Unhandled exception", e); - } - // Check for not authorized - try { - JSONObject response = (JSONObject) (args[0]); - if (response.has("result")) { - _id = null; - if (response.getString("result").contains("Not")) { - rxBus.send(new EventNSClientRestart()); - return; - } - aapsLogger.debug(LTag.NSCLIENT, "DBACCESS " + response.getString("result")); - } - } catch (Exception e) { - aapsLogger.error("Unhandled exception", e); - } - } -} \ No newline at end of file diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/nsclient/acks/NSAddAck.kt b/app/src/main/java/info/nightscout/androidaps/plugins/general/nsclient/acks/NSAddAck.kt new file mode 100644 index 0000000000..930defad05 --- /dev/null +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/nsclient/acks/NSAddAck.kt @@ -0,0 +1,54 @@ +package info.nightscout.androidaps.plugins.general.nsclient.acks + +import info.nightscout.androidaps.events.Event +import info.nightscout.androidaps.logging.AAPSLogger +import info.nightscout.androidaps.logging.LTag +import info.nightscout.androidaps.plugins.bus.RxBusWrapper +import info.nightscout.androidaps.plugins.general.nsclient.events.EventNSClientRestart +import io.socket.client.Ack +import org.json.JSONArray +import org.json.JSONObject + +class NSAddAck( + private val aapsLogger: AAPSLogger, + private val rxBus: RxBusWrapper, + val originalObject: Any? = null +) : Event(), Ack { + + var id: String? = null + @JvmField var nsClientID: String? = null + @JvmField var json: JSONObject? = null + override fun call(vararg args: Any) { + // Regular response + try { + val responseArray = args[0] as JSONArray + val response: JSONObject + if (responseArray.length() > 0) { + response = responseArray.getJSONObject(0) + id = response.getString("_id") + json = response + if (response.has("NSCLIENT_ID")) { + nsClientID = response.getString("NSCLIENT_ID") + } + } + rxBus.send(this) + return + } catch (e: Exception) { + aapsLogger.error("Unhandled exception", e) + } + // Check for not authorized + try { + val response = args[0] as JSONObject + if (response.has("result")) { + id = null + if (response.getString("result").contains("Not")) { + rxBus.send(EventNSClientRestart()) + return + } + aapsLogger.debug(LTag.NSCLIENT, "DBACCESS " + response.getString("result")) + } + } catch (e: Exception) { + aapsLogger.error("Unhandled exception", e) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/nsclient/acks/NSUpdateAck.java b/app/src/main/java/info/nightscout/androidaps/plugins/general/nsclient/acks/NSUpdateAck.java deleted file mode 100644 index 95a00279cf..0000000000 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/nsclient/acks/NSUpdateAck.java +++ /dev/null @@ -1,46 +0,0 @@ -package info.nightscout.androidaps.plugins.general.nsclient.acks; - -import org.json.JSONException; -import org.json.JSONObject; - -import info.nightscout.androidaps.events.Event; -import info.nightscout.androidaps.logging.AAPSLogger; -import info.nightscout.androidaps.logging.LTag; -import info.nightscout.androidaps.plugins.bus.RxBusWrapper; -import io.socket.client.Ack; - -/** - * Created by mike on 21.02.2016. - */ -public class NSUpdateAck extends Event implements Ack { - private final AAPSLogger aapsLogger; - private final RxBusWrapper rxBus; - - public boolean result = false; - public String _id; - public String action; - - public void call(Object... args) { - JSONObject response = (JSONObject) args[0]; - if (response.has("result")) - try { - if (response.getString("result").equals("success")) - result = true; - else if (response.getString("result").equals("Missing _id")) { - result = true; - aapsLogger.debug(LTag.NSCLIENT, "Internal error: Missing _id returned on dbUpdate ack"); - } - rxBus.send(this); - } catch (JSONException e) { - aapsLogger.error("Unhandled exception", e); - } - } - - public NSUpdateAck(String action, String _id, AAPSLogger aapsLogger, RxBusWrapper rxBus) { - super(); - this.action = action; - this._id = _id; - this.aapsLogger = aapsLogger; - this.rxBus = rxBus; - } -} diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/nsclient/acks/NSUpdateAck.kt b/app/src/main/java/info/nightscout/androidaps/plugins/general/nsclient/acks/NSUpdateAck.kt new file mode 100644 index 0000000000..5d91178f82 --- /dev/null +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/nsclient/acks/NSUpdateAck.kt @@ -0,0 +1,37 @@ +package info.nightscout.androidaps.plugins.general.nsclient.acks + +import info.nightscout.androidaps.events.Event +import info.nightscout.androidaps.logging.AAPSLogger +import info.nightscout.androidaps.logging.LTag +import info.nightscout.androidaps.plugins.bus.RxBusWrapper +import io.socket.client.Ack +import org.json.JSONException +import org.json.JSONObject + +/** + * Created by mike on 21.02.2016. + */ +class NSUpdateAck( + val action : String, + var _id: String, + private val aapsLogger: AAPSLogger, + private val rxBus: RxBusWrapper, + val originalObject: Any? = null +) : Event(), Ack { + + var result = false + override fun call(vararg args: Any) { + val response = args[0] as JSONObject + if (response.has("result")) try { + if (response.getString("result") == "success") { + result = true + } else if (response.getString("result") == "Missing _id") { + result = true + aapsLogger.debug(LTag.NSCLIENT, "Internal error: Missing _id returned on dbUpdate ack") + } + rxBus.send(this) + } catch (e: JSONException) { + aapsLogger.error("Unhandled exception", e) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/nsclient/data/NSDeviceStatus.kt b/app/src/main/java/info/nightscout/androidaps/plugins/general/nsclient/data/NSDeviceStatus.kt index 5657f1d48e..5faa6861c1 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/nsclient/data/NSDeviceStatus.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/nsclient/data/NSDeviceStatus.kt @@ -3,7 +3,7 @@ package info.nightscout.androidaps.plugins.general.nsclient.data import android.text.Spanned import dagger.android.HasAndroidInjector import info.nightscout.androidaps.R -import info.nightscout.androidaps.interfaces.ConfigInterface +import info.nightscout.androidaps.interfaces.Config import info.nightscout.androidaps.logging.AAPSLogger import info.nightscout.androidaps.logging.LTag import info.nightscout.androidaps.plugins.aps.loop.APSResult @@ -78,7 +78,7 @@ class NSDeviceStatus @Inject constructor( private val sp: SP, private val resourceHelper: ResourceHelper, private val nsSettingsStatus: NSSettingsStatus, - private val config: ConfigInterface, + private val config: Config, private val dateUtil: DateUtil, private val runningConfiguration: RunningConfiguration ) { @@ -164,12 +164,12 @@ class NSDeviceStatus @Inject constructor( // test warning level val level = when { - pumpData.clock + nsSettingsStatus.extendedPumpSettings("urgentClock") * 60 * 1000L < dateUtil._now() -> Levels.URGENT - pumpData.reservoir < nsSettingsStatus.extendedPumpSettings("urgentRes") -> Levels.URGENT + pumpData.clock + nsSettingsStatus.extendedPumpSettings("urgentClock") * 60 * 1000L < dateUtil.now() -> Levels.URGENT + pumpData.reservoir < nsSettingsStatus.extendedPumpSettings("urgentRes") -> Levels.URGENT pumpData.isPercent && pumpData.percent < nsSettingsStatus.extendedPumpSettings("urgentBattP") -> Levels.URGENT - !pumpData.isPercent && pumpData.voltage < nsSettingsStatus.extendedPumpSettings("urgentBattV") -> Levels.URGENT - pumpData.clock + nsSettingsStatus.extendedPumpSettings("warnClock") * 60 * 1000L < dateUtil._now() -> Levels.WARN - pumpData.reservoir < nsSettingsStatus.extendedPumpSettings("warnRes") -> Levels.WARN + !pumpData.isPercent && pumpData.voltage < nsSettingsStatus.extendedPumpSettings("urgentBattV") -> Levels.URGENT + pumpData.clock + nsSettingsStatus.extendedPumpSettings("warnClock") * 60 * 1000L < dateUtil.now() -> Levels.WARN + pumpData.reservoir < nsSettingsStatus.extendedPumpSettings("warnRes") -> Levels.WARN pumpData.isPercent && pumpData.percent < nsSettingsStatus.extendedPumpSettings("warnBattP") -> Levels.WARN !pumpData.isPercent && pumpData.voltage < nsSettingsStatus.extendedPumpSettings("warnBattV") -> Levels.WARN else -> Levels.INFO @@ -179,7 +179,7 @@ class NSDeviceStatus @Inject constructor( if (fields.contains("reservoir")) string.append(pumpData.reservoir.toInt()).append("U ") if (fields.contains("battery") && pumpData.isPercent) string.append(pumpData.percent).append("% ") if (fields.contains("battery") && !pumpData.isPercent) string.append(Round.roundTo(pumpData.voltage, 0.001)).append(" ") - if (fields.contains("clock")) string.append(DateUtil.minAgo(resourceHelper, pumpData.clock)).append(" ") + if (fields.contains("clock")) string.append(dateUtil.minAgo(resourceHelper, pumpData.clock)).append(" ") if (fields.contains("status")) string.append(pumpData.status).append(" ") if (fields.contains("device")) string.append(device).append(" ") string.append("") // color @@ -201,7 +201,7 @@ class NSDeviceStatus @Inject constructor( try { val data = this.data ?: return val pump = if (data.has("pump")) data.getJSONObject("pump") else JSONObject() - val clock = if (pump.has("clock")) DateUtil.fromISODateString(pump.getString("clock")).time else 0L + val clock = if (pump.has("clock")) dateUtil.fromISODateString(pump.getString("clock")) else 0L // check if this is new data if (clock == 0L || deviceStatusPumpData != null && clock < deviceStatusPumpData!!.clock) return @@ -247,13 +247,13 @@ class NSDeviceStatus @Inject constructor( val openAps = if (jsonObject.has("openaps")) jsonObject.getJSONObject("openaps") else JSONObject() val suggested = if (openAps.has("suggested")) openAps.getJSONObject("suggested") else JSONObject() val enacted = if (openAps.has("enacted")) openAps.getJSONObject("enacted") else JSONObject() - var clock = if (suggested.has("timestamp")) DateUtil.fromISODateString(suggested.getString("timestamp")).time else 0L + var clock = if (suggested.has("timestamp")) dateUtil.fromISODateString(suggested.getString("timestamp")) else 0L // check if this is new data if (clock != 0L && clock > deviceStatusOpenAPSData.clockSuggested) { deviceStatusOpenAPSData.suggested = suggested deviceStatusOpenAPSData.clockSuggested = clock } - clock = if (enacted.has("timestamp")) DateUtil.fromISODateString(enacted.getString("timestamp")).time else 0L + clock = if (enacted.has("timestamp")) dateUtil.fromISODateString(enacted.getString("timestamp")) else 0L // check if this is new data if (clock != 0L && clock > deviceStatusOpenAPSData.clockEnacted) { deviceStatusOpenAPSData.enacted = enacted @@ -273,12 +273,12 @@ class NSDeviceStatus @Inject constructor( // test warning level val level = when { - deviceStatusOpenAPSData.clockSuggested + T.mins(sp.getLong(R.string.key_nsalarm_urgent_staledatavalue, 31)).msecs() < dateUtil._now() -> Levels.URGENT - deviceStatusOpenAPSData.clockSuggested + T.mins(sp.getLong(R.string.key_nsalarm_staledatavalue, 16)).msecs() < dateUtil._now() -> Levels.WARN - else -> Levels.INFO + deviceStatusOpenAPSData.clockSuggested + T.mins(sp.getLong(R.string.key_nsalarm_urgent_staledatavalue, 31)).msecs() < dateUtil.now() -> Levels.URGENT + deviceStatusOpenAPSData.clockSuggested + T.mins(sp.getLong(R.string.key_nsalarm_staledatavalue, 16)).msecs() < dateUtil.now() -> Levels.WARN + else -> Levels.INFO } string.append("") - if (deviceStatusOpenAPSData.clockSuggested != 0L) string.append(DateUtil.minAgo(resourceHelper, deviceStatusOpenAPSData.clockSuggested)).append(" ") + if (deviceStatusOpenAPSData.clockSuggested != 0L) string.append(dateUtil.minAgo(resourceHelper, deviceStatusOpenAPSData.clockSuggested)).append(" ") string.append("") // color return fromHtml(string.toString()) } @@ -287,8 +287,8 @@ class NSDeviceStatus @Inject constructor( get() { val string = StringBuilder() try { - if (deviceStatusOpenAPSData.enacted != null && deviceStatusOpenAPSData.clockEnacted != deviceStatusOpenAPSData.clockSuggested) string.append("").append(DateUtil.minAgo(resourceHelper, deviceStatusOpenAPSData.clockEnacted)).append(" ").append(deviceStatusOpenAPSData.enacted!!.getString("reason")).append("
") - if (deviceStatusOpenAPSData.suggested != null) string.append("").append(DateUtil.minAgo(resourceHelper, deviceStatusOpenAPSData.clockSuggested)).append(" ").append(deviceStatusOpenAPSData.suggested!!.getString("reason")).append("
") + if (deviceStatusOpenAPSData.enacted != null && deviceStatusOpenAPSData.clockEnacted != deviceStatusOpenAPSData.clockSuggested) string.append("").append(dateUtil.minAgo(resourceHelper, deviceStatusOpenAPSData.clockEnacted)).append(" ").append(deviceStatusOpenAPSData.enacted!!.getString("reason")).append("
") + if (deviceStatusOpenAPSData.suggested != null) string.append("").append(dateUtil.minAgo(resourceHelper, deviceStatusOpenAPSData.clockSuggested)).append(" ").append(deviceStatusOpenAPSData.suggested!!.getString("reason")).append("
") return fromHtml(string.toString()) } catch (e: JSONException) { aapsLogger.error("Unhandled exception", e) @@ -307,7 +307,7 @@ class NSDeviceStatus @Inject constructor( val clock = when { jsonObject.has("mills") -> jsonObject.getLong("mills") - jsonObject.has("created_at") -> DateUtil.fromISODateString(jsonObject.getString("created_at")).time + jsonObject.has("created_at") -> dateUtil.fromISODateString(jsonObject.getString("created_at")) else -> 0L } val device = device diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/nsclient/data/NSSettingsStatus.kt b/app/src/main/java/info/nightscout/androidaps/plugins/general/nsclient/data/NSSettingsStatus.kt index e6aafce3c1..7efeb7c466 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/nsclient/data/NSSettingsStatus.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/nsclient/data/NSSettingsStatus.kt @@ -1,8 +1,9 @@ package info.nightscout.androidaps.plugins.general.nsclient.data import android.content.Context -import info.nightscout.androidaps.Config +import info.nightscout.androidaps.interfaces.Config import info.nightscout.androidaps.R +import info.nightscout.androidaps.database.entities.UserEntry import info.nightscout.androidaps.database.entities.UserEntry.Action import info.nightscout.androidaps.logging.AAPSLogger import info.nightscout.androidaps.logging.LTag @@ -246,7 +247,7 @@ class NSSettingsStatus @Inject constructor( getExtendedWarnValue("sage", "urgent")?.let { sp.putDouble(R.string.key_statuslights_sage_critical, it) } getExtendedWarnValue("bage", "warn")?.let { sp.putDouble(R.string.key_statuslights_bage_warning, it) } getExtendedWarnValue("bage", "urgent")?.let { sp.putDouble(R.string.key_statuslights_bage_critical, it) } - uel.log(Action.NS_SETTINGS_COPIED) + uel.log(Action.NS_SETTINGS_COPIED, UserEntry.Sources.NSClient) } if (context != null) OKDialog.showConfirmation(context, resourceHelper.gs(R.string.statuslights), resourceHelper.gs(R.string.copyexistingvalues), action) 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 809bbae38b..b63e31feec 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 @@ -10,7 +10,6 @@ import android.os.IBinder; import android.os.PowerManager; import android.os.SystemClock; -import androidx.localbroadcastmanager.content.LocalBroadcastManager; import androidx.work.OneTimeWorkRequest; import com.google.common.base.Charsets; @@ -30,12 +29,14 @@ import javax.inject.Inject; import dagger.android.DaggerService; import dagger.android.HasAndroidInjector; -import info.nightscout.androidaps.Config; +import info.nightscout.androidaps.interfaces.Config; import info.nightscout.androidaps.R; +import info.nightscout.androidaps.database.AppRepository; import info.nightscout.androidaps.db.DbRequest; import info.nightscout.androidaps.events.EventAppExit; import info.nightscout.androidaps.events.EventConfigBuilderChange; import info.nightscout.androidaps.events.EventPreferenceChange; +import info.nightscout.androidaps.interfaces.DataSyncSelector; import info.nightscout.androidaps.interfaces.DatabaseHelperInterface; import info.nightscout.androidaps.interfaces.PluginType; import info.nightscout.androidaps.interfaces.UploadQueueInterface; @@ -43,10 +44,12 @@ import info.nightscout.androidaps.logging.AAPSLogger; import info.nightscout.androidaps.logging.LTag; import info.nightscout.androidaps.plugins.bus.RxBusWrapper; import info.nightscout.androidaps.plugins.general.food.FoodPlugin; +import info.nightscout.androidaps.plugins.general.nsclient.NSClientAddAckWorker; import info.nightscout.androidaps.plugins.general.nsclient.NSClientAddUpdateWorker; import info.nightscout.androidaps.plugins.general.nsclient.NSClientMbgWorker; import info.nightscout.androidaps.plugins.general.nsclient.NSClientPlugin; import info.nightscout.androidaps.plugins.general.nsclient.NSClientRemoveWorker; +import info.nightscout.androidaps.plugins.general.nsclient.NSClientUpdateRemoveAckWorker; import info.nightscout.androidaps.plugins.general.nsclient.acks.NSAddAck; import info.nightscout.androidaps.plugins.general.nsclient.acks.NSAuthAck; import info.nightscout.androidaps.plugins.general.nsclient.acks.NSUpdateAck; @@ -96,6 +99,8 @@ public class NSClientService extends DaggerService { @Inject DateUtil dateUtil; @Inject UploadQueueInterface uploadQueue; @Inject DataWorker dataWorker; + @Inject DataSyncSelector dataSyncSelector; + @Inject AppRepository repository; private final CompositeDisposable disposable = new CompositeDisposable(); @@ -118,6 +123,7 @@ public class NSClientService extends DaggerService { private final Integer nsHours = 48; public long lastResendTime = 0; + public long lastAckTime = 0; public long latestDateInReceivedData = 0; @@ -126,7 +132,7 @@ public class NSClientService extends DaggerService { private final ArrayList reconnections = new ArrayList<>(); private final int WATCHDOG_INTERVAL_MINUTES = 2; private final int WATCHDOG_RECONNECT_IN = 15; - private final int WATCHDOG_MAXCONNECTIONS = 5; + private final int WATCHDOG_MAX_CONNECTIONS = 5; public NSClientService() { super(); @@ -213,6 +219,14 @@ public class NSClientService extends DaggerService { } public void processAddAck(NSAddAck ack) { + lastAckTime = dateUtil.now(); + // new room way + dataWorker.enqueue( + new OneTimeWorkRequest.Builder(NSClientAddAckWorker.class) + .setInputData(dataWorker.storeInputData(ack, null)) + .build()); + + // old way if (ack.nsClientID != null) { uploadQueue.removeByNsClientIdIfExists(ack.json); rxBus.send(new EventNSClientNewLog("DBADD", "Acked " + ack.nsClientID)); @@ -222,9 +236,17 @@ public class NSClientService extends DaggerService { } public void processUpdateAck(NSUpdateAck ack) { - if (ack.result) { - uploadQueue.removeByMongoId(ack.action, ack._id); - rxBus.send(new EventNSClientNewLog("DBUPDATE/DBREMOVE", "Acked " + ack._id)); + lastAckTime = dateUtil.now(); + // new room way + dataWorker.enqueue( + new OneTimeWorkRequest.Builder(NSClientUpdateRemoveAckWorker.class) + .setInputData(dataWorker.storeInputData(ack, null)) + .build()); + + // old way + if (ack.getResult()) { + uploadQueue.removeByMongoId(ack.getAction(), ack.get_id()); + rxBus.send(new EventNSClientNewLog("DBUPDATE/DBREMOVE", "Acked " + ack.get_id())); } else { rxBus.send(new EventNSClientNewLog("ERROR", "DBUPDATE/DBREMOVE Unknown response")); } @@ -258,6 +280,7 @@ public class NSClientService extends DaggerService { public NSClientService getServiceInstance() { return NSClientService.this; } + } @Override @@ -337,7 +360,7 @@ public class NSClientService extends DaggerService { void watchdog() { synchronized (reconnections) { - long now = DateUtil.now(); + long now = dateUtil.now(); reconnections.add(now); for (int i = 0; i < reconnections.size(); i++) { Long r = reconnections.get(i); @@ -345,8 +368,8 @@ public class NSClientService extends DaggerService { reconnections.remove(r); } } - rxBus.send(new EventNSClientNewLog("WATCHDOG", "connections in last " + WATCHDOG_INTERVAL_MINUTES + " mins: " + reconnections.size() + "/" + WATCHDOG_MAXCONNECTIONS)); - if (reconnections.size() >= WATCHDOG_MAXCONNECTIONS) { + rxBus.send(new EventNSClientNewLog("WATCHDOG", "connections in last " + WATCHDOG_INTERVAL_MINUTES + " mins: " + reconnections.size() + "/" + WATCHDOG_MAX_CONNECTIONS)); + if (reconnections.size() >= WATCHDOG_MAX_CONNECTIONS) { Notification n = new Notification(Notification.NS_MALFUNCTION, resourceHelper.gs(R.string.nsmalfunction), Notification.URGENT); rxBus.send(new EventNewNotification(n)); rxBus.send(new EventNSClientNewLog("WATCHDOG", "pausing for " + WATCHDOG_RECONNECT_IN + " mins")); @@ -579,7 +602,7 @@ public class NSClientService extends DaggerService { if (action == null) addedOrUpdatedTreatments.put(jsonTreatment); else if (action.equals("update")) addedOrUpdatedTreatments.put(jsonTreatment); - else if (action.equals("remove") && mills > dateUtil._now() - T.days(1).msecs()) // handle 1 day old deletions only + else if (action.equals("remove") && mills > dateUtil.now() - T.days(1).msecs()) // handle 1 day old deletions only removedTreatments.put(jsonTreatment); } if (removedTreatments.length() > 0) { @@ -698,15 +721,15 @@ public class NSClientService extends DaggerService { } } - public void dbUpdateUnset(DbRequest dbr, NSUpdateAck ack) { + public void dbUpdate(String collection, String _id, JSONObject data, Object originalObject) { try { if (!isConnected || !hasWriteAuth) return; JSONObject message = new JSONObject(); - message.put("collection", dbr.collection); - message.put("_id", dbr._id); - message.put("data", new JSONObject(dbr.data)); - mSocket.emit("dbUpdateUnset", message, ack); - rxBus.send(new EventNSClientNewLog("DBUPDATEUNSET " + dbr.collection, "Sent " + dbr._id)); + message.put("collection", collection); + message.put("_id", _id); + message.put("data", data); + mSocket.emit("dbUpdate", message, new NSUpdateAck("dbUpdate", _id, aapsLogger, rxBus, originalObject)); + rxBus.send(new EventNSClientNewLog("DBUPDATE " + collection, "Sent " + originalObject.getClass().getSimpleName() + " " + _id)); } catch (JSONException e) { aapsLogger.error("Unhandled exception", e); } @@ -725,6 +748,19 @@ public class NSClientService extends DaggerService { } } + public void dbRemove(String collection, String _id, Object originalObject) { + try { + if (!isConnected || !hasWriteAuth) return; + JSONObject message = new JSONObject(); + message.put("collection", collection); + message.put("_id", _id); + mSocket.emit("dbRemove", message, new NSUpdateAck("dbRemove", _id, aapsLogger, rxBus, originalObject)); + rxBus.send(new EventNSClientNewLog("DBREMOVE " + collection, "Sent " + originalObject.getClass().getSimpleName() + " " + _id)); + } catch (JSONException e) { + aapsLogger.error("Unhandled exception", e); + } + } + public void dbAdd(DbRequest dbr, NSAddAck ack) { try { if (!isConnected || !hasWriteAuth) return; @@ -738,6 +774,19 @@ public class NSClientService extends DaggerService { } } + public void dbAdd(String collection, JSONObject data, Object originalObject) { + try { + if (!isConnected || !hasWriteAuth) return; + JSONObject message = new JSONObject(); + message.put("collection", collection); + message.put("data", data); + mSocket.emit("dbAdd", message, new NSAddAck(aapsLogger, rxBus, originalObject)); + rxBus.send(new EventNSClientNewLog("DBADD " + collection, "Sent " + originalObject.getClass().getSimpleName() + " " + data)); + } catch (JSONException e) { + aapsLogger.error("Unhandled exception", e); + } + } + public void sendAlarmAck(AlarmAck alarmAck) { if (!isConnected || !hasWriteAuth) return; mSocket.emit("ack", alarmAck.level, alarmAck.group, alarmAck.silenceTime); @@ -745,22 +794,38 @@ public class NSClientService extends DaggerService { } public void resend(final String reason) { - if (uploadQueue.size() == 0) - return; - if (!isConnected || !hasWriteAuth) return; handler.post(() -> { if (mSocket == null || !mSocket.connected()) return; + rxBus.send(new EventNSClientNewLog("QUEUE", "Resend started: " + reason)); + + if (lastAckTime > System.currentTimeMillis() - 10 * 1000L) { + aapsLogger.debug(LTag.NSCLIENT, "Skipping resend by lastAckTime: " + ((System.currentTimeMillis() - lastAckTime) / 1000L) + " sec"); + return; + } + + dataSyncSelector.processChangedBolusesCompat(); + dataSyncSelector.processChangedCarbsCompat(); + dataSyncSelector.processChangedBolusCalculatorResultsCompat(); + dataSyncSelector.processChangedTemporaryBasalsCompat(); + dataSyncSelector.processChangedExtendedBolusesCompat(); + dataSyncSelector.processChangedGlucoseValuesCompat(); + dataSyncSelector.processChangedTempTargetsCompat(); + dataSyncSelector.processChangedFoodsCompat(); + dataSyncSelector.processChangedTherapyEventsCompat(); + dataSyncSelector.processChangedDeviceStatusesCompat(); + + if (uploadQueue.size() == 0) + return; + if (lastResendTime > System.currentTimeMillis() - 10 * 1000L) { aapsLogger.debug(LTag.NSCLIENT, "Skipping resend by lastResendTime: " + ((System.currentTimeMillis() - lastResendTime) / 1000L) + " sec"); return; } lastResendTime = System.currentTimeMillis(); - rxBus.send(new EventNSClientNewLog("QUEUE", "Resend started: " + reason)); - CloseableIterator iterator; int maxcount = 30; try { @@ -769,17 +834,14 @@ public class NSClientService extends DaggerService { while (iterator.hasNext() && maxcount > 0) { DbRequest dbr = iterator.next(); if (dbr.action.equals("dbAdd")) { - NSAddAck addAck = new NSAddAck(aapsLogger, rxBus); + NSAddAck addAck = new NSAddAck(aapsLogger, rxBus, null); dbAdd(dbr, addAck); } else if (dbr.action.equals("dbRemove")) { - NSUpdateAck removeAck = new NSUpdateAck(dbr.action, dbr._id, aapsLogger, rxBus); + NSUpdateAck removeAck = new NSUpdateAck("dbRemove", dbr._id, aapsLogger, rxBus, null); dbRemove(dbr, removeAck); } else if (dbr.action.equals("dbUpdate")) { - NSUpdateAck updateAck = new NSUpdateAck(dbr.action, dbr._id, aapsLogger, rxBus); + NSUpdateAck updateAck = new NSUpdateAck("dbUpdate", dbr._id, aapsLogger, rxBus, null); dbUpdate(dbr, updateAck); - } else if (dbr.action.equals("dbUpdateUnset")) { - NSUpdateAck updateUnsetAck = new NSUpdateAck(dbr.action, dbr._id, aapsLogger, rxBus); - dbUpdateUnset(dbr, updateUnsetAck); } maxcount--; } @@ -838,32 +900,6 @@ public class NSClientService extends DaggerService { } } - public void handleNewTreatment(JSONArray treatments, boolean isDelta) { - List splitted = splitArray(treatments); - for (JSONArray part : splitted) { - Bundle bundle = new Bundle(); - bundle.putString("treatments", part.toString()); - bundle.putBoolean("delta", isDelta); - Intent intent = new Intent(Intents.ACTION_NEW_TREATMENT); - intent.putExtras(bundle); - intent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES); - LocalBroadcastManager.getInstance(this).sendBroadcast(intent); - } - - if (sp.getBoolean(R.string.key_nsclient_localbroadcasts, false)) { - splitted = splitArray(treatments); - for (JSONArray part : splitted) { - Bundle bundle = new Bundle(); - bundle.putString("treatments", part.toString()); - bundle.putBoolean("delta", isDelta); - Intent intent = new Intent(Intents.ACTION_NEW_TREATMENT); - intent.putExtras(bundle); - intent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES); - this.getApplicationContext().sendBroadcast(intent); - } - } - } - public List splitArray(JSONArray array) { List ret = new ArrayList<>(); try { diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/openhumans/OpenHumansUploader.kt b/app/src/main/java/info/nightscout/androidaps/plugins/general/openhumans/OpenHumansUploader.kt index b1de3bab2e..92e008ca91 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/openhumans/OpenHumansUploader.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/openhumans/OpenHumansUploader.kt @@ -28,8 +28,7 @@ import info.nightscout.androidaps.interfaces.PluginType import info.nightscout.androidaps.logging.AAPSLogger import info.nightscout.androidaps.logging.LTag import info.nightscout.androidaps.plugins.bus.RxBusWrapper -import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin -import info.nightscout.androidaps.utils.extensions.toConstant +import info.nightscout.androidaps.extensions.toConstant import info.nightscout.androidaps.utils.resources.ResourceHelper import info.nightscout.androidaps.utils.rx.AapsSchedulers import info.nightscout.androidaps.utils.sharedPreferences.SP @@ -61,7 +60,6 @@ class OpenHumansUploader @Inject constructor( private val sp: SP, private val rxBus: RxBusWrapper, private val context: Context, - private val treatmentsPlugin: TreatmentsPlugin, private val databaseHelper: DatabaseHelperInterface, val repository: AppRepository ) : PluginBase( @@ -356,29 +354,29 @@ class OpenHumansUploader @Inject constructor( if (currentProgress % 1000L == 0L) showOngoingNotification(maxProgress, currentProgress) } copyDisposable = Completable.fromCallable { databaseHelper.clearOpenHumansQueue() } - .andThen(Single.defer { Single.just(databaseHelper.getCountOfAllRows() + treatmentsPlugin.service.count()) }) - .doOnSuccess { maxProgress = it } - .flatMapObservable { Observable.defer { Observable.fromIterable(treatmentsPlugin.service.getTreatmentData()) } } - .map { enqueueTreatment(it); increaseCounter() } - .ignoreElements() +// .andThen(Single.defer { Single.just(databaseHelper.getCountOfAllRows() + treatmentsPlugin.service.count()) }) +// .doOnSuccess { maxProgress = it } +// .flatMapObservable { Observable.defer { Observable.fromIterable(treatmentsPlugin.service.getTreatmentData()) } } +// .map { enqueueTreatment(it); increaseCounter() } +// .ignoreElements() .andThen(Observable.defer { Observable.fromIterable(repository.compatGetBgReadingsDataFromTime(0, true).blockingGet()) }) .map { enqueueBGReading(it); increaseCounter() } .ignoreElements() .andThen(Observable.defer { Observable.fromIterable(repository.compatGetTherapyEventDataFromTime(0, true).blockingGet()) }) .map { enqueueTherapyEvent(it); increaseCounter() } .ignoreElements() - .andThen(Observable.defer { Observable.fromIterable(databaseHelper.getAllExtendedBoluses()) }) - .map { enqueueExtendedBolus(it); increaseCounter() } - .ignoreElements() +// .andThen(Observable.defer { Observable.fromIterable(databaseHelper.getAllExtendedBoluses()) }) +// .map { enqueueExtendedBolus(it); increaseCounter() } +// .ignoreElements() .andThen(Observable.defer { Observable.fromIterable(databaseHelper.getAllProfileSwitches()) }) .map { enqueueProfileSwitch(it); increaseCounter() } .ignoreElements() .andThen(Observable.defer { Observable.fromIterable(databaseHelper.getAllTDDs()) }) .map { enqueueTotalDailyDose(it); increaseCounter() } .ignoreElements() - .andThen(Observable.defer { Observable.fromIterable(databaseHelper.getAllTemporaryBasals()) }) - .map { enqueueTemporaryBasal(it); increaseCounter() } - .ignoreElements() + // .andThen(Observable.defer { Observable.fromIterable(databaseHelper.getAllTemporaryBasals()) }) + // .map { enqueueTemporaryBasal(it); increaseCounter() } + // .ignoreElements() .andThen(Observable.defer { Observable.fromIterable(repository.compatGetTemporaryTargetData().blockingGet()) }) .map { enqueueTempTarget(it); increaseCounter() } .ignoreElements() diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/OverviewFragment.kt b/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/OverviewFragment.kt index c7fd5f2a1a..cde772b458 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/OverviewFragment.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/OverviewFragment.kt @@ -24,33 +24,34 @@ import androidx.recyclerview.widget.LinearLayoutManager import com.jjoe64.graphview.GraphView import dagger.android.HasAndroidInjector import dagger.android.support.DaggerFragment -import info.nightscout.androidaps.Config +import info.nightscout.androidaps.interfaces.Config import info.nightscout.androidaps.Constants import info.nightscout.androidaps.R import info.nightscout.androidaps.data.Profile import info.nightscout.androidaps.database.AppRepository import info.nightscout.androidaps.database.ValueWrapper import info.nightscout.androidaps.database.entities.TemporaryTarget -import info.nightscout.androidaps.database.entities.UserEntry.* +import info.nightscout.androidaps.database.entities.UserEntry.Action +import info.nightscout.androidaps.database.entities.UserEntry.Sources import info.nightscout.androidaps.database.interfaces.end import info.nightscout.androidaps.databinding.OverviewFragmentBinding import info.nightscout.androidaps.dialogs.* import info.nightscout.androidaps.events.* +import info.nightscout.androidaps.extensions.* import info.nightscout.androidaps.interfaces.* import info.nightscout.androidaps.logging.AAPSLogger import info.nightscout.androidaps.logging.UserEntryLogger import info.nightscout.androidaps.plugins.aps.loop.LoopPlugin import info.nightscout.androidaps.plugins.aps.loop.events.EventNewOpenLoopNotification import info.nightscout.androidaps.plugins.bus.RxBusWrapper -import info.nightscout.androidaps.plugins.configBuilder.ConfigBuilderPlugin import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker import info.nightscout.androidaps.plugins.general.nsclient.data.NSDeviceStatus import info.nightscout.androidaps.plugins.general.overview.activities.QuickWizardListActivity import info.nightscout.androidaps.plugins.general.overview.graphData.GraphData +import info.nightscout.androidaps.plugins.general.overview.graphExtensions.GlucoseValueDataPoint import info.nightscout.androidaps.plugins.general.overview.notifications.NotificationStore import info.nightscout.androidaps.plugins.general.wear.events.EventWearInitiateAction import info.nightscout.androidaps.plugins.iob.iobCobCalculator.GlucoseStatusProvider -import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorPlugin import info.nightscout.androidaps.plugins.iob.iobCobCalculator.events.EventIobCalculationProgress import info.nightscout.androidaps.plugins.pump.common.defs.PumpType import info.nightscout.androidaps.plugins.source.DexcomPlugin @@ -61,10 +62,7 @@ import info.nightscout.androidaps.skins.SkinProvider import info.nightscout.androidaps.utils.* import info.nightscout.androidaps.utils.alertDialogs.OKDialog import info.nightscout.androidaps.utils.buildHelper.BuildHelper -import info.nightscout.androidaps.utils.extensions.directionToIcon -import info.nightscout.androidaps.utils.extensions.toVisibility -import info.nightscout.androidaps.utils.extensions.valueToUnits -import info.nightscout.androidaps.utils.extensions.valueToUnitsString +import info.nightscout.androidaps.utils.extensions.* import info.nightscout.androidaps.utils.protection.ProtectionCheck import info.nightscout.androidaps.utils.resources.ResourceHelper import info.nightscout.androidaps.utils.rx.AapsSchedulers @@ -97,10 +95,9 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList @Inject lateinit var statusLightHandler: StatusLightHandler @Inject lateinit var nsDeviceStatus: NSDeviceStatus @Inject lateinit var loopPlugin: LoopPlugin - @Inject lateinit var configBuilderPlugin: ConfigBuilderPlugin - @Inject lateinit var activePlugin: ActivePluginProvider + @Inject lateinit var activePlugin: ActivePlugin @Inject lateinit var treatmentsPlugin: TreatmentsPlugin - @Inject lateinit var iobCobCalculatorPlugin: IobCobCalculatorPlugin + @Inject lateinit var iobCobCalculator: IobCobCalculator @Inject lateinit var dexcomPlugin: DexcomPlugin @Inject lateinit var dexcomMediator: DexcomPlugin.DexcomMediator @Inject lateinit var xdripPlugin: XdripPlugin @@ -310,7 +307,7 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList R.id.active_profile -> { ProfileViewerDialog().also { pvd -> pvd.arguments = Bundle().also { - it.putLong("time", DateUtil.now()) + it.putLong("time", dateUtil.now()) it.putInt("mode", ProfileViewerDialog.Mode.RUNNING_PROFILE.ordinal) } }.show(childFragmentManager, "ProfileViewDialog") @@ -351,7 +348,7 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList protectionCheck.queryProtection(activity, ProtectionCheck.Protection.BOLUS, UIRunnable { OKDialog.showConfirmation(activity, resourceHelper.gs(R.string.tempbasal_label), lastRun.constraintsProcessed?.toSpanned() ?: "".toSpanned(), { - uel.log(Action.ACCEPTS_TEMP_BASAL) + uel.log(Action.ACCEPTS_TEMP_BASAL, Sources.Overview) binding.buttonsLayout.acceptTempButton.visibility = View.GONE (context?.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager).cancel(Constants.notificationID) rxBus.send(EventWearInitiateAction("cancelChangeRequest")) @@ -412,7 +409,7 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList } private fun onClickQuickWizard() { - val actualBg = iobCobCalculatorPlugin.actualBg() + val actualBg = iobCobCalculator.ads.actualBg() val profile = profileFunction.getProfile() val profileName = profileFunction.getProfileName() val pump = activePlugin.activePump @@ -447,11 +444,11 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList @SuppressLint("SetTextI18n") private fun processButtonsVisibility() { - val lastBG = iobCobCalculatorPlugin.lastBg() + val lastBG = iobCobCalculator.ads.lastBg() val pump = activePlugin.activePump val profile = profileFunction.getProfile() val profileName = profileFunction.getProfileName() - val actualBG = iobCobCalculatorPlugin.actualBg() + val actualBG = iobCobCalculator.ads.actualBg() // QuickWizard button val quickWizardEntry = quickWizard.getActive() @@ -550,7 +547,7 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList if (_binding == null) return aapsLogger.debug("UpdateGUI from $from") - binding.infoLayout.time.text = dateUtil.timeString(Date()) + binding.infoLayout.time.text = dateUtil.timeString(dateUtil.now()) if (!profileFunction.isProfileValid("Overview")) { binding.loopPumpStatusLayout.pumpStatus.setText(R.string.noprofileset) @@ -563,8 +560,8 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList binding.loopPumpStatusLayout.loopLayout.visibility = View.VISIBLE val profile = profileFunction.getProfile() ?: return - val actualBG = iobCobCalculatorPlugin.actualBg() - val lastBG = iobCobCalculatorPlugin.lastBg() + val actualBG = iobCobCalculator.ads.actualBg() + val lastBG = iobCobCalculator.ads.lastBg() val pump = activePlugin.activePump val units = profileFunction.getUnits() val lowLine = defaultValueHelper.determineLowLine() @@ -613,8 +610,8 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList } else flag and Paint.STRIKE_THRU_TEXT_FLAG.inv() overview_bg.paintFlags = flag } - binding.infoLayout.timeAgo.text = DateUtil.minAgo(resourceHelper, lastBG.timestamp) - binding.infoLayout.timeAgoShort.text = "(" + DateUtil.minAgoShort(lastBG.timestamp) + ")" + binding.infoLayout.timeAgo.text = dateUtil.minAgo(resourceHelper, lastBG.timestamp) + binding.infoLayout.timeAgoShort.text = "(" + dateUtil.minAgoShort(lastBG.timestamp) + ")" } val closedLoopEnabled = constraintChecker.isClosedLoopAllowed() @@ -626,24 +623,24 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList when { loopPlugin.isEnabled() && loopPlugin.isSuperBolus -> { binding.infoLayout.apsMode.setImageResource(R.drawable.ic_loop_superbolus) - binding.infoLayout.apsModeText.text = DateUtil.age(loopPlugin.minutesToEndOfSuspend() * 60000L, true, resourceHelper) + binding.infoLayout.apsModeText.text = dateUtil.age(loopPlugin.minutesToEndOfSuspend() * 60000L, true, resourceHelper) binding.infoLayout.apsModeText.visibility = View.VISIBLE } loopPlugin.isDisconnected -> { binding.infoLayout.apsMode.setImageResource(R.drawable.ic_loop_disconnected) - binding.infoLayout.apsModeText.text = DateUtil.age(loopPlugin.minutesToEndOfSuspend() * 60000L, true, resourceHelper) + binding.infoLayout.apsModeText.text = dateUtil.age(loopPlugin.minutesToEndOfSuspend() * 60000L, true, resourceHelper) binding.infoLayout.apsModeText.visibility = View.VISIBLE } loopPlugin.isEnabled() && loopPlugin.isSuspended -> { binding.infoLayout.apsMode.setImageResource(R.drawable.ic_loop_paused) - binding.infoLayout.apsModeText.text = DateUtil.age(loopPlugin.minutesToEndOfSuspend() * 60000L, true, resourceHelper) + binding.infoLayout.apsModeText.text = dateUtil.age(loopPlugin.minutesToEndOfSuspend() * 60000L, true, resourceHelper) binding.infoLayout.apsModeText.visibility = View.VISIBLE } pump.isSuspended() -> { - binding.infoLayout.apsMode.setImageResource(if (pump.model() == PumpType.Omnipod_Eros || pump.model() == PumpType.Omnipod_Dash) { + binding.infoLayout.apsMode.setImageResource(if (pump.model() == PumpType.OMNIPOD_EROS || pump.model() == PumpType.OMNIPOD_DASH) { // For Omnipod, indicate the pump as disconnected when it's suspended. // The only way to 'reconnect' it, is through the Omnipod tab R.drawable.ic_loop_disconnected @@ -681,11 +678,11 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList } // temp target - val tempTarget: ValueWrapper = repository.getTemporaryTargetActiveAt(dateUtil._now()).blockingGet() + val tempTarget: ValueWrapper = repository.getTemporaryTargetActiveAt(dateUtil.now()).blockingGet() if (tempTarget is ValueWrapper.Existing) { binding.loopPumpStatusLayout.tempTarget.setTextColor(resourceHelper.gc(R.color.ribbonTextWarning)) binding.loopPumpStatusLayout.tempTarget.setBackgroundColor(resourceHelper.gc(R.color.ribbonWarning)) - binding.loopPumpStatusLayout.tempTarget.text = Profile.toTargetRangeString(tempTarget.value.lowTarget, tempTarget.value.highTarget, Constants.MGDL, units) + " " + DateUtil.untilString(tempTarget.value.end, resourceHelper) + binding.loopPumpStatusLayout.tempTarget.text = Profile.toTargetRangeString(tempTarget.value.lowTarget, tempTarget.value.highTarget, Constants.MGDL, units) + " " + dateUtil.untilString(tempTarget.value.end, resourceHelper) } else { // If the target is not the same as set in the profile then oref has overridden it val targetUsed = lastRun?.constraintsProcessed?.targetBG ?: 0.0 @@ -703,13 +700,13 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList } // Basal, TBR - val activeTemp = treatmentsPlugin.getTempBasalFromHistory(System.currentTimeMillis()) - binding.infoLayout.baseBasal.text = activeTemp?.let { "T:" + activeTemp.toStringVeryShort() } + val activeTemp = iobCobCalculator.getTempBasalIncludingConvertedExtended(System.currentTimeMillis()) + binding.infoLayout.baseBasal.text = activeTemp?.let { "T:" + activeTemp.toStringShort() } ?: resourceHelper.gs(R.string.pump_basebasalrate, profile.basal) binding.infoLayout.basalLayout.setOnClickListener { var fullText = "${resourceHelper.gs(R.string.basebasalrate_label)}: ${resourceHelper.gs(R.string.pump_basebasalrate, profile.basal)}" if (activeTemp != null) - fullText += "\n" + resourceHelper.gs(R.string.tempbasal_label) + ": " + activeTemp.toStringFull() + fullText += "\n" + resourceHelper.gs(R.string.tempbasal_label) + ": " + activeTemp.toStringFull(profile, dateUtil) activity?.let { OKDialog.show(it, resourceHelper.gs(R.string.basal), fullText) } @@ -718,23 +715,23 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList ?: resourceHelper.gc(R.color.defaulttextcolor)) binding.infoLayout.baseBasalIcon.setImageResource(R.drawable.ic_cp_basal_no_tbr) - val percentRate = activeTemp?.tempBasalConvertedToPercent(System.currentTimeMillis(), profile) + val percentRate = activeTemp?.convertedToPercent(System.currentTimeMillis(), profile) ?: 100 if (percentRate > 100) binding.infoLayout.baseBasalIcon.setImageResource(R.drawable.ic_cp_basal_tbr_high) if (percentRate < 100) binding.infoLayout.baseBasalIcon.setImageResource(R.drawable.ic_cp_basal_tbr_low) // Extended bolus - val extendedBolus = treatmentsPlugin.getExtendedBolusFromHistory(System.currentTimeMillis()) + val extendedBolus = repository.getExtendedBolusActiveAt(dateUtil.now()).blockingGet() binding.infoLayout.extendedBolus.text = - if (extendedBolus != null && !pump.isFakingTempsByExtendedBoluses) - resourceHelper.gs(R.string.pump_basebasalrate, extendedBolus.absoluteRate()) + if (extendedBolus is ValueWrapper.Existing && !pump.isFakingTempsByExtendedBoluses) + resourceHelper.gs(R.string.pump_basebasalrate, extendedBolus.value.rate) else "" binding.infoLayout.extendedBolus.setOnClickListener { - if (extendedBolus != null) activity?.let { - OKDialog.show(it, resourceHelper.gs(R.string.extended_bolus), extendedBolus.toString()) + if (extendedBolus is ValueWrapper.Existing) activity?.let { + OKDialog.show(it, resourceHelper.gs(R.string.extended_bolus), extendedBolus.value.toStringFull(dateUtil)) } } - binding.infoLayout.extendedLayout.visibility = (extendedBolus != null && !pump.isFakingTempsByExtendedBoluses).toVisibility() + binding.infoLayout.extendedLayout.visibility = (extendedBolus is ValueWrapper.Existing && !pump.isFakingTempsByExtendedBoluses).toVisibility() // Active profile binding.loopPumpStatusLayout.activeProfile.text = profileFunction.getProfileNameWithDuration() @@ -749,10 +746,8 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList processButtonsVisibility() // iob - treatmentsPlugin.updateTotalIOBTreatments() - treatmentsPlugin.updateTotalIOBTempBasals() - val bolusIob = treatmentsPlugin.lastCalculationTreatments.round() - val basalIob = treatmentsPlugin.lastCalculationTempBasals.round() + val bolusIob = iobCobCalculator.calculateIobFromBolus().round() + val basalIob = iobCobCalculator.calculateIobFromTempBasalsIncludingConvertedExtended().round() binding.infoLayout.iob.text = resourceHelper.gs(R.string.formatinsulinunits, bolusIob.iob + basalIob.basaliob) binding.infoLayout.iobLayout.setOnClickListener { @@ -771,7 +766,7 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList // cob var cobText: String = resourceHelper.gs(R.string.value_unavailable_short) - val cobInfo = iobCobCalculatorPlugin.getCobInfo(false, "Overview COB") + val cobInfo = iobCobCalculator.getCobInfo(false, "Overview COB") if (cobInfo.displayCob != null) { cobText = resourceHelper.gs(R.string.format_carbs, cobInfo.displayCob!!.toInt()) if (cobInfo.futureCarbs > 0) cobText += "(" + DecimalFormatter.to0Decimal(cobInfo.futureCarbs) + ")" @@ -780,7 +775,9 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList if (config.APS && lastRun?.constraintsProcessed != null) { if (lastRun.constraintsProcessed!!.carbsReq > 0) { //only display carbsreq when carbs have not been entered recently - if (treatmentsPlugin.lastCarbTime < lastRun.lastAPSRun) { + val lastCarb = repository.getLastCarbsRecordWrapped().blockingGet() + val lastCarbsTime = if (lastCarb is ValueWrapper.Existing) lastCarb.value.timestamp else 0L + if (lastCarbsTime < lastRun.lastAPSRun) { cobText = cobText + " | " + lastRun.constraintsProcessed!!.carbsReq + " " + resourceHelper.gs(R.string.required) } binding.infoLayout.cob.text = cobText @@ -813,17 +810,17 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList } binding.infoLayout.sensitivity.text = - iobCobCalculatorPlugin.getLastAutosensData("Overview")?.let { autosensData -> + iobCobCalculator.ads.getLastAutosensData("Overview", aapsLogger, dateUtil)?.let { autosensData -> String.format(Locale.ENGLISH, "%.0f%%", autosensData.autosensResult.ratio * 100) } ?: "" } - private fun updateGraph(lastRun: LoopInterface.LastRun?, predictionsAvailable: Boolean, lowLine: Double, highLine: Double, pump: PumpInterface, profile: Profile) { + private fun updateGraph(lastRun: LoopInterface.LastRun?, predictionsAvailable: Boolean, lowLine: Double, highLine: Double, pump: Pump, profile: Profile) { viewLifecycleOwner.lifecycleScope.launch(Dispatchers.Main) { if (_binding == null) return@launch val menuChartSettings = overviewMenus.setting prepareGraphsIfNeeded(menuChartSettings.size) - val graphData = GraphData(injector, binding.graphsLayout.bgGraph, iobCobCalculatorPlugin, treatmentsPlugin) + val graphData = GraphData(injector, binding.graphsLayout.bgGraph, iobCobCalculator, treatmentsPlugin) val secondaryGraphsData: ArrayList = ArrayList() // do preparation in different thread @@ -863,8 +860,9 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList // **** BG **** if (predictionsAvailable && menuChartSettings[0][OverviewMenus.CharType.PRE.ordinal]) - graphData.addBgReadings(fromTime, toTime, lowLine, highLine, apsResult?.predictions) - else graphData.addBgReadings(fromTime, toTime, lowLine, highLine, null) + graphData.addBgReadings(fromTime, toTime, highLine, apsResult?.predictions?.map { bg-> GlucoseValueDataPoint(bg, defaultValueHelper, profileFunction, resourceHelper) }?.toMutableList()) + else graphData.addBgReadings(fromTime, toTime, highLine, null) + if (buildHelper.isDev()) graphData.addBucketedData(fromTime, toTime) // Treatments graphData.addTreatments(fromTime, endTime) @@ -890,7 +888,7 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList // ------------------ 2nd graph synchronized(graphLock) { for (g in 0 until min(secondaryGraphs.size, menuChartSettings.size + 1)) { - val secondGraphData = GraphData(injector, secondaryGraphs[g], iobCobCalculatorPlugin, treatmentsPlugin) + val secondGraphData = GraphData(injector, secondaryGraphs[g], iobCobCalculator, treatmentsPlugin) var useABSForScale = false var useIobForScale = false var useCobForScale = false diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/OverviewMenus.kt b/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/OverviewMenus.kt index 3bbeac5404..1dfa734247 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/OverviewMenus.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/OverviewMenus.kt @@ -9,7 +9,7 @@ import androidx.annotation.ColorRes import androidx.annotation.StringRes import androidx.appcompat.widget.PopupMenu import com.google.gson.Gson -import info.nightscout.androidaps.Config +import info.nightscout.androidaps.interfaces.Config import info.nightscout.androidaps.R import info.nightscout.androidaps.events.EventRefreshOverview import info.nightscout.androidaps.logging.AAPSLogger diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/OverviewPlugin.kt b/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/OverviewPlugin.kt index d8308f346e..8aadd2ea34 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/OverviewPlugin.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/OverviewPlugin.kt @@ -3,10 +3,11 @@ package info.nightscout.androidaps.plugins.general.overview import androidx.preference.PreferenceFragmentCompat import androidx.preference.SwitchPreference import dagger.android.HasAndroidInjector -import info.nightscout.androidaps.Config +import info.nightscout.androidaps.interfaces.Config import info.nightscout.androidaps.R import info.nightscout.androidaps.events.EventRefreshOverview -import info.nightscout.androidaps.interfaces.OverviewInterface +import info.nightscout.androidaps.extensions.* +import info.nightscout.androidaps.interfaces.Overview import info.nightscout.androidaps.interfaces.PluginBase import info.nightscout.androidaps.interfaces.PluginDescription import info.nightscout.androidaps.interfaces.PluginType @@ -16,7 +17,6 @@ import info.nightscout.androidaps.plugins.general.overview.events.EventDismissNo import info.nightscout.androidaps.plugins.general.overview.events.EventNewNotification import info.nightscout.androidaps.plugins.general.overview.notifications.NotificationStore import info.nightscout.androidaps.utils.FabricPrivacy -import info.nightscout.androidaps.utils.extensions.* import info.nightscout.androidaps.utils.resources.ResourceHelper import info.nightscout.androidaps.utils.rx.AapsSchedulers import info.nightscout.androidaps.utils.sharedPreferences.SP @@ -48,7 +48,7 @@ class OverviewPlugin @Inject constructor( .preferencesId(R.xml.pref_overview) .description(R.string.description_overview), aapsLogger, resourceHelper, injector -), OverviewInterface { +), Overview { private var disposable: CompositeDisposable = CompositeDisposable() diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/StatusLightHandler.kt b/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/StatusLightHandler.kt index e4f5074afe..917ff84630 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/StatusLightHandler.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/StatusLightHandler.kt @@ -3,18 +3,19 @@ package info.nightscout.androidaps.plugins.general.overview import android.graphics.Color import android.widget.TextView import androidx.annotation.StringRes -import info.nightscout.androidaps.Config +import info.nightscout.androidaps.interfaces.Config import info.nightscout.androidaps.R import info.nightscout.androidaps.database.AppRepository import info.nightscout.androidaps.database.ValueWrapper import info.nightscout.androidaps.database.entities.TherapyEvent -import info.nightscout.androidaps.interfaces.ActivePluginProvider +import info.nightscout.androidaps.interfaces.ActivePlugin import info.nightscout.androidaps.plugins.pump.common.defs.PumpType import info.nightscout.androidaps.plugins.pump.omnipod.eros.OmnipodErosPumpPlugin import info.nightscout.androidaps.plugins.pump.omnipod.eros.driver.definition.OmnipodConstants import info.nightscout.androidaps.utils.DecimalFormatter import info.nightscout.androidaps.utils.WarnColors -import info.nightscout.androidaps.utils.extensions.age +import info.nightscout.androidaps.extensions.age +import info.nightscout.androidaps.utils.DateUtil import info.nightscout.androidaps.utils.resources.ResourceHelper import info.nightscout.androidaps.utils.sharedPreferences.SP import javax.inject.Inject @@ -24,7 +25,8 @@ import javax.inject.Singleton class StatusLightHandler @Inject constructor( private val resourceHelper: ResourceHelper, private val sp: SP, - private val activePlugin: ActivePluginProvider, + private val dateUtil: DateUtil, + private val activePlugin: ActivePlugin, private val warnColors: WarnColors, private val config: Config, private val repository: AppRepository @@ -43,7 +45,7 @@ class StatusLightHandler @Inject constructor( handleAge(careportal_pb_age, TherapyEvent.Type.PUMP_BATTERY_CHANGE, R.string.key_statuslights_bage_warning, 216.0, R.string.key_statuslights_bage_critical, 240.0) } if (!config.NSCLIENT) { - if (pump.model() == PumpType.Omnipod_Eros || pump.model() == PumpType.Omnipod_Dash) { + if (pump.model() == PumpType.OMNIPOD_EROS || pump.model() == PumpType.OMNIPOD_DASH) { handleOmnipodReservoirLevel(careportal_reservoir_level, R.string.key_statuslights_res_critical, 10.0, R.string.key_statuslights_res_warning, 80.0, pump.reservoirLevel, "U") } else { handleLevel(careportal_reservoir_level, R.string.key_statuslights_res_critical, 10.0, R.string.key_statuslights_res_warning, 80.0, pump.reservoirLevel, "U") @@ -55,15 +57,15 @@ class StatusLightHandler @Inject constructor( } if (!config.NSCLIENT) { - if (pump.model() == PumpType.Omnipod_Dash) { + if (pump.model() == PumpType.OMNIPOD_DASH) { // Omnipod Dash does not report its battery level careportal_battery_level?.text = resourceHelper.gs(R.string.notavailable) careportal_battery_level?.setTextColor(Color.WHITE) - } else if (pump.model() == PumpType.Omnipod_Eros && pump is OmnipodErosPumpPlugin) { // instance of check is needed because at startup, pump can still be VirtualPumpPlugin and that will cause a crash because of the class cast below + } else if (pump.model() == PumpType.OMNIPOD_EROS && pump is OmnipodErosPumpPlugin) { // instance of check is needed because at startup, pump can still be VirtualPumpPlugin and that will cause a crash because of the class cast below // The Omnipod Eros does not report its battery level. However, some RileyLink alternatives do. // Depending on the user's configuration, we will either show the battery level reported by the RileyLink or "n/a" handleOmnipodErosBatteryLevel(careportal_battery_level, R.string.key_statuslights_bat_critical, 26.0, R.string.key_statuslights_bat_warning, 51.0, pump.batteryLevel.toDouble(), "%", pump.isUseRileyLinkBatteryLevel) - } else if (pump.model() != PumpType.AccuChekCombo) { + } else if (pump.model() != PumpType.ACCU_CHEK_COMBO) { handleLevel(careportal_battery_level, R.string.key_statuslights_bat_critical, 26.0, R.string.key_statuslights_bat_warning, 51.0, pump.batteryLevel.toDouble(), "%") } } @@ -75,7 +77,7 @@ class StatusLightHandler @Inject constructor( val therapyEvent = repository.getLastTherapyRecord(type).blockingGet() if (therapyEvent is ValueWrapper.Existing) { warnColors.setColorByAge(view, therapyEvent.value, warn, urgent) - view?.text = therapyEvent.value.age(resourceHelper.shortTextMode(), resourceHelper) + view?.text = therapyEvent.value.age(resourceHelper.shortTextMode(), resourceHelper, dateUtil) } else { view?.text = if (resourceHelper.shortTextMode()) "-" else resourceHelper.gs(R.string.notavailable) } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/dialogs/EditQuickWizardDialog.kt b/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/dialogs/EditQuickWizardDialog.kt index 237afba172..366850607f 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/dialogs/EditQuickWizardDialog.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/dialogs/EditQuickWizardDialog.kt @@ -83,7 +83,7 @@ class EditQuickWizardDialog : DaggerDialogFragment(), View.OnClickListener { // create an OnTimeSetListener val fromTimeSetListener = TimePickerDialog.OnTimeSetListener { _, hour, minute -> fromSeconds = (T.hours(hour.toLong()).secs() + T.mins(minute.toLong()).secs()).toInt() - binding.from.text = dateUtil.timeString(DateUtil.toDate(fromSeconds)) + binding.from.text = dateUtil.timeString(dateUtil.secondsOfTheDayToMilliseconds(fromSeconds)) } binding.from.setOnClickListener { @@ -96,11 +96,11 @@ class EditQuickWizardDialog : DaggerDialogFragment(), View.OnClickListener { } } fromSeconds = entry.validFrom() - binding.from.text = dateUtil.timeString(DateUtil.toDate(fromSeconds)) + binding.from.text = dateUtil.timeString(dateUtil.secondsOfTheDayToMilliseconds(fromSeconds)) val toTimeSetListener = TimePickerDialog.OnTimeSetListener { _, hour, minute -> toSeconds = (T.hours(hour.toLong()).secs() + T.mins(minute.toLong()).secs()).toInt() - binding.from.text = dateUtil.timeString(DateUtil.toDate(toSeconds)) + binding.from.text = dateUtil.timeString(dateUtil.secondsOfTheDayToMilliseconds(toSeconds)) } binding.to.setOnClickListener { @@ -113,7 +113,7 @@ class EditQuickWizardDialog : DaggerDialogFragment(), View.OnClickListener { } } toSeconds = entry.validFrom() - binding.to.text = dateUtil.timeString(DateUtil.toDate(toSeconds)) + binding.to.text = dateUtil.timeString(dateUtil.secondsOfTheDayToMilliseconds(toSeconds)) binding.buttonEdit.setText(entry.buttonText()) binding.carbsEdit.setText(entry.carbs().toString()) diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/graphData/GraphData.kt b/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/graphData/GraphData.kt index 3722fd1eaa..99d8d57a03 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/graphData/GraphData.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/graphData/GraphData.kt @@ -11,28 +11,20 @@ import com.jjoe64.graphview.series.Series import dagger.android.HasAndroidInjector import info.nightscout.androidaps.Constants import info.nightscout.androidaps.R -import info.nightscout.androidaps.data.GlucoseValueDataPoint import info.nightscout.androidaps.data.IobTotal import info.nightscout.androidaps.data.Profile -import info.nightscout.androidaps.data.TherapyEventDataPoint import info.nightscout.androidaps.database.AppRepository import info.nightscout.androidaps.database.ValueWrapper +import info.nightscout.androidaps.database.entities.Bolus import info.nightscout.androidaps.database.entities.GlucoseValue -import info.nightscout.androidaps.interfaces.ActivePluginProvider -import info.nightscout.androidaps.interfaces.DatabaseHelperInterface -import info.nightscout.androidaps.interfaces.LoopInterface -import info.nightscout.androidaps.interfaces.ProfileFunction -import info.nightscout.androidaps.interfaces.TreatmentsInterface +import info.nightscout.androidaps.interfaces.* import info.nightscout.androidaps.logging.AAPSLogger import info.nightscout.androidaps.logging.LTag import info.nightscout.androidaps.plugins.aps.openAPSSMB.SMBDefaults import info.nightscout.androidaps.plugins.general.overview.graphExtensions.* import info.nightscout.androidaps.plugins.iob.iobCobCalculator.AutosensResult -import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorPlugin -import info.nightscout.androidaps.utils.DateUtil -import info.nightscout.androidaps.utils.DecimalFormatter -import info.nightscout.androidaps.utils.Round -import info.nightscout.androidaps.utils.extensions.target +import info.nightscout.androidaps.utils.* +import info.nightscout.androidaps.extensions.target import info.nightscout.androidaps.utils.resources.ResourceHelper import java.util.* import javax.inject.Inject @@ -43,7 +35,7 @@ import kotlin.math.min class GraphData( private val injector: HasAndroidInjector, private val graph: GraphView, - private val iobCobCalculatorPlugin: IobCobCalculatorPlugin, + private val iobCobCalculator: IobCobCalculator, private val treatmentsPlugin: TreatmentsInterface ) { @@ -51,10 +43,12 @@ class GraphData( @Inject lateinit var aapsLogger: AAPSLogger @Inject lateinit var profileFunction: ProfileFunction @Inject lateinit var resourceHelper: ResourceHelper - @Inject lateinit var activePlugin: ActivePluginProvider + @Inject lateinit var activePlugin: ActivePlugin @Inject lateinit var databaseHelper: DatabaseHelperInterface @Inject lateinit var repository: AppRepository @Inject lateinit var dateUtil: DateUtil + @Inject lateinit var defaultValueHelper: DefaultValueHelper + @Inject lateinit var translator: Translator var maxY = Double.MIN_VALUE private var minY = Double.MAX_VALUE @@ -67,10 +61,23 @@ class GraphData( units = profileFunction.getUnits() } - @Suppress("UNUSED_PARAMETER") - fun addBgReadings(fromTime: Long, toTime: Long, lowLine: Double, highLine: Double, predictions: MutableList?) { + fun addBucketedData(fromTime: Long, toTime: Long) { + val bucketedData = iobCobCalculator.ads.getBucketedDataTableCopy() ?: return + if (bucketedData.isEmpty()) { + aapsLogger.debug("No bucketed data.") + return + } + val bucketedListArray: MutableList = ArrayList() + for (inMemoryGlucoseValue in bucketedData) { + if (inMemoryGlucoseValue.timestamp < fromTime || inMemoryGlucoseValue.timestamp > toTime) continue + bucketedListArray.add(InMemoryGlucoseValueDataPoint(inMemoryGlucoseValue, profileFunction, resourceHelper)) + } + addSeries(PointsWithLabelGraphSeries(Array(bucketedListArray.size) { i -> bucketedListArray[i] })) + } + + fun addBgReadings(fromTime: Long, toTime: Long, highLine: Double, predictions: MutableList?) { var maxBgValue = Double.MIN_VALUE - bgReadingsArray = iobCobCalculatorPlugin.bgReadings + bgReadingsArray = repository.compatGetBgReadingsDataFromTime(fromTime, toTime, false).blockingGet() if (bgReadingsArray?.isEmpty() != false) { aapsLogger.debug("No BG data.") maxY = if (units == Constants.MGDL) 180.0 else 10.0 @@ -81,7 +88,7 @@ class GraphData( for (bg in bgReadingsArray!!) { if (bg.timestamp < fromTime || bg.timestamp > toTime) continue if (bg.value > maxBgValue) maxBgValue = bg.value - bgListArray.add(GlucoseValueDataPoint(injector, bg)) + bgListArray.add(GlucoseValueDataPoint(bg, defaultValueHelper, profileFunction, resourceHelper)) } if (predictions != null) { predictions.sortWith(Comparator { o1: GlucoseValueDataPoint, o2: GlucoseValueDataPoint -> o1.x.compareTo(o2.x) }) @@ -134,7 +141,7 @@ class GraphData( time += 60 * 1000L continue } - val basalData = iobCobCalculatorPlugin.getBasalData(profile, time) + val basalData = iobCobCalculator.getBasalData(profile, time) val baseBasalValue = basalData.basal var absoluteLineValue = baseBasalValue var tempBasalValue = 0.0 @@ -244,9 +251,15 @@ class GraphData( fun addTreatments(fromTime: Long, endTime: Long) { val filteredTreatments: MutableList = ArrayList() - treatmentsPlugin.treatmentsFromHistory - .filterTimeframe(fromTime, endTime) - .filter { !it.isSMB || it.isValid } + repository.getBolusesIncludingInvalidFromTimeToTime(fromTime, endTime, true).blockingGet() + .map { BolusDataPoint(it, resourceHelper, activePlugin, defaultValueHelper) } + .filter { it.data.type != Bolus.Type.SMB || it.data.isValid } + .forEach { + it.y = getNearestBg(it.x.toLong()) + filteredTreatments.add(it) + } + repository.getCarbsIncludingInvalidFromTimeToTimeExpanded(fromTime, endTime, true).blockingGet() + .map { CarbsDataPoint(it, resourceHelper) } .forEach { it.y = getNearestBg(it.x.toLong()) filteredTreatments.add(it) @@ -259,8 +272,8 @@ class GraphData( // Extended bolus if (!activePlugin.activePump.isFakingTempsByExtendedBoluses) { - treatmentsPlugin.extendedBolusesFromHistory.list - .filterTimeframe(fromTime, endTime) + repository.getExtendedBolusDataFromTimeToTime(fromTime, endTime, true).blockingGet() + .map { ExtendedBolusDataPoint(it) } .filter { it.duration != 0L } .forEach { it.y = getNearestBg(it.x.toLong()) @@ -270,8 +283,8 @@ class GraphData( // Careportal // databaseHelper.getCareportalEventsFromTime(fromTime - 6 * 60 * 60 * 1000, true) - repository.compatGetTherapyEventDataFromToTime(fromTime - 6 * 60 * 60 * 1000, endTime).blockingGet() - .map { TherapyEventDataPoint(injector, it) } + repository.compatGetTherapyEventDataFromToTime(fromTime - T.hours(6).msecs(), endTime).blockingGet() + .map { TherapyEventDataPoint(it, resourceHelper, profileFunction, translator) } .filterTimeframe(fromTime, endTime) .forEach { if (it.y == 0.0) it.y = getNearestBg(it.x.toLong()) @@ -289,8 +302,7 @@ class GraphData( private fun getNearestBg(date: Long): Double { bgReadingsArray?.let { bgReadingsArray -> - for (r in bgReadingsArray.indices) { - val reading = bgReadingsArray[r] + for (reading in bgReadingsArray) { if (reading.timestamp > date) continue return Profile.fromMgdlToUnits(reading.value, units) } @@ -312,7 +324,7 @@ class GraphData( time += 5 * 60 * 1000L continue } - total = iobCobCalculatorPlugin.calculateFromTreatmentsAndTempsSynchronized(time, profile) + total = iobCobCalculator.calculateFromTreatmentsAndTemps(time, profile) val act: Double = total.activity if (time <= now) actArrayHist.add(ScaledDataPoint(time, act, actScale)) else actArrayPrediction.add(ScaledDataPoint(time, act, actScale)) maxIAValue = max(maxIAValue, abs(act)) @@ -353,10 +365,10 @@ class GraphData( time += 5 * 60 * 1000L continue } - val deviation = if (devBgiScale) iobCobCalculatorPlugin.getAutosensData(time)?.deviation + val deviation = if (devBgiScale) iobCobCalculator.ads.getAutosensDataAtTime(time)?.deviation ?: 0.0 else 0.0 - total = iobCobCalculatorPlugin.calculateFromTreatmentsAndTempsSynchronized(time, profile) + total = iobCobCalculator.calculateFromTreatmentsAndTemps(time, profile) val bgi: Double = total.activity * profile.getIsfMgdl(time) * 5.0 if (time <= now) bgiArrayHist.add(ScaledDataPoint(time, bgi, bgiScale)) else bgiArrayPrediction.add(ScaledDataPoint(time, bgi, bgiScale)) maxBGIValue = max(maxBGIValue, max(abs(bgi), deviation)) @@ -395,8 +407,8 @@ class GraphData( var iob = 0.0 var absIob = 0.0 if (profile != null) { - iob = iobCobCalculatorPlugin.calculateFromTreatmentsAndTempsSynchronized(time, profile).iob - if (absScale) absIob = iobCobCalculatorPlugin.calculateAbsInsulinFromTreatmentsAndTempsSynchronized(time).iob + iob = iobCobCalculator.calculateFromTreatmentsAndTemps(time, profile).iob + if (absScale) absIob = iobCobCalculator.calculateAbsInsulinFromTreatmentsAndTemps(time).iob } if (abs(lastIob - iob) > 0.02) { if (abs(lastIob - iob) > 0.2) iobArray.add(ScaledDataPoint(time, lastIob, iobScale)) @@ -413,25 +425,25 @@ class GraphData( it.thickness = 3 } if (showPrediction) { - val autosensData = iobCobCalculatorPlugin.getLastAutosensDataSynchronized("GraphData") + val autosensData = iobCobCalculator.getLastAutosensDataWithWaitForCalculationFinish("GraphData") val lastAutosensResult = autosensData?.autosensResult ?: AutosensResult() - val isTempTarget = repository.getTemporaryTargetActiveAt(dateUtil._now()).blockingGet() is ValueWrapper.Existing + val isTempTarget = repository.getTemporaryTargetActiveAt(dateUtil.now()).blockingGet() is ValueWrapper.Existing val iobPrediction: MutableList = ArrayList() - val iobPredictionArray = iobCobCalculatorPlugin.calculateIobArrayForSMB(lastAutosensResult, SMBDefaults.exercise_mode, SMBDefaults.half_basal_exercise_target, isTempTarget) + val iobPredictionArray = iobCobCalculator.calculateIobArrayForSMB(lastAutosensResult, SMBDefaults.exercise_mode, SMBDefaults.half_basal_exercise_target, isTempTarget) for (i in iobPredictionArray) { iobPrediction.add(i.setColor(resourceHelper.gc(R.color.iobPredAS))) maxIobValueFound = max(maxIobValueFound, abs(i.iob)) } addSeries(PointsWithLabelGraphSeries(Array(iobPrediction.size) { i -> iobPrediction[i] })) val iobPrediction2: MutableList = ArrayList() - val iobPredictionArray2 = iobCobCalculatorPlugin.calculateIobArrayForSMB(AutosensResult(), SMBDefaults.exercise_mode, SMBDefaults.half_basal_exercise_target, isTempTarget) + val iobPredictionArray2 = iobCobCalculator.calculateIobArrayForSMB(AutosensResult(), SMBDefaults.exercise_mode, SMBDefaults.half_basal_exercise_target, isTempTarget) for (i in iobPredictionArray2) { iobPrediction2.add(i.setColor(resourceHelper.gc(R.color.iobPred))) maxIobValueFound = max(maxIobValueFound, abs(i.iob)) } addSeries(PointsWithLabelGraphSeries(Array(iobPrediction2.size) { i -> iobPrediction2[i] })) - aapsLogger.debug(LTag.AUTOSENS, "IOB prediction for AS=" + DecimalFormatter.to2Decimal(lastAutosensResult.ratio) + ": " + iobCobCalculatorPlugin.iobArrayToString(iobPredictionArray)) - aapsLogger.debug(LTag.AUTOSENS, "IOB prediction for AS=" + DecimalFormatter.to2Decimal(1.0) + ": " + iobCobCalculatorPlugin.iobArrayToString(iobPredictionArray2)) + aapsLogger.debug(LTag.AUTOSENS, "IOB prediction for AS=" + DecimalFormatter.to2Decimal(lastAutosensResult.ratio) + ": " + iobCobCalculator.iobArrayToString(iobPredictionArray)) + aapsLogger.debug(LTag.AUTOSENS, "IOB prediction for AS=" + DecimalFormatter.to2Decimal(1.0) + ": " + iobCobCalculator.iobArrayToString(iobPredictionArray2)) } if (useForScale) { maxY = maxIobValueFound @@ -452,7 +464,7 @@ class GraphData( while (time <= toTime) { val profile = profileFunction.getProfile(time) var iob = 0.0 - if (profile != null) iob = iobCobCalculatorPlugin.calculateAbsInsulinFromTreatmentsAndTempsSynchronized(time).iob + if (profile != null) iob = iobCobCalculator.calculateAbsInsulinFromTreatmentsAndTemps(time).iob if (abs(lastIob - iob) > 0.02) { if (abs(lastIob - iob) > 0.2) iobArray.add(ScaledDataPoint(time, lastIob, iobScale)) iobArray.add(ScaledDataPoint(time, iob, iobScale)) @@ -484,7 +496,7 @@ class GraphData( val cobScale = Scale() var time = fromTime while (time <= toTime) { - iobCobCalculatorPlugin.getAutosensData(time)?.let { autosensData -> + iobCobCalculator.ads.getAutosensDataAtTime(time)?.let { autosensData -> val cob = autosensData.cob.toInt() if (cob != lastCob) { if (autosensData.carbsFromBolus > 0) cobArray.add(ScaledDataPoint(time, lastCob.toDouble(), cobScale)) @@ -529,12 +541,12 @@ class GraphData( while (time <= toTime) { // if align Dev Scale with BGI scale, then calculate BGI value, else bgi = 0.0 val bgi: Double = if (devBgiScale) { - val profile = profileFunction.getProfile(time) - total = iobCobCalculatorPlugin.calculateFromTreatmentsAndTempsSynchronized(time, profile) - total.activity * (profile?.getIsfMgdl(time) ?: 0.0) * 5.0 + val profile = profileFunction.getProfile(time) ?: continue + total = iobCobCalculator.calculateFromTreatmentsAndTemps(time, profile) + total.activity * profile.getIsfMgdl(time) * 5.0 } else 0.0 - iobCobCalculatorPlugin.getAutosensData(time)?.let { autosensData -> + iobCobCalculator.ads.getAutosensDataAtTime(time)?.let { autosensData -> var color = resourceHelper.gc(R.color.deviationblack) // "=" if (autosensData.type == "" || autosensData.type == "non-meal") { if (autosensData.pastSensitivity == "C") color = resourceHelper.gc(R.color.deviationgrey) @@ -565,15 +577,15 @@ class GraphData( // scale in % of vertical size (like 0.3) fun addRatio(fromTime: Long, toTime: Long, useForScale: Boolean, scale: Double) { val ratioArray: MutableList = ArrayList() - var maxRatioValueFound = 5.0 //even if sens data equals 0 for all the period, minimum scale is between 95% and 105% - var minRatioValueFound = - maxRatioValueFound - val ratioScale = if (useForScale) Scale(100.0) else Scale() + var maxRatioValueFound = Double.MIN_VALUE + var minRatioValueFound = Double.MAX_VALUE + val ratioScale = Scale() var time = fromTime while (time <= toTime) { - iobCobCalculatorPlugin.getAutosensData(time)?.let { autosensData -> - ratioArray.add(ScaledDataPoint(time, 100.0 * (autosensData.autosensResult.ratio - 1 ), ratioScale)) - maxRatioValueFound = max(maxRatioValueFound, 100.0 * (autosensData.autosensResult.ratio - 1)) - minRatioValueFound = min(minRatioValueFound, 100.0 * (autosensData.autosensResult.ratio - 1)) + iobCobCalculator.ads.getAutosensDataAtTime(time)?.let { autosensData -> + ratioArray.add(ScaledDataPoint(time, autosensData.autosensResult.ratio - 1, ratioScale)) + maxRatioValueFound = max(maxRatioValueFound, autosensData.autosensResult.ratio - 1) + minRatioValueFound = min(minRatioValueFound, autosensData.autosensResult.ratio - 1) } time += 5 * 60 * 1000L } @@ -584,11 +596,10 @@ class GraphData( it.thickness = 3 }) if (useForScale) { - maxY = 100.0 + max(maxRatioValueFound, abs(minRatioValueFound)) - minY = 100.0 - max(maxRatioValueFound, abs(minRatioValueFound)) - ratioScale.setMultiplier(1.0) - } else - ratioScale.setMultiplier(maxY * scale / max(maxRatioValueFound, abs(minRatioValueFound))) + maxY = max(maxRatioValueFound, abs(minRatioValueFound)) + minY = -maxY + } + ratioScale.setMultiplier(maxY * scale / max(maxRatioValueFound, abs(minRatioValueFound))) } // scale in % of vertical size (like 0.3) @@ -601,7 +612,7 @@ class GraphData( val dsMinScale = Scale() var time = fromTime while (time <= toTime) { - iobCobCalculatorPlugin.getAutosensData(time)?.let { autosensData -> + iobCobCalculator.ads.getAutosensDataAtTime(time)?.let { autosensData -> dsMaxArray.add(ScaledDataPoint(time, autosensData.slopeFromMaxDeviation, dsMaxScale)) dsMinArray.add(ScaledDataPoint(time, autosensData.slopeFromMinDeviation, dsMinScale)) maxFromMaxValueFound = max(maxFromMaxValueFound, abs(autosensData.slopeFromMaxDeviation)) diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/graphExtensions/BolusDataPoint.kt b/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/graphExtensions/BolusDataPoint.kt new file mode 100644 index 0000000000..89136b5b69 --- /dev/null +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/graphExtensions/BolusDataPoint.kt @@ -0,0 +1,39 @@ +package info.nightscout.androidaps.plugins.general.overview.graphExtensions + +import android.graphics.Color +import info.nightscout.androidaps.core.R +import info.nightscout.androidaps.database.entities.Bolus +import info.nightscout.androidaps.interfaces.ActivePlugin +import info.nightscout.androidaps.utils.DecimalFormatter +import info.nightscout.androidaps.utils.DefaultValueHelper +import info.nightscout.androidaps.utils.resources.ResourceHelper +import javax.inject.Inject + +class BolusDataPoint @Inject constructor( + val data: Bolus, + private val resourceHelper: ResourceHelper, + private val activePlugin: ActivePlugin, + private val defaultValueHelper: DefaultValueHelper +) : DataPointWithLabelInterface { + + private var yValue = 0.0 + + override fun getX(): Double = data.timestamp.toDouble() + override fun getY(): Double = if (data.type == Bolus.Type.SMB) defaultValueHelper.determineLowLine() else yValue + override fun getLabel(): String = DecimalFormatter.toPumpSupportedBolus(data.amount, activePlugin.activePump, resourceHelper) + override fun getDuration(): Long = 0 + override fun getSize(): Float = 2f + + override fun getShape(): PointsWithLabelGraphSeries.Shape = + if (data.type == Bolus.Type.SMB) PointsWithLabelGraphSeries.Shape.SMB + else PointsWithLabelGraphSeries.Shape.BOLUS + + override fun getColor(): Int = + if (data.type == Bolus.Type.SMB) resourceHelper.gc(R.color.tempbasal) + else if (data.isValid) Color.CYAN + else resourceHelper.gc(android.R.color.holo_red_light) + + override fun setY(y: Double) { + yValue = y + } +} \ No newline at end of file diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/graphExtensions/CarbsDataPoint.kt b/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/graphExtensions/CarbsDataPoint.kt new file mode 100644 index 0000000000..719533da98 --- /dev/null +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/graphExtensions/CarbsDataPoint.kt @@ -0,0 +1,30 @@ +package info.nightscout.androidaps.plugins.general.overview.graphExtensions + +import info.nightscout.androidaps.core.R +import info.nightscout.androidaps.database.entities.Carbs +import info.nightscout.androidaps.utils.resources.ResourceHelper +import javax.inject.Inject + +class CarbsDataPoint @Inject constructor( + val data: Carbs, + private val resourceHelper: ResourceHelper +) : DataPointWithLabelInterface { + + private var yValue = 0.0 + + override fun getX(): Double = data.timestamp.toDouble() + override fun getY(): Double = yValue + override fun getLabel(): String = resourceHelper.gs(R.string.format_carbs, data.amount.toInt()) + override fun getDuration(): Long = 0 + override fun getSize(): Float = 2f + + override fun getShape(): PointsWithLabelGraphSeries.Shape = PointsWithLabelGraphSeries.Shape.CARBS + + override fun getColor(): Int = + if (data.isValid) resourceHelper.gc(R.color.carbs) + else resourceHelper.gc(android.R.color.holo_red_light) + + override fun setY(y: Double) { + yValue = y + } +} \ No newline at end of file diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/graphExtensions/ExtendedBolusDataPoint.kt b/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/graphExtensions/ExtendedBolusDataPoint.kt new file mode 100644 index 0000000000..d286f83a45 --- /dev/null +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/graphExtensions/ExtendedBolusDataPoint.kt @@ -0,0 +1,25 @@ +package info.nightscout.androidaps.plugins.general.overview.graphExtensions + +import android.graphics.Color +import info.nightscout.androidaps.database.entities.ExtendedBolus +import info.nightscout.androidaps.extensions.toStringTotal +import javax.inject.Inject + +class ExtendedBolusDataPoint @Inject constructor( + val data: ExtendedBolus +) : DataPointWithLabelInterface { + + private var yValue = 0.0 + + override fun getX(): Double = data.timestamp.toDouble() + override fun getY(): Double = yValue + override fun getLabel(): String = data.toStringTotal() + override fun getDuration(): Long = data.duration + override fun getSize(): Float = 10f + override fun getShape(): PointsWithLabelGraphSeries.Shape = PointsWithLabelGraphSeries.Shape.EXTENDEDBOLUS + override fun getColor(): Int = Color.CYAN + + override fun setY(y: Double) { + yValue = y + } +} \ No newline at end of file diff --git a/core/src/main/java/info/nightscout/androidaps/data/GlucoseValueDataPoint.kt b/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/graphExtensions/GlucoseValueDataPoint.kt similarity index 65% rename from core/src/main/java/info/nightscout/androidaps/data/GlucoseValueDataPoint.kt rename to app/src/main/java/info/nightscout/androidaps/plugins/general/overview/graphExtensions/GlucoseValueDataPoint.kt index 9c884b5315..02e4545582 100644 --- a/core/src/main/java/info/nightscout/androidaps/data/GlucoseValueDataPoint.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/graphExtensions/GlucoseValueDataPoint.kt @@ -1,29 +1,20 @@ -package info.nightscout.androidaps.data +package info.nightscout.androidaps.plugins.general.overview.graphExtensions -import dagger.android.HasAndroidInjector import info.nightscout.androidaps.Constants import info.nightscout.androidaps.core.R import info.nightscout.androidaps.database.entities.GlucoseValue import info.nightscout.androidaps.interfaces.ProfileFunction -import info.nightscout.androidaps.plugins.general.overview.graphExtensions.DataPointWithLabelInterface -import info.nightscout.androidaps.plugins.general.overview.graphExtensions.PointsWithLabelGraphSeries import info.nightscout.androidaps.utils.DefaultValueHelper import info.nightscout.androidaps.utils.resources.ResourceHelper import javax.inject.Inject class GlucoseValueDataPoint @Inject constructor( - val injector: HasAndroidInjector, - val data: GlucoseValue + val data: GlucoseValue, + private val defaultValueHelper: DefaultValueHelper, + private val profileFunction: ProfileFunction, + private val resourceHelper: ResourceHelper ) : DataPointWithLabelInterface { - @Inject lateinit var defaultValueHelper: DefaultValueHelper - @Inject lateinit var profileFunction: ProfileFunction - @Inject lateinit var resourceHelper: ResourceHelper - - init { - injector.androidInjector().inject(this) - } - fun valueToUnits(units: String): Double = if (units == Constants.MGDL) data.value else data.value * Constants.MGDL_TO_MMOLL @@ -59,11 +50,11 @@ class GlucoseValueDataPoint @Inject constructor( val predictionColor: Int get() { return when (data.sourceSensor) { - GlucoseValue.SourceSensor.IOB_PREDICTION -> resourceHelper.gc(R.color.iob) - GlucoseValue.SourceSensor.COB_PREDICTION -> resourceHelper.gc(R.color.cob) - GlucoseValue.SourceSensor.aCOB_PREDICTION -> -0x7f000001 and resourceHelper.gc(R.color.cob) - GlucoseValue.SourceSensor.UAM_PREDICTION -> resourceHelper.gc(R.color.uam) - GlucoseValue.SourceSensor.ZT_PREDICTION -> resourceHelper.gc(R.color.zt) + GlucoseValue.SourceSensor.IOB_PREDICTION -> resourceHelper.gc(R.color.iob) + GlucoseValue.SourceSensor.COB_PREDICTION -> resourceHelper.gc(R.color.cob) + GlucoseValue.SourceSensor.A_COB_PREDICTION -> -0x7f000001 and resourceHelper.gc(R.color.cob) + GlucoseValue.SourceSensor.UAM_PREDICTION -> resourceHelper.gc(R.color.uam) + GlucoseValue.SourceSensor.ZT_PREDICTION -> resourceHelper.gc(R.color.zt) else -> R.color.white } } @@ -71,7 +62,7 @@ class GlucoseValueDataPoint @Inject constructor( private val isPrediction: Boolean get() = data.sourceSensor == GlucoseValue.SourceSensor.IOB_PREDICTION || data.sourceSensor == GlucoseValue.SourceSensor.COB_PREDICTION || - data.sourceSensor == GlucoseValue.SourceSensor.aCOB_PREDICTION || + data.sourceSensor == GlucoseValue.SourceSensor.A_COB_PREDICTION || data.sourceSensor == GlucoseValue.SourceSensor.UAM_PREDICTION || data.sourceSensor == GlucoseValue.SourceSensor.ZT_PREDICTION diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/graphExtensions/InMemoryGlucoseValueDataPoint.kt b/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/graphExtensions/InMemoryGlucoseValueDataPoint.kt new file mode 100644 index 0000000000..fbeec72693 --- /dev/null +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/graphExtensions/InMemoryGlucoseValueDataPoint.kt @@ -0,0 +1,27 @@ +package info.nightscout.androidaps.plugins.general.overview.graphExtensions + +import info.nightscout.androidaps.Constants +import info.nightscout.androidaps.core.R +import info.nightscout.androidaps.data.InMemoryGlucoseValue +import info.nightscout.androidaps.interfaces.ProfileFunction +import info.nightscout.androidaps.utils.resources.ResourceHelper +import javax.inject.Inject + +class InMemoryGlucoseValueDataPoint @Inject constructor( + val data: InMemoryGlucoseValue, + private val profileFunction: ProfileFunction, + private val resourceHelper: ResourceHelper +) : DataPointWithLabelInterface { + + fun valueToUnits(units: String): Double = + if (units == Constants.MGDL) data.value else data.value * Constants.MGDL_TO_MMOLL + + override fun getX(): Double = data.timestamp.toDouble() + override fun getY(): Double = valueToUnits(profileFunction.getUnits()) + override fun setY(y: Double) {} + override fun getLabel(): String? = null + override fun getDuration(): Long = 0 + override fun getShape(): PointsWithLabelGraphSeries.Shape = PointsWithLabelGraphSeries.Shape.BUCKETED_BG + override fun getSize(): Float = 0.3f + override fun getColor(): Int = resourceHelper.gc(R.color.white) +} \ No newline at end of file diff --git a/core/src/main/java/info/nightscout/androidaps/data/TherapyEventDataPoint.kt b/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/graphExtensions/TherapyEventDataPoint.kt similarity index 83% rename from core/src/main/java/info/nightscout/androidaps/data/TherapyEventDataPoint.kt rename to app/src/main/java/info/nightscout/androidaps/plugins/general/overview/graphExtensions/TherapyEventDataPoint.kt index 7c884db7f1..8021fcc1b3 100644 --- a/core/src/main/java/info/nightscout/androidaps/data/TherapyEventDataPoint.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/graphExtensions/TherapyEventDataPoint.kt @@ -1,35 +1,25 @@ -package info.nightscout.androidaps.data +package info.nightscout.androidaps.plugins.general.overview.graphExtensions import android.graphics.Color -import dagger.android.HasAndroidInjector import info.nightscout.androidaps.Constants import info.nightscout.androidaps.core.R +import info.nightscout.androidaps.data.Profile import info.nightscout.androidaps.database.entities.TherapyEvent import info.nightscout.androidaps.interfaces.Interval import info.nightscout.androidaps.interfaces.ProfileFunction -import info.nightscout.androidaps.plugins.general.overview.graphExtensions.DataPointWithLabelInterface -import info.nightscout.androidaps.plugins.general.overview.graphExtensions.PointsWithLabelGraphSeries -import info.nightscout.androidaps.utils.DefaultValueHelper import info.nightscout.androidaps.utils.Translator import info.nightscout.androidaps.utils.resources.ResourceHelper import javax.inject.Inject class TherapyEventDataPoint @Inject constructor( - val injector: HasAndroidInjector, - val data: TherapyEvent + val data: TherapyEvent, + private val resourceHelper: ResourceHelper, + private val profileFunction: ProfileFunction, + private val translator: Translator ) : DataPointWithLabelInterface, Interval { - @Inject lateinit var defaultValueHelper: DefaultValueHelper - @Inject lateinit var profileFunction: ProfileFunction - @Inject lateinit var resourceHelper: ResourceHelper - @Inject lateinit var translator: Translator - private var yValue = 0.0 - init { - injector.androidInjector().inject(this) - } - override fun getX(): Double { return data.timestamp.toDouble() } @@ -59,7 +49,7 @@ class TherapyEventDataPoint @Inject constructor( override fun getLabel(): String? = if (data.note != null) data.note - else translator.translate(data.type.text) + else translator.translate(data.type) override fun getDuration(): Long = end() - start() override fun getShape(): PointsWithLabelGraphSeries.Shape = diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/notifications/NotificationStore.kt b/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/notifications/NotificationStore.kt index a732aaffd9..2ac420ade8 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/notifications/NotificationStore.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/notifications/NotificationStore.kt @@ -14,14 +14,14 @@ import androidx.core.app.NotificationCompat import androidx.recyclerview.widget.RecyclerView import info.nightscout.androidaps.R import info.nightscout.androidaps.databinding.OverviewNotificationItemBinding -import info.nightscout.androidaps.interfaces.NotificationHolderInterface +import info.nightscout.androidaps.interfaces.IconsProvider +import info.nightscout.androidaps.interfaces.NotificationHolder import info.nightscout.androidaps.logging.AAPSLogger import info.nightscout.androidaps.logging.LTag import info.nightscout.androidaps.plugins.bus.RxBusWrapper import info.nightscout.androidaps.plugins.general.overview.events.EventDismissNotification import info.nightscout.androidaps.services.AlarmSoundServiceHelper import info.nightscout.androidaps.utils.DateUtil -import info.nightscout.androidaps.utils.resources.IconsProvider import info.nightscout.androidaps.utils.resources.ResourceHelper import info.nightscout.androidaps.utils.sharedPreferences.SP import java.util.* @@ -38,7 +38,7 @@ class NotificationStore @Inject constructor( private val iconsProvider: IconsProvider, private val alarmSoundServiceHelper: AlarmSoundServiceHelper, private val dateUtil: DateUtil, - private val notificationHolder: NotificationHolderInterface + private val notificationHolder: NotificationHolder ) { private var store: MutableList = ArrayList() diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/persistentNotification/DummyService.kt b/app/src/main/java/info/nightscout/androidaps/plugins/general/persistentNotification/DummyService.kt index 3534146fe0..85675df350 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/persistentNotification/DummyService.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/persistentNotification/DummyService.kt @@ -7,11 +7,11 @@ import android.os.Binder import android.os.IBinder import dagger.android.DaggerService import info.nightscout.androidaps.events.EventAppExit +import info.nightscout.androidaps.interfaces.NotificationHolder import info.nightscout.androidaps.logging.AAPSLogger import info.nightscout.androidaps.logging.LTag import info.nightscout.androidaps.plugins.bus.RxBusWrapper import info.nightscout.androidaps.utils.FabricPrivacy -import info.nightscout.androidaps.utils.androidNotification.NotificationHolder import info.nightscout.androidaps.utils.rx.AapsSchedulers import io.reactivex.disposables.CompositeDisposable import javax.inject.Inject diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/persistentNotification/DummyServiceHelper.kt b/app/src/main/java/info/nightscout/androidaps/plugins/general/persistentNotification/DummyServiceHelper.kt index 5f52035bac..f5373abec0 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/persistentNotification/DummyServiceHelper.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/persistentNotification/DummyServiceHelper.kt @@ -5,7 +5,7 @@ import android.content.Context import android.content.Intent import android.content.ServiceConnection import android.os.IBinder -import info.nightscout.androidaps.interfaces.NotificationHolderInterface +import info.nightscout.androidaps.interfaces.NotificationHolder import javax.inject.Inject import javax.inject.Singleton @@ -21,7 +21,7 @@ import javax.inject.Singleton */ @Singleton class DummyServiceHelper @Inject constructor( - private val notificationHolder: NotificationHolderInterface + private val notificationHolder: NotificationHolder ) { fun startService(context: Context) { diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/persistentNotification/PersistentNotificationPlugin.kt b/app/src/main/java/info/nightscout/androidaps/plugins/general/persistentNotification/PersistentNotificationPlugin.kt index 8c028c89be..13a681c296 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/persistentNotification/PersistentNotificationPlugin.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/persistentNotification/PersistentNotificationPlugin.kt @@ -15,15 +15,13 @@ import info.nightscout.androidaps.events.* import info.nightscout.androidaps.interfaces.* import info.nightscout.androidaps.logging.AAPSLogger import info.nightscout.androidaps.plugins.bus.RxBusWrapper -import info.nightscout.androidaps.plugins.iob.iobCobCalculator.GlucoseStatus import info.nightscout.androidaps.plugins.iob.iobCobCalculator.GlucoseStatusProvider -import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorPlugin import info.nightscout.androidaps.utils.DecimalFormatter import info.nightscout.androidaps.utils.FabricPrivacy -import info.nightscout.androidaps.utils.resources.IconsProvider +import info.nightscout.androidaps.extensions.toStringShort import info.nightscout.androidaps.utils.resources.ResourceHelper import info.nightscout.androidaps.utils.rx.AapsSchedulers -import info.nightscout.androidaps.utils.extensions.valueToUnitsString +import info.nightscout.androidaps.extensions.valueToUnitsString import io.reactivex.disposables.CompositeDisposable import javax.inject.Inject import javax.inject.Singleton @@ -37,11 +35,11 @@ class PersistentNotificationPlugin @Inject constructor( private val aapsSchedulers: AapsSchedulers, private val profileFunction: ProfileFunction, private val fabricPrivacy: FabricPrivacy, - private val activePlugins: ActivePluginProvider, - private val iobCobCalculatorPlugin: IobCobCalculatorPlugin, + private val activePlugins: ActivePlugin, + private val iobCobCalculator: IobCobCalculator, private val rxBus: RxBusWrapper, private val context: Context, - private val notificationHolder: NotificationHolderInterface, + private val notificationHolder: NotificationHolder, private val dummyServiceHelper: DummyServiceHelper, private val iconsProvider: IconsProvider, private val glucoseStatusProvider: GlucoseStatusProvider @@ -131,7 +129,7 @@ class PersistentNotificationPlugin @Inject constructor( if (profileFunction.isProfileValid("Notification")) { var line1aa: String val units = profileFunction.getUnits() - val lastBG = iobCobCalculatorPlugin.lastBg() + val lastBG = iobCobCalculator.ads.lastBg() val glucoseStatus = glucoseStatusProvider.glucoseStatusData if (lastBG != null) { line1aa = lastBG.valueToUnitsString(units) @@ -150,18 +148,16 @@ class PersistentNotificationPlugin @Inject constructor( line1aa = resourceHelper.gs(R.string.missed_bg_readings) line1 = line1aa } - val activeTemp = activePlugins.activeTreatments.getTempBasalFromHistory(System.currentTimeMillis()) + val activeTemp = iobCobCalculator.getTempBasalIncludingConvertedExtended(System.currentTimeMillis()) if (activeTemp != null) { line1 += " " + activeTemp.toStringShort() line1aa += " " + activeTemp.toStringShort() + "." } //IOB - activePlugins.activeTreatments.updateTotalIOBTreatments() - activePlugins.activeTreatments.updateTotalIOBTempBasals() - val bolusIob = activePlugins.activeTreatments.lastCalculationTreatments.round() - val basalIob = activePlugins.activeTreatments.lastCalculationTempBasals.round() - line2 = resourceHelper.gs(R.string.treatments_iob_label_string) + " " + DecimalFormatter.to2Decimal(bolusIob.iob + basalIob.basaliob) + "U " + resourceHelper.gs(R.string.cob) + ": " + iobCobCalculatorPlugin.getCobInfo(false, "PersistentNotificationPlugin").generateCOBString() - val line2aa = resourceHelper.gs(R.string.treatments_iob_label_string) + " " + DecimalFormatter.to2Decimal(bolusIob.iob + basalIob.basaliob) + "U. " + resourceHelper.gs(R.string.cob) + ": " + iobCobCalculatorPlugin.getCobInfo(false, "PersistentNotificationPlugin").generateCOBString() + "." + val bolusIob = iobCobCalculator.calculateIobFromBolus().round() + val basalIob = iobCobCalculator.calculateIobFromTempBasalsIncludingConvertedExtended().round() + line2 = resourceHelper.gs(R.string.treatments_iob_label_string) + " " + DecimalFormatter.to2Decimal(bolusIob.iob + basalIob.basaliob) + "U " + resourceHelper.gs(R.string.cob) + ": " + iobCobCalculator.getCobInfo(false, "PersistentNotificationPlugin").generateCOBString() + val line2aa = resourceHelper.gs(R.string.treatments_iob_label_string) + " " + DecimalFormatter.to2Decimal(bolusIob.iob + basalIob.basaliob) + "U. " + resourceHelper.gs(R.string.cob) + ": " + iobCobCalculator.getCobInfo(false, "PersistentNotificationPlugin").generateCOBString() + "." line3 = DecimalFormatter.to2Decimal(pump.baseBasalRate) + " U/h" var line3aa = DecimalFormatter.to2Decimal(pump.baseBasalRate) + " U/h." line3 += " - " + profileFunction.getProfileName() diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/smsCommunicator/AuthRequest.kt b/app/src/main/java/info/nightscout/androidaps/plugins/general/smsCommunicator/AuthRequest.kt index ae454e1f2b..7d19bed23d 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/smsCommunicator/AuthRequest.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/smsCommunicator/AuthRequest.kt @@ -22,12 +22,14 @@ class AuthRequest internal constructor( @Inject lateinit var smsCommunicatorPlugin: SmsCommunicatorPlugin @Inject lateinit var resourceHelper: ResourceHelper @Inject lateinit var otp: OneTimePassword + @Inject lateinit var dateUtil: DateUtil - private val date = DateUtil.now() + private var date = 0L private var processed = false init { injector.androidInjector().inject(this) + date = dateUtil.now() smsCommunicatorPlugin.sendSMS(Sms(requester.phoneNumber, requestText)) } @@ -45,7 +47,7 @@ class AuthRequest internal constructor( smsCommunicatorPlugin.sendSMS(Sms(requester.phoneNumber, resourceHelper.gs(R.string.sms_wrongcode))) return } - if (DateUtil.now() - date < Constants.SMS_CONFIRM_TIMEOUT) { + if (dateUtil.now() - date < Constants.SMS_CONFIRM_TIMEOUT) { processed = true aapsLogger.debug(LTag.SMS, "Processing confirmed SMS: " + requester.text) action.run() diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/smsCommunicator/Sms.kt b/app/src/main/java/info/nightscout/androidaps/plugins/general/smsCommunicator/Sms.kt index bab25dfe3e..6efac44dbb 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/smsCommunicator/Sms.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/smsCommunicator/Sms.kt @@ -1,10 +1,9 @@ package info.nightscout.androidaps.plugins.general.smsCommunicator import android.telephony.SmsMessage -import info.nightscout.androidaps.MainApp -import info.nightscout.androidaps.utils.DateUtil class Sms { + var phoneNumber: String var text: String var date: Long @@ -23,7 +22,7 @@ class Sms { internal constructor(phoneNumber: String, text: String) { this.phoneNumber = phoneNumber this.text = text - date = DateUtil.now() + date = System.currentTimeMillis() sent = true } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/smsCommunicator/SmsCommunicatorPlugin.kt b/app/src/main/java/info/nightscout/androidaps/plugins/general/smsCommunicator/SmsCommunicatorPlugin.kt index e8e490bcf5..0ab7a4566b 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/smsCommunicator/SmsCommunicatorPlugin.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/smsCommunicator/SmsCommunicatorPlugin.kt @@ -9,18 +9,20 @@ import androidx.preference.Preference import androidx.preference.PreferenceFragmentCompat import androidx.work.Worker import androidx.work.WorkerParameters +import androidx.work.workDataOf import dagger.android.HasAndroidInjector -import info.nightscout.androidaps.Config +import info.nightscout.androidaps.interfaces.Config import info.nightscout.androidaps.Constants import info.nightscout.androidaps.R import info.nightscout.androidaps.data.DetailedBolusInfo import info.nightscout.androidaps.data.Profile import info.nightscout.androidaps.database.AppRepository +import info.nightscout.androidaps.database.entities.ValueWithUnit import info.nightscout.androidaps.database.entities.TemporaryTarget -import info.nightscout.androidaps.database.entities.UserEntry.* +import info.nightscout.androidaps.database.entities.UserEntry.Action +import info.nightscout.androidaps.database.entities.UserEntry.Sources import info.nightscout.androidaps.database.transactions.CancelCurrentTemporaryTargetIfAnyTransaction import info.nightscout.androidaps.database.transactions.InsertTemporaryTargetAndCancelCurrentTransaction -import info.nightscout.androidaps.db.Source import info.nightscout.androidaps.events.EventPreferenceChange import info.nightscout.androidaps.events.EventRefreshOverview import info.nightscout.androidaps.interfaces.* @@ -30,19 +32,16 @@ import info.nightscout.androidaps.logging.UserEntryLogger import info.nightscout.androidaps.plugins.aps.loop.LoopPlugin import info.nightscout.androidaps.plugins.bus.RxBusWrapper import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker -import info.nightscout.androidaps.plugins.general.nsclient.NSUpload import info.nightscout.androidaps.plugins.general.nsclient.events.EventNSClientRestart import info.nightscout.androidaps.plugins.general.overview.events.EventNewNotification import info.nightscout.androidaps.plugins.general.overview.notifications.Notification import info.nightscout.androidaps.plugins.general.smsCommunicator.events.EventSmsCommunicatorUpdateGui import info.nightscout.androidaps.plugins.general.smsCommunicator.otp.OneTimePassword import info.nightscout.androidaps.plugins.iob.iobCobCalculator.GlucoseStatusProvider -import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorPlugin import info.nightscout.androidaps.queue.Callback import info.nightscout.androidaps.receivers.DataWorker -import info.nightscout.androidaps.receivers.DataReceiver import info.nightscout.androidaps.utils.* -import info.nightscout.androidaps.utils.extensions.valueToUnitsString +import info.nightscout.androidaps.extensions.valueToUnitsString import info.nightscout.androidaps.utils.resources.ResourceHelper import info.nightscout.androidaps.utils.rx.AapsSchedulers import info.nightscout.androidaps.utils.sharedPreferences.SP @@ -50,9 +49,11 @@ import info.nightscout.androidaps.utils.textValidator.ValidatingEditTextPreferen import io.reactivex.disposables.CompositeDisposable import io.reactivex.rxkotlin.plusAssign import org.apache.commons.lang3.StringUtils +import org.joda.time.DateTime import java.text.Normalizer import java.util.* import java.util.concurrent.TimeUnit +import java.util.regex.Pattern import javax.inject.Inject import javax.inject.Singleton import kotlin.math.max @@ -69,16 +70,15 @@ class SmsCommunicatorPlugin @Inject constructor( private val rxBus: RxBusWrapper, private val profileFunction: ProfileFunction, private val fabricPrivacy: FabricPrivacy, - private val activePlugin: ActivePluginProvider, + private val activePlugin: ActivePlugin, private val commandQueue: CommandQueueProvider, private val loopPlugin: LoopPlugin, - private val iobCobCalculatorPlugin: IobCobCalculatorPlugin, + private val iobCobCalculator: IobCobCalculator, private val xdripCalibrations: XdripCalibrations, private var otp: OneTimePassword, private val config: Config, private val dateUtil: DateUtil, private val uel: UserEntryLogger, - private val nsUpload: NSUpload, private val glucoseStatusProvider: GlucoseStatusProvider, private val repository: AppRepository ) : PluginBase(PluginDescription() @@ -90,7 +90,7 @@ class SmsCommunicatorPlugin @Inject constructor( .preferencesId(R.xml.pref_smscommunicator) .description(R.string.description_sms_communicator), aapsLogger, resourceHelper, injector -), SmsCommunicatorInterface { +), SmsCommunicator { private val disposable = CompositeDisposable() var allowedNumbers: MutableList = ArrayList() @@ -101,7 +101,6 @@ class SmsCommunicatorPlugin @Inject constructor( val commands = mapOf( "BG" to "BG", "LOOP" to "LOOP STOP/DISABLE/START/ENABLE/RESUME/STATUS\nLOOP SUSPEND 20", - "TREATMENTS" to "TREATMENTS REFRESH", "NSCLIENT" to "NSCLIENT RESTART", "PUMP" to "PUMP\nPUMP CONNECT\nPUMP DISCONNECT 30\n", "BASAL" to "BASAL STOP/CANCEL\nBASAL 0.3\nBASAL 0.3 20\nBASAL 30%\nBASAL 30% 20\n", @@ -184,8 +183,9 @@ class SmsCommunicatorPlugin @Inject constructor( @Suppress("SpellCheckingInspection") override fun doWork(): Result { val bundle = dataWorker.pickupBundle(inputData.getLong(DataWorker.STORE_KEY, -1)) - ?: return Result.failure() - val format = bundle.getString("format") ?: return Result.failure() + ?: return Result.failure(workDataOf("Error" to "missing input data")) + val format = bundle.getString("format") + ?: return Result.failure(workDataOf("Error" to "missing format in input data")) val pdus = bundle["pdus"] as Array<*> for (pdu in pdus) { val message = SmsMessage.createFromPdu(pdu as ByteArray, format) @@ -248,61 +248,58 @@ class SmsCommunicatorPlugin @Inject constructor( if (divided.isNotEmpty() && isCommand(divided[0].toUpperCase(Locale.getDefault()), receivedSms.phoneNumber)) { when (divided[0].toUpperCase(Locale.getDefault())) { - "BG" -> + "BG" -> if (divided.size == 1) processBG(receivedSms) else sendSMS(Sms(receivedSms.phoneNumber, resourceHelper.gs(R.string.wrongformat))) - "LOOP" -> + "LOOP" -> if (!remoteCommandsAllowed) sendSMS(Sms(receivedSms.phoneNumber, resourceHelper.gs(R.string.smscommunicator_remotecommandnotallowed))) else if (divided.size == 2 || divided.size == 3) processLOOP(divided, receivedSms) else sendSMS(Sms(receivedSms.phoneNumber, resourceHelper.gs(R.string.wrongformat))) - "TREATMENTS" -> - if (divided.size == 2) processTREATMENTS(divided, receivedSms) - else sendSMS(Sms(receivedSms.phoneNumber, resourceHelper.gs(R.string.wrongformat))) - "NSCLIENT" -> + "NSCLIENT" -> if (divided.size == 2) processNSCLIENT(divided, receivedSms) else sendSMS(Sms(receivedSms.phoneNumber, resourceHelper.gs(R.string.wrongformat))) - "PUMP" -> + "PUMP" -> if (!remoteCommandsAllowed && divided.size > 1) sendSMS(Sms(receivedSms.phoneNumber, resourceHelper.gs(R.string.smscommunicator_remotecommandnotallowed))) else if (divided.size <= 3) processPUMP(divided, receivedSms) else sendSMS(Sms(receivedSms.phoneNumber, resourceHelper.gs(R.string.wrongformat))) - "PROFILE" -> + "PROFILE" -> if (!remoteCommandsAllowed) sendSMS(Sms(receivedSms.phoneNumber, resourceHelper.gs(R.string.smscommunicator_remotecommandnotallowed))) else if (divided.size == 2 || divided.size == 3) processPROFILE(divided, receivedSms) else sendSMS(Sms(receivedSms.phoneNumber, resourceHelper.gs(R.string.wrongformat))) - "BASAL" -> + "BASAL" -> if (!remoteCommandsAllowed) sendSMS(Sms(receivedSms.phoneNumber, resourceHelper.gs(R.string.smscommunicator_remotecommandnotallowed))) else if (divided.size == 2 || divided.size == 3) processBASAL(divided, receivedSms) else sendSMS(Sms(receivedSms.phoneNumber, resourceHelper.gs(R.string.wrongformat))) - "EXTENDED" -> + "EXTENDED" -> if (!remoteCommandsAllowed) sendSMS(Sms(receivedSms.phoneNumber, resourceHelper.gs(R.string.smscommunicator_remotecommandnotallowed))) else if (divided.size == 2 || divided.size == 3) processEXTENDED(divided, receivedSms) else sendSMS(Sms(receivedSms.phoneNumber, resourceHelper.gs(R.string.wrongformat))) - "BOLUS" -> + "BOLUS" -> if (!remoteCommandsAllowed) sendSMS(Sms(receivedSms.phoneNumber, resourceHelper.gs(R.string.smscommunicator_remotecommandnotallowed))) - else if (divided.size == 2 && DateUtil.now() - lastRemoteBolusTime < minDistance) sendSMS(Sms(receivedSms.phoneNumber, resourceHelper.gs(R.string.smscommunicator_remotebolusnotallowed))) + else if (divided.size == 2 && dateUtil.now() - lastRemoteBolusTime < minDistance) sendSMS(Sms(receivedSms.phoneNumber, resourceHelper.gs(R.string.smscommunicator_remotebolusnotallowed))) else if (divided.size == 2 && pump.isSuspended()) sendSMS(Sms(receivedSms.phoneNumber, resourceHelper.gs(R.string.pumpsuspended))) else if (divided.size == 2 || divided.size == 3) processBOLUS(divided, receivedSms) else sendSMS(Sms(receivedSms.phoneNumber, resourceHelper.gs(R.string.wrongformat))) - "CARBS" -> + "CARBS" -> if (!remoteCommandsAllowed) sendSMS(Sms(receivedSms.phoneNumber, resourceHelper.gs(R.string.smscommunicator_remotecommandnotallowed))) else if (divided.size == 2 || divided.size == 3) processCARBS(divided, receivedSms) else sendSMS(Sms(receivedSms.phoneNumber, resourceHelper.gs(R.string.wrongformat))) - "CAL" -> + "CAL" -> if (!remoteCommandsAllowed) sendSMS(Sms(receivedSms.phoneNumber, resourceHelper.gs(R.string.smscommunicator_remotecommandnotallowed))) else if (divided.size == 2) processCAL(divided, receivedSms) else sendSMS(Sms(receivedSms.phoneNumber, resourceHelper.gs(R.string.wrongformat))) - "TARGET" -> + "TARGET" -> if (!remoteCommandsAllowed) sendSMS(Sms(receivedSms.phoneNumber, resourceHelper.gs(R.string.smscommunicator_remotecommandnotallowed))) else if (divided.size == 2) processTARGET(divided, receivedSms) else sendSMS(Sms(receivedSms.phoneNumber, resourceHelper.gs(R.string.wrongformat))) - "SMS" -> + "SMS" -> if (!remoteCommandsAllowed) sendSMS(Sms(receivedSms.phoneNumber, resourceHelper.gs(R.string.smscommunicator_remotecommandnotallowed))) else if (divided.size == 2) processSMS(divided, receivedSms) else sendSMS(Sms(receivedSms.phoneNumber, resourceHelper.gs(R.string.wrongformat))) - "HELP" -> + "HELP" -> if (divided.size == 1 || divided.size == 2) processHELP(divided, receivedSms) else sendSMS(Sms(receivedSms.phoneNumber, resourceHelper.gs(R.string.wrongformat))) - else -> + else -> if (messageToConfirm?.requester?.phoneNumber == receivedSms.phoneNumber) { messageToConfirm?.action(divided[0]) messageToConfirm = null @@ -313,24 +310,22 @@ class SmsCommunicatorPlugin @Inject constructor( } private fun processBG(receivedSms: Sms) { - val actualBG = iobCobCalculatorPlugin.actualBg() - val lastBG = iobCobCalculatorPlugin.lastBg() + val actualBG = iobCobCalculator.ads.actualBg() + val lastBG = iobCobCalculator.ads.lastBg() var reply = "" val units = profileFunction.getUnits() if (actualBG != null) { reply = resourceHelper.gs(R.string.sms_actualbg) + " " + actualBG.valueToUnitsString(units) + ", " } else if (lastBG != null) { - val agoMilliseconds = System.currentTimeMillis() - lastBG.timestamp + val agoMilliseconds = dateUtil.now() - lastBG.timestamp val agoMin = (agoMilliseconds / 60.0 / 1000.0).toInt() reply = resourceHelper.gs(R.string.sms_lastbg) + " " + lastBG.valueToUnitsString(units) + " " + String.format(resourceHelper.gs(R.string.sms_minago), agoMin) + ", " } val glucoseStatus = glucoseStatusProvider.glucoseStatusData if (glucoseStatus != null) reply += resourceHelper.gs(R.string.sms_delta) + " " + Profile.toUnitsString(glucoseStatus.delta, glucoseStatus.delta * Constants.MGDL_TO_MMOLL, units) + " " + units + ", " - activePlugin.activeTreatments.updateTotalIOBTreatments() - val bolusIob = activePlugin.activeTreatments.lastCalculationTreatments.round() - activePlugin.activeTreatments.updateTotalIOBTempBasals() - val basalIob = activePlugin.activeTreatments.lastCalculationTempBasals.round() - val cobInfo = iobCobCalculatorPlugin.getCobInfo(false, "SMS COB") + val bolusIob = iobCobCalculator.calculateIobFromBolus().round() + val basalIob = iobCobCalculator.calculateIobFromTempBasalsIncludingConvertedExtended().round() + val cobInfo = iobCobCalculator.getCobInfo(false, "SMS COB") reply += (resourceHelper.gs(R.string.sms_iob) + " " + DecimalFormatter.to2Decimal(bolusIob.iob + basalIob.basaliob) + "U (" + resourceHelper.gs(R.string.sms_bolus) + " " + DecimalFormatter.to2Decimal(bolusIob.iob) + "U " + resourceHelper.gs(R.string.sms_basal) + " " + DecimalFormatter.to2Decimal(basalIob.basaliob) + "U), " @@ -348,7 +343,7 @@ class SmsCommunicatorPlugin @Inject constructor( receivedSms.processed = true messageToConfirm = AuthRequest(injector, receivedSms, reply, passCode, object : SmsAction() { override fun run() { - uel.log(Action.SMS_LOOP_DISABLED) + uel.log(Action.LOOP_DISABLED, Sources.SMS) loopPlugin.setPluginEnabled(PluginType.LOOP, false) commandQueue.cancelTempBasal(true, object : Callback() { override fun run() { @@ -372,7 +367,7 @@ class SmsCommunicatorPlugin @Inject constructor( receivedSms.processed = true messageToConfirm = AuthRequest(injector, receivedSms, reply, passCode, object : SmsAction() { override fun run() { - uel.log(Action.SMS_LOOP_ENABLED) + uel.log(Action.LOOP_ENABLED, Sources.SMS) loopPlugin.setPluginEnabled(PluginType.LOOP, true) sendSMS(Sms(receivedSms.phoneNumber, resourceHelper.gs(R.string.smscommunicator_loophasbeenenabled))) rxBus.send(EventRefreshOverview("SMS_LOOP_START")) @@ -399,7 +394,7 @@ class SmsCommunicatorPlugin @Inject constructor( receivedSms.processed = true messageToConfirm = AuthRequest(injector, receivedSms, reply, passCode, object : SmsAction() { override fun run() { - uel.log(Action.SMS_LOOP_RESUME) + uel.log(Action.RESUME, Sources.SMS) loopPlugin.suspendTo(0L) rxBus.send(EventRefreshOverview("SMS_LOOP_RESUME")) commandQueue.cancelTempBasal(true, object : Callback() { @@ -432,11 +427,11 @@ class SmsCommunicatorPlugin @Inject constructor( receivedSms.processed = true messageToConfirm = AuthRequest(injector, receivedSms, reply, passCode, object : SmsAction(duration) { override fun run() { - uel.log(Action.SMS_LOOP_SUSPEND) + uel.log(Action.SUSPEND, Sources.SMS) commandQueue.cancelTempBasal(true, object : Callback() { override fun run() { if (result.success) { - loopPlugin.suspendTo(System.currentTimeMillis() + anInteger() * 60L * 1000) + loopPlugin.suspendTo(dateUtil.now() + anInteger() * 60L * 1000) loopPlugin.createOfflineEvent(anInteger() * 60) rxBus.send(EventRefreshOverview("SMS_LOOP_SUSPENDED")) val replyText = resourceHelper.gs(R.string.smscommunicator_loopsuspended) + " " + @@ -458,16 +453,6 @@ class SmsCommunicatorPlugin @Inject constructor( } } - private fun processTREATMENTS(divided: Array, receivedSms: Sms) { - if (divided[1].toUpperCase(Locale.getDefault()) == "REFRESH") { - activePlugin.activeTreatments.service.resetTreatments() - rxBus.send(EventNSClientRestart()) - sendSMS(Sms(receivedSms.phoneNumber, "TREATMENTS REFRESH SENT")) - receivedSms.processed = true - } else - sendSMS(Sms(receivedSms.phoneNumber, resourceHelper.gs(R.string.wrongformat))) - } - private fun processNSCLIENT(divided: Array, receivedSms: Sms) { if (divided[1].toUpperCase(Locale.getDefault()) == "RESTART") { rxBus.send(EventNSClientRestart()) @@ -516,7 +501,7 @@ class SmsCommunicatorPlugin @Inject constructor( receivedSms.processed = true messageToConfirm = AuthRequest(injector, receivedSms, reply, passCode, object : SmsAction() { override fun run() { - uel.log(Action.SMS_PUMP_CONNECT) + uel.log(Action.RECONNECT, Sources.SMS) commandQueue.cancelTempBasal(true, object : Callback() { override fun run() { if (!result.success) { @@ -545,7 +530,7 @@ class SmsCommunicatorPlugin @Inject constructor( receivedSms.processed = true messageToConfirm = AuthRequest(injector, receivedSms, reply, passCode, object : SmsAction() { override fun run() { - uel.log(Action.SMS_PUMP_DISCONNECT) + uel.log(Action.DISCONNECT, Sources.SMS) val profile = profileFunction.getProfile() loopPlugin.disconnectPump(duration, profile) rxBus.send(EventRefreshOverview("SMS_PUMP_DISCONNECT")) @@ -560,7 +545,7 @@ class SmsCommunicatorPlugin @Inject constructor( } private fun processPROFILE(divided: Array, receivedSms: Sms) { // load profiles - val anInterface = activePlugin.activeProfileInterface + val anInterface = activePlugin.activeProfileSource val store = anInterface.profile if (store == null) { sendSMS(Sms(receivedSms.phoneNumber, resourceHelper.gs(R.string.notconfigured))) @@ -599,10 +584,11 @@ class SmsCommunicatorPlugin @Inject constructor( val finalPercentage = percentage messageToConfirm = AuthRequest(injector, receivedSms, reply, passCode, object : SmsAction(list[pIndex - 1] as String, finalPercentage) { override fun run() { - activePlugin.activeTreatments.doProfileSwitch(store, list[pIndex - 1] as String, 0, finalPercentage, 0, DateUtil.now()) + activePlugin.activeTreatments.doProfileSwitch(store, list[pIndex - 1] as String, 0, finalPercentage, 0, dateUtil.now()) val replyText = resourceHelper.gs(R.string.profileswitchcreated) sendSMS(Sms(receivedSms.phoneNumber, replyText)) - uel.log(Action.SMS_PROFILE, ValueWithUnit(R.string.profileswitchcreated, Units.R_String)) + uel.log(Action.PROFILE_SWITCH, Sources.SMS, resourceHelper.gs(R.string.profileswitchcreated), + ValueWithUnit.SimpleString(resourceHelper.gsNotLocalised(R.string.profileswitchcreated))) } }) } @@ -624,12 +610,14 @@ class SmsCommunicatorPlugin @Inject constructor( var replyText = resourceHelper.gs(R.string.smscommunicator_tempbasalcanceled) replyText += "\n" + activePlugin.activePump.shortStatus(true) sendSMSToAllNumbers(Sms(receivedSms.phoneNumber, replyText)) - uel.log(Action.SMS_BASAL, activePlugin.activePump.shortStatus(true), ValueWithUnit(R.string.smscommunicator_tempbasalcanceled, Units.R_String)) + uel.log(Action.TEMP_BASAL, Sources.SMS, activePlugin.activePump.shortStatus(true) + "\n" + resourceHelper.gs(R.string.smscommunicator_tempbasalcanceled), + ValueWithUnit.SimpleString(resourceHelper.gsNotLocalised(R.string.smscommunicator_tempbasalcanceled))) } else { var replyText = resourceHelper.gs(R.string.smscommunicator_tempbasalcancelfailed) replyText += "\n" + activePlugin.activePump.shortStatus(true) sendSMS(Sms(receivedSms.phoneNumber, replyText)) - uel.log(Action.SMS_BASAL, activePlugin.activePump.shortStatus(true), ValueWithUnit(R.string.smscommunicator_tempbasalcancelfailed, Units.R_String)) + uel.log(Action.TEMP_BASAL, Sources.SMS, activePlugin.activePump.shortStatus(true) + "\n" + resourceHelper.gs(R.string.smscommunicator_tempbasalcancelfailed), + ValueWithUnit.SimpleString(resourceHelper.gsNotLocalised(R.string.smscommunicator_tempbasalcancelfailed))) } } }) @@ -637,7 +625,7 @@ class SmsCommunicatorPlugin @Inject constructor( }) } else if (divided[1].endsWith("%")) { var tempBasalPct = SafeParse.stringToInt(StringUtils.removeEnd(divided[1], "%")) - val durationStep = activePlugin.activePump.model().tbrSettings.durationStep + val durationStep = activePlugin.activePump.model().tbrSettings?.durationStep ?: 60 var duration = 30 if (divided.size > 2) duration = SafeParse.stringToInt(divided[2]) val profile = profileFunction.getProfile() @@ -651,21 +639,28 @@ class SmsCommunicatorPlugin @Inject constructor( receivedSms.processed = true messageToConfirm = AuthRequest(injector, receivedSms, reply, passCode, object : SmsAction(tempBasalPct, duration) { override fun run() { - commandQueue.tempBasalPercent(anInteger(), secondInteger(), true, profile, object : Callback() { + commandQueue.tempBasalPercent(anInteger(), secondInteger(), true, profile, PumpSync.TemporaryBasalType.NORMAL, object : Callback() { override fun run() { if (result.success) { var replyText = if (result.isPercent) String.format(resourceHelper.gs(R.string.smscommunicator_tempbasalset_percent), result.percent, result.duration) else String.format(resourceHelper.gs(R.string.smscommunicator_tempbasalset), result.absolute, result.duration) replyText += "\n" + activePlugin.activePump.shortStatus(true) sendSMSToAllNumbers(Sms(receivedSms.phoneNumber, replyText)) if (result.isPercent) - uel.log(Action.SMS_BASAL, activePlugin.activePump.shortStatus(true), ValueWithUnit(R.string.smscommunicator_tempbasalset_percent, 2), ValueWithUnit(result.percent, Units.Percent), ValueWithUnit(result.duration, Units.M)) + uel.log(Action.TEMP_BASAL, Sources.SMS, + activePlugin.activePump.shortStatus(true) + "\n" + resourceHelper.gs(R.string.smscommunicator_tempbasalset_percent, result.percent, result.duration), + ValueWithUnit.Percent(result.percent), + ValueWithUnit.Minute(result.duration)) else - uel.log(Action.SMS_BASAL, activePlugin.activePump.shortStatus(true), ValueWithUnit(R.string.smscommunicator_tempbasalset, 2), ValueWithUnit(result.absolute, Units.U_H), ValueWithUnit(result.duration, Units.M)) + uel.log(Action.TEMP_BASAL, Sources.SMS, + activePlugin.activePump.shortStatus(true) + "\n" + resourceHelper.gs(R.string.smscommunicator_tempbasalset, result.absolute, result.duration), + ValueWithUnit.UnitPerHour(result.absolute), + ValueWithUnit.Minute(result.duration)) } else { var replyText = resourceHelper.gs(R.string.smscommunicator_tempbasalfailed) replyText += "\n" + activePlugin.activePump.shortStatus(true) sendSMS(Sms(receivedSms.phoneNumber, replyText)) - uel.log(Action.SMS_BASAL, activePlugin.activePump.shortStatus(true), ValueWithUnit(R.string.smscommunicator_tempbasalfailed, Units.R_String)) + uel.log(Action.TEMP_BASAL, Sources.SMS, activePlugin.activePump.shortStatus(true) + "\n" + resourceHelper.gs(R.string.smscommunicator_tempbasalfailed), + ValueWithUnit.SimpleString(resourceHelper.gsNotLocalised(R.string.smscommunicator_tempbasalfailed))) } } }) @@ -674,7 +669,7 @@ class SmsCommunicatorPlugin @Inject constructor( } } else { var tempBasal = SafeParse.stringToDouble(divided[1]) - val durationStep = activePlugin.activePump.model().tbrSettings.durationStep + val durationStep = activePlugin.activePump.model().tbrSettings?.durationStep ?: 60 var duration = 30 if (divided.size > 2) duration = SafeParse.stringToInt(divided[2]) val profile = profileFunction.getProfile() @@ -688,7 +683,7 @@ class SmsCommunicatorPlugin @Inject constructor( receivedSms.processed = true messageToConfirm = AuthRequest(injector, receivedSms, reply, passCode, object : SmsAction(tempBasal, duration) { override fun run() { - commandQueue.tempBasalAbsolute(aDouble(), secondInteger(), true, profile, object : Callback() { + commandQueue.tempBasalAbsolute(aDouble(), secondInteger(), true, profile, PumpSync.TemporaryBasalType.NORMAL, object : Callback() { override fun run() { if (result.success) { var replyText = if (result.isPercent) String.format(resourceHelper.gs(R.string.smscommunicator_tempbasalset_percent), result.percent, result.duration) @@ -696,14 +691,19 @@ class SmsCommunicatorPlugin @Inject constructor( replyText += "\n" + activePlugin.activePump.shortStatus(true) sendSMSToAllNumbers(Sms(receivedSms.phoneNumber, replyText)) if (result.isPercent) - uel.log(Action.SMS_BASAL, activePlugin.activePump.shortStatus(true), ValueWithUnit(R.string.smscommunicator_tempbasalset_percent, 2), ValueWithUnit(result.percent, Units.Percent), ValueWithUnit(result.duration, Units.M)) + uel.log(Action.TEMP_BASAL, Sources.SMS, activePlugin.activePump.shortStatus(true) + "\n" + resourceHelper.gs(R.string.smscommunicator_tempbasalset_percent, result.percent, result.duration), + ValueWithUnit.Percent(result.percent), + ValueWithUnit.Minute(result.duration)) else - uel.log(Action.SMS_BASAL, activePlugin.activePump.shortStatus(true), ValueWithUnit(R.string.smscommunicator_tempbasalset, 2), ValueWithUnit(result.absolute, Units.U_H), ValueWithUnit(result.duration, Units.M)) + uel.log(Action.TEMP_BASAL, Sources.SMS, activePlugin.activePump.shortStatus(true) + "\n" + resourceHelper.gs(R.string.smscommunicator_tempbasalset, result.absolute, result.duration), + ValueWithUnit.UnitPerHour(result.absolute), + ValueWithUnit.Minute(result.duration)) } else { var replyText = resourceHelper.gs(R.string.smscommunicator_tempbasalfailed) replyText += "\n" + activePlugin.activePump.shortStatus(true) sendSMS(Sms(receivedSms.phoneNumber, replyText)) - uel.log(Action.SMS_BASAL, activePlugin.activePump.shortStatus(true), ValueWithUnit(R.string.smscommunicator_tempbasalfailed, Units.R_String)) + uel.log(Action.TEMP_BASAL, Sources.SMS, activePlugin.activePump.shortStatus(true) + "\n" + resourceHelper.gs(R.string.smscommunicator_tempbasalfailed), + ValueWithUnit.SimpleString(resourceHelper.gsNotLocalised(R.string.smscommunicator_tempbasalfailed))) } } }) @@ -730,7 +730,8 @@ class SmsCommunicatorPlugin @Inject constructor( var replyText = resourceHelper.gs(R.string.smscommunicator_extendedcancelfailed) replyText += "\n" + activePlugin.activePump.shortStatus(true) sendSMS(Sms(receivedSms.phoneNumber, replyText)) - uel.log(Action.SMS_EXTENDED_BOLUS, activePlugin.activePump.shortStatus(true), ValueWithUnit(R.string.smscommunicator_extendedcanceled, Units.R_String)) + uel.log(Action.EXTENDED_BOLUS, Sources.SMS, activePlugin.activePump.shortStatus(true) + "\n" + resourceHelper.gs(R.string.smscommunicator_extendedcanceled), + ValueWithUnit.SimpleString(resourceHelper.gsNotLocalised(R.string.smscommunicator_extendedcanceled))) } } }) @@ -757,16 +758,20 @@ class SmsCommunicatorPlugin @Inject constructor( replyText += "\n" + activePlugin.activePump.shortStatus(true) sendSMSToAllNumbers(Sms(receivedSms.phoneNumber, replyText)) if (config.APS) - uel.log(Action.SMS_EXTENDED_BOLUS, activePlugin.activePump.shortStatus(true), ValueWithUnit(R.string.smscommunicator_extendedset, 2), ValueWithUnit(aDouble - ?: 0.0, Units.U), ValueWithUnit(duration, Units.M), ValueWithUnit(R.string.loopsuspended, Units.R_String)) + uel.log(Action.EXTENDED_BOLUS, Sources.SMS, activePlugin.activePump.shortStatus(true) + "\n" + resourceHelper.gs(R.string.smscommunicator_extendedset, aDouble, duration) + " / " + resourceHelper.gs(R.string.loopsuspended), + ValueWithUnit.Insulin(aDouble ?: 0.0), + ValueWithUnit.Minute(duration), + ValueWithUnit.SimpleString(resourceHelper.gsNotLocalised(R.string.loopsuspended))) else - uel.log(Action.SMS_EXTENDED_BOLUS, activePlugin.activePump.shortStatus(true), ValueWithUnit(R.string.smscommunicator_extendedset, 2), ValueWithUnit(aDouble - ?: 0.0, Units.U), ValueWithUnit(duration, Units.M)) + uel.log(Action.EXTENDED_BOLUS, Sources.SMS, activePlugin.activePump.shortStatus(true) + "\n" + resourceHelper.gs(R.string.smscommunicator_extendedset, aDouble, duration), + ValueWithUnit.Insulin(aDouble ?: 0.0), + ValueWithUnit.Minute(duration)) } else { var replyText = resourceHelper.gs(R.string.smscommunicator_extendedfailed) replyText += "\n" + activePlugin.activePump.shortStatus(true) sendSMS(Sms(receivedSms.phoneNumber, replyText)) - uel.log(Action.SMS_EXTENDED_BOLUS, activePlugin.activePump.shortStatus(true), ValueWithUnit(R.string.smscommunicator_extendedfailed, Units.R_String)) + uel.log(Action.EXTENDED_BOLUS, Sources.SMS, activePlugin.activePump.shortStatus(true) + "\n" + resourceHelper.gs(R.string.smscommunicator_extendedfailed), + ValueWithUnit.SimpleString(resourceHelper.gsNotLocalised(R.string.smscommunicator_extendedfailed))) } } }) @@ -793,7 +798,6 @@ class SmsCommunicatorPlugin @Inject constructor( override fun run() { val detailedBolusInfo = DetailedBolusInfo() detailedBolusInfo.insulin = aDouble() - detailedBolusInfo.source = Source.USER commandQueue.bolus(detailedBolusInfo, object : Callback() { override fun run() { val resultSuccess = result.success @@ -806,7 +810,7 @@ class SmsCommunicatorPlugin @Inject constructor( else String.format(resourceHelper.gs(R.string.smscommunicator_bolusdelivered), resultBolusDelivered) replyText += "\n" + activePlugin.activePump.shortStatus(true) - lastRemoteBolusTime = DateUtil.now() + lastRemoteBolusTime = dateUtil.now() if (isMeal) { profileFunction.getProfile()?.let { currentProfile -> var eatingSoonTTDuration = sp.getInt(R.string.key_eatingsoon_duration, Constants.defaultEatingSoonTTDuration) @@ -821,16 +825,16 @@ class SmsCommunicatorPlugin @Inject constructor( else -> Constants.defaultEatingSoonTTmgdl } disposable += repository.runTransactionForResult(InsertTemporaryTargetAndCancelCurrentTransaction( - timestamp = System.currentTimeMillis(), + timestamp = dateUtil.now(), duration = TimeUnit.MINUTES.toMillis(eatingSoonTTDuration.toLong()), reason = TemporaryTarget.Reason.EATING_SOON, lowTarget = Profile.toMgdl(eatingSoonTT, profileFunction.getUnits()), highTarget = Profile.toMgdl(eatingSoonTT, profileFunction.getUnits()) )).subscribe({ result -> - result.inserted.forEach { nsUpload.uploadTempTarget(it) } - result.updated.forEach { nsUpload.updateTempTarget(it) } + result.inserted.forEach { aapsLogger.debug(LTag.DATABASE, "Inserted temp target $it") } + result.updated.forEach { aapsLogger.debug(LTag.DATABASE, "Updated temp target $it") } }, { - aapsLogger.error(LTag.BGSOURCE, "Error while saving temporary target", it) + aapsLogger.error(LTag.DATABASE, "Error while saving temporary target", it) }) val tt = if (currentProfile.units == Constants.MMOL) { DecimalFormatter.to1Decimal(eatingSoonTT) @@ -839,12 +843,13 @@ class SmsCommunicatorPlugin @Inject constructor( } } sendSMSToAllNumbers(Sms(receivedSms.phoneNumber, replyText)) - uel.log(Action.SMS_BOLUS, replyText) + uel.log(Action.BOLUS, Sources.SMS, replyText) } else { var replyText = resourceHelper.gs(R.string.smscommunicator_bolusfailed) replyText += "\n" + activePlugin.activePump.shortStatus(true) sendSMS(Sms(receivedSms.phoneNumber, replyText)) - uel.log(Action.SMS_BOLUS, activePlugin.activePump.shortStatus(true), ValueWithUnit(R.string.smscommunicator_bolusfailed, Units.R_String)) + uel.log(Action.BOLUS, Sources.SMS, activePlugin.activePump.shortStatus(true) + "\n" + resourceHelper.gs(R.string.smscommunicator_bolusfailed), + ValueWithUnit.SimpleString(resourceHelper.gsNotLocalised(R.string.smscommunicator_bolusfailed))) } } }) @@ -855,11 +860,30 @@ class SmsCommunicatorPlugin @Inject constructor( } else sendSMS(Sms(receivedSms.phoneNumber, resourceHelper.gs(R.string.wrongformat))) } + private fun toTodayTime(hh_colon_mm: String): Long { + val p = Pattern.compile("(\\d+):(\\d+)( a.m.| p.m.| AM| PM|AM|PM|)") + val m = p.matcher(hh_colon_mm) + var retval: Long = 0 + if (m.find()) { + var hours = SafeParse.stringToInt(m.group(1)) + val minutes = SafeParse.stringToInt(m.group(2)) + if ((m.group(3) == " a.m." || m.group(3) == " AM" || m.group(3) == "AM") && m.group(1) == "12") hours -= 12 + if ((m.group(3) == " p.m." || m.group(3) == " PM" || m.group(3) == "PM") && m.group(1) != "12") hours += 12 + val t = DateTime() + .withHourOfDay(hours) + .withMinuteOfHour(minutes) + .withSecondOfMinute(0) + .withMillisOfSecond(0) + retval = t.millis + } + return retval + } + private fun processCARBS(divided: Array, receivedSms: Sms) { var grams = SafeParse.stringToInt(divided[1]) - var time = DateUtil.now() + var time = dateUtil.now() if (divided.size > 2) { - time = DateUtil.toTodayTime(divided[2].toUpperCase(Locale.getDefault())) + time = toTodayTime(divided[2].toUpperCase(Locale.getDefault())) if (time == 0L) { sendSMS(Sms(receivedSms.phoneNumber, resourceHelper.gs(R.string.wrongformat))) return @@ -875,34 +899,24 @@ class SmsCommunicatorPlugin @Inject constructor( override fun run() { val detailedBolusInfo = DetailedBolusInfo() detailedBolusInfo.carbs = anInteger().toDouble() - detailedBolusInfo.source = Source.USER - detailedBolusInfo.date = secondLong() - if (activePlugin.activePump.pumpDescription.storesCarbInfo) { - commandQueue.bolus(detailedBolusInfo, object : Callback() { - override fun run() { - if (result.success) { - var replyText = String.format(resourceHelper.gs(R.string.smscommunicator_carbsset), anInteger) - replyText += "\n" + activePlugin.activePump.shortStatus(true) - sendSMSToAllNumbers(Sms(receivedSms.phoneNumber, replyText)) - uel.log(Action.SMS_CARBS, activePlugin.activePump.shortStatus(true), ValueWithUnit(R.string.smscommunicator_carbsset, 1), ValueWithUnit(anInteger - ?: 0, Units.G)) - } else { - var replyText = resourceHelper.gs(R.string.smscommunicator_carbsfailed, anInteger) - replyText += "\n" + activePlugin.activePump.shortStatus(true) - sendSMS(Sms(receivedSms.phoneNumber, replyText)) - uel.log(Action.SMS_CARBS, activePlugin.activePump.shortStatus(true), ValueWithUnit(R.string.smscommunicator_carbsfailed, 1), ValueWithUnit(anInteger - ?: 0, Units.G)) - } + detailedBolusInfo.timestamp = secondLong() + commandQueue.bolus(detailedBolusInfo, object : Callback() { + override fun run() { + if (result.success) { + var replyText = String.format(resourceHelper.gs(R.string.smscommunicator_carbsset), anInteger) + replyText += "\n" + activePlugin.activePump.shortStatus(true) + sendSMSToAllNumbers(Sms(receivedSms.phoneNumber, replyText)) + uel.log(Action.CARBS, Sources.SMS, activePlugin.activePump.shortStatus(true) + ": " + resourceHelper.gs(R.string.smscommunicator_carbsset, anInteger), + ValueWithUnit.Gram(anInteger ?: 0)) + } else { + var replyText = resourceHelper.gs(R.string.smscommunicator_carbsfailed, anInteger) + replyText += "\n" + activePlugin.activePump.shortStatus(true) + sendSMS(Sms(receivedSms.phoneNumber, replyText)) + uel.log(Action.CARBS, Sources.SMS, activePlugin.activePump.shortStatus(true) + ": " + resourceHelper.gs(R.string.smscommunicator_carbsfailed, anInteger), + ValueWithUnit.Gram(anInteger ?: 0)) } - }) - } else { - activePlugin.activeTreatments.addToHistoryTreatment(detailedBolusInfo, true) - var replyText = String.format(resourceHelper.gs(R.string.smscommunicator_carbsset), anInteger) - replyText += "\n" + activePlugin.activePump.shortStatus(true) - sendSMSToAllNumbers(Sms(receivedSms.phoneNumber, replyText)) - uel.log(Action.SMS_CARBS, activePlugin.activePump.shortStatus(true), ValueWithUnit(R.string.smscommunicator_carbsset, 1), ValueWithUnit(anInteger - ?: 0, Units.G)) - } + } + }) } }) } @@ -956,22 +970,23 @@ class SmsCommunicatorPlugin @Inject constructor( tt = Profile.toCurrentUnits(profileFunction, tt) tt = if (tt > 0) tt else if (units == Constants.MMOL) defaultTargetMMOL else defaultTargetMGDL disposable += repository.runTransactionForResult(InsertTemporaryTargetAndCancelCurrentTransaction( - timestamp = System.currentTimeMillis(), + timestamp = dateUtil.now(), duration = TimeUnit.MINUTES.toMillis(ttDuration.toLong()), reason = TemporaryTarget.Reason.EATING_SOON, lowTarget = Profile.toMgdl(tt, profileFunction.getUnits()), highTarget = Profile.toMgdl(tt, profileFunction.getUnits()) )).subscribe({ result -> - result.inserted.forEach { nsUpload.uploadTempTarget(it) } - result.updated.forEach { nsUpload.updateTempTarget(it) } + result.inserted.forEach { aapsLogger.debug(LTag.DATABASE, "Inserted temp target $it") } + result.updated.forEach { aapsLogger.debug(LTag.DATABASE, "Updated temp target $it") } }, { - aapsLogger.error(LTag.BGSOURCE, "Error while saving temporary target", it) + aapsLogger.error(LTag.DATABASE, "Error while saving temporary target", it) }) val ttString = if (units == Constants.MMOL) DecimalFormatter.to1Decimal(tt) else DecimalFormatter.to0Decimal(tt) val replyText = String.format(resourceHelper.gs(R.string.smscommunicator_tt_set), ttString, ttDuration) sendSMSToAllNumbers(Sms(receivedSms.phoneNumber, replyText)) - //uel.log(Action.SMS_TT, ValueWithUnit(R.string.smscommunicator_tt_set, 2), ValueWithUnit(tt, units), ValueWithUnit(ttDuration, Units.M)) - uel.log(Action.SMS_TT, ValueWithUnit(tt, units), ValueWithUnit(ttDuration, Units.M)) + uel.log(Action.TT, Sources.SMS, + ValueWithUnit.fromGlucoseUnit(tt, units), + ValueWithUnit.Minute(ttDuration)) } }) } else if (isStop) { @@ -980,15 +995,16 @@ class SmsCommunicatorPlugin @Inject constructor( receivedSms.processed = true messageToConfirm = AuthRequest(injector, receivedSms, reply, passCode, object : SmsAction() { override fun run() { - disposable += repository.runTransactionForResult(CancelCurrentTemporaryTargetIfAnyTransaction(dateUtil._now())) + disposable += repository.runTransactionForResult(CancelCurrentTemporaryTargetIfAnyTransaction(dateUtil.now())) .subscribe({ result -> - result.updated.forEach { nsUpload.updateTempTarget(it) } + result.updated.forEach { aapsLogger.debug(LTag.DATABASE, "Updated temp target $it") } }, { - aapsLogger.error(LTag.BGSOURCE, "Error while saving temporary target", it) + aapsLogger.error(LTag.DATABASE, "Error while saving temporary target", it) }) val replyText = String.format(resourceHelper.gs(R.string.smscommunicator_tt_canceled)) sendSMSToAllNumbers(Sms(receivedSms.phoneNumber, replyText)) - uel.log(Action.SMS_TT, ValueWithUnit(R.string.smscommunicator_tt_canceled, Units.R_String)) + uel.log(Action.CANCEL_TT, Sources.SMS, resourceHelper.gs(R.string.smscommunicator_tt_canceled), + ValueWithUnit.SimpleString(resourceHelper.gsNotLocalised(R.string.smscommunicator_tt_canceled))) } }) } else @@ -1007,7 +1023,8 @@ class SmsCommunicatorPlugin @Inject constructor( sp.putBoolean(R.string.key_smscommunicator_remotecommandsallowed, false) val replyText = String.format(resourceHelper.gs(R.string.smscommunicator_stoppedsms)) sendSMSToAllNumbers(Sms(receivedSms.phoneNumber, replyText)) - uel.log(Action.SMS_SMS, ValueWithUnit(R.string.smscommunicator_stoppedsms, Units.R_String)) + uel.log(Action.STOP_SMS, Sources.SMS, resourceHelper.gs(R.string.smscommunicator_stoppedsms), + ValueWithUnit.SimpleString(resourceHelper.gsNotLocalised(R.string.smscommunicator_stoppedsms))) } }) } else sendSMS(Sms(receivedSms.phoneNumber, resourceHelper.gs(R.string.wrongformat))) @@ -1026,9 +1043,11 @@ class SmsCommunicatorPlugin @Inject constructor( if (result) resourceHelper.gs(R.string.smscommunicator_calibrationsent) else resourceHelper.gs(R.string.smscommunicator_calibrationfailed) sendSMSToAllNumbers(Sms(receivedSms.phoneNumber, replyText)) if (result) - uel.log(Action.SMS_CAL, ValueWithUnit(R.string.smscommunicator_calibrationsent, Units.R_String)) + uel.log(Action.CALIBRATION, Sources.SMS, resourceHelper.gs(R.string.smscommunicator_calibrationsent), + ValueWithUnit.SimpleString(resourceHelper.gsNotLocalised(R.string.smscommunicator_calibrationsent))) else - uel.log(Action.SMS_CAL, ValueWithUnit(R.string.smscommunicator_calibrationfailed, Units.R_String)) + uel.log(Action.CALIBRATION, Sources.SMS, resourceHelper.gs(R.string.smscommunicator_calibrationfailed), + ValueWithUnit.SimpleString(resourceHelper.gsNotLocalised(R.string.smscommunicator_calibrationfailed))) } }) } else sendSMS(Sms(receivedSms.phoneNumber, resourceHelper.gs(R.string.wrongformat))) diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/smsCommunicator/activities/SmsCommunicatorOtpActivity.kt b/app/src/main/java/info/nightscout/androidaps/plugins/general/smsCommunicator/activities/SmsCommunicatorOtpActivity.kt index 848dc05faf..bc81bc1f7d 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/smsCommunicator/activities/SmsCommunicatorOtpActivity.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/smsCommunicator/activities/SmsCommunicatorOtpActivity.kt @@ -14,7 +14,8 @@ import com.google.common.primitives.Ints.min import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel import info.nightscout.androidaps.R import info.nightscout.androidaps.activities.NoSplashAppCompatActivity -import info.nightscout.androidaps.database.entities.UserEntry.* +import info.nightscout.androidaps.database.entities.UserEntry.Action +import info.nightscout.androidaps.database.entities.UserEntry.Sources import info.nightscout.androidaps.databinding.ActivitySmscommunicatorOtpBinding import info.nightscout.androidaps.logging.UserEntryLogger import info.nightscout.androidaps.plugins.bus.RxBusWrapper @@ -73,7 +74,7 @@ class SmsCommunicatorOtpActivity : NoSplashAppCompatActivity() { resourceHelper.gs(R.string.smscommunicator_otp_reset_title), resourceHelper.gs(R.string.smscommunicator_otp_reset_prompt), Runnable { - uel.log(Action.OTP_RESET) + uel.log(Action.OTP_RESET, Sources.SMS) otp.ensureKey(true) updateGui() ToastUtils.Long.infoToast(this, resourceHelper.gs(R.string.smscommunicator_otp_reset_successful)) @@ -89,7 +90,7 @@ class SmsCommunicatorOtpActivity : NoSplashAppCompatActivity() { val clip = ClipData.newPlainText("OTP Secret", otp.provisioningSecret()) clipboard.primaryClip = clip ToastUtils.Long.infoToast(this, resourceHelper.gs(R.string.smscommunicator_otp_export_successful)) - uel.log(Action.OTP_EXPORT) + uel.log(Action.OTP_EXPORT, Sources.SMS) }) true diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/smsCommunicator/otp/OneTimePassword.kt b/app/src/main/java/info/nightscout/androidaps/plugins/general/smsCommunicator/otp/OneTimePassword.kt index 68018f8f9f..77470340a1 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/smsCommunicator/otp/OneTimePassword.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/smsCommunicator/otp/OneTimePassword.kt @@ -18,7 +18,8 @@ import javax.inject.Singleton @Singleton class OneTimePassword @Inject constructor( private val sp: SP, - private val resourceHelper: ResourceHelper + private val resourceHelper: ResourceHelper, + private val dateUtil: DateUtil ) { private var key: SecretKey? = null @@ -85,7 +86,7 @@ class OneTimePassword @Inject constructor( return OneTimePasswordValidationResult.ERROR_WRONG_PIN } - val counter: Long = DateUtil.now() / 30000L + val counter: Long = dateUtil.now() / 30000L val acceptableTokens: MutableList = mutableListOf(generateOneTimePassword(counter)) for (i in 0 until Constants.OTP_ACCEPT_OLD_TOKENS_COUNT) { diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/tidepool/comm/TidepoolUploader.kt b/app/src/main/java/info/nightscout/androidaps/plugins/general/tidepool/comm/TidepoolUploader.kt index faaa1b40d6..c7bb146343 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/tidepool/comm/TidepoolUploader.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/tidepool/comm/TidepoolUploader.kt @@ -4,9 +4,8 @@ import android.content.Context import android.os.PowerManager import android.os.SystemClock import info.nightscout.androidaps.BuildConfig -import info.nightscout.androidaps.MainApp import info.nightscout.androidaps.R -import info.nightscout.androidaps.interfaces.ActivePluginProvider +import info.nightscout.androidaps.interfaces.ActivePlugin import info.nightscout.androidaps.logging.AAPSLogger import info.nightscout.androidaps.logging.LTag import info.nightscout.androidaps.plugins.bus.RxBusWrapper @@ -17,8 +16,8 @@ import info.nightscout.androidaps.plugins.general.tidepool.messages.DatasetReply import info.nightscout.androidaps.plugins.general.tidepool.messages.OpenDatasetRequestMessage import info.nightscout.androidaps.plugins.general.tidepool.messages.UploadReplyMessage import info.nightscout.androidaps.utils.DateUtil -import info.nightscout.androidaps.utils.alertDialogs.OKDialog import info.nightscout.androidaps.utils.T +import info.nightscout.androidaps.utils.alertDialogs.OKDialog import info.nightscout.androidaps.utils.resources.ResourceHelper import info.nightscout.androidaps.utils.sharedPreferences.SP import okhttp3.MediaType.Companion.toMediaTypeOrNull @@ -34,17 +33,18 @@ import javax.inject.Singleton class TidepoolUploader @Inject constructor( private val aapsLogger: AAPSLogger, private val rxBus: RxBusWrapper, - private val mainApp: MainApp, + private val ctx: Context, private val resourceHelper: ResourceHelper, private val sp: SP, private val uploadChunk: UploadChunk, - private val activePlugin: ActivePluginProvider, + private val activePlugin: ActivePlugin, private val dateUtil: DateUtil ) { private var wl: PowerManager.WakeLock? = null companion object { + private const val INTEGRATION_BASE_URL = "https://int-api.tidepool.org" private const val PRODUCTION_BASE_URL = "https://api.tidepool.org" internal const val VERSION = "0.0.1" @@ -151,7 +151,7 @@ class TidepoolUploader @Inject constructor( if (session.datasetReply == null) { rxBus.send(EventTidepoolStatus(("Creating new dataset"))) val call = session.service.openDataSet(session.token!!, session.authReply!!.userid!!, - OpenDatasetRequestMessage(activePlugin.activePump.serialNumber()).getBody()) + OpenDatasetRequestMessage(activePlugin.activePump.serialNumber(), dateUtil).getBody()) call.enqueue(TidepoolCallback(aapsLogger, rxBus, session, "Open New Dataset", { connectionStatus = ConnectionStatus.CONNECTED rxBus.send(EventTidepoolStatus(("New dataset OK"))) @@ -232,7 +232,7 @@ class TidepoolUploader @Inject constructor( } private fun uploadNext() { - if (uploadChunk.getLastEnd() < DateUtil.now() - T.mins(1).msecs()) { + if (uploadChunk.getLastEnd() < dateUtil.now() - T.mins(1).msecs()) { SystemClock.sleep(3000) aapsLogger.debug(LTag.TIDEPOOL, "Restarting doUpload. Last: " + dateUtil.dateAndTimeString(uploadChunk.getLastEnd())) doUpload() @@ -285,7 +285,7 @@ class TidepoolUploader @Inject constructor( @Synchronized private fun extendWakeLock(ms: Long) { if (wl == null) { - val pm = mainApp.getSystemService(Context.POWER_SERVICE) as PowerManager + val pm = ctx.getSystemService(Context.POWER_SERVICE) as PowerManager wl = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "AndroidAPS:TidepoolUploader") wl?.acquire(ms) } else { diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/tidepool/comm/UploadChunk.kt b/app/src/main/java/info/nightscout/androidaps/plugins/general/tidepool/comm/UploadChunk.kt index 74a7f29a5f..be7ab19a02 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/tidepool/comm/UploadChunk.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/tidepool/comm/UploadChunk.kt @@ -1,11 +1,10 @@ package info.nightscout.androidaps.plugins.general.tidepool.comm import info.nightscout.androidaps.R -import info.nightscout.androidaps.data.Intervals import info.nightscout.androidaps.database.AppRepository +import info.nightscout.androidaps.database.entities.TemporaryBasal import info.nightscout.androidaps.db.ProfileSwitch -import info.nightscout.androidaps.db.TemporaryBasal -import info.nightscout.androidaps.interfaces.ActivePluginProvider +import info.nightscout.androidaps.interfaces.ActivePlugin import info.nightscout.androidaps.interfaces.DatabaseHelperInterface import info.nightscout.androidaps.interfaces.ProfileFunction import info.nightscout.androidaps.logging.AAPSLogger @@ -14,7 +13,6 @@ import info.nightscout.androidaps.plugins.bus.RxBusWrapper import info.nightscout.androidaps.plugins.general.tidepool.elements.* import info.nightscout.androidaps.plugins.general.tidepool.events.EventTidepoolStatus import info.nightscout.androidaps.plugins.general.tidepool.utils.GsonInstance -import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin import info.nightscout.androidaps.utils.DateUtil import info.nightscout.androidaps.utils.T import info.nightscout.androidaps.utils.sharedPreferences.SP @@ -30,8 +28,7 @@ class UploadChunk @Inject constructor( private val rxBus: RxBusWrapper, private val aapsLogger: AAPSLogger, private val profileFunction: ProfileFunction, - private val treatmentsPlugin: TreatmentsPlugin, - private val activePlugin: ActivePluginProvider, + private val activePlugin: ActivePlugin, private val databaseHelper: DatabaseHelperInterface, private val repository: AppRepository, private val dateUtil: DateUtil @@ -44,7 +41,7 @@ class UploadChunk @Inject constructor( return null session.start = getLastEnd() - session.end = min(session.start + maxUploadSize, DateUtil.now()) + session.end = min(session.start + maxUploadSize, dateUtil.now()) val result = get(session.start, session.end) if (result.length < 3) { @@ -84,7 +81,7 @@ class UploadChunk @Inject constructor( fun getLastEnd(): Long { val result = sp.getLong(R.string.key_tidepool_last_end, 0) - return max(result, DateUtil.now() - T.months(2).msecs()) + return max(result, dateUtil.now() - T.months(2).msecs()) } fun setLastEnd(time: Long) { @@ -104,7 +101,7 @@ class UploadChunk @Inject constructor( // TODO we could make sure we include records older than the first bg record for completeness val start: Long = 0 - val end = DateUtil.now() + val end = dateUtil.now() val bgReadingList = repository.compatGetBgReadingsDataFromTime(start, end, true) .blockingGet() @@ -115,20 +112,22 @@ class UploadChunk @Inject constructor( private fun getTreatments(start: Long, end: Long): List { val result = LinkedList() - val treatments = treatmentsPlugin.service.getTreatmentDataFromTime(start, end, true) - for (treatment in treatments) { - if (treatment.carbs > 0) { - result.add(WizardElement(treatment)) - } else if (treatment.insulin > 0) { - result.add(BolusElement(treatment)) + repository.getBolusesDataFromTimeToTime(start, end, true) + .blockingGet() + .forEach { bolus -> + result.add(BolusElement(bolus, dateUtil)) + } + repository.getCarbsDataFromTimeToTimeExpanded(start, end, true) + .blockingGet() + .forEach { carb -> + result.add(WizardElement(carb, dateUtil)) } - } return result } private fun getBloodTests(start: Long, end: Long): List { val readings = repository.compatGetTherapyEventDataFromToTime(start, end).blockingGet() - val selection = BloodGlucoseElement.fromCareportalEvents(readings) + val selection = BloodGlucoseElement.fromCareportalEvents(readings, dateUtil) if (selection.isNotEmpty()) rxBus.send(EventTidepoolStatus("${selection.size} BGs selected for upload")) return selection @@ -138,24 +137,25 @@ class UploadChunk @Inject constructor( private fun getBgReadings(start: Long, end: Long): List { val readings = repository.compatGetBgReadingsDataFromTime(start, end, true) .blockingGet() - val selection = SensorGlucoseElement.fromBgReadings(readings) + val selection = SensorGlucoseElement.fromBgReadings(readings, dateUtil) if (selection.isNotEmpty()) rxBus.send(EventTidepoolStatus("${selection.size} CGMs selected for upload")) return selection } - private fun fromTemporaryBasals(tbrList: Intervals, start: Long, end: Long): List { + private fun fromTemporaryBasals(tbrList: List, start: Long, end: Long): List { val results = LinkedList() - for (tbr in tbrList.list) { - if (tbr.date in start..end && tbr.durationInMinutes != 0) - results.add(BasalElement(tbr, profileFunction)) + for (tbr in tbrList) { + if (tbr.timestamp in start..end) + profileFunction.getProfile(tbr.timestamp)?.let { + results.add(BasalElement(tbr, it, dateUtil)) + } } return results } private fun getBasals(start: Long, end: Long): List { - val temporaryBasals = treatmentsPlugin.temporaryBasalsFromHistory - temporaryBasals.merge() + val temporaryBasals = repository.getTemporaryBasalsDataFromTimeToTime(start, end, true).blockingGet() val selection = fromTemporaryBasals(temporaryBasals, start, end) // TODO do not upload running TBR if (selection.isNotEmpty()) rxBus.send(EventTidepoolStatus("${selection.size} TBRs selected for upload")) @@ -163,7 +163,7 @@ class UploadChunk @Inject constructor( } private fun newInstanceOrNull(ps: ProfileSwitch): ProfileElement? = try { - ProfileElement(ps, activePlugin.activePump.serialNumber()) + ProfileElement(ps, activePlugin.activePump.serialNumber(), dateUtil) } catch (e: Throwable) { null } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/tidepool/elements/BasalElement.kt b/app/src/main/java/info/nightscout/androidaps/plugins/general/tidepool/elements/BasalElement.kt index 50e07a4096..905b3d6cf4 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/tidepool/elements/BasalElement.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/tidepool/elements/BasalElement.kt @@ -1,32 +1,39 @@ package info.nightscout.androidaps.plugins.general.tidepool.elements import com.google.gson.annotations.Expose -import info.nightscout.androidaps.db.TemporaryBasal -import info.nightscout.androidaps.interfaces.ProfileFunction +import info.nightscout.androidaps.data.Profile +import info.nightscout.androidaps.database.entities.TemporaryBasal +import info.nightscout.androidaps.extensions.convertedToAbsolute +import info.nightscout.androidaps.utils.DateUtil import java.util.* -class BasalElement(tbr: TemporaryBasal, private val profileFunction: ProfileFunction) - : BaseElement(tbr.date, UUID.nameUUIDFromBytes(("AAPS-basal" + tbr.date).toByteArray()).toString()) { +class BasalElement(tbr: TemporaryBasal, private val profile: Profile, dateUtil: DateUtil) + : BaseElement(tbr.timestamp, UUID.nameUUIDFromBytes(("AAPS-basal" + tbr.timestamp).toByteArray()).toString(), dateUtil) { internal var timestamp: Long = 0 // not exposed @Expose internal var deliveryType = "automated" + @Expose internal var duration: Long = 0 + @Expose internal var rate = -1.0 + @Expose internal var scheduleName = "AAPS" + @Expose internal var clockDriftOffset: Long = 0 + @Expose internal var conversionOffset: Long = 0 init { type = "basal" - timestamp = tbr.date - rate = tbr.tempBasalConvertedToAbsolute(tbr.date, profileFunction.getProfile(tbr.date)) - duration = tbr.end() - tbr.start() + timestamp = tbr.timestamp + rate = tbr.convertedToAbsolute(tbr.timestamp, profile) + duration = tbr.duration } } \ No newline at end of file diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/tidepool/elements/BaseElement.kt b/app/src/main/java/info/nightscout/androidaps/plugins/general/tidepool/elements/BaseElement.kt index 96900e62d6..49aa6eae18 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/tidepool/elements/BaseElement.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/tidepool/elements/BaseElement.kt @@ -3,7 +3,7 @@ package info.nightscout.androidaps.plugins.general.tidepool.elements import com.google.gson.annotations.Expose import info.nightscout.androidaps.utils.DateUtil -open class BaseElement(timestamp: Long, uuid: String) { +open class BaseElement(timestamp: Long, uuid: String, dateUtil: DateUtil) { @Expose var deviceTime: String = "" @Expose @@ -16,9 +16,9 @@ open class BaseElement(timestamp: Long, uuid: String) { var origin: Origin? = null init { - deviceTime = DateUtil.toISONoZone(timestamp) - time = DateUtil.toISOAsUTC(timestamp) - timezoneOffset = DateUtil.getTimeZoneOffsetMinutes(timestamp) // TODO + deviceTime = dateUtil.toISONoZone(timestamp) + time = dateUtil.toISOAsUTC(timestamp) + timezoneOffset = dateUtil.getTimeZoneOffsetMinutes(timestamp) // TODO origin = Origin(uuid) } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/tidepool/elements/BloodGlucoseElement.kt b/app/src/main/java/info/nightscout/androidaps/plugins/general/tidepool/elements/BloodGlucoseElement.kt index a181a4a768..9a70c34049 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/tidepool/elements/BloodGlucoseElement.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/tidepool/elements/BloodGlucoseElement.kt @@ -3,11 +3,12 @@ package info.nightscout.androidaps.plugins.general.tidepool.elements import com.google.gson.annotations.Expose import info.nightscout.androidaps.data.Profile import info.nightscout.androidaps.database.entities.TherapyEvent -import info.nightscout.androidaps.utils.extensions.toConstant +import info.nightscout.androidaps.extensions.toConstant +import info.nightscout.androidaps.utils.DateUtil import java.util.* -class BloodGlucoseElement(therapyEvent: TherapyEvent) - : BaseElement(therapyEvent.timestamp, UUID.nameUUIDFromBytes(("AAPS-bg" + therapyEvent.timestamp).toByteArray()).toString()) { +class BloodGlucoseElement(therapyEvent: TherapyEvent, dateUtil: DateUtil) + : BaseElement(therapyEvent.timestamp, UUID.nameUUIDFromBytes(("AAPS-bg" + therapyEvent.timestamp).toByteArray()).toString(), dateUtil) { @Expose var subType: String = "manual" @@ -28,13 +29,13 @@ class BloodGlucoseElement(therapyEvent: TherapyEvent) companion object { - fun fromCareportalEvents(careportalList: List): List { + fun fromCareportalEvents(careportalList: List, dateUtil: DateUtil): List { val results = LinkedList() for (bt in careportalList) { if (bt.type == TherapyEvent.Type.NS_MBG || bt.type == TherapyEvent.Type.FINGER_STICK_BG_VALUE) { - val bge = BloodGlucoseElement(bt) + val bge = BloodGlucoseElement(bt, dateUtil) if (bge.value > 0) - results.add(BloodGlucoseElement(bt)) + results.add(BloodGlucoseElement(bt, dateUtil)) } } return results diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/tidepool/elements/BolusElement.kt b/app/src/main/java/info/nightscout/androidaps/plugins/general/tidepool/elements/BolusElement.kt index f437018994..6c3a05b0eb 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/tidepool/elements/BolusElement.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/tidepool/elements/BolusElement.kt @@ -1,22 +1,20 @@ package info.nightscout.androidaps.plugins.general.tidepool.elements import com.google.gson.annotations.Expose -import info.nightscout.androidaps.db.Treatment +import info.nightscout.androidaps.database.entities.Bolus +import info.nightscout.androidaps.utils.DateUtil import java.util.* -class BolusElement(treatment: Treatment) - : BaseElement(treatment.date, UUID.nameUUIDFromBytes(("AAPS-bolus" + treatment.date).toByteArray()).toString()) { +class BolusElement(bolus: Bolus, dateUtil: DateUtil) + : BaseElement(bolus.timestamp, UUID.nameUUIDFromBytes(("AAPS-bolus" + bolus.timestamp).toByteArray()).toString(), dateUtil) { - @Expose - var subType = "normal" - @Expose - var normal: Double = 0.0 - @Expose - var expectedNormal: Double = 0.0 + @Expose var subType = "normal" + @Expose var normal: Double = 0.0 + @Expose var expectedNormal: Double = 0.0 init { type = "bolus" - normal = treatment.insulin - expectedNormal = treatment.insulin + normal = bolus.amount + expectedNormal = bolus.amount } } \ No newline at end of file diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/tidepool/elements/ProfileElement.kt b/app/src/main/java/info/nightscout/androidaps/plugins/general/tidepool/elements/ProfileElement.kt index dbc9888e3e..46b63d8663 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/tidepool/elements/ProfileElement.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/tidepool/elements/ProfileElement.kt @@ -4,11 +4,12 @@ import com.google.gson.annotations.Expose import info.nightscout.androidaps.data.Profile import info.nightscout.androidaps.db.ProfileSwitch import info.nightscout.androidaps.plugins.general.tidepool.comm.TidepoolUploader +import info.nightscout.androidaps.utils.DateUtil import java.util.* import kotlin.collections.ArrayList -class ProfileElement(ps: ProfileSwitch, serialNumber: String) - : BaseElement(ps.date, UUID.nameUUIDFromBytes(("AAPS-profile" + ps.date).toByteArray()).toString()) { +class ProfileElement(ps: ProfileSwitch, serialNumber: String, dateUtil: DateUtil) + : BaseElement(ps.date, UUID.nameUUIDFromBytes(("AAPS-profile" + ps.date).toByteArray()).toString(), dateUtil) { @Expose internal var activeSchedule = "Normal" diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/tidepool/elements/SensorGlucoseElement.kt b/app/src/main/java/info/nightscout/androidaps/plugins/general/tidepool/elements/SensorGlucoseElement.kt index da769f902e..cd9538018a 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/tidepool/elements/SensorGlucoseElement.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/tidepool/elements/SensorGlucoseElement.kt @@ -2,10 +2,11 @@ package info.nightscout.androidaps.plugins.general.tidepool.elements import com.google.gson.annotations.Expose import info.nightscout.androidaps.database.entities.GlucoseValue +import info.nightscout.androidaps.utils.DateUtil import java.util.* -class SensorGlucoseElement(bgReading: GlucoseValue) - : BaseElement(bgReading.timestamp, UUID.nameUUIDFromBytes(("AAPS-cgm" + bgReading.timestamp).toByteArray()).toString()) { +class SensorGlucoseElement(bgReading: GlucoseValue, private val dateUtil: DateUtil) + : BaseElement(bgReading.timestamp, UUID.nameUUIDFromBytes(("AAPS-cgm" + bgReading.timestamp).toByteArray()).toString(), dateUtil) { @Expose internal var units: String = "mg/dL" @@ -20,10 +21,10 @@ class SensorGlucoseElement(bgReading: GlucoseValue) companion object { - internal fun fromBgReadings(bgReadingList: List): List { + internal fun fromBgReadings(bgReadingList: List, dateUtil: DateUtil): List { val results = LinkedList() for (bgReading in bgReadingList) { - results.add(SensorGlucoseElement(bgReading)) + results.add(SensorGlucoseElement(bgReading, dateUtil)) } return results } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/tidepool/elements/WizardElement.kt b/app/src/main/java/info/nightscout/androidaps/plugins/general/tidepool/elements/WizardElement.kt index 87aba24d1c..a6615e45a3 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/tidepool/elements/WizardElement.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/tidepool/elements/WizardElement.kt @@ -1,33 +1,28 @@ package info.nightscout.androidaps.plugins.general.tidepool.elements import com.google.gson.annotations.Expose -import info.nightscout.androidaps.db.Treatment +import info.nightscout.androidaps.database.entities.Bolus +import info.nightscout.androidaps.database.entities.Carbs +import info.nightscout.androidaps.utils.DateUtil import java.util.* -class WizardElement(treatment: Treatment) - : BaseElement(treatment.date, UUID.nameUUIDFromBytes(("AAPS-wizard" + treatment.date).toByteArray()).toString()) { +class WizardElement(carbs: Carbs, dateUtil: DateUtil) + : BaseElement(carbs.timestamp, UUID.nameUUIDFromBytes(("AAPS-wizard" + carbs.timestamp).toByteArray()).toString(), dateUtil) { - @Expose - var units = "mg/dL" - @Expose - var carbInput: Double = 0.toDouble() - @Expose - var insulinCarbRatio: Double = 0.toDouble() - @Expose - var bolus: BolusElement? = null + @Expose var units = "mg/dL" + @Expose var carbInput: Double = 0.toDouble() + @Expose var insulinCarbRatio: Double = 0.toDouble() + @Expose var bolus: BolusElement? = null init { type = "wizard" - carbInput = treatment.carbs - insulinCarbRatio = treatment.ic - if (treatment.insulin > 0) { - bolus = BolusElement(treatment) - } else { - val fake = Treatment() - fake.insulin = 0.0001 - fake.date = treatment.date - bolus = BolusElement(fake) // fake insulin record - } + carbInput = carbs.amount + val fake = Bolus( + amount = 0.0001, + timestamp = carbs.timestamp, + type = Bolus.Type.NORMAL + ) + bolus = BolusElement(fake, dateUtil) // fake insulin record } } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/tidepool/events/EventTidepoolStatus.kt b/app/src/main/java/info/nightscout/androidaps/plugins/general/tidepool/events/EventTidepoolStatus.kt index aff358ba08..e2e0caf8ae 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/tidepool/events/EventTidepoolStatus.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/tidepool/events/EventTidepoolStatus.kt @@ -1,12 +1,12 @@ package info.nightscout.androidaps.plugins.general.tidepool.events import info.nightscout.androidaps.events.Event -import info.nightscout.androidaps.utils.DateUtil import java.text.SimpleDateFormat import java.util.* class EventTidepoolStatus(val status: String) : Event() { - var date: Long = DateUtil.now() + + var date: Long = System.currentTimeMillis() private var timeFormat = SimpleDateFormat("HH:mm:ss", Locale.getDefault()) diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/tidepool/messages/OpenDatasetRequestMessage.kt b/app/src/main/java/info/nightscout/androidaps/plugins/general/tidepool/messages/OpenDatasetRequestMessage.kt index e6fd2c63dd..631a0259bd 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/tidepool/messages/OpenDatasetRequestMessage.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/tidepool/messages/OpenDatasetRequestMessage.kt @@ -7,46 +7,62 @@ import info.nightscout.androidaps.utils.DateUtil import info.nightscout.androidaps.utils.T import java.util.* -class OpenDatasetRequestMessage (val serialNumber : String): BaseMessage() { +class OpenDatasetRequestMessage(serialNumber: String, dateUtil: DateUtil) : BaseMessage() { @Expose var deviceId: String = TidepoolUploader.PUMP_TYPE + ":" + serialNumber + @Expose - var time: String = DateUtil.toISOAsUTC(DateUtil.now()) + var time: String = dateUtil.toISOAsUTC(System.currentTimeMillis()) + @Expose - var timezoneOffset = (DateUtil.getTimeZoneOffsetMs() / T.mins(1).msecs()).toInt() + var timezoneOffset = (dateUtil.getTimeZoneOffsetMs() / T.mins(1).msecs()).toInt() + @Expose var type = "upload" + //public String byUser; @Expose var client = ClientInfo() + @Expose - var computerTime: String = DateUtil.toISONoZone(DateUtil.now()) + var computerTime: String = dateUtil.toISONoZone(System.currentTimeMillis()) + @Expose var dataSetType = "continuous" + @Expose var deviceManufacturers = arrayOf(TidepoolUploader.PUMP_TYPE) + @Expose var deviceModel = TidepoolUploader.PUMP_TYPE + @Expose var deviceTags = arrayOf("bgm", "cgm", "insulin-pump") + @Expose var deduplicator = Deduplicator() + @Expose var timeProcessing = "none" + @Expose var timezone: String = TimeZone.getDefault().id + @Expose var version = BuildConfig.VERSION_NAME inner class ClientInfo { + @Expose val name = BuildConfig.APPLICATION_ID + @Expose val version = TidepoolUploader.VERSION } inner class Deduplicator { + @Expose val name = "org.tidepool.deduplicator.dataset.delete.origin" } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/tidepool/utils/RateLimit.kt b/app/src/main/java/info/nightscout/androidaps/plugins/general/tidepool/utils/RateLimit.kt index 9e48d0b90f..020e6714f3 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/tidepool/utils/RateLimit.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/tidepool/utils/RateLimit.kt @@ -10,7 +10,8 @@ import javax.inject.Singleton @Singleton class RateLimit @Inject constructor( - val aapsLogger: AAPSLogger + private val aapsLogger: AAPSLogger, + private val dateUtil: DateUtil ) { private val rateLimits = HashMap() @@ -20,13 +21,13 @@ class RateLimit @Inject constructor( fun rateLimit(name: String, seconds: Int): Boolean { // check if over limit rateLimits[name]?.let { - if (DateUtil.now() - it < T.secs(seconds.toLong()).msecs()) { + if (dateUtil.now() - it < T.secs(seconds.toLong()).msecs()) { aapsLogger.debug(LTag.TIDEPOOL, "$name rate limited: $seconds seconds") return false } } // not over limit - rateLimits[name] = DateUtil.now() + rateLimits[name] = dateUtil.now() return true } } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/wear/ActionStringHandler.kt b/app/src/main/java/info/nightscout/androidaps/plugins/general/wear/ActionStringHandler.kt index 1fa4210b9a..4785d0653d 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/wear/ActionStringHandler.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/wear/ActionStringHandler.kt @@ -3,7 +3,7 @@ package info.nightscout.androidaps.plugins.general.wear import android.app.NotificationManager import android.content.Context import dagger.android.HasAndroidInjector -import info.nightscout.androidaps.Config +import info.nightscout.androidaps.interfaces.Config import info.nightscout.androidaps.Constants import info.nightscout.androidaps.R import info.nightscout.androidaps.dana.DanaPump @@ -16,27 +16,27 @@ import info.nightscout.androidaps.data.Profile import info.nightscout.androidaps.database.AppRepository import info.nightscout.androidaps.database.ValueWrapper import info.nightscout.androidaps.database.entities.TemporaryTarget -import info.nightscout.androidaps.database.entities.TherapyEvent +import info.nightscout.androidaps.database.entities.UserEntry.Action +import info.nightscout.androidaps.database.entities.UserEntry.Sources +import info.nightscout.androidaps.database.entities.ValueWithUnit import info.nightscout.androidaps.database.interfaces.end import info.nightscout.androidaps.database.transactions.CancelCurrentTemporaryTargetIfAnyTransaction import info.nightscout.androidaps.database.transactions.InsertTemporaryTargetAndCancelCurrentTransaction -import info.nightscout.androidaps.db.Source import info.nightscout.androidaps.db.TDD +import info.nightscout.androidaps.extensions.valueToUnits import info.nightscout.androidaps.interfaces.* import info.nightscout.androidaps.logging.AAPSLogger +import info.nightscout.androidaps.logging.LTag +import info.nightscout.androidaps.logging.UserEntryLogger import info.nightscout.androidaps.plugins.aps.loop.LoopPlugin import info.nightscout.androidaps.plugins.bus.RxBusWrapper import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker -import info.nightscout.androidaps.plugins.general.nsclient.NSUpload import info.nightscout.androidaps.plugins.general.overview.events.EventDismissNotification import info.nightscout.androidaps.plugins.general.wear.events.EventWearConfirmAction import info.nightscout.androidaps.plugins.general.wear.events.EventWearInitiateAction -import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorPlugin import info.nightscout.androidaps.plugins.pump.insight.LocalInsightPlugin -import info.nightscout.androidaps.plugins.treatments.CarbsGenerator import info.nightscout.androidaps.queue.Callback import info.nightscout.androidaps.utils.* -import info.nightscout.androidaps.utils.extensions.valueToUnits import info.nightscout.androidaps.utils.resources.ResourceHelper import info.nightscout.androidaps.utils.rx.AapsSchedulers import info.nightscout.androidaps.utils.sharedPreferences.SP @@ -69,20 +69,19 @@ class ActionStringHandler @Inject constructor( private val wearPlugin: WearPlugin, private val fabricPrivacy: FabricPrivacy, private val commandQueue: CommandQueueProvider, - private val activePlugin: ActivePluginProvider, - private val iobCobCalculatorPlugin: IobCobCalculatorPlugin, + private val activePlugin: ActivePlugin, + private val iobCobCalculator: IobCobCalculator, private val localInsightPlugin: LocalInsightPlugin, private val danaRPlugin: DanaRPlugin, private val danaRKoreanPlugin: DanaRKoreanPlugin, private val danaRv2Plugin: DanaRv2Plugin, private val danaRSPlugin: DanaRSPlugin, private val danaPump: DanaPump, - private val carbsGenerator: CarbsGenerator, private val dateUtil: DateUtil, private val config: Config, private val databaseHelper: DatabaseHelperInterface, private val repository: AppRepository, - private val nsUpload: NSUpload + private val uel: UserEntryLogger ) { private val timeout = 65 * 1000 @@ -104,7 +103,7 @@ class ActionStringHandler @Inject constructor( .subscribe({ handleConfirmation(it.action) }, fabricPrivacy::logException) } - fun tearDown(){ + fun tearDown() { disposable.clear() } @@ -208,24 +207,24 @@ class ActionStringHandler @Inject constructor( sendError("No profile found!") return } - val bgReading = iobCobCalculatorPlugin.actualBg() + val bgReading = iobCobCalculator.ads.actualBg() if (bgReading == null) { sendError("No recent BG to base calculation on!") return } - val cobInfo = iobCobCalculatorPlugin.getCobInfo(false, "Wizard wear") + val cobInfo = iobCobCalculator.getCobInfo(false, "Wizard wear") if (cobInfo.displayCob == null) { sendError("Unknown COB! BG reading missing or recent app restart?") return } val format = DecimalFormat("0.00") val formatInt = DecimalFormat("0") - val dbRecord = repository.getTemporaryTargetActiveAt(dateUtil._now()).blockingGet() + val dbRecord = repository.getTemporaryTargetActiveAt(dateUtil.now()).blockingGet() val tempTarget = if (dbRecord is ValueWrapper.Existing) dbRecord.value else null val bolusWizard = BolusWizard(injector).doCalc(profile, profileName, tempTarget, carbsAfterConstraints, if (cobInfo.displayCob != null) cobInfo.displayCob!! else 0.0, bgReading.valueToUnits(profileFunction.getUnits()), - 0.0, percentage.toDouble(), useBG, useCOB, useBolusIOB, useBasalIOB, false, useTT, useTrend, false) + 0.0, percentage, useBG, useCOB, useBolusIOB, useBasalIOB, false, useTT, useTrend, false) if (abs(bolusWizard.insulinAfterConstraints - bolusWizard.calculatedTotalInsulin) >= 0.01) { sendError("Insulin constraint violation!" + "\nCannot deliver " + format.format(bolusWizard.calculatedTotalInsulin) + "!") @@ -457,7 +456,7 @@ class ActionStringHandler @Inject constructor( } val profile = profileFunction.getProfile() ?: return "No profile set :(" //Check for Temp-Target: - val tempTarget = repository.getTemporaryTargetActiveAt(dateUtil._now()).blockingGet() + val tempTarget = repository.getTemporaryTargetActiveAt(dateUtil.now()).blockingGet() if (tempTarget is ValueWrapper.Existing) { ret += "Temp Target: " + Profile.toTargetRangeString(tempTarget.value.lowTarget, tempTarget.value.lowTarget, Constants.MGDL, profileFunction.getUnits()) ret += "\nuntil: " + dateUtil.timeString(tempTarget.value.end) @@ -520,13 +519,13 @@ class ActionStringHandler @Inject constructor( generateTempTarget(duration, low, high) } else if ("wizard2" == act[0]) { if (lastBolusWizard != null) { //use last calculation as confirmed string matches - doBolus(lastBolusWizard!!.calculatedTotalInsulin, lastBolusWizard!!.carbs) + doBolus(lastBolusWizard!!.calculatedTotalInsulin, lastBolusWizard!!.carbs, null, 0) lastBolusWizard = null } } else if ("bolus" == act[0]) { val insulin = SafeParse.stringToDouble(act[1]) val carbs = SafeParse.stringToInt(act[2]) - doBolus(insulin, carbs) + doBolus(insulin, carbs, null, 0) } else if ("cppset" == act[0]) { val timeshift = SafeParse.stringToInt(act[1]) val percentage = SafeParse.stringToInt(act[2]) @@ -546,16 +545,6 @@ class ActionStringHandler @Inject constructor( lastBolusWizard = null } - private fun doECarbs(carbs: Int, time: Long, duration: Int) { - if (carbs > 0) { - if (duration == 0) { - carbsGenerator.createCarb(carbs, time, TherapyEvent.Type.CARBS_CORRECTION.text, "watch") - } else { - carbsGenerator.generateCarbs(carbs, time, duration, "watch eCarbs") - } - } - } - private fun setCPP(timeshift: Int, percentage: Int) { var msg = "" //check for validity @@ -579,11 +568,14 @@ class ActionStringHandler @Inject constructor( return } //send profile to pump + uel.log(Action.PROFILE_SWITCH, Sources.Wear, + ValueWithUnit.Percent(percentage), + ValueWithUnit.Hour(timeshift).takeIf { timeshift != 0 }) activePlugin.activeTreatments.doProfileSwitch(0, percentage, timeshift) } private fun generateTempTarget(duration: Int, low: Double, high: Double) { - if (duration != 0) + if (duration != 0) { disposable += repository.runTransactionForResult(InsertTemporaryTargetAndCancelCurrentTransaction( timestamp = System.currentTimeMillis(), duration = TimeUnit.MINUTES.toMillis(duration.toLong()), @@ -591,25 +583,34 @@ class ActionStringHandler @Inject constructor( lowTarget = Profile.toMgdl(low, profileFunction.getUnits()), highTarget = Profile.toMgdl(high, profileFunction.getUnits()) )).subscribe({ result -> - result.inserted.forEach { nsUpload.uploadTempTarget(it) } - result.updated.forEach { nsUpload.updateTempTarget(it) } + result.inserted.forEach { aapsLogger.debug(LTag.DATABASE, "Inserted temp target $it") } + result.updated.forEach { aapsLogger.debug(LTag.DATABASE, "Updated temp target $it") } }, { - aapsLogger.error("Error while saving temporary target", it) + aapsLogger.error(LTag.DATABASE, "Error while saving temporary target", it) }) - else + uel.log(Action.TT, Sources.Wear, + ValueWithUnit.TherapyEventTTReason(TemporaryTarget.Reason.WEAR), + ValueWithUnit.fromGlucoseUnit(low, profileFunction.getUnits()), + ValueWithUnit.fromGlucoseUnit(high, profileFunction.getUnits()).takeIf { low != high }, + ValueWithUnit.Minute(duration)) + } else { disposable += repository.runTransactionForResult(CancelCurrentTemporaryTargetIfAnyTransaction(System.currentTimeMillis())) .subscribe({ result -> - result.updated.forEach { nsUpload.updateTempTarget(it) } + result.updated.forEach { aapsLogger.debug(LTag.DATABASE, "Updated temp target $it") } }, { - aapsLogger.error("Error while saving temporary target", it) + aapsLogger.error(LTag.DATABASE, "Error while saving temporary target", it) }) + uel.log(Action.CANCEL_TT, Sources.Wear, + ValueWithUnit.TherapyEventTTReason(TemporaryTarget.Reason.WEAR)) + } } private fun doFillBolus(amount: Double) { val detailedBolusInfo = DetailedBolusInfo() detailedBolusInfo.insulin = amount - detailedBolusInfo.isValid = false - detailedBolusInfo.source = Source.USER + detailedBolusInfo.bolusType = DetailedBolusInfo.BolusType.PRIMING + uel.log(Action.PRIME_BOLUS, Sources.Wear, + ValueWithUnit.Insulin(amount).takeIf { amount != 0.0 }) commandQueue.bolus(detailedBolusInfo, object : Callback() { override fun run() { if (!result.success) { @@ -621,13 +622,32 @@ class ActionStringHandler @Inject constructor( }) } - private fun doBolus(amount: Double, carbs: Int) { + private fun doECarbs(carbs: Int, time: Long, duration: Int) { + uel.log(if (duration == 0) Action.CARBS else Action.EXTENDED_CARBS, Sources.Wear, + ValueWithUnit.Timestamp(time), + ValueWithUnit.Gram(carbs), + ValueWithUnit.Hour(duration).takeIf { duration != 0 }) + doBolus(0.0, carbs, time, duration) + } + + private fun doBolus(amount: Double, carbs: Int, carbsTime: Long?, carbsDuration: Int) { val detailedBolusInfo = DetailedBolusInfo() detailedBolusInfo.insulin = amount detailedBolusInfo.carbs = carbs.toDouble() - detailedBolusInfo.source = Source.USER - val storesCarbs = activePlugin.activePump.pumpDescription.storesCarbInfo - if (detailedBolusInfo.insulin > 0 || storesCarbs) { + detailedBolusInfo.bolusType = DetailedBolusInfo.BolusType.NORMAL + detailedBolusInfo.carbsTimestamp = carbsTime + detailedBolusInfo.carbsDuration = T.hours(carbsDuration.toLong()).msecs() + if (detailedBolusInfo.insulin > 0 || detailedBolusInfo.carbs > 0) { + val action = when { + amount.equals(0.0) -> Action.CARBS + carbs.equals(0) -> Action.BOLUS + carbsDuration > 0 -> Action.EXTENDED_CARBS + else -> Action.TREATMENT + } + uel.log(action, Sources.Wear, + ValueWithUnit.Insulin(amount).takeIf { amount != 0.0 }, + ValueWithUnit.Gram(carbs).takeIf { carbs != 0 }, + ValueWithUnit.Hour(carbsDuration).takeIf { carbsDuration != 0 }) commandQueue.bolus(detailedBolusInfo, object : Callback() { override fun run() { if (!result.success) { @@ -637,8 +657,6 @@ class ActionStringHandler @Inject constructor( } } }) - } else { - activePlugin.activeTreatments.addToHistoryTreatment(detailedBolusInfo, false) } } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/wear/WearPlugin.kt b/app/src/main/java/info/nightscout/androidaps/plugins/general/wear/WearPlugin.kt index e4a486a89e..d08dba47d8 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/wear/WearPlugin.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/wear/WearPlugin.kt @@ -1,9 +1,9 @@ package info.nightscout.androidaps.plugins.general.wear +import android.content.Context import android.content.Intent import dagger.Lazy import dagger.android.HasAndroidInjector -import info.nightscout.androidaps.MainApp import info.nightscout.androidaps.R import info.nightscout.androidaps.events.* import info.nightscout.androidaps.interfaces.PluginBase @@ -16,7 +16,6 @@ import info.nightscout.androidaps.plugins.bus.RxBusWrapper import info.nightscout.androidaps.plugins.general.overview.events.EventDismissBolusProgressIfRunning import info.nightscout.androidaps.plugins.general.overview.events.EventOverviewBolusProgress import info.nightscout.androidaps.plugins.general.wear.wearintegration.WatchUpdaterService -import info.nightscout.androidaps.events.EventAutosensCalculationFinished import info.nightscout.androidaps.utils.FabricPrivacy import info.nightscout.androidaps.utils.resources.ResourceHelper import info.nightscout.androidaps.utils.rx.AapsSchedulers @@ -32,7 +31,7 @@ class WearPlugin @Inject constructor( resourceHelper: ResourceHelper, private val aapsSchedulers: AapsSchedulers, private val sp: SP, - private val mainApp: MainApp, + private val ctx: Context, private val fabricPrivacy: FabricPrivacy, private val loopPlugin: Lazy, private val rxBus: RxBusWrapper, @@ -97,10 +96,10 @@ class WearPlugin @Inject constructor( .observeOn(aapsSchedulers.io) .subscribe({ event: EventBolusRequested -> val status = String.format(resourceHelper.gs(R.string.bolusrequested), event.amount) - val intent = Intent(mainApp, WatchUpdaterService::class.java).setAction(WatchUpdaterService.ACTION_SEND_BOLUSPROGRESS) + val intent = Intent(ctx, WatchUpdaterService::class.java).setAction(WatchUpdaterService.ACTION_SEND_BOLUSPROGRESS) intent.putExtra("progresspercent", 0) intent.putExtra("progressstatus", status) - mainApp.startService(intent) + ctx.startService(intent) }, fabricPrivacy::logException)) disposable.add(rxBus .toObservable(EventDismissBolusProgressIfRunning::class.java) @@ -112,20 +111,20 @@ class WearPlugin @Inject constructor( } else { resourceHelper.gs(R.string.nosuccess) } - val intent = Intent(mainApp, WatchUpdaterService::class.java).setAction(WatchUpdaterService.ACTION_SEND_BOLUSPROGRESS) + val intent = Intent(ctx, WatchUpdaterService::class.java).setAction(WatchUpdaterService.ACTION_SEND_BOLUSPROGRESS) intent.putExtra("progresspercent", 100) intent.putExtra("progressstatus", status) - mainApp.startService(intent) + ctx.startService(intent) }, fabricPrivacy::logException)) disposable.add(rxBus .toObservable(EventOverviewBolusProgress::class.java) .observeOn(aapsSchedulers.io) .subscribe({ event: EventOverviewBolusProgress -> if (!event.isSMB() || sp.getBoolean("wear_notifySMB", true)) { - val intent = Intent(mainApp, WatchUpdaterService::class.java).setAction(WatchUpdaterService.ACTION_SEND_BOLUSPROGRESS) + val intent = Intent(ctx, WatchUpdaterService::class.java).setAction(WatchUpdaterService.ACTION_SEND_BOLUSPROGRESS) intent.putExtra("progresspercent", event.percent) intent.putExtra("progressstatus", event.status) - mainApp.startService(intent) + ctx.startService(intent) } }, fabricPrivacy::logException)) actionStringHandler.get().setup() @@ -142,47 +141,47 @@ class WearPlugin @Inject constructor( if (isEnabled(getType())) { // only start service when this plugin is enabled if (bgValue) { - mainApp.startService(Intent(mainApp, WatchUpdaterService::class.java)) + ctx.startService(Intent(ctx, WatchUpdaterService::class.java)) } if (basals) { - mainApp.startService(Intent(mainApp, WatchUpdaterService::class.java).setAction(WatchUpdaterService.ACTION_SEND_BASALS)) + ctx.startService(Intent(ctx, WatchUpdaterService::class.java).setAction(WatchUpdaterService.ACTION_SEND_BASALS)) } if (status) { - mainApp.startService(Intent(mainApp, WatchUpdaterService::class.java).setAction(WatchUpdaterService.ACTION_SEND_STATUS)) + ctx.startService(Intent(ctx, WatchUpdaterService::class.java).setAction(WatchUpdaterService.ACTION_SEND_STATUS)) } } } fun resendDataToWatch() { //Log.d(TAG, "WR: WearPlugin:resendDataToWatch"); - mainApp.startService(Intent(mainApp, WatchUpdaterService::class.java).setAction(WatchUpdaterService.ACTION_RESEND)) + ctx.startService(Intent(ctx, WatchUpdaterService::class.java).setAction(WatchUpdaterService.ACTION_RESEND)) } fun openSettings() { //Log.d(TAG, "WR: WearPlugin:openSettings"); - mainApp.startService(Intent(mainApp, WatchUpdaterService::class.java).setAction(WatchUpdaterService.ACTION_OPEN_SETTINGS)) + ctx.startService(Intent(ctx, WatchUpdaterService::class.java).setAction(WatchUpdaterService.ACTION_OPEN_SETTINGS)) } fun requestNotificationCancel(actionString: String?) { //Log.d(TAG, "WR: WearPlugin:requestNotificationCancel"); - val intent = Intent(mainApp, WatchUpdaterService::class.java) + val intent = Intent(ctx, WatchUpdaterService::class.java) .setAction(WatchUpdaterService.ACTION_CANCEL_NOTIFICATION) intent.putExtra("actionstring", actionString) - mainApp.startService(intent) + ctx.startService(intent) } fun requestActionConfirmation(title: String, message: String, actionString: String) { - val intent = Intent(mainApp, WatchUpdaterService::class.java).setAction(WatchUpdaterService.ACTION_SEND_ACTIONCONFIRMATIONREQUEST) + val intent = Intent(ctx, WatchUpdaterService::class.java).setAction(WatchUpdaterService.ACTION_SEND_ACTIONCONFIRMATIONREQUEST) intent.putExtra("title", title) intent.putExtra("message", message) intent.putExtra("actionstring", actionString) - mainApp.startService(intent) + ctx.startService(intent) } fun requestChangeConfirmation(title: String, message: String, actionString: String) { - val intent = Intent(mainApp, WatchUpdaterService::class.java).setAction(WatchUpdaterService.ACTION_SEND_CHANGECONFIRMATIONREQUEST) + val intent = Intent(ctx, WatchUpdaterService::class.java).setAction(WatchUpdaterService.ACTION_SEND_CHANGECONFIRMATIONREQUEST) intent.putExtra("title", title) intent.putExtra("message", message) intent.putExtra("actionstring", actionString) - mainApp.startService(intent) + ctx.startService(intent) } } \ No newline at end of file diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/wear/wearintegration/WatchUpdaterService.java b/app/src/main/java/info/nightscout/androidaps/plugins/general/wear/wearintegration/WatchUpdaterService.java index db97d25b17..b3683ae8c8 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/wear/wearintegration/WatchUpdaterService.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/wear/wearintegration/WatchUpdaterService.java @@ -24,22 +24,24 @@ import com.google.android.gms.wearable.WearableListenerService; import java.util.ArrayList; import java.util.List; import java.util.Set; +import java.util.stream.Collectors; import javax.inject.Inject; import dagger.android.AndroidInjection; -import dagger.android.HasAndroidInjector; -import info.nightscout.androidaps.Config; +import info.nightscout.androidaps.interfaces.Config; import info.nightscout.androidaps.Constants; import info.nightscout.androidaps.R; -import info.nightscout.androidaps.data.GlucoseValueDataPoint; import info.nightscout.androidaps.data.IobTotal; import info.nightscout.androidaps.data.Profile; import info.nightscout.androidaps.database.AppRepository; +import info.nightscout.androidaps.database.entities.Bolus; import info.nightscout.androidaps.database.entities.GlucoseValue; -import info.nightscout.androidaps.db.TemporaryBasal; -import info.nightscout.androidaps.db.Treatment; -import info.nightscout.androidaps.interfaces.ActivePluginProvider; +import info.nightscout.androidaps.database.entities.TemporaryBasal; +import info.nightscout.androidaps.extensions.GlucoseValueExtensionKt; +import info.nightscout.androidaps.extensions.TemporaryBasalExtensionKt; +import info.nightscout.androidaps.interfaces.ActivePlugin; +import info.nightscout.androidaps.interfaces.IobCobCalculator; import info.nightscout.androidaps.interfaces.PluginType; import info.nightscout.androidaps.interfaces.ProfileFunction; import info.nightscout.androidaps.logging.AAPSLogger; @@ -47,18 +49,16 @@ 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.data.NSDeviceStatus; +import info.nightscout.androidaps.plugins.general.overview.graphExtensions.GlucoseValueDataPoint; import info.nightscout.androidaps.plugins.general.wear.WearPlugin; import info.nightscout.androidaps.plugins.general.wear.events.EventWearConfirmAction; import info.nightscout.androidaps.plugins.general.wear.events.EventWearInitiateAction; import info.nightscout.androidaps.plugins.iob.iobCobCalculator.GlucoseStatus; import info.nightscout.androidaps.plugins.iob.iobCobCalculator.GlucoseStatusProvider; -import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorPlugin; -import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin; import info.nightscout.androidaps.receivers.ReceiverStatusStore; import info.nightscout.androidaps.utils.DecimalFormatter; import info.nightscout.androidaps.utils.DefaultValueHelper; import info.nightscout.androidaps.utils.ToastUtils; -import info.nightscout.androidaps.utils.extensions.GlucoseValueUtilsKt; import info.nightscout.androidaps.utils.resources.ResourceHelper; import info.nightscout.androidaps.utils.sharedPreferences.SP; @@ -72,10 +72,9 @@ public class WatchUpdaterService extends WearableListenerService implements Goog @Inject public ProfileFunction profileFunction; @Inject public DefaultValueHelper defaultValueHelper; @Inject public NSDeviceStatus nsDeviceStatus; - @Inject public ActivePluginProvider activePlugin; + @Inject public ActivePlugin activePlugin; @Inject public LoopPlugin loopPlugin; - @Inject public IobCobCalculatorPlugin iobCobCalculatorPlugin; - @Inject public TreatmentsPlugin treatmentsPlugin; + @Inject public IobCobCalculator iobCobCalculator; @Inject public AppRepository repository; @Inject ReceiverStatusStore receiverStatusStore; @Inject Config config; @@ -280,7 +279,7 @@ public class WatchUpdaterService extends WearableListenerService implements Goog private void sendData() { - GlucoseValue lastBG = iobCobCalculatorPlugin.lastBg(); + GlucoseValue lastBG = iobCobCalculator.getAds().lastBg(); // Log.d(TAG, logPrefix + "LastBg=" + lastBG); if (lastBG != null) { GlucoseStatus glucoseStatus = glucoseStatusProvider.getGlucoseStatusData(); @@ -314,7 +313,7 @@ public class WatchUpdaterService extends WearableListenerService implements Goog } DataMap dataMap = new DataMap(); - dataMap.putString("sgvString", GlucoseValueUtilsKt.valueToUnitsString(lastBG, units)); + dataMap.putString("sgvString", GlucoseValueExtensionKt.valueToUnitsString(lastBG, units)); dataMap.putString("glucoseUnits", units); dataMap.putLong("timestamp", lastBG.getTimestamp()); if (glucoseStatus == null) { @@ -382,7 +381,7 @@ public class WatchUpdaterService extends WearableListenerService implements Goog googleApiConnect(); } long startTime = System.currentTimeMillis() - (long) (60000 * 60 * 5.5); - GlucoseValue last_bg = iobCobCalculatorPlugin.lastBg(); + GlucoseValue last_bg = iobCobCalculator.getAds().lastBg(); if (last_bg == null) return; @@ -437,8 +436,8 @@ public class WatchUpdaterService extends WearableListenerService implements Goog double beginBasalValue = profile.getBasal(beginBasalSegmentTime); double endBasalValue = beginBasalValue; - TemporaryBasal tb1 = treatmentsPlugin.getTempBasalFromHistory(runningTime); - TemporaryBasal tb2 = treatmentsPlugin.getTempBasalFromHistory(runningTime); //TODO for Adrian ... what's the meaning? + TemporaryBasal tb1 = iobCobCalculator.getTempBasalIncludingConvertedExtended(runningTime); + TemporaryBasal tb2 = iobCobCalculator.getTempBasalIncludingConvertedExtended(runningTime); //TODO for Adrian ... what's the meaning? double tb_before = beginBasalValue; double tb_amount = beginBasalValue; long tb_start = runningTime; @@ -447,7 +446,7 @@ public class WatchUpdaterService extends WearableListenerService implements Goog tb_before = beginBasalValue; Profile profileTB = profileFunction.getProfile(runningTime); if (profileTB != null) { - tb_amount = tb1.tempBasalConvertedToAbsolute(runningTime, profileTB); + tb_amount = TemporaryBasalExtensionKt.convertedToAbsolute(tb1, runningTime, profileTB); tb_start = runningTime; } } @@ -469,7 +468,7 @@ public class WatchUpdaterService extends WearableListenerService implements Goog } //temps - tb2 = treatmentsPlugin.getTempBasalFromHistory(runningTime); + tb2 = iobCobCalculator.getTempBasalIncludingConvertedExtended(runningTime); if (tb1 == null && tb2 == null) { //no temp stays no temp @@ -484,10 +483,10 @@ public class WatchUpdaterService extends WearableListenerService implements Goog tb1 = tb2; tb_start = runningTime; tb_before = endBasalValue; - tb_amount = tb1.tempBasalConvertedToAbsolute(runningTime, profileTB); + tb_amount = TemporaryBasalExtensionKt.convertedToAbsolute(tb1, runningTime, profileTB); } else if (tb1 != null && tb2 != null) { - double currentAmount = tb2.tempBasalConvertedToAbsolute(runningTime, profileTB); + double currentAmount = TemporaryBasalExtensionKt.convertedToAbsolute(tb2, runningTime, profileTB); if (currentAmount != tb_amount) { temps.add(tempDatamap(tb_start, tb_before, runningTime, currentAmount, tb_amount)); tb_start = runningTime; @@ -502,14 +501,14 @@ public class WatchUpdaterService extends WearableListenerService implements Goog basals.add(basalMap(beginBasalSegmentTime, runningTime, beginBasalValue)); } if (tb1 != null) { - tb2 = treatmentsPlugin.getTempBasalFromHistory(now); //use "now" to express current situation + tb2 = iobCobCalculator.getTempBasalIncludingConvertedExtended(now); //use "now" to express current situation if (tb2 == null) { //express the cancelled temp by painting it down one minute early temps.add(tempDatamap(tb_start, tb_before, now - 1 * 60 * 1000, endBasalValue, tb_amount)); } else { //express currently running temp by painting it a bit into the future Profile profileNow = profileFunction.getProfile(now); - double currentAmount = tb2.tempBasalConvertedToAbsolute(now, profileNow); + double currentAmount = TemporaryBasalExtensionKt.convertedToAbsolute(tb2, now, profileNow); if (currentAmount != tb_amount) { temps.add(tempDatamap(tb_start, tb_before, now, tb_amount, tb_amount)); temps.add(tempDatamap(now, tb_amount, runningTime + 5 * 60 * 1000, currentAmount, currentAmount)); @@ -518,26 +517,28 @@ public class WatchUpdaterService extends WearableListenerService implements Goog } } } else { - tb2 = treatmentsPlugin.getTempBasalFromHistory(now); //use "now" to express current situation + tb2 = iobCobCalculator.getTempBasalIncludingConvertedExtended(now); //use "now" to express current situation if (tb2 != null) { //onset at the end Profile profileTB = profileFunction.getProfile(runningTime); - double currentAmount = tb2.tempBasalConvertedToAbsolute(runningTime, profileTB); + double currentAmount = TemporaryBasalExtensionKt.convertedToAbsolute(tb2, runningTime, profileTB); temps.add(tempDatamap(now - 1 * 60 * 1000, endBasalValue, runningTime + 5 * 60 * 1000, currentAmount, currentAmount)); } } - List treatments = treatmentsPlugin.getTreatmentsFromHistory(); - for (Treatment treatment : treatments) { - if (treatment.date > startTimeWindow) { - boluses.add(treatmentMap(treatment.date, treatment.insulin, treatment.carbs, treatment.isSMB, treatment.isValid)); - } - - } + repository.getBolusesIncludingInvalidFromTime(startTimeWindow, true).blockingGet() + .stream() + .filter(bolus -> bolus.getType() != Bolus.Type.PRIMING) + .forEach(bolus -> boluses.add(treatmentMap(bolus.getTimestamp(), bolus.getAmount(), 0, bolus.getType() == Bolus.Type.SMB, bolus.isValid()))); + repository.getCarbsDataFromTimeExpanded(startTimeWindow, true).blockingGet() + .forEach(carb -> boluses.add(treatmentMap(carb.getTimestamp(), 0, carb.getAmount(), false, carb.isValid()))); final LoopPlugin.LastRun finalLastRun = loopPlugin.getLastRun(); if (sp.getBoolean("wear_predictions", true) && finalLastRun != null && finalLastRun.getRequest().getHasPredictions() && finalLastRun.getConstraintsProcessed() != null) { - List predArray = finalLastRun.getConstraintsProcessed().getPredictions(); + List predArray = + finalLastRun.getConstraintsProcessed().getPredictions() + .stream().map(bg -> new GlucoseValueDataPoint(bg, defaultValueHelper, profileFunction, resourceHelper)) + .collect(Collectors.toList()); if (!predArray.isEmpty()) { final String units = profileFunction.getUnits(); @@ -685,14 +686,12 @@ public class WatchUpdaterService extends WearableListenerService implements Goog String iobSum, iobDetail, cobString, currentBasal, bgiString; iobSum = iobDetail = cobString = currentBasal = bgiString = ""; if (profile != null) { - treatmentsPlugin.updateTotalIOBTreatments(); - IobTotal bolusIob = treatmentsPlugin.getLastCalculationTreatments().round(); - treatmentsPlugin.updateTotalIOBTempBasals(); - IobTotal basalIob = treatmentsPlugin.getLastCalculationTempBasals().round(); + IobTotal bolusIob = iobCobCalculator.calculateIobFromBolus().round(); + IobTotal basalIob = iobCobCalculator.calculateIobFromTempBasalsIncludingConvertedExtended().round(); iobSum = DecimalFormatter.INSTANCE.to2Decimal(bolusIob.iob + basalIob.basaliob); iobDetail = "(" + DecimalFormatter.INSTANCE.to2Decimal(bolusIob.iob) + "|" + DecimalFormatter.INSTANCE.to2Decimal(basalIob.basaliob) + ")"; - cobString = iobCobCalculatorPlugin.getCobInfo(false, "WatcherUpdaterService").generateCOBString(); + cobString = iobCobCalculator.getCobInfo(false, "WatcherUpdaterService").generateCOBString(); currentBasal = generateBasalString(); //bgi @@ -798,15 +797,11 @@ public class WatchUpdaterService extends WearableListenerService implements Goog if (profile == null) return ""; - TemporaryBasal activeTemp = treatmentsPlugin.getTempBasalFromHistory(System.currentTimeMillis()); + TemporaryBasal activeTemp = iobCobCalculator.getTempBasalIncludingConvertedExtended(System.currentTimeMillis()); if (activeTemp != null) { - basalStringResult = activeTemp.toStringShort(); + basalStringResult = TemporaryBasalExtensionKt.toStringShort(activeTemp); } else { - if (sp.getBoolean(R.string.key_danar_visualizeextendedaspercentage, false)) { - basalStringResult = "100%"; - } else { - basalStringResult = DecimalFormatter.INSTANCE.to2Decimal(profile.getBasal()) + "U/h"; - } + basalStringResult = DecimalFormatter.INSTANCE.to2Decimal(profile.getBasal()) + "U/h"; } return basalStringResult; } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/xdripStatusline/StatusLinePlugin.kt b/app/src/main/java/info/nightscout/androidaps/plugins/general/xdripStatusline/StatusLinePlugin.kt index a705394f59..2359789f69 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/xdripStatusline/StatusLinePlugin.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/xdripStatusline/StatusLinePlugin.kt @@ -7,23 +7,18 @@ import dagger.android.HasAndroidInjector import info.nightscout.androidaps.R import info.nightscout.androidaps.data.Profile import info.nightscout.androidaps.events.* -import info.nightscout.androidaps.interfaces.ActivePluginProvider -import info.nightscout.androidaps.interfaces.PluginBase -import info.nightscout.androidaps.interfaces.PluginDescription -import info.nightscout.androidaps.interfaces.PluginType -import info.nightscout.androidaps.interfaces.ProfileFunction +import info.nightscout.androidaps.interfaces.* import info.nightscout.androidaps.logging.AAPSLogger import info.nightscout.androidaps.plugins.aps.loop.LoopPlugin import info.nightscout.androidaps.plugins.bus.RxBusWrapper -import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorPlugin -import info.nightscout.androidaps.events.EventAutosensCalculationFinished import info.nightscout.androidaps.utils.DecimalFormatter import info.nightscout.androidaps.utils.FabricPrivacy -import io.reactivex.rxkotlin.plusAssign +import info.nightscout.androidaps.extensions.toStringShort import info.nightscout.androidaps.utils.resources.ResourceHelper import info.nightscout.androidaps.utils.rx.AapsSchedulers import info.nightscout.androidaps.utils.sharedPreferences.SP import io.reactivex.disposables.CompositeDisposable +import io.reactivex.rxkotlin.plusAssign import javax.inject.Inject import javax.inject.Singleton @@ -36,9 +31,9 @@ class StatusLinePlugin @Inject constructor( private val aapsSchedulers: AapsSchedulers, private val context: Context, private val fabricPrivacy: FabricPrivacy, - private val activePlugin: ActivePluginProvider, + private val activePlugin: ActivePlugin, private val loopPlugin: LoopPlugin, - private val iobCobCalculatorPlugin: IobCobCalculatorPlugin, + private val iobCobCalculator: IobCobCalculator, private val rxBus: RxBusWrapper, aapsLogger: AAPSLogger ) : PluginBase( @@ -127,15 +122,13 @@ class StatusLinePlugin @Inject constructor( lastLoopStatus = true } //Temp basal - val activeTemp = activePlugin.activeTreatments.getTempBasalFromHistory(System.currentTimeMillis()) + val activeTemp = iobCobCalculator.getTempBasalIncludingConvertedExtended(System.currentTimeMillis()) if (activeTemp != null) { status += activeTemp.toStringShort() + " " } //IOB - activePlugin.activeTreatments.updateTotalIOBTreatments() - val bolusIob = activePlugin.activeTreatments.lastCalculationTreatments.round() - activePlugin.activeTreatments.updateTotalIOBTempBasals() - val basalIob = activePlugin.activeTreatments.lastCalculationTempBasals.round() + val bolusIob = iobCobCalculator.calculateIobFromBolus().round() + val basalIob = iobCobCalculator.calculateIobFromTempBasalsIncludingConvertedExtended().round() status += DecimalFormatter.to2Decimal(bolusIob.iob + basalIob.basaliob) + "U" if (sp.getBoolean(R.string.key_xdripstatus_detailediob, true)) { status += ("(" @@ -147,7 +140,7 @@ class StatusLinePlugin @Inject constructor( status += " " + (if (bgi >= 0) "+" else "") + DecimalFormatter.to2Decimal(bgi) } // COB - status += " " + iobCobCalculatorPlugin.getCobInfo(false, "StatusLinePlugin").generateCOBString() + status += " " + iobCobCalculator.getCobInfo(false, "StatusLinePlugin").generateCOBString() return status } } \ No newline at end of file diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/insulin/ActivityGraph.kt b/app/src/main/java/info/nightscout/androidaps/plugins/insulin/ActivityGraph.kt index a6575c1886..93932d5633 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/insulin/ActivityGraph.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/insulin/ActivityGraph.kt @@ -6,8 +6,8 @@ import android.util.AttributeSet import com.jjoe64.graphview.GraphView import com.jjoe64.graphview.series.DataPoint import com.jjoe64.graphview.series.LineGraphSeries -import info.nightscout.androidaps.db.Treatment -import info.nightscout.androidaps.interfaces.InsulinInterface +import info.nightscout.androidaps.database.entities.Bolus +import info.nightscout.androidaps.interfaces.Insulin import info.nightscout.androidaps.utils.T import java.util.* import kotlin.math.floor @@ -18,19 +18,20 @@ class ActivityGraph : GraphView { constructor(context: Context, attrs: AttributeSet?) : super(context, attrs) - fun show(insulin: InsulinInterface) { + fun show(insulin: Insulin) { removeAllSeries() mSecondScale = null val hours = floor(insulin.dia + 1).toLong() - val t = Treatment().also { - it.date = 0 - it.insulin = 1.0 - } + val bolus = Bolus( + timestamp = 0, + amount = 1.0, + type = Bolus.Type.NORMAL + ) val activityArray: MutableList = ArrayList() val iobArray: MutableList = ArrayList() var time: Long = 0 while (time <= T.hours(hours).msecs()) { - val iob = t.iobCalc(time, insulin.dia) + val iob = insulin.iobCalcForTreatment(bolus, time, insulin.dia) activityArray.add(DataPoint(T.msecs(time).mins().toDouble(), iob.activityContrib)) iobArray.add(DataPoint(T.msecs(time).mins().toDouble(), iob.iobContrib)) time += T.mins(5).msecs() diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/insulin/InsulinFragment.kt b/app/src/main/java/info/nightscout/androidaps/plugins/insulin/InsulinFragment.kt index 6d5f2c6df8..640a0b80be 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/insulin/InsulinFragment.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/insulin/InsulinFragment.kt @@ -7,13 +7,13 @@ import android.view.ViewGroup import dagger.android.support.DaggerFragment import info.nightscout.androidaps.R import info.nightscout.androidaps.databinding.InsulinFragmentBinding -import info.nightscout.androidaps.interfaces.ActivePluginProvider +import info.nightscout.androidaps.interfaces.ActivePlugin import info.nightscout.androidaps.utils.resources.ResourceHelper import javax.inject.Inject class InsulinFragment : DaggerFragment() { - @Inject lateinit var activePlugin: ActivePluginProvider + @Inject lateinit var activePlugin: ActivePlugin @Inject lateinit var resourceHelper: ResourceHelper private var _binding: InsulinFragmentBinding? = null diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/insulin/InsulinLyumjevPlugin.kt b/app/src/main/java/info/nightscout/androidaps/plugins/insulin/InsulinLyumjevPlugin.kt index 717429eb44..9c40a7bcdc 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/insulin/InsulinLyumjevPlugin.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/insulin/InsulinLyumjevPlugin.kt @@ -2,7 +2,7 @@ package info.nightscout.androidaps.plugins.insulin import dagger.android.HasAndroidInjector import info.nightscout.androidaps.R -import info.nightscout.androidaps.interfaces.InsulinInterface +import info.nightscout.androidaps.interfaces.Insulin import info.nightscout.androidaps.interfaces.ProfileFunction import info.nightscout.androidaps.logging.AAPSLogger import info.nightscout.androidaps.plugins.bus.RxBusWrapper @@ -19,7 +19,7 @@ class InsulinLyumjevPlugin @Inject constructor( rxBus: RxBusWrapper, aapsLogger: AAPSLogger ) : InsulinOrefBasePlugin(injector, resourceHelper, profileFunction, rxBus, aapsLogger) { - override val id get(): InsulinInterface.InsulinType = InsulinInterface.InsulinType.OREF_LYUMJEV + override val id get(): Insulin.InsulinType = Insulin.InsulinType.OREF_LYUMJEV override val friendlyName get(): String = resourceHelper.gs(R.string.lyumjev) override fun configuration(): JSONObject = JSONObject() diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/insulin/InsulinOrefBasePlugin.kt b/app/src/main/java/info/nightscout/androidaps/plugins/insulin/InsulinOrefBasePlugin.kt index 1ffb885866..fd41873cf2 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/insulin/InsulinOrefBasePlugin.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/insulin/InsulinOrefBasePlugin.kt @@ -3,8 +3,8 @@ package info.nightscout.androidaps.plugins.insulin import dagger.android.HasAndroidInjector import info.nightscout.androidaps.R import info.nightscout.androidaps.data.Iob -import info.nightscout.androidaps.db.Treatment -import info.nightscout.androidaps.interfaces.InsulinInterface +import info.nightscout.androidaps.database.entities.Bolus +import info.nightscout.androidaps.interfaces.Insulin import info.nightscout.androidaps.interfaces.PluginBase import info.nightscout.androidaps.interfaces.PluginDescription import info.nightscout.androidaps.interfaces.PluginType @@ -14,6 +14,8 @@ import info.nightscout.androidaps.plugins.bus.RxBusWrapper import info.nightscout.androidaps.plugins.general.overview.events.EventNewNotification import info.nightscout.androidaps.plugins.general.overview.notifications.Notification import info.nightscout.androidaps.utils.resources.ResourceHelper +import kotlin.math.exp +import kotlin.math.pow /** * Created by adrian on 13.08.2017. @@ -33,7 +35,7 @@ abstract class InsulinOrefBasePlugin( .shortName(R.string.insulin_shortname) .visibleByDefault(false), aapsLogger, resourceHelper, injector -), InsulinInterface { +), Insulin { private var lastWarned: Long = 0 override val dia @@ -64,11 +66,11 @@ abstract class InsulinOrefBasePlugin( return profile?.dia ?: MIN_DIA } - override fun iobCalcForTreatment(treatment: Treatment, time: Long, dia: Double): Iob { + override fun iobCalcForTreatment(bolus: Bolus, time: Long, dia: Double): Iob { val result = Iob() val peak = peak - if (treatment.insulin != 0.0) { - val bolusTime = treatment.date + if (bolus.amount != 0.0) { + val bolusTime = bolus.timestamp val t = (time - bolusTime) / 1000.0 / 60.0 val td = dia * 60 //getDIA() always >= MIN_DIA val tp = peak.toDouble() @@ -76,9 +78,9 @@ abstract class InsulinOrefBasePlugin( if (t < td) { val tau = tp * (1 - tp / td) / (1 - 2 * tp / td) val a = 2 * tau / td - val S = 1 / (1 - a + (1 + a) * Math.exp(-td / tau)) - result.activityContrib = treatment.insulin * (S / Math.pow(tau, 2.0)) * t * (1 - t / td) * Math.exp(-t / tau) - result.iobContrib = treatment.insulin * (1 - S * (1 - a) * ((Math.pow(t, 2.0) / (tau * td * (1 - a)) - t / tau - 1) * Math.exp(-t / tau) + 1)) + val S = 1 / (1 - a + (1 + a) * exp(-td / tau)) + result.activityContrib = bolus.amount * (S / tau.pow(2.0)) * t * (1 - t / td) * exp(-t / tau) + result.iobContrib = bolus.amount * (1 - S * (1 - a) * ((t.pow(2.0) / (tau * td * (1 - a)) - t / tau - 1) * Math.exp(-t / tau) + 1)) } } return result diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/insulin/InsulinOrefFreePeakPlugin.kt b/app/src/main/java/info/nightscout/androidaps/plugins/insulin/InsulinOrefFreePeakPlugin.kt index 7200032b3c..d80ac43481 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/insulin/InsulinOrefFreePeakPlugin.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/insulin/InsulinOrefFreePeakPlugin.kt @@ -2,12 +2,12 @@ package info.nightscout.androidaps.plugins.insulin import dagger.android.HasAndroidInjector import info.nightscout.androidaps.R -import info.nightscout.androidaps.interfaces.InsulinInterface +import info.nightscout.androidaps.interfaces.Insulin import info.nightscout.androidaps.interfaces.ProfileFunction import info.nightscout.androidaps.logging.AAPSLogger import info.nightscout.androidaps.plugins.bus.RxBusWrapper -import info.nightscout.androidaps.utils.extensions.storeInt -import info.nightscout.androidaps.utils.extensions.putInt +import info.nightscout.androidaps.extensions.storeInt +import info.nightscout.androidaps.extensions.putInt import info.nightscout.androidaps.utils.resources.ResourceHelper import info.nightscout.androidaps.utils.sharedPreferences.SP import org.json.JSONObject @@ -26,7 +26,7 @@ class InsulinOrefFreePeakPlugin @Inject constructor( rxBus: RxBusWrapper, aapsLogger: AAPSLogger ) : InsulinOrefBasePlugin(injector, resourceHelper, profileFunction, rxBus, aapsLogger) { - override val id get(): InsulinInterface.InsulinType = InsulinInterface.InsulinType.OREF_FREE_PEAK + override val id get(): Insulin.InsulinType = Insulin.InsulinType.OREF_FREE_PEAK override val friendlyName get(): String = resourceHelper.gs(R.string.free_peak_oref) diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/insulin/InsulinOrefRapidActingPlugin.kt b/app/src/main/java/info/nightscout/androidaps/plugins/insulin/InsulinOrefRapidActingPlugin.kt index bcf526253c..c18313a405 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/insulin/InsulinOrefRapidActingPlugin.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/insulin/InsulinOrefRapidActingPlugin.kt @@ -2,7 +2,7 @@ package info.nightscout.androidaps.plugins.insulin import dagger.android.HasAndroidInjector import info.nightscout.androidaps.R -import info.nightscout.androidaps.interfaces.InsulinInterface +import info.nightscout.androidaps.interfaces.Insulin import info.nightscout.androidaps.interfaces.ProfileFunction import info.nightscout.androidaps.logging.AAPSLogger import info.nightscout.androidaps.plugins.bus.RxBusWrapper @@ -22,7 +22,7 @@ class InsulinOrefRapidActingPlugin @Inject constructor( rxBus: RxBusWrapper, aapsLogger: AAPSLogger ) : InsulinOrefBasePlugin(injector, resourceHelper, profileFunction, rxBus, aapsLogger) { - override val id get(): InsulinInterface.InsulinType = InsulinInterface.InsulinType.OREF_RAPID_ACTING + override val id get(): Insulin.InsulinType = Insulin.InsulinType.OREF_RAPID_ACTING override val friendlyName get(): String = resourceHelper.gs(R.string.rapid_acting_oref) override fun configuration(): JSONObject = JSONObject() diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/insulin/InsulinOrefUltraRapidActingPlugin.kt b/app/src/main/java/info/nightscout/androidaps/plugins/insulin/InsulinOrefUltraRapidActingPlugin.kt index 257ae10ffe..7a32408984 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/insulin/InsulinOrefUltraRapidActingPlugin.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/insulin/InsulinOrefUltraRapidActingPlugin.kt @@ -2,7 +2,7 @@ package info.nightscout.androidaps.plugins.insulin import dagger.android.HasAndroidInjector import info.nightscout.androidaps.R -import info.nightscout.androidaps.interfaces.InsulinInterface +import info.nightscout.androidaps.interfaces.Insulin import info.nightscout.androidaps.interfaces.ProfileFunction import info.nightscout.androidaps.logging.AAPSLogger import info.nightscout.androidaps.plugins.bus.RxBusWrapper @@ -22,7 +22,7 @@ class InsulinOrefUltraRapidActingPlugin @Inject constructor( rxBus: RxBusWrapper, aapsLogger: AAPSLogger ) : InsulinOrefBasePlugin(injector, resourceHelper, profileFunction, rxBus, aapsLogger) { - override val id get(): InsulinInterface.InsulinType = InsulinInterface.InsulinType.OREF_ULTRA_RAPID_ACTING + override val id get(): Insulin.InsulinType = Insulin.InsulinType.OREF_ULTRA_RAPID_ACTING override val friendlyName get(): String = resourceHelper.gs(R.string.ultrarapid_oref) override fun configuration(): JSONObject = JSONObject() diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/iob/iobCobCalculator/InMemoryGlucoseValue.kt b/app/src/main/java/info/nightscout/androidaps/plugins/iob/iobCobCalculator/InMemoryGlucoseValue.kt index 52cd403f54..fef18ff95c 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/iob/iobCobCalculator/InMemoryGlucoseValue.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/iob/iobCobCalculator/InMemoryGlucoseValue.kt @@ -1,9 +1,2 @@ package info.nightscout.androidaps.plugins.iob.iobCobCalculator -import info.nightscout.androidaps.database.entities.GlucoseValue - -class InMemoryGlucoseValue @JvmOverloads constructor(var timestamp: Long = 0L, var value: Double = 0.0, var interpolated: Boolean = false) { - - constructor(gv: GlucoseValue) : this(gv.timestamp, gv.value) - // var generated : value doesn't correspond to real value with timestamp close to real BG -} \ No newline at end of file diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/iob/iobCobCalculator/IobCobCalculatorPlugin.kt b/app/src/main/java/info/nightscout/androidaps/plugins/iob/iobCobCalculator/IobCobCalculatorPlugin.kt index 1009972939..b93a772a0f 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/iob/iobCobCalculator/IobCobCalculatorPlugin.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/iob/iobCobCalculator/IobCobCalculatorPlugin.kt @@ -9,20 +9,24 @@ import info.nightscout.androidaps.data.IobTotal import info.nightscout.androidaps.data.MealData import info.nightscout.androidaps.data.Profile import info.nightscout.androidaps.database.AppRepository -import info.nightscout.androidaps.database.entities.GlucoseValue -import info.nightscout.androidaps.db.TemporaryBasal +import info.nightscout.androidaps.database.ValueWrapper +import info.nightscout.androidaps.database.entities.Bolus +import info.nightscout.androidaps.database.entities.ExtendedBolus +import info.nightscout.androidaps.database.entities.TemporaryBasal +import info.nightscout.androidaps.database.interfaces.end import info.nightscout.androidaps.events.* +import info.nightscout.androidaps.extensions.convertedToAbsolute +import info.nightscout.androidaps.extensions.iobCalc +import info.nightscout.androidaps.extensions.toTemporaryBasal import info.nightscout.androidaps.interfaces.* import info.nightscout.androidaps.logging.AAPSLogger import info.nightscout.androidaps.logging.LTag import info.nightscout.androidaps.plugins.bus.RxBusWrapper import info.nightscout.androidaps.plugins.iob.iobCobCalculator.data.AutosensData -import info.nightscout.androidaps.plugins.iob.iobCobCalculator.events.EventNewHistoryBgData import info.nightscout.androidaps.plugins.iob.iobCobCalculator.events.EventNewHistoryData import info.nightscout.androidaps.plugins.sensitivity.SensitivityAAPSPlugin import info.nightscout.androidaps.plugins.sensitivity.SensitivityOref1Plugin import info.nightscout.androidaps.plugins.sensitivity.SensitivityWeightedAveragePlugin -import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin import info.nightscout.androidaps.utils.DateUtil import info.nightscout.androidaps.utils.DecimalFormatter import info.nightscout.androidaps.utils.FabricPrivacy @@ -31,14 +35,13 @@ import info.nightscout.androidaps.utils.resources.ResourceHelper import info.nightscout.androidaps.utils.rx.AapsSchedulers import info.nightscout.androidaps.utils.sharedPreferences.SP import io.reactivex.disposables.CompositeDisposable +import io.reactivex.rxkotlin.plusAssign import org.json.JSONArray -import java.util.concurrent.TimeUnit import javax.inject.Inject import javax.inject.Singleton -import kotlin.math.abs import kotlin.math.floor import kotlin.math.max -import kotlin.math.roundToLong +import kotlin.math.min @Singleton open class IobCobCalculatorPlugin @Inject constructor( @@ -49,8 +52,7 @@ open class IobCobCalculatorPlugin @Inject constructor( private val sp: SP, resourceHelper: ResourceHelper, private val profileFunction: ProfileFunction, - private val activePlugin: ActivePluginProvider, - private val treatmentsPlugin: TreatmentsPlugin, + private val activePlugin: ActivePlugin, private val sensitivityOref1Plugin: SensitivityOref1Plugin, private val sensitivityAAPSPlugin: SensitivityAAPSPlugin, private val sensitivityWeightedAveragePlugin: SensitivityWeightedAveragePlugin, @@ -64,64 +66,34 @@ open class IobCobCalculatorPlugin @Inject constructor( .neverVisible(true) .alwaysEnabled(true), aapsLogger, resourceHelper, injector -), IobCobCalculatorInterface { +), IobCobCalculator { private val disposable = CompositeDisposable() - private var iobTable = LongSparseArray() // oldest at index 0 - private var absIobTable = LongSparseArray() // oldest at index 0, absolute insulin in the body - private var autosensDataTable = LongSparseArray() // oldest at index 0 - private var basalDataTable = LongSparseArray() // oldest at index 0 - @Volatile override var bgReadings: List = listOf() // newest at index 0 - @Volatile var bucketedData: MutableList? = null - // we need to make sure that bucketed_data will always have the same timestamp for correct use of cached values - // once referenceTime != null all bucketed data should be (x * 5min) from referenceTime - var referenceTime: Long = -1 - private var lastUsed5minCalculation: Boolean? = null // true if used 5min bucketed data - override val dataLock = Any() + private var iobTable = LongSparseArray() // oldest at index 0 + private var absIobTable = LongSparseArray() // oldest at index 0, absolute insulin in the body + private var basalDataTable = LongSparseArray() // oldest at index 0 + + override var ads: AutosensDataStore = AutosensDataStore() + + private val dataLock = Any() var stopCalculationTrigger = false private var thread: Thread? = null override fun onStart() { super.onStart() // EventConfigBuilderChange - disposable.add(rxBus + disposable += rxBus .toObservable(EventConfigBuilderChange::class.java) .observeOn(aapsSchedulers.io) - .subscribe({ event -> - stopCalculation("onEventConfigBuilderChange") - synchronized(dataLock) { - aapsLogger.debug(LTag.AUTOSENS, "Invalidating cached data because of configuration change.") - resetData() - } - runCalculation("onEventConfigBuilderChange", System.currentTimeMillis(), bgDataReload = false, limitDataToOldestAvailable = true, cause = event) - }, fabricPrivacy::logException) - ) + .subscribe({ event -> resetDataAndRunCalculation("onEventConfigBuilderChange", event) }, fabricPrivacy::logException) // EventNewBasalProfile - disposable.add(rxBus + disposable += rxBus .toObservable(EventNewBasalProfile::class.java) .observeOn(aapsSchedulers.io) - .subscribe({ event -> - stopCalculation("onNewProfile") - synchronized(dataLock) { - aapsLogger.debug(LTag.AUTOSENS, "Invalidating cached data because of new profile.") - resetData() - } - runCalculation("onNewProfile", System.currentTimeMillis(), bgDataReload = false, limitDataToOldestAvailable = true, cause = event) - }, fabricPrivacy::logException) - ) - // EventNewBG .... cannot be used for invalidating because only event with last BG is fired - disposable.add(rxBus - .toObservable(EventNewBG::class.java) - .observeOn(aapsSchedulers.io) - .debounce(1L, TimeUnit.SECONDS) - .subscribe({ event -> - stopCalculation("onEventNewBG") - runCalculation("onEventNewBG", System.currentTimeMillis(), bgDataReload = true, limitDataToOldestAvailable = true, cause = event) - }, fabricPrivacy::logException) - ) + .subscribe({ event -> resetDataAndRunCalculation("onNewProfile", event) }, fabricPrivacy::logException) // EventPreferenceChange - disposable.add(rxBus + disposable += rxBus .toObservable(EventPreferenceChange::class.java) .observeOn(aapsSchedulers.io) .subscribe({ event -> @@ -133,33 +105,19 @@ open class IobCobCalculatorPlugin @Inject constructor( event.isChanged(resourceHelper, R.string.key_openapsama_autosens_max) || event.isChanged(resourceHelper, R.string.key_openapsama_autosens_min) || event.isChanged(resourceHelper, R.string.key_insulin_oref_peak)) { - stopCalculation("onEventPreferenceChange") - synchronized(dataLock) { - aapsLogger.debug(LTag.AUTOSENS, "Invalidating cached data because of preference change.") - resetData() - } - runCalculation("onEventPreferenceChange", System.currentTimeMillis(), bgDataReload = false, limitDataToOldestAvailable = true, cause = event) + resetDataAndRunCalculation("onEventPreferenceChange", event) } }, fabricPrivacy::logException) - ) // EventAppInitialized - disposable.add(rxBus + disposable += rxBus .toObservable(EventAppInitialized::class.java) .observeOn(aapsSchedulers.io) .subscribe({ event -> runCalculation("onEventAppInitialized", System.currentTimeMillis(), bgDataReload = true, limitDataToOldestAvailable = true, cause = event) }, fabricPrivacy::logException) - ) // EventNewHistoryData - disposable.add(rxBus + disposable += rxBus .toObservable(EventNewHistoryData::class.java) .observeOn(aapsSchedulers.io) - .subscribe({ event -> newHistoryData(event, false) }, fabricPrivacy::logException) - ) - // EventNewHistoryBgData - disposable.add(rxBus - .toObservable(EventNewHistoryBgData::class.java) - .observeOn(aapsSchedulers.io) - .subscribe({ event -> newHistoryData(EventNewHistoryData(event.timestamp), true) }, fabricPrivacy::logException) - ) + .subscribe({ event -> newHistoryData(event.oldDataTimestamp, event.reloadBgData, if (event.newestGlucoseValue != null) EventNewBG(event.newestGlucoseValue) else event) }, fabricPrivacy::logException) } override fun onStop() { @@ -167,219 +125,40 @@ open class IobCobCalculatorPlugin @Inject constructor( super.onStop() } - override fun getAutosensDataTable(): LongSparseArray { - return autosensDataTable + private fun resetDataAndRunCalculation(reason: String, event: Event?) { + stopCalculation(reason) + clearCache() + ads.reset() + runCalculation(reason, System.currentTimeMillis(), bgDataReload = false, limitDataToOldestAvailable = true, cause = event) } - fun adjustToReferenceTime(someTime: Long): Long { - if (referenceTime == -1L) { - referenceTime = someTime - return someTime - } - var diff = abs(someTime - referenceTime) - diff %= T.mins(5).msecs() - if (diff > T.mins(2).plus(T.secs(30)).msecs()) diff -= T.mins(5).msecs() - return someTime + diff - } - - fun loadBgData(to: Long) { - val profile = profileFunction.getProfile(to) - var dia = Constants.defaultDIA - if (profile != null) dia = profile.dia - val start = to - T.hours((24 + dia).toLong()).msecs() - if (DateUtil.isCloseToNow(to)) { - // if close to now expect there can be some readings with time in close future (caused by wrong time setting) - // so read all records - bgReadings = repository.compatGetBgReadingsDataFromTime(start, false).blockingGet() - aapsLogger.debug(LTag.AUTOSENS, "BG data loaded. Size: " + bgReadings.size + " Start date: " + dateUtil.dateAndTimeString(start)) - } else { - bgReadings = repository.compatGetBgReadingsDataFromTime(start, to, false).blockingGet() - aapsLogger.debug(LTag.AUTOSENS, "BG data loaded. Size: " + bgReadings.size + " Start date: " + dateUtil.dateAndTimeString(start) + " End date: " + dateUtil.dateAndTimeString(to)) - } - } - - val isAbout5minData: Boolean - get() { - synchronized(dataLock) { - if (bgReadings.size < 3) return true - - var totalDiff: Long = 0 - for (i in 1 until bgReadings.size) { - val bgTime = bgReadings[i].timestamp - val lastBgTime = bgReadings[i - 1].timestamp - var diff = lastBgTime - bgTime - diff %= T.mins(5).msecs() - if (diff > T.mins(2).plus(T.secs(30)).msecs()) diff -= T.mins(5).msecs() - totalDiff += diff - diff = abs(diff) - if (diff > T.secs(30).msecs()) { - aapsLogger.debug(LTag.AUTOSENS, "Interval detection: values: " + bgReadings.size + " diff: " + diff / 1000 + "[s] is5minData: " + false) - return false - } - } - val averageDiff = totalDiff / bgReadings.size / 1000 - val is5minData = averageDiff < 1 - aapsLogger.debug(LTag.AUTOSENS, "Interval detection: values: " + bgReadings.size + " averageDiff: " + averageDiff + "[s] is5minData: " + is5minData) - return is5minData - } - } - - private fun resetData() { + fun clearCache() { synchronized(dataLock) { + aapsLogger.debug(LTag.AUTOSENS, "Clearing cached data.") iobTable = LongSparseArray() - autosensDataTable = LongSparseArray() basalDataTable = LongSparseArray() - absIobTable = LongSparseArray() } } - fun createBucketedData() { - val fiveMinData = isAbout5minData - if (lastUsed5minCalculation != null && lastUsed5minCalculation != fiveMinData) { - // changing mode => clear cache - aapsLogger.debug("Invalidating cached data because of changed mode.") - resetData() - } - lastUsed5minCalculation = fiveMinData - if (isAbout5minData) createBucketedData5min() else createBucketedDataRecalculated() - } - - fun findNewer(time: Long): GlucoseValue? { - var lastFound = bgReadings[0] - if (lastFound.timestamp < time) return null - for (i in 1 until bgReadings.size) { - if (bgReadings[i].timestamp == time) return bgReadings[i] - if (bgReadings[i].timestamp > time) continue - lastFound = bgReadings[i - 1] - if (bgReadings[i].timestamp < time) break - } - return lastFound - } - - fun findOlder(time: Long): GlucoseValue? { - var lastFound = bgReadings[bgReadings.size - 1] - if (lastFound.timestamp > time) return null - for (i in bgReadings.size - 2 downTo 0) { - if (bgReadings[i].timestamp == time) return bgReadings[i] - if (bgReadings[i].timestamp < time) continue - lastFound = bgReadings[i + 1] - if (bgReadings[i].timestamp > time) break - } - return lastFound - } - - private fun createBucketedDataRecalculated() { - if (bgReadings.size < 3) { - bucketedData = null - return - } - bucketedData = ArrayList() - var currentTime = bgReadings[0].timestamp - bgReadings[0].timestamp % T.mins(5).msecs() - currentTime = adjustToReferenceTime(currentTime) - aapsLogger.debug("Adjusted time " + dateUtil.dateAndTimeAndSecondsString(currentTime)) - //log.debug("First reading: " + new Date(currentTime).toLocaleString()); - while (true) { - // test if current value is older than current time - val newer = findNewer(currentTime) - val older = findOlder(currentTime) - if (newer == null || older == null) break - if (older.timestamp == newer.timestamp) { // direct hit - bucketedData?.add(InMemoryGlucoseValue(newer)) - } else { - val bgDelta = newer.value - older.value - val timeDiffToNew = newer.timestamp - currentTime - val currentBg = newer.value - timeDiffToNew.toDouble() / (newer.timestamp - older.timestamp) * bgDelta - val newBgReading = InMemoryGlucoseValue(currentTime, currentBg.roundToLong().toDouble(), true) - bucketedData?.add(newBgReading) - //log.debug("BG: " + newBgReading.value + " (" + new Date(newBgReading.date).toLocaleString() + ") Prev: " + older.value + " (" + new Date(older.date).toLocaleString() + ") Newer: " + newer.value + " (" + new Date(newer.date).toLocaleString() + ")"); - } - currentTime -= T.mins(5).msecs() - } - } - - private fun createBucketedData5min() { - if (bgReadings.size < 3) { - bucketedData = null - return - } - val bData: MutableList = ArrayList() - bData.add(InMemoryGlucoseValue(bgReadings[0])) - aapsLogger.debug(LTag.AUTOSENS, "Adding. bgTime: " + DateUtil.toISOString(bgReadings[0].timestamp) + " lastBgTime: " + "none-first-value" + " " + bgReadings[0].toString()) - var j = 0 - for (i in 1 until bgReadings.size) { - val bgTime = bgReadings[i].timestamp - var lastBgTime = bgReadings[i - 1].timestamp - //log.error("Processing " + i + ": " + new Date(bgTime).toString() + " " + bgReadings.get(i).value + " Previous: " + new Date(lastBgTime).toString() + " " + bgReadings.get(i - 1).value); - check(!(bgReadings[i].value < 39 || bgReadings[i - 1].value < 39)) { "<39" } - var elapsedMinutes = (bgTime - lastBgTime) / (60 * 1000) - when { - abs(elapsedMinutes) > 8 -> { - // interpolate missing data points - var lastBg = bgReadings[i - 1].value - elapsedMinutes = abs(elapsedMinutes) - //console.error(elapsed_minutes); - var nextBgTime: Long - while (elapsedMinutes > 5) { - nextBgTime = lastBgTime - 5 * 60 * 1000 - j++ - val gapDelta = bgReadings[i].value - lastBg - //console.error(gapDelta, lastBg, elapsed_minutes); - val nextBg = lastBg + 5.0 / elapsedMinutes * gapDelta - val newBgReading = InMemoryGlucoseValue(nextBgTime, nextBg.roundToLong().toDouble(), true) - //console.error("Interpolated", bData[j]); - bData.add(newBgReading) - aapsLogger.debug(LTag.AUTOSENS, "Adding. bgTime: " + DateUtil.toISOString(bgTime) + " lastBgTime: " + DateUtil.toISOString(lastBgTime) + " " + newBgReading.toString()) - elapsedMinutes -= 5 - lastBg = nextBg - lastBgTime = nextBgTime - } - j++ - val newBgReading = InMemoryGlucoseValue(bgTime, bgReadings[i].value) - bData.add(newBgReading) - aapsLogger.debug(LTag.AUTOSENS, "Adding. bgTime: " + DateUtil.toISOString(bgTime) + " lastBgTime: " + DateUtil.toISOString(lastBgTime) + " " + newBgReading.toString()) - } - - abs(elapsedMinutes) > 2 -> { - j++ - val newBgReading = InMemoryGlucoseValue(bgTime, bgReadings[i].value) - bData.add(newBgReading) - aapsLogger.debug(LTag.AUTOSENS, "Adding. bgTime: " + DateUtil.toISOString(bgTime) + " lastBgTime: " + DateUtil.toISOString(lastBgTime) + " " + newBgReading.toString()) - } - - else -> { - bData[j].value = (bData[j].value + bgReadings[i].value) / 2 - //log.error("***** Average"); - } - } - } - - // Normalize bucketed data - val oldest = bData[bData.size - 1] - oldest.timestamp = adjustToReferenceTime(oldest.timestamp) - aapsLogger.debug("Adjusted time " + dateUtil.dateAndTimeAndSecondsString(oldest.timestamp)) - for (i in bData.size - 2 downTo 0) { - val current = bData[i] - val previous = bData[i + 1] - val mSecDiff = current.timestamp - previous.timestamp - val adjusted = (mSecDiff - T.mins(5).msecs()) / 1000 - aapsLogger.debug(LTag.AUTOSENS, "Adjusting bucketed data time. Current: " + dateUtil.dateAndTimeAndSecondsString(current.timestamp) + " to: " + dateUtil.dateAndTimeAndSecondsString(previous.timestamp + T.mins(5).msecs()) + " by " + adjusted + " sec") - if (abs(adjusted) > 90) { - // too big adjustment, fallback to non 5 min data - aapsLogger.debug(LTag.AUTOSENS, "Fallback to non 5 min data") - createBucketedDataRecalculated() - return - } - current.timestamp = previous.timestamp + T.mins(5).msecs() - } - aapsLogger.debug(LTag.AUTOSENS, "Bucketed data created. Size: " + bData.size) - bucketedData = bData + private fun oldestDataAvailable(): Long { + var oldestTime = System.currentTimeMillis() + val oldestTempBasal = repository.getOldestTemporaryBasalRecord() + if (oldestTempBasal != null) oldestTime = min(oldestTime, oldestTempBasal.timestamp) + val oldestExtendedBolus = repository.getOldestExtendedBolusRecord() + if (oldestExtendedBolus != null) oldestTime = min(oldestTime, oldestExtendedBolus.timestamp) + val oldestBolus = repository.getOldestBolusRecord() + if (oldestBolus != null) oldestTime = min(oldestTime, oldestBolus.timestamp) + val oldestCarbs = repository.getOldestCarbsRecord() + if (oldestCarbs != null) oldestTime = min(oldestTime, oldestCarbs.timestamp) + oldestTime -= 15 * 60 * 1000L // allow 15 min before + return oldestTime } fun calculateDetectionStart(from: Long, limitDataToOldestAvailable: Boolean): Long { val profile = profileFunction.getProfile(from) var dia = Constants.defaultDIA if (profile != null) dia = profile.dia - val oldestDataAvailable = treatmentsPlugin.oldestDataAvailable() + val oldestDataAvailable = oldestDataAvailable() val getBGDataFrom: Long if (limitDataToOldestAvailable) { getBGDataFrom = max(oldestDataAvailable, (from - T.hours(1).msecs() * (24 + dia)).toLong()) @@ -388,33 +167,27 @@ open class IobCobCalculatorPlugin @Inject constructor( return getBGDataFrom } - override fun calculateFromTreatmentsAndTempsSynchronized(time: Long, profile: Profile?): IobTotal { - synchronized(dataLock) { return calculateFromTreatmentsAndTemps(time, profile) } - } - - private fun calculateFromTreatmentsAndTempsSynchronized(time: Long, lastAutosensResult: AutosensResult, exercise_mode: Boolean, half_basal_exercise_target: Int, isTempTarget: Boolean): IobTotal { - synchronized(dataLock) { return calculateFromTreatmentsAndTemps(time, lastAutosensResult, exercise_mode, half_basal_exercise_target, isTempTarget) } - } - - fun calculateFromTreatmentsAndTemps(fromTime: Long, profile: Profile?): IobTotal { + override fun calculateFromTreatmentsAndTemps(fromTime: Long, profile: Profile): IobTotal { val now = System.currentTimeMillis() - val time = roundUpTime(fromTime) + val time = ads.roundUpTime(fromTime) val cacheHit = iobTable[time] if (time < now && cacheHit != null) { //og.debug(">>> calculateFromTreatmentsAndTemps Cache hit " + new Date(time).toLocaleString()); return cacheHit } // else log.debug(">>> calculateFromTreatmentsAndTemps Cache miss " + new Date(time).toLocaleString()); - val bolusIob = treatmentsPlugin.getCalculationToTimeTreatments(time).round() - val basalIob = treatmentsPlugin.getCalculationToTimeTempBasals(time, true, now).round() + val bolusIob = calculateIobFromBolusToTime(time).round() + val basalIob = calculateIobToTimeFromTempBasalsIncludingConvertedExtended(time).round() // OpenAPSSMB only // Add expected zero temp basal for next 240 minutes val basalIobWithZeroTemp = basalIob.copy() - val t = TemporaryBasal(injector) - .date(now + 60 * 1000L) - .duration(240) - .absolute(0.0) - if (t.date < time) { - val calc = t.iobCalc(time, profile) + val t = TemporaryBasal( + timestamp = now + 60 * 1000L, + duration = 240, + rate = 0.0, + isAbsolute = true, + type = TemporaryBasal.Type.NORMAL) + if (t.timestamp < time) { + val calc = t.iobCalc(time, profile, activePlugin.activeInsulin) basalIobWithZeroTemp.plus(calc) } basalIob.iobWithZeroTemp = IobTotal.combine(bolusIob, basalIobWithZeroTemp).round() @@ -425,17 +198,17 @@ open class IobCobCalculatorPlugin @Inject constructor( return iobTotal } - fun calculateAbsInsulinFromTreatmentsAndTempsSynchronized(fromTime: Long): IobTotal { + override fun calculateAbsInsulinFromTreatmentsAndTemps(fromTime: Long): IobTotal { synchronized(dataLock) { val now = System.currentTimeMillis() - val time = roundUpTime(fromTime) + val time = ads.roundUpTime(fromTime) val cacheHit = absIobTable[time] if (time < now && cacheHit != null) { //log.debug(">>> calculateFromTreatmentsAndTemps Cache hit " + new Date(time).toLocaleString()); return cacheHit } // else log.debug(">>> calculateFromTreatmentsAndTemps Cache miss " + new Date(time).toLocaleString()); - val bolusIob = treatmentsPlugin.getCalculationToTimeTreatments(time).round() - val basalIob = treatmentsPlugin.getAbsoluteIOBTempBasals(time).round() + val bolusIob = calculateIobFromBolusToTime(time).round() + val basalIob = calculateAbsoluteIobTempBasals(time).round() val iobTotal = IobTotal.combine(bolusIob, basalIob).round() if (time < System.currentTimeMillis()) { absIobTable.put(time, iobTotal) @@ -445,20 +218,22 @@ open class IobCobCalculatorPlugin @Inject constructor( } private fun calculateFromTreatmentsAndTemps(time: Long, lastAutosensResult: AutosensResult, exercise_mode: Boolean, half_basal_exercise_target: Int, isTempTarget: Boolean): IobTotal { - val now = DateUtil.now() - val bolusIob = treatmentsPlugin.getCalculationToTimeTreatments(time).round() - val basalIob = treatmentsPlugin.getCalculationToTimeTempBasals(time, now, lastAutosensResult, exercise_mode, half_basal_exercise_target, isTempTarget).round() + val now = dateUtil.now() + val bolusIob = calculateIobFromBolusToTime(time).round() + val basalIob = getCalculationToTimeTempBasals(time, lastAutosensResult, exercise_mode, half_basal_exercise_target, isTempTarget).round() // OpenAPSSMB only // Add expected zero temp basal for next 240 minutes val basalIobWithZeroTemp = basalIob.copy() - val t = TemporaryBasal(injector) - .date(now + 60 * 1000L) - .duration(240) - .absolute(0.0) - if (t.date < time) { - val profile = profileFunction.getProfile(t.date) + val t = TemporaryBasal( + timestamp = now + 60 * 1000L, + duration = 240, + rate = 0.0, + isAbsolute = true, + type = TemporaryBasal.Type.NORMAL) + if (t.timestamp < time) { + val profile = profileFunction.getProfile(t.timestamp) if (profile != null) { - val calc = t.iobCalc(time, profile, lastAutosensResult, exercise_mode, half_basal_exercise_target, isTempTarget) + val calc = t.iobCalc(time, profile, lastAutosensResult, exercise_mode, half_basal_exercise_target, isTempTarget, activePlugin.activeInsulin) basalIobWithZeroTemp.plus(calc) } } @@ -466,27 +241,19 @@ open class IobCobCalculatorPlugin @Inject constructor( return IobTotal.combine(bolusIob, basalIob).round() } - fun findPreviousTimeFromBucketedData(time: Long): Long? { - val bData = bucketedData ?: return null - for (index in bData.indices) { - if (bData[index].timestamp <= time) return bData[index].timestamp - } - return null - } - - fun getBasalData(profile: Profile, fromTime: Long): BasalData { + override fun getBasalData(profile: Profile, fromTime: Long): BasalData { synchronized(dataLock) { val now = System.currentTimeMillis() - val time = roundUpTime(fromTime) + val time = ads.roundUpTime(fromTime) var retVal = basalDataTable[time] if (retVal == null) { //log.debug(">>> getBasalData Cache miss " + new Date(time).toLocaleString()); retVal = BasalData() - val tb = treatmentsPlugin.getTempBasalFromHistory(time) + val tb = getTempBasalIncludingConvertedExtended(time) retVal.basal = profile.getBasal(time) if (tb != null) { retVal.isTempBasalRunning = true - retVal.tempBasalAbsolute = tb.tempBasalConvertedToAbsolute(time, profile) + retVal.tempBasalAbsolute = tb.convertedToAbsolute(time, profile) } else { retVal.isTempBasalRunning = false retVal.tempBasalAbsolute = retVal.basal @@ -499,20 +266,7 @@ open class IobCobCalculatorPlugin @Inject constructor( } } - override fun getAutosensData(fromTime: Long): AutosensData? { - var time = fromTime - synchronized(dataLock) { - val now = System.currentTimeMillis() - if (time > now) { - return null - } - val previous = findPreviousTimeFromBucketedData(time) ?: return null - time = roundUpTime(previous) - return autosensDataTable[time] - } - } - - fun getLastAutosensDataSynchronized(reason: String): AutosensData? { + override fun getLastAutosensDataWithWaitForCalculationFinish(reason: String): AutosensData? { if (thread?.isAlive == true) { aapsLogger.debug(LTag.AUTOSENS, "AUTOSENSDATA is waiting for calculation thread: $reason") try { @@ -521,146 +275,87 @@ open class IobCobCalculatorPlugin @Inject constructor( } aapsLogger.debug(LTag.AUTOSENS, "AUTOSENSDATA finished waiting for calculation thread: $reason") } - synchronized(dataLock) { return getLastAutosensData(reason) } + return ads.getLastAutosensData(reason, aapsLogger, dateUtil) } - override fun getCobInfo(_synchronized: Boolean, reason: String): CobInfo { - val autosensData = if (_synchronized) getLastAutosensDataSynchronized(reason) else getLastAutosensData(reason) + override fun getCobInfo(waitForCalculationFinish: Boolean, reason: String): CobInfo { + val autosensData = + if (waitForCalculationFinish) getLastAutosensDataWithWaitForCalculationFinish(reason) + else ads.getLastAutosensData(reason, aapsLogger, dateUtil) var displayCob: Double? = null var futureCarbs = 0.0 - val now = DateUtil.now() - val treatments = treatmentsPlugin.treatmentsFromHistory + val now = dateUtil.now() + val carbs = repository.getCarbsDataFromTimeExpanded(now, true).blockingGet() if (autosensData != null) { displayCob = autosensData.cob - for (treatment in treatments) { - if (!treatment.isValid) continue - if (roundUpTime(treatment.date) > roundUpTime(autosensData.time) && treatment.date <= now && treatment.carbs > 0) { - displayCob += treatment.carbs + carbs.forEach { carb -> + if (ads.roundUpTime(carb.timestamp) > ads.roundUpTime(autosensData.time) && carb.timestamp <= now) { + displayCob += carb.amount } } } - for (treatment in treatments) { - if (!treatment.isValid) continue - if (treatment.date > now && treatment.carbs > 0) { - futureCarbs += treatment.carbs - } - } + // Future carbs + carbs.forEach { carb -> if (carb.timestamp > now) futureCarbs += carb.amount } return CobInfo(displayCob, futureCarbs) } - fun slowAbsorptionPercentage(timeInMinutes: Int): Double { - var sum = 0.0 - var count = 0 - val valuesToProcess = timeInMinutes / 5 - synchronized(dataLock) { - var i = autosensDataTable.size() - 1 - while (i >= 0 && count < valuesToProcess) { - if (autosensDataTable.valueAt(i).failoverToMinAbsorbtionRate) sum++ - count++ - i-- - } - } - return sum / count - } - - override fun getLastAutosensData(reason: String): AutosensData? { - if (autosensDataTable.size() < 1) { - aapsLogger.debug(LTag.AUTOSENS, "AUTOSENSDATA null: autosensDataTable empty ($reason)") - return null - } - val data: AutosensData? = try { - autosensDataTable.valueAt(autosensDataTable.size() - 1) - } catch (e: Exception) { - // data can be processed on the background - // in this rare case better return null and do not block UI - // APS plugin should use getLastAutosensDataSynchronized where the blocking is not an issue - aapsLogger.error("AUTOSENSDATA null: Exception caught ($reason)") - return null - } - if (data == null) { - aapsLogger.error("AUTOSENSDATA null: data==null") - return null - } - return if (data.time < System.currentTimeMillis() - 11 * 60 * 1000) { - aapsLogger.debug(LTag.AUTOSENS, "AUTOSENSDATA null: data is old (" + reason + ") size()=" + autosensDataTable.size() + " lastData=" + dateUtil.dateAndTimeAndSecondsString(data.time)) - null + override fun getMealDataWithWaitingForCalculationFinish(): MealData { + val result = MealData() + val now = System.currentTimeMillis() + val maxAbsorptionHours: Double = if (sensitivityAAPSPlugin.isEnabled() || sensitivityWeightedAveragePlugin.isEnabled()) { + sp.getDouble(R.string.key_absorption_maxtime, Constants.DEFAULT_MAX_ABSORPTION_TIME) } else { - aapsLogger.debug(LTag.AUTOSENS, "AUTOSENSDATA ($reason) $data") - data + sp.getDouble(R.string.key_absorption_cutoff, Constants.DEFAULT_MAX_ABSORPTION_TIME) } - } - - override fun lastDataTime(): String { - return if (autosensDataTable.size() > 0) dateUtil.dateAndTimeAndSecondsString(autosensDataTable.valueAt(autosensDataTable.size() - 1).time) else "autosensDataTable empty" - } - - val mealData: MealData - get() { - val result = MealData() - val profile = profileFunction.getProfile() ?: return result - val now = System.currentTimeMillis() - val diaAgo = now - java.lang.Double.valueOf(profile.dia * T.hours(1).msecs()).toLong() - val maxAbsorptionHours: Double = if (sensitivityAAPSPlugin.isEnabled() || sensitivityWeightedAveragePlugin.isEnabled()) { - sp.getDouble(R.string.key_absorption_maxtime, Constants.DEFAULT_MAX_ABSORPTION_TIME) - } else { - sp.getDouble(R.string.key_absorption_cutoff, Constants.DEFAULT_MAX_ABSORPTION_TIME) - } - val absorptionTimeAgo = now - java.lang.Double.valueOf(maxAbsorptionHours * T.hours(1).msecs()).toLong() - val treatments = treatmentsPlugin.treatmentsFromHistory - for (treatment in treatments) { - if (!treatment.isValid) continue - val t = treatment.date - if (t in (diaAgo + 1)..now) { - if (treatment.insulin > 0 && treatment.mealBolus) { - result.boluses += treatment.insulin - } - } - if (t in (absorptionTimeAgo + 1)..now) { - if (treatment.carbs >= 1) { - result.carbs += treatment.carbs - if (t > result.lastCarbTime) result.lastCarbTime = t - } + val absorptionTimeAgo = now - (maxAbsorptionHours * T.hours(1).msecs()).toLong() + repository.getCarbsDataFromTimeToTimeExpanded(absorptionTimeAgo + 1, now, true) + .blockingGet() + .forEach { + if (it.amount > 0) { + result.carbs += it.amount + if (it.timestamp > result.lastCarbTime) result.lastCarbTime = it.timestamp } } - val autosensData = getLastAutosensDataSynchronized("getMealData()") - if (autosensData != null) { - result.mealCOB = autosensData.cob - result.slopeFromMinDeviation = autosensData.slopeFromMinDeviation - result.slopeFromMaxDeviation = autosensData.slopeFromMaxDeviation - result.usedMinCarbsImpact = autosensData.usedMinCarbsImpact - } - result.lastBolusTime = treatmentsPlugin.lastBolusTime - return result + val autosensData = getLastAutosensDataWithWaitForCalculationFinish("getMealData()") + if (autosensData != null) { + result.mealCOB = autosensData.cob + result.slopeFromMinDeviation = autosensData.slopeFromMinDeviation + result.slopeFromMaxDeviation = autosensData.slopeFromMaxDeviation + result.usedMinCarbsImpact = autosensData.usedMinCarbsImpact } + val lastBolus = repository.getLastBolusRecordWrapped().blockingGet() + result.lastBolusTime = if (lastBolus is ValueWrapper.Existing) lastBolus.value.timestamp else 0L + return result + } override fun calculateIobArrayInDia(profile: Profile): Array { // predict IOB out to DIA plus 30m var time = System.currentTimeMillis() - time = roundUpTime(time) + time = ads.roundUpTime(time) val len = ((profile.dia * 60 + 30) / 5).toInt() val array = Array(len) { IobTotal(0) } for ((pos, i) in (0 until len).withIndex()) { val t = time + i * 5 * 60000 - val iob = calculateFromTreatmentsAndTempsSynchronized(t, profile) + val iob = calculateFromTreatmentsAndTemps(t, profile) array[pos] = iob } return array } - fun calculateIobArrayForSMB(lastAutosensResult: AutosensResult, exercise_mode: Boolean, half_basal_exercise_target: Int, isTempTarget: Boolean): Array { + override fun calculateIobArrayForSMB(lastAutosensResult: AutosensResult, exercise_mode: Boolean, half_basal_exercise_target: Int, isTempTarget: Boolean): Array { // predict IOB out to DIA plus 30m - val now = DateUtil.now() + val now = dateUtil.now() val len = 4 * 60 / 5 val array = Array(len) { IobTotal(0) } for ((pos, i) in (0 until len).withIndex()) { val t = now + i * 5 * 60000 - val iob = calculateFromTreatmentsAndTempsSynchronized(t, lastAutosensResult, exercise_mode, half_basal_exercise_target, isTempTarget) + val iob = calculateFromTreatmentsAndTemps(t, lastAutosensResult, exercise_mode, half_basal_exercise_target, isTempTarget) array[pos] = iob } return array } - fun iobArrayToString(array: Array): String { + override fun iobArrayToString(array: Array): String { val sb = StringBuilder() sb.append("[") for (i in array) { @@ -671,37 +366,35 @@ open class IobCobCalculatorPlugin @Inject constructor( return sb.toString() } - fun detectSensitivityWithLock(fromTime: Long, toTime: Long): AutosensResult { - synchronized(dataLock) { return activePlugin.activeSensitivity.detectSensitivity(this, fromTime, toTime) } - } - fun stopCalculation(from: String) { if (thread?.state != Thread.State.TERMINATED) { stopCalculationTrigger = true aapsLogger.debug(LTag.AUTOSENS, "Stopping calculation thread: $from") - while (thread?.state != Thread.State.TERMINATED) { + while (thread != null && thread?.state != Thread.State.TERMINATED) { SystemClock.sleep(100) } aapsLogger.debug(LTag.AUTOSENS, "Calculation thread stopped: $from") } } - fun runCalculation(from: String, end: Long, bgDataReload: Boolean, limitDataToOldestAvailable: Boolean, cause: Event) { + fun runCalculation(from: String, end: Long, bgDataReload: Boolean, limitDataToOldestAvailable: Boolean, cause: Event?) { aapsLogger.debug(LTag.AUTOSENS, "Starting calculation thread: " + from + " to " + dateUtil.dateAndTimeAndSecondsString(end)) if (thread == null || thread?.state == Thread.State.TERMINATED) { - thread = if (sensitivityOref1Plugin.isEnabled()) IobCobOref1Thread(injector, this, treatmentsPlugin, from, end, bgDataReload, limitDataToOldestAvailable, cause) else IobCobThread(injector, this, treatmentsPlugin, from, end, bgDataReload, limitDataToOldestAvailable, cause) + thread = + if (sensitivityOref1Plugin.isEnabled()) IobCobOref1Thread(injector, this, from, end, bgDataReload, limitDataToOldestAvailable, cause) + else IobCobThread(injector, this, from, end, bgDataReload, limitDataToOldestAvailable, cause) thread?.start() } } // When historical data is changed (coming from NS etc) finished calculations after this date must be invalidated - private fun newHistoryData(ev: EventNewHistoryData, bgDataReload: Boolean) { + private fun newHistoryData(oldDataTimestamp: Long, bgDataReload: Boolean, event: Event) { //log.debug("Locking onNewHistoryData"); stopCalculation("onEventNewHistoryData") synchronized(dataLock) { // clear up 5 min back for proper COB calculation - val time = ev.time - 5 * 60 * 1000L + val time = oldDataTimestamp - 5 * 60 * 1000L aapsLogger.debug(LTag.AUTOSENS, "Invalidating cached data to: " + dateUtil.dateAndTimeAndSecondsString(time)) for (index in iobTable.size() - 1 downTo 0) { if (iobTable.keyAt(index) > time) { @@ -719,14 +412,6 @@ open class IobCobCalculatorPlugin @Inject constructor( break } } - for (index in autosensDataTable.size() - 1 downTo 0) { - if (autosensDataTable.keyAt(index) > time) { - aapsLogger.debug(LTag.AUTOSENS, "Removing from autosensDataTable: " + dateUtil.dateAndTimeAndSecondsString(autosensDataTable.keyAt(index))) - autosensDataTable.removeAt(index) - } else { - break - } - } for (index in basalDataTable.size() - 1 downTo 0) { if (basalDataTable.keyAt(index) > time) { aapsLogger.debug(LTag.AUTOSENS, "Removing from basalDataTable: " + dateUtil.dateAndTimeAndSecondsString(basalDataTable.keyAt(index))) @@ -735,53 +420,22 @@ open class IobCobCalculatorPlugin @Inject constructor( break } } + ads.newHistoryData(time, aapsLogger, dateUtil) } - runCalculation("onEventNewHistoryData", System.currentTimeMillis(), bgDataReload, true, ev) + runCalculation("onEventNewHistoryData", System.currentTimeMillis(), bgDataReload, true, event) //log.debug("Releasing onNewHistoryData"); } - fun clearCache() { - synchronized(dataLock) { - aapsLogger.debug(LTag.AUTOSENS, "Clearing cached data.") - iobTable = LongSparseArray() - autosensDataTable = LongSparseArray() - basalDataTable = LongSparseArray() + override fun convertToJSONArray(iobArray: Array): JSONArray { + val array = JSONArray() + for (i in iobArray.indices) { + array.put(iobArray[i].determineBasalJson(dateUtil)) } - } - - /* - * Return last BgReading from database or null if db is empty - */ - fun lastBg(): GlucoseValue? { - val bgList = bgReadings - for (i in bgList.indices) if (bgList[i].value >= 39) return bgList[i] - return null - } - - /* - * Return bg reading if not old ( <9 min ) - * or null if older - */ - fun actualBg(): GlucoseValue? { - val lastBg = lastBg() ?: return null - return if (lastBg.timestamp > System.currentTimeMillis() - 9 * 60 * 1000) lastBg else null + return array } companion object { - // roundup to whole minute - fun roundUpTime(time: Long): Long { - return if (time % 60000 == 0L) time else (time / 60000 + 1) * 60000 - } - - fun convertToJSONArray(iobArray: Array): JSONArray { - val array = JSONArray() - for (i in iobArray.indices) { - array.put(iobArray[i].determineBasalJson()) - } - return array - } - // From https://gist.github.com/IceCreamYou/6ffa1b18c4c8f6aeaad2 // Returns the value at a given percentile in a sorted numeric array. // "Linear interpolation between closest ranks" method @@ -796,4 +450,190 @@ open class IobCobCalculatorPlugin @Inject constructor( return if (upper >= arr.size) arr[lower.toInt()] else arr[lower.toInt()] * (1 - weight) + arr[upper.toInt()] * weight } } + + /** + * Time range to the past for IOB calculation + * @return milliseconds + */ + fun range(): Long = ((profileFunction.getProfile()?.dia + ?: Constants.defaultDIA) * 60 * 60 * 1000).toLong() + + override fun calculateIobFromBolus(): IobTotal = calculateIobFromBolusToTime(dateUtil.now()) + + /** + * Calculate IobTotal from boluses and extended to provided timestamp. + * NOTE: Only isValid == true boluses are included + * NOTE: if faking by TBR by extended boluses is enabled, extended boluses are not included + * and are calculated towards temporary basals + * + * @param toTime timestamp in milliseconds + * @return calculated iob + */ + private fun calculateIobFromBolusToTime(toTime: Long): IobTotal { + val total = IobTotal(toTime) + val profile = profileFunction.getProfile() ?: return total + val dia = profile.dia + val divisor = sp.getDouble(R.string.key_openapsama_bolussnooze_dia_divisor, 2.0) + + val boluses = repository.getBolusesDataFromTime(toTime - range(), true).blockingGet() + + boluses.forEach { t -> + if (t.isValid && t.timestamp < toTime) { + val tIOB = t.iobCalc(activePlugin, toTime, dia) + total.iob += tIOB.iobContrib + total.activity += tIOB.activityContrib + if (t.amount > 0 && t.timestamp > total.lastBolusTime) total.lastBolusTime = t.timestamp + if (t.type != Bolus.Type.SMB) { + // instead of dividing the DIA that only worked on the bilinear curves, + // multiply the time the treatment is seen active. + val timeSinceTreatment = toTime - t.timestamp + val snoozeTime = t.timestamp + (timeSinceTreatment * divisor).toLong() + val bIOB = t.iobCalc(activePlugin, snoozeTime, dia) + total.bolussnooze += bIOB.iobContrib + } + } + } + + total.plus(calculateIobToTimeFromExtendedBoluses(toTime)) + return total + } + + private fun calculateIobToTimeFromExtendedBoluses(toTime: Long): IobTotal { + val total = IobTotal(toTime) + val now = dateUtil.now() + val pumpInterface = activePlugin.activePump + if (!pumpInterface.isFakingTempsByExtendedBoluses) { + val extendedBoluses = repository.getExtendedBolusDataFromTimeToTime(toTime - range(), toTime, true).blockingGet() + for (pos in extendedBoluses.indices) { + val e = extendedBoluses[pos] + if (e.timestamp > toTime) continue + if (e.end > now) e.end = now + val profile = profileFunction.getProfile(e.timestamp) ?: return total + val calc = e.iobCalc(toTime, profile, activePlugin.activeInsulin) + total.plus(calc) + } + } + return total + } + + override fun getTempBasal(timestamp: Long): TemporaryBasal? { + val tb = repository.getTemporaryBasalActiveAt(timestamp).blockingGet() + if (tb is ValueWrapper.Existing) return tb.value + return null + } + + override fun getExtendedBolus(timestamp: Long): ExtendedBolus? { + val tb = repository.getExtendedBolusActiveAt(timestamp).blockingGet() + if (tb is ValueWrapper.Existing) return tb.value + return null + } + + override fun getTempBasalIncludingConvertedExtended(timestamp: Long): TemporaryBasal? { + val tb = repository.getTemporaryBasalActiveAt(timestamp).blockingGet() + if (tb is ValueWrapper.Existing) return tb.value + val eb = repository.getExtendedBolusActiveAt(timestamp).blockingGet() + val profile = profileFunction.getProfile(timestamp) ?: return null + if (eb is ValueWrapper.Existing && activePlugin.activePump.isFakingTempsByExtendedBoluses) + return eb.value.toTemporaryBasal(profile) + return null + } + + override fun calculateAbsoluteIobTempBasals(toTime: Long): IobTotal { + val total = IobTotal(toTime) + var i = toTime - range() + while (i < toTime) { + val profile = profileFunction.getProfile(i) + if (profile == null) { + i += T.mins(5).msecs() + continue + } + val runningTBR = getTempBasalIncludingConvertedExtended(i) + val running = runningTBR?.convertedToAbsolute(i, profile) ?: profile.getBasal(i) + val bolus = Bolus( + timestamp = i, + amount = running * 5.0 / 60.0, + type = Bolus.Type.NORMAL, + isBasalInsulin = true + ) + val iob = bolus.iobCalc(activePlugin, toTime, profile.dia) + total.basaliob += iob.iobContrib + total.activity += iob.activityContrib + i += T.mins(5).msecs() + } + return total + } + + override fun calculateIobFromTempBasalsIncludingConvertedExtended(): IobTotal = + calculateIobToTimeFromTempBasalsIncludingConvertedExtended(dateUtil.now()) + + override fun calculateIobToTimeFromTempBasalsIncludingConvertedExtended(toTime: Long): IobTotal { + val total = IobTotal(toTime) + val now = dateUtil.now() + val pumpInterface = activePlugin.activePump + + val temporaryBasals = repository.getTemporaryBasalsDataFromTimeToTime(toTime - range(), toTime, true).blockingGet() + for (pos in temporaryBasals.indices) { + val t = temporaryBasals[pos] + if (t.timestamp > toTime) continue + val profile = profileFunction.getProfile(t.timestamp) ?: continue + if (t.end > now) t.end = now + val calc = t.iobCalc(toTime, profile, activePlugin.activeInsulin) + //log.debug("BasalIOB " + new Date(time) + " >>> " + calc.basalIob); + total.plus(calc) + } + if (pumpInterface.isFakingTempsByExtendedBoluses) { + val totalExt = IobTotal(toTime) + val extendedBoluses = repository.getExtendedBolusDataFromTimeToTime(toTime - range(), toTime, true).blockingGet() + for (pos in extendedBoluses.indices) { + val e = extendedBoluses[pos] + if (e.timestamp > toTime) continue + val profile = profileFunction.getProfile(e.timestamp) ?: continue + if (e.end > now) e.end = now + val calc = e.iobCalc(toTime, profile, activePlugin.activeInsulin) + totalExt.plus(calc) + } + // Convert to basal iob + totalExt.basaliob = totalExt.iob + totalExt.iob = 0.0 + totalExt.netbasalinsulin = totalExt.extendedBolusInsulin + totalExt.hightempinsulin = totalExt.extendedBolusInsulin + total.plus(totalExt) + } + return total + } + + open fun getCalculationToTimeTempBasals(toTime: Long, lastAutosensResult: AutosensResult, exercise_mode: Boolean, half_basal_exercise_target: Int, isTempTarget: Boolean): IobTotal { + val total = IobTotal(toTime) + val pumpInterface = activePlugin.activePump + val now = dateUtil.now() + val temporaryBasals = repository.getTemporaryBasalsDataFromTimeToTime(toTime - range(), toTime, true).blockingGet() + for (pos in temporaryBasals.indices) { + val t = temporaryBasals[pos] + if (t.timestamp > toTime) continue + val profile = profileFunction.getProfile(t.timestamp) ?: continue + if (t.end > now) t.end = now + val calc = t.iobCalc(toTime, profile, lastAutosensResult, exercise_mode, half_basal_exercise_target, isTempTarget, activePlugin.activeInsulin) + //log.debug("BasalIOB " + new Date(time) + " >>> " + calc.basalIob); + total.plus(calc) + } + if (pumpInterface.isFakingTempsByExtendedBoluses) { + val totalExt = IobTotal(toTime) + val extendedBoluses = repository.getExtendedBolusDataFromTimeToTime(toTime - range(), toTime, true).blockingGet() + for (pos in extendedBoluses.indices) { + val e = extendedBoluses[pos] + if (e.timestamp > toTime) continue + val profile = profileFunction.getProfile(e.timestamp) ?: continue + if (e.end > now) e.end = now + val calc = e.iobCalc(toTime, profile, lastAutosensResult, exercise_mode, half_basal_exercise_target, isTempTarget, activePlugin.activeInsulin) + totalExt.plus(calc) + } + // Convert to basal iob + totalExt.basaliob = totalExt.iob + totalExt.iob = 0.0 + totalExt.netbasalinsulin = totalExt.extendedBolusInsulin + totalExt.hightempinsulin = totalExt.extendedBolusInsulin + total.plus(totalExt) + } + return total + } } \ No newline at end of file diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/iob/iobCobCalculator/IobCobOref1Thread.kt b/app/src/main/java/info/nightscout/androidaps/plugins/iob/iobCobCalculator/IobCobOref1Thread.kt index 2bfc38d813..88c9291f86 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/iob/iobCobCalculator/IobCobOref1Thread.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/iob/iobCobCalculator/IobCobOref1Thread.kt @@ -10,6 +10,8 @@ import info.nightscout.androidaps.database.AppRepository import info.nightscout.androidaps.database.ValueWrapper import info.nightscout.androidaps.events.Event import info.nightscout.androidaps.events.EventAutosensCalculationFinished +import info.nightscout.androidaps.extensions.target +import info.nightscout.androidaps.interfaces.ActivePlugin import info.nightscout.androidaps.interfaces.ProfileFunction import info.nightscout.androidaps.logging.AAPSLogger import info.nightscout.androidaps.logging.LTag @@ -17,16 +19,16 @@ import info.nightscout.androidaps.plugins.aps.openAPSSMB.SMBDefaults import info.nightscout.androidaps.plugins.bus.RxBusWrapper import info.nightscout.androidaps.plugins.general.overview.events.EventNewNotification import info.nightscout.androidaps.plugins.general.overview.notifications.Notification -import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorPlugin.Companion.roundUpTime import info.nightscout.androidaps.plugins.iob.iobCobCalculator.data.AutosensData -import info.nightscout.androidaps.plugins.iob.iobCobCalculator.events.EventAutosensBgLoaded import info.nightscout.androidaps.plugins.iob.iobCobCalculator.events.EventIobCalculationProgress import info.nightscout.androidaps.plugins.sensitivity.SensitivityAAPSPlugin import info.nightscout.androidaps.plugins.sensitivity.SensitivityWeightedAveragePlugin -import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin -import info.nightscout.androidaps.utils.* +import info.nightscout.androidaps.utils.DateUtil +import info.nightscout.androidaps.utils.DecimalFormatter +import info.nightscout.androidaps.utils.FabricPrivacy +import info.nightscout.androidaps.utils.Profiler +import info.nightscout.androidaps.utils.T import info.nightscout.androidaps.utils.buildHelper.BuildHelper -import info.nightscout.androidaps.utils.extensions.target import info.nightscout.androidaps.utils.resources.ResourceHelper import info.nightscout.androidaps.utils.sharedPreferences.SP import java.util.* @@ -39,12 +41,11 @@ import kotlin.math.roundToLong class IobCobOref1Thread internal constructor( private val injector: HasAndroidInjector, private val iobCobCalculatorPlugin: IobCobCalculatorPlugin, // cannot be injected : HistoryBrowser uses different instance - private val treatmentsPlugin: TreatmentsPlugin, // cannot be injected : HistoryBrowser uses different instance private val from: String, private val end: Long, private val bgDataReload: Boolean, private val limitDataToOldestAvailable: Boolean, - private val cause: Event + private val cause: Event? ) : Thread() { @Inject lateinit var aapsLogger: AAPSLogger @@ -55,6 +56,7 @@ class IobCobOref1Thread internal constructor( @Inject lateinit var context: Context @Inject lateinit var sensitivityAAPSPlugin: SensitivityAAPSPlugin @Inject lateinit var sensitivityWeightedAveragePlugin: SensitivityWeightedAveragePlugin + @Inject lateinit var activePlugin: ActivePlugin @Inject lateinit var buildHelper: BuildHelper @Inject lateinit var profiler: Profiler @Inject lateinit var fabricPrivacy: FabricPrivacy @@ -69,7 +71,7 @@ class IobCobOref1Thread internal constructor( } override fun run() { - val start = DateUtil.now() + val start = dateUtil.now() mWakeLock?.acquire(T.mins(10).msecs()) try { aapsLogger.debug(LTag.AUTOSENS, "AUTOSENSDATA thread started: $from") @@ -79,244 +81,244 @@ class IobCobOref1Thread internal constructor( } //log.debug("Locking calculateSensitivityData"); val oldestTimeWithData = iobCobCalculatorPlugin.calculateDetectionStart(end, limitDataToOldestAvailable) - synchronized(iobCobCalculatorPlugin.dataLock) { - if (bgDataReload) { - iobCobCalculatorPlugin.loadBgData(end) - iobCobCalculatorPlugin.createBucketedData() - rxBus.send(EventAutosensBgLoaded(cause)) - } - val bucketedData = iobCobCalculatorPlugin.bucketedData - val autosensDataTable = iobCobCalculatorPlugin.getAutosensDataTable() - if (bucketedData == null || bucketedData.size < 3) { - aapsLogger.debug(LTag.AUTOSENS, "Aborting calculation thread (No bucketed data available): $from") + if (bgDataReload) { + iobCobCalculatorPlugin.ads.loadBgData(end, repository, aapsLogger, dateUtil) + iobCobCalculatorPlugin.clearCache() + } + // work on local copy and set back when finished + val ads = iobCobCalculatorPlugin.ads.clone() + val bucketedData = ads.bucketedData + val autosensDataTable = ads.autosensDataTable + if (bucketedData == null || bucketedData.size < 3) { + aapsLogger.debug(LTag.AUTOSENS, "Aborting calculation thread (No bucketed data available): $from") + return + } + val prevDataTime = ads.roundUpTime(bucketedData[bucketedData.size - 3].timestamp) + aapsLogger.debug(LTag.AUTOSENS, "Prev data time: " + dateUtil.dateAndTimeString(prevDataTime)) + var previous = autosensDataTable[prevDataTime] + // start from oldest to be able sub cob + for (i in bucketedData.size - 4 downTo 0) { + val progress = i.toString() + if (buildHelper.isDev()) " ($from)" else "" + rxBus.send(EventIobCalculationProgress(progress)) + if (iobCobCalculatorPlugin.stopCalculationTrigger) { + iobCobCalculatorPlugin.stopCalculationTrigger = false + aapsLogger.debug(LTag.AUTOSENS, "Aborting calculation thread (trigger): $from") return } - val prevDataTime = roundUpTime(bucketedData[bucketedData.size - 3].timestamp) - aapsLogger.debug(LTag.AUTOSENS, "Prev data time: " + dateUtil.dateAndTimeString(prevDataTime)) - var previous = autosensDataTable[prevDataTime] - // start from oldest to be able sub cob - for (i in bucketedData.size - 4 downTo 0) { - val progress = i.toString() + if (buildHelper.isDev()) " ($from)" else "" - rxBus.send(EventIobCalculationProgress(progress)) - if (iobCobCalculatorPlugin.stopCalculationTrigger) { - iobCobCalculatorPlugin.stopCalculationTrigger = false - aapsLogger.debug(LTag.AUTOSENS, "Aborting calculation thread (trigger): $from") - return - } - // check if data already exists - var bgTime = bucketedData[i].timestamp - bgTime = roundUpTime(bgTime) - if (bgTime > roundUpTime(DateUtil.now())) continue - var existing: AutosensData? - if (autosensDataTable[bgTime].also { existing = it } != null) { - previous = existing - continue - } - val profile = profileFunction.getProfile(bgTime) - if (profile == null) { - aapsLogger.debug(LTag.AUTOSENS, "Aborting calculation thread (no profile): $from") - return // profile not set yet - } - aapsLogger.debug(LTag.AUTOSENS, "Processing calculation thread: " + from + " (" + i + "/" + bucketedData.size + ")") - val sens = profile.getIsfMgdl(bgTime) - val autosensData = AutosensData(injector) - autosensData.time = bgTime - if (previous != null) autosensData.activeCarbsList = previous.cloneCarbsList() else autosensData.activeCarbsList = ArrayList() - - //console.error(bgTime , bucketed_data[i].glucose); - var avgDelta: Double - var delta: Double - val bg: Double = bucketedData[i].value - if (bg < 39 || bucketedData[i + 3].value < 39) { - aapsLogger.error("! value < 39") - continue - } - autosensData.bg = bg - delta = bg - bucketedData[i + 1].value - avgDelta = (bg - bucketedData[i + 3].value) / 3 - val iob = iobCobCalculatorPlugin.calculateFromTreatmentsAndTemps(bgTime, profile) - val bgi = -iob.activity * sens * 5 - val deviation = delta - bgi - val avgDeviation = ((avgDelta - bgi) * 1000).roundToLong() / 1000.0 - var slopeFromMaxDeviation = 0.0 - var slopeFromMinDeviation = 999.0 - - // https://github.com/openaps/oref0/blob/master/lib/determine-basal/cob-autosens.js#L169 - if (i < bucketedData.size - 16) { // we need 1h of data to calculate minDeviationSlope - @Suppress("UNUSED_VARIABLE") var maxDeviation = 0.0 - @Suppress("UNUSED_VARIABLE") var minDeviation = 999.0 - val hourAgo = bgTime + 10 * 1000 - 60 * 60 * 1000L - val hourAgoData = iobCobCalculatorPlugin.getAutosensData(hourAgo) - if (hourAgoData != null) { - val initialIndex = autosensDataTable.indexOfKey(hourAgoData.time) - aapsLogger.debug(LTag.AUTOSENS, ">>>>> bucketed_data.size()=" + bucketedData.size + " i=" + i + " hourAgoData=" + hourAgoData.toString()) - var past = 1 - try { - while (past < 12) { - val ad = autosensDataTable.valueAt(initialIndex + past) - aapsLogger.debug(LTag.AUTOSENS, ">>>>> past=" + past + " ad=" + ad?.toString()) - if (ad == null) { - aapsLogger.debug(LTag.AUTOSENS, autosensDataTable.toString()) - aapsLogger.debug(LTag.AUTOSENS, bucketedData.toString()) - aapsLogger.debug(LTag.AUTOSENS, iobCobCalculatorPlugin.bgReadings.toString()) - val notification = Notification(Notification.SEND_LOGFILES, resourceHelper.gs(R.string.sendlogfiles), Notification.LOW) - rxBus.send(EventNewNotification(notification)) - sp.putBoolean("log_AUTOSENS", true) - break - } - // let it here crash on NPE to get more data as i cannot reproduce this bug - val deviationSlope = (ad.avgDeviation - avgDeviation) / (ad.time - bgTime) * 1000 * 60 * 5 - if (ad.avgDeviation > maxDeviation) { - slopeFromMaxDeviation = min(0.0, deviationSlope) - maxDeviation = ad.avgDeviation - } - if (ad.avgDeviation < minDeviation) { - slopeFromMinDeviation = max(0.0, deviationSlope) - minDeviation = ad.avgDeviation - } - past++ - } - } catch (e: Exception) { - aapsLogger.error("Unhandled exception", e) - fabricPrivacy.logException(e) - aapsLogger.debug(autosensDataTable.toString()) - aapsLogger.debug(bucketedData.toString()) - aapsLogger.debug(iobCobCalculatorPlugin.bgReadings.toString()) - val notification = Notification(Notification.SEND_LOGFILES, resourceHelper.gs(R.string.sendlogfiles), Notification.LOW) - rxBus.send(EventNewNotification(notification)) - sp.putBoolean("log_AUTOSENS", true) - break - } - } else { - aapsLogger.debug(LTag.AUTOSENS, ">>>>> bucketed_data.size()=" + bucketedData.size + " i=" + i + " hourAgoData=" + "null") - } - } - val recentCarbTreatments = treatmentsPlugin.getCarbTreatments5MinBackFromHistory(bgTime) - for (recentCarbTreatment in recentCarbTreatments) { - autosensData.carbsFromBolus += recentCarbTreatment.carbs - val isAAPSOrWeighted = sensitivityAAPSPlugin.isEnabled() || sensitivityWeightedAveragePlugin.isEnabled() - autosensData.activeCarbsList.add(autosensData.CarbsInPast(recentCarbTreatment, isAAPSOrWeighted)) - autosensData.pastSensitivity += "[" + DecimalFormatter.to0Decimal(recentCarbTreatment.carbs) + "g]" - } - - // if we are absorbing carbs - if (previous != null && previous.cob > 0) { - // calculate sum of min carb impact from all active treatments - val totalMinCarbsImpact = sp.getDouble(R.string.key_openapsama_min_5m_carbimpact, SMBDefaults.min_5m_carbimpact) - - // figure out how many carbs that represents - // but always assume at least 3mg/dL/5m (default) absorption per active treatment - val ci = max(deviation, totalMinCarbsImpact) - if (ci != deviation) autosensData.failoverToMinAbsorbtionRate = true - autosensData.absorbed = ci * profile.getIc(bgTime) / sens - // and add that to the running total carbsAbsorbed - autosensData.cob = max(previous.cob - autosensData.absorbed, 0.0) - autosensData.mealCarbs = previous.mealCarbs - autosensData.substractAbosorbedCarbs() - autosensData.usedMinCarbsImpact = totalMinCarbsImpact - autosensData.absorbing = previous.absorbing - autosensData.mealStartCounter = previous.mealStartCounter - autosensData.type = previous.type - autosensData.uam = previous.uam - } - val isAAPSOrWeighted = sensitivityAAPSPlugin.isEnabled() || sensitivityWeightedAveragePlugin.isEnabled() - autosensData.removeOldCarbs(bgTime, isAAPSOrWeighted) - autosensData.cob += autosensData.carbsFromBolus - autosensData.mealCarbs += autosensData.carbsFromBolus - autosensData.deviation = deviation - autosensData.bgi = bgi - autosensData.delta = delta - autosensData.avgDelta = avgDelta - autosensData.avgDeviation = avgDeviation - autosensData.slopeFromMaxDeviation = slopeFromMaxDeviation - autosensData.slopeFromMinDeviation = slopeFromMinDeviation - - // If mealCOB is zero but all deviations since hitting COB=0 are positive, exclude from autosens - if (autosensData.cob > 0 || autosensData.absorbing || autosensData.mealCarbs > 0) { - autosensData.absorbing = deviation > 0 - // stop excluding positive deviations as soon as mealCOB=0 if meal has been absorbing for >5h - if (autosensData.mealStartCounter > 60 && autosensData.cob < 0.5) { - autosensData.absorbing = false - } - if (!autosensData.absorbing && autosensData.cob < 0.5) { - autosensData.mealCarbs = 0.0 - } - // check previous "type" value, and if it wasn't csf, set a mealAbsorption start flag - if (autosensData.type != "csf") { -// process.stderr.write("("); - autosensData.mealStartCounter = 0 - } - autosensData.mealStartCounter++ - autosensData.type = "csf" - } else { - // check previous "type" value, and if it was csf, set a mealAbsorption end flag - val currentBasal = profile.getBasal(bgTime) - // always exclude the first 45m after each carb entry - //if (iob.iob > currentBasal || uam ) { - if (iob.iob > 2 * currentBasal || autosensData.uam || autosensData.mealStartCounter < 9) { - autosensData.mealStartCounter++ - autosensData.uam = deviation > 0 - autosensData.type = "uam" - } else { - autosensData.type = "non-meal" - } - } - - // Exclude meal-related deviations (carb absorption) from autosens - when (autosensData.type) { - "non-meal" -> { - when { - abs(deviation) < Constants.DEVIATION_TO_BE_EQUAL -> { - autosensData.pastSensitivity += "=" - autosensData.validDeviation = true - } - - deviation > 0 -> { - autosensData.pastSensitivity += "+" - autosensData.validDeviation = true - } - - else -> { - autosensData.pastSensitivity += "-" - autosensData.validDeviation = true - } - } - } - - "uam" -> { - autosensData.pastSensitivity += "u" - } - - else -> { - autosensData.pastSensitivity += "x" - } - } - - // add an extra negative deviation if a high temp target is running and exercise mode is set - // TODO AS-FIX - @Suppress("SimplifyBooleanWithConstants") - if (false && sp.getBoolean(R.string.key_high_temptarget_raises_sensitivity, SMBDefaults.high_temptarget_raises_sensitivity)) { - val tempTarget = repository.getTemporaryTargetActiveAt(dateUtil._now()).blockingGet() - if (tempTarget is ValueWrapper.Existing && tempTarget.value.target() >= 100) { - autosensData.extraDeviation.add(-(tempTarget.value.target() - 100) / 20) - } - } - - // add one neutral deviation every 2 hours to help decay over long exclusion periods - val calendar = GregorianCalendar() - calendar.timeInMillis = bgTime - val min = calendar[Calendar.MINUTE] - val hours = calendar[Calendar.HOUR_OF_DAY] - if (min in 0..4 && hours % 2 == 0) autosensData.extraDeviation.add(0.0) - previous = autosensData - if (bgTime < DateUtil.now()) autosensDataTable.put(bgTime, autosensData) - aapsLogger.debug(LTag.AUTOSENS, "Running detectSensitivity from: " + dateUtil.dateAndTimeString(oldestTimeWithData) + " to: " + dateUtil.dateAndTimeString(bgTime) + " lastDataTime:" + iobCobCalculatorPlugin.lastDataTime()) - val sensitivity = iobCobCalculatorPlugin.detectSensitivityWithLock(oldestTimeWithData, bgTime) - aapsLogger.debug(LTag.AUTOSENS, "Sensitivity result: $sensitivity") - autosensData.autosensResult = sensitivity - aapsLogger.debug(LTag.AUTOSENS, autosensData.toString()) + // check if data already exists + var bgTime = bucketedData[i].timestamp + bgTime = ads.roundUpTime(bgTime) + if (bgTime > ads.roundUpTime(dateUtil.now())) continue + var existing: AutosensData? + if (autosensDataTable[bgTime].also { existing = it } != null) { + previous = existing + continue } + val profile = profileFunction.getProfile(bgTime) + if (profile == null) { + aapsLogger.debug(LTag.AUTOSENS, "Aborting calculation thread (no profile): $from") + return // profile not set yet + } + aapsLogger.debug(LTag.AUTOSENS, "Processing calculation thread: " + from + " (" + i + "/" + bucketedData.size + ")") + val sens = profile.getIsfMgdl(bgTime) + val autosensData = AutosensData(injector) + autosensData.time = bgTime + if (previous != null) autosensData.activeCarbsList = previous.cloneCarbsList() else autosensData.activeCarbsList = ArrayList() + + //console.error(bgTime , bucketed_data[i].glucose); + var avgDelta: Double + var delta: Double + val bg: Double = bucketedData[i].value + if (bg < 39 || bucketedData[i + 3].value < 39) { + aapsLogger.error("! value < 39") + continue + } + autosensData.bg = bg + delta = bg - bucketedData[i + 1].value + avgDelta = (bg - bucketedData[i + 3].value) / 3 + val iob = iobCobCalculatorPlugin.calculateFromTreatmentsAndTemps(bgTime, profile) + val bgi = -iob.activity * sens * 5 + val deviation = delta - bgi + val avgDeviation = ((avgDelta - bgi) * 1000).roundToLong() / 1000.0 + var slopeFromMaxDeviation = 0.0 + var slopeFromMinDeviation = 999.0 + + // https://github.com/openaps/oref0/blob/master/lib/determine-basal/cob-autosens.js#L169 + if (i < bucketedData.size - 16) { // we need 1h of data to calculate minDeviationSlope + @Suppress("UNUSED_VARIABLE") var maxDeviation = 0.0 + @Suppress("UNUSED_VARIABLE") var minDeviation = 999.0 + val hourAgo = bgTime + 10 * 1000 - 60 * 60 * 1000L + val hourAgoData = ads.getAutosensDataAtTime(hourAgo) + if (hourAgoData != null) { + val initialIndex = autosensDataTable.indexOfKey(hourAgoData.time) + aapsLogger.debug(LTag.AUTOSENS, ">>>>> bucketed_data.size()=" + bucketedData.size + " i=" + i + " hourAgoData=" + hourAgoData.toString()) + var past = 1 + try { + while (past < 12) { + val ad = autosensDataTable.valueAt(initialIndex + past) + aapsLogger.debug(LTag.AUTOSENS, ">>>>> past=" + past + " ad=" + ad?.toString()) + if (ad == null) { + aapsLogger.debug(LTag.AUTOSENS, autosensDataTable.toString()) + aapsLogger.debug(LTag.AUTOSENS, bucketedData.toString()) + //aapsLogger.debug(LTag.AUTOSENS, iobCobCalculatorPlugin.getBgReadingsDataTable().toString()) + val notification = Notification(Notification.SEND_LOGFILES, resourceHelper.gs(R.string.sendlogfiles), Notification.LOW) + rxBus.send(EventNewNotification(notification)) + sp.putBoolean("log_AUTOSENS", true) + break + } + // let it here crash on NPE to get more data as i cannot reproduce this bug + val deviationSlope = (ad.avgDeviation - avgDeviation) / (ad.time - bgTime) * 1000 * 60 * 5 + if (ad.avgDeviation > maxDeviation) { + slopeFromMaxDeviation = min(0.0, deviationSlope) + maxDeviation = ad.avgDeviation + } + if (ad.avgDeviation < minDeviation) { + slopeFromMinDeviation = max(0.0, deviationSlope) + minDeviation = ad.avgDeviation + } + past++ + } + } catch (e: Exception) { + aapsLogger.error("Unhandled exception", e) + fabricPrivacy.logException(e) + aapsLogger.debug(autosensDataTable.toString()) + aapsLogger.debug(bucketedData.toString()) + //aapsLogger.debug(iobCobCalculatorPlugin.getBgReadingsDataTable().toString()) + val notification = Notification(Notification.SEND_LOGFILES, resourceHelper.gs(R.string.sendlogfiles), Notification.LOW) + rxBus.send(EventNewNotification(notification)) + sp.putBoolean("log_AUTOSENS", true) + break + } + } else { + aapsLogger.debug(LTag.AUTOSENS, ">>>>> bucketed_data.size()=" + bucketedData.size + " i=" + i + " hourAgoData=" + "null") + } + } + val recentCarbTreatments = repository.getCarbsDataFromTimeToTimeExpanded(bgTime - T.mins(5).msecs(), bgTime, true).blockingGet() + for (recentCarbTreatment in recentCarbTreatments) { + autosensData.carbsFromBolus += recentCarbTreatment.amount + val isAAPSOrWeighted = sensitivityAAPSPlugin.isEnabled() || sensitivityWeightedAveragePlugin.isEnabled() + autosensData.activeCarbsList.add(autosensData.CarbsInPast(recentCarbTreatment, isAAPSOrWeighted)) + autosensData.pastSensitivity += "[" + DecimalFormatter.to0Decimal(recentCarbTreatment.amount) + "g]" + } + + // if we are absorbing carbs + if (previous != null && previous.cob > 0) { + // calculate sum of min carb impact from all active treatments + val totalMinCarbsImpact = sp.getDouble(R.string.key_openapsama_min_5m_carbimpact, SMBDefaults.min_5m_carbimpact) + + // figure out how many carbs that represents + // but always assume at least 3mg/dL/5m (default) absorption per active treatment + val ci = max(deviation, totalMinCarbsImpact) + if (ci != deviation) autosensData.failoverToMinAbsorbtionRate = true + autosensData.absorbed = ci * profile.getIc(bgTime) / sens + // and add that to the running total carbsAbsorbed + autosensData.cob = max(previous.cob - autosensData.absorbed, 0.0) + autosensData.mealCarbs = previous.mealCarbs + autosensData.substractAbosorbedCarbs() + autosensData.usedMinCarbsImpact = totalMinCarbsImpact + autosensData.absorbing = previous.absorbing + autosensData.mealStartCounter = previous.mealStartCounter + autosensData.type = previous.type + autosensData.uam = previous.uam + } + val isAAPSOrWeighted = sensitivityAAPSPlugin.isEnabled() || sensitivityWeightedAveragePlugin.isEnabled() + autosensData.removeOldCarbs(bgTime, isAAPSOrWeighted) + autosensData.cob += autosensData.carbsFromBolus + autosensData.mealCarbs += autosensData.carbsFromBolus + autosensData.deviation = deviation + autosensData.bgi = bgi + autosensData.delta = delta + autosensData.avgDelta = avgDelta + autosensData.avgDeviation = avgDeviation + autosensData.slopeFromMaxDeviation = slopeFromMaxDeviation + autosensData.slopeFromMinDeviation = slopeFromMinDeviation + + // If mealCOB is zero but all deviations since hitting COB=0 are positive, exclude from autosens + if (autosensData.cob > 0 || autosensData.absorbing || autosensData.mealCarbs > 0) { + autosensData.absorbing = deviation > 0 + // stop excluding positive deviations as soon as mealCOB=0 if meal has been absorbing for >5h + if (autosensData.mealStartCounter > 60 && autosensData.cob < 0.5) { + autosensData.absorbing = false + } + if (!autosensData.absorbing && autosensData.cob < 0.5) { + autosensData.mealCarbs = 0.0 + } + // check previous "type" value, and if it wasn't csf, set a mealAbsorption start flag + if (autosensData.type != "csf") { +// process.stderr.write("("); + autosensData.mealStartCounter = 0 + } + autosensData.mealStartCounter++ + autosensData.type = "csf" + } else { + // check previous "type" value, and if it was csf, set a mealAbsorption end flag + val currentBasal = profile.getBasal(bgTime) + // always exclude the first 45m after each carb entry + //if (iob.iob > currentBasal || uam ) { + if (iob.iob > 2 * currentBasal || autosensData.uam || autosensData.mealStartCounter < 9) { + autosensData.mealStartCounter++ + autosensData.uam = deviation > 0 + autosensData.type = "uam" + } else { + autosensData.type = "non-meal" + } + } + + // Exclude meal-related deviations (carb absorption) from autosens + when (autosensData.type) { + "non-meal" -> { + when { + abs(deviation) < Constants.DEVIATION_TO_BE_EQUAL -> { + autosensData.pastSensitivity += "=" + autosensData.validDeviation = true + } + + deviation > 0 -> { + autosensData.pastSensitivity += "+" + autosensData.validDeviation = true + } + + else -> { + autosensData.pastSensitivity += "-" + autosensData.validDeviation = true + } + } + } + + "uam" -> { + autosensData.pastSensitivity += "u" + } + + else -> { + autosensData.pastSensitivity += "x" + } + } + + // add an extra negative deviation if a high temp target is running and exercise mode is set + // TODO AS-FIX + @Suppress("SimplifyBooleanWithConstants") + if (false && sp.getBoolean(R.string.key_high_temptarget_raises_sensitivity, SMBDefaults.high_temptarget_raises_sensitivity)) { + val tempTarget = repository.getTemporaryTargetActiveAt(dateUtil.now()).blockingGet() + if (tempTarget is ValueWrapper.Existing && tempTarget.value.target() >= 100) { + autosensData.extraDeviation.add(-(tempTarget.value.target() - 100) / 20) + } + } + + // add one neutral deviation every 2 hours to help decay over long exclusion periods + val calendar = GregorianCalendar() + calendar.timeInMillis = bgTime + val min = calendar[Calendar.MINUTE] + val hours = calendar[Calendar.HOUR_OF_DAY] + if (min in 0..4 && hours % 2 == 0) autosensData.extraDeviation.add(0.0) + previous = autosensData + if (bgTime < dateUtil.now()) autosensDataTable.put(bgTime, autosensData) + aapsLogger.debug(LTag.AUTOSENS, "Running detectSensitivity from: " + dateUtil.dateAndTimeString(oldestTimeWithData) + " to: " + dateUtil.dateAndTimeString(bgTime) + " lastDataTime:" + ads.lastDataTime(dateUtil)) + val sensitivity = activePlugin.activeSensitivity.detectSensitivity(ads, oldestTimeWithData, bgTime) + aapsLogger.debug(LTag.AUTOSENS, "Sensitivity result: $sensitivity") + autosensData.autosensResult = sensitivity + aapsLogger.debug(LTag.AUTOSENS, autosensData.toString()) } + iobCobCalculatorPlugin.ads = ads Thread { SystemClock.sleep(1000) rxBus.send(EventAutosensCalculationFinished(cause)) @@ -325,7 +327,6 @@ class IobCobOref1Thread internal constructor( mWakeLock?.release() rxBus.send(EventIobCalculationProgress("")) aapsLogger.debug(LTag.AUTOSENS, "AUTOSENSDATA thread ended: $from") - aapsLogger.debug(LTag.AUTOSENS, "Midnights: " + MidnightTime.log()) profiler.log(LTag.AUTOSENS, "IobCobOref1Thread", start) } } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/iob/iobCobCalculator/IobCobThread.kt b/app/src/main/java/info/nightscout/androidaps/plugins/iob/iobCobCalculator/IobCobThread.kt index bba3777c40..b7a04cde7d 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/iob/iobCobCalculator/IobCobThread.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/iob/iobCobCalculator/IobCobThread.kt @@ -6,7 +6,10 @@ import android.os.SystemClock import dagger.android.HasAndroidInjector import info.nightscout.androidaps.Constants import info.nightscout.androidaps.R +import info.nightscout.androidaps.database.AppRepository import info.nightscout.androidaps.events.Event +import info.nightscout.androidaps.events.EventAutosensCalculationFinished +import info.nightscout.androidaps.interfaces.ActivePlugin import info.nightscout.androidaps.interfaces.PluginType import info.nightscout.androidaps.interfaces.ProfileFunction import info.nightscout.androidaps.logging.AAPSLogger @@ -15,15 +18,15 @@ import info.nightscout.androidaps.plugins.aps.openAPSSMB.SMBDefaults import info.nightscout.androidaps.plugins.bus.RxBusWrapper import info.nightscout.androidaps.plugins.general.overview.events.EventNewNotification import info.nightscout.androidaps.plugins.general.overview.notifications.Notification -import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorPlugin.Companion.roundUpTime import info.nightscout.androidaps.plugins.iob.iobCobCalculator.data.AutosensData -import info.nightscout.androidaps.plugins.iob.iobCobCalculator.events.EventAutosensBgLoaded -import info.nightscout.androidaps.events.EventAutosensCalculationFinished import info.nightscout.androidaps.plugins.iob.iobCobCalculator.events.EventIobCalculationProgress import info.nightscout.androidaps.plugins.sensitivity.SensitivityAAPSPlugin import info.nightscout.androidaps.plugins.sensitivity.SensitivityWeightedAveragePlugin -import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin -import info.nightscout.androidaps.utils.* +import info.nightscout.androidaps.utils.DateUtil +import info.nightscout.androidaps.utils.DecimalFormatter +import info.nightscout.androidaps.utils.FabricPrivacy +import info.nightscout.androidaps.utils.Profiler +import info.nightscout.androidaps.utils.T import info.nightscout.androidaps.utils.buildHelper.BuildHelper import info.nightscout.androidaps.utils.resources.ResourceHelper import info.nightscout.androidaps.utils.sharedPreferences.SP @@ -37,12 +40,11 @@ import kotlin.math.roundToLong class IobCobThread @Inject internal constructor( private val injector: HasAndroidInjector, private val iobCobCalculatorPlugin: IobCobCalculatorPlugin, // cannot be injected : HistoryBrowser uses different instance - private val treatmentsPlugin: TreatmentsPlugin, // cannot be injected : HistoryBrowser uses different instance private val from: String, private val end: Long, private val bgDataReload: Boolean, private val limitDataToOldestAvailable: Boolean, - private val cause: Event + private val cause: Event? ) : Thread() { @Inject lateinit var aapsLogger: AAPSLogger @@ -53,10 +55,12 @@ class IobCobThread @Inject internal constructor( @Inject lateinit var context: Context @Inject lateinit var sensitivityAAPSPlugin: SensitivityAAPSPlugin @Inject lateinit var sensitivityWeightedAveragePlugin: SensitivityWeightedAveragePlugin + @Inject lateinit var activePlugin: ActivePlugin @Inject lateinit var buildHelper: BuildHelper @Inject lateinit var profiler: Profiler @Inject lateinit var fabricPrivacy: FabricPrivacy @Inject lateinit var dateUtil: DateUtil + @Inject lateinit var repository: AppRepository private var mWakeLock: PowerManager.WakeLock? = null @@ -66,7 +70,7 @@ class IobCobThread @Inject internal constructor( } override fun run() { - val start = DateUtil.now() + val start = dateUtil.now() mWakeLock?.acquire(T.mins(10).msecs()) try { aapsLogger.debug(LTag.AUTOSENS, "AUTOSENSDATA thread started: $from") @@ -76,192 +80,192 @@ class IobCobThread @Inject internal constructor( } //log.debug("Locking calculateSensitivityData"); val oldestTimeWithData = iobCobCalculatorPlugin.calculateDetectionStart(end, limitDataToOldestAvailable) - synchronized(iobCobCalculatorPlugin.dataLock) { - if (bgDataReload) { - iobCobCalculatorPlugin.loadBgData(end) - iobCobCalculatorPlugin.createBucketedData() - rxBus.send(EventAutosensBgLoaded(cause)) - } - val bucketedData = iobCobCalculatorPlugin.bucketedData - val autosensDataTable = iobCobCalculatorPlugin.getAutosensDataTable() - if (bucketedData == null || bucketedData.size < 3) { - aapsLogger.debug(LTag.AUTOSENS, "Aborting calculation thread (No bucketed data available): $from") + if (bgDataReload) { + iobCobCalculatorPlugin.ads.loadBgData(end, repository, aapsLogger, dateUtil) + iobCobCalculatorPlugin.clearCache() + } + // work on local copy and set back when finished + val ads = iobCobCalculatorPlugin.ads.clone() + val bucketedData = ads.bucketedData + val autosensDataTable = ads.autosensDataTable + if (bucketedData == null || bucketedData.size < 3) { + aapsLogger.debug(LTag.AUTOSENS, "Aborting calculation thread (No bucketed data available): $from") + return + } + val prevDataTime = ads.roundUpTime(bucketedData[bucketedData.size - 3].timestamp) + aapsLogger.debug(LTag.AUTOSENS, "Prev data time: " + dateUtil.dateAndTimeString(prevDataTime)) + var previous = autosensDataTable[prevDataTime] + // start from oldest to be able sub cob + for (i in bucketedData.size - 4 downTo 0) { + val progress = i.toString() + if (buildHelper.isDev()) " ($from)" else "" + rxBus.send(EventIobCalculationProgress(progress)) + if (iobCobCalculatorPlugin.stopCalculationTrigger) { + iobCobCalculatorPlugin.stopCalculationTrigger = false + aapsLogger.debug(LTag.AUTOSENS, "Aborting calculation thread (trigger): $from") return } - val prevDataTime = roundUpTime(bucketedData[bucketedData.size - 3].timestamp) - aapsLogger.debug(LTag.AUTOSENS, "Prev data time: " + dateUtil.dateAndTimeString(prevDataTime)) - var previous = autosensDataTable[prevDataTime] - // start from oldest to be able sub cob - for (i in bucketedData.size - 4 downTo 0) { - val progress = i.toString() + if (buildHelper.isDev()) " ($from)" else "" - rxBus.send(EventIobCalculationProgress(progress)) - if (iobCobCalculatorPlugin.stopCalculationTrigger) { - iobCobCalculatorPlugin.stopCalculationTrigger = false - aapsLogger.debug(LTag.AUTOSENS, "Aborting calculation thread (trigger): $from") - return - } - // check if data already exists - var bgTime = bucketedData[i].timestamp - bgTime = roundUpTime(bgTime) - if (bgTime > roundUpTime(DateUtil.now())) continue - var existing: AutosensData? - if (autosensDataTable[bgTime].also { existing = it } != null) { - previous = existing - continue - } - val profile = profileFunction.getProfile(bgTime) - if (profile == null) { - aapsLogger.debug(LTag.AUTOSENS, "Aborting calculation thread (no profile): $from") - return // profile not set yet - } - aapsLogger.debug(LTag.AUTOSENS, "Processing calculation thread: " + from + " (" + i + "/" + bucketedData.size + ")") - val sens = profile.getIsfMgdl(bgTime) - val autosensData = AutosensData(injector) - autosensData.time = bgTime - if (previous != null) autosensData.activeCarbsList = previous.cloneCarbsList() else autosensData.activeCarbsList = ArrayList() + // check if data already exists + var bgTime = bucketedData[i].timestamp + bgTime = ads.roundUpTime(bgTime) + if (bgTime > ads.roundUpTime(dateUtil.now())) continue + var existing: AutosensData? + if (autosensDataTable[bgTime].also { existing = it } != null) { + previous = existing + continue + } + val profile = profileFunction.getProfile(bgTime) + if (profile == null) { + aapsLogger.debug(LTag.AUTOSENS, "Aborting calculation thread (no profile): $from") + return // profile not set yet + } + aapsLogger.debug(LTag.AUTOSENS, "Processing calculation thread: " + from + " (" + i + "/" + bucketedData.size + ")") + val sens = profile.getIsfMgdl(bgTime) + val autosensData = AutosensData(injector) + autosensData.time = bgTime + if (previous != null) autosensData.activeCarbsList = previous.cloneCarbsList() else autosensData.activeCarbsList = ArrayList() - //console.error(bgTime , bucketed_data[i].glucose); - var avgDelta: Double - var delta: Double - val bg: Double = bucketedData[i].value - if (bg < 39 || bucketedData[i + 3].value < 39) { - aapsLogger.error("! value < 39") - continue - } - autosensData.bg = bg - delta = bg - bucketedData[i + 1].value - avgDelta = (bg - bucketedData[i + 3].value) / 3 - val iob = iobCobCalculatorPlugin.calculateFromTreatmentsAndTemps(bgTime, profile) - val bgi = -iob.activity * sens * 5 - val deviation = delta - bgi - val avgDeviation = ((avgDelta - bgi) * 1000).roundToLong() / 1000.0 - var slopeFromMaxDeviation = 0.0 - var slopeFromMinDeviation = 999.0 + //console.error(bgTime , bucketed_data[i].glucose); + var avgDelta: Double + var delta: Double + val bg: Double = bucketedData[i].value + if (bg < 39 || bucketedData[i + 3].value < 39) { + aapsLogger.error("! value < 39") + continue + } + autosensData.bg = bg + delta = bg - bucketedData[i + 1].value + avgDelta = (bg - bucketedData[i + 3].value) / 3 + val iob = iobCobCalculatorPlugin.calculateFromTreatmentsAndTemps(bgTime, profile) + val bgi = -iob.activity * sens * 5 + val deviation = delta - bgi + val avgDeviation = ((avgDelta - bgi) * 1000).roundToLong() / 1000.0 + var slopeFromMaxDeviation = 0.0 + var slopeFromMinDeviation = 999.0 - // https://github.com/openaps/oref0/blob/master/lib/determine-basal/cob-autosens.js#L169 - if (i < bucketedData.size - 16) { // we need 1h of data to calculate minDeviationSlope - @Suppress("UNUSED_VARIABLE") var maxDeviation = 0.0 - @Suppress("UNUSED_VARIABLE") var minDeviation = 999.0 - val hourAgo = bgTime + 10 * 1000 - 60 * 60 * 1000L - val hourAgoData = iobCobCalculatorPlugin.getAutosensData(hourAgo) - if (hourAgoData != null) { - val initialIndex = autosensDataTable.indexOfKey(hourAgoData.time) - aapsLogger.debug(LTag.AUTOSENS, ">>>>> bucketed_data.size()=" + bucketedData.size + " i=" + i + " hourAgoData=" + hourAgoData.toString()) - var past = 1 - try { - while (past < 12) { - val ad = autosensDataTable.valueAt(initialIndex + past) - aapsLogger.debug(LTag.AUTOSENS, ">>>>> past=" + past + " ad=" + ad?.toString()) - if (ad == null) { - aapsLogger.debug(LTag.AUTOSENS, autosensDataTable.toString()) - aapsLogger.debug(LTag.AUTOSENS, bucketedData.toString()) - aapsLogger.debug(LTag.AUTOSENS, iobCobCalculatorPlugin.bgReadings.toString()) - val notification = Notification(Notification.SEND_LOGFILES, resourceHelper.gs(R.string.sendlogfiles), Notification.LOW) - rxBus.send(EventNewNotification(notification)) - sp.putBoolean("log_AUTOSENS", true) - break - } - // let it here crash on NPE to get more data as i cannot reproduce this bug - val deviationSlope = (ad.avgDeviation - avgDeviation) / (ad.time - bgTime) * 1000 * 60 * 5 - if (ad.avgDeviation > maxDeviation) { - slopeFromMaxDeviation = min(0.0, deviationSlope) - maxDeviation = ad.avgDeviation - } - if (ad.avgDeviation < minDeviation) { - slopeFromMinDeviation = max(0.0, deviationSlope) - minDeviation = ad.avgDeviation - } - past++ + // https://github.com/openaps/oref0/blob/master/lib/determine-basal/cob-autosens.js#L169 + if (i < bucketedData.size - 16) { // we need 1h of data to calculate minDeviationSlope + @Suppress("UNUSED_VARIABLE") var maxDeviation = 0.0 + @Suppress("UNUSED_VARIABLE") var minDeviation = 999.0 + val hourAgo = bgTime + 10 * 1000 - 60 * 60 * 1000L + val hourAgoData = ads.getAutosensDataAtTime(hourAgo) + if (hourAgoData != null) { + val initialIndex = autosensDataTable.indexOfKey(hourAgoData.time) + aapsLogger.debug(LTag.AUTOSENS, ">>>>> bucketed_data.size()=" + bucketedData.size + " i=" + i + " hourAgoData=" + hourAgoData.toString()) + var past = 1 + try { + while (past < 12) { + val ad = autosensDataTable.valueAt(initialIndex + past) + aapsLogger.debug(LTag.AUTOSENS, ">>>>> past=" + past + " ad=" + ad?.toString()) + if (ad == null) { + aapsLogger.debug(LTag.AUTOSENS, autosensDataTable.toString()) + aapsLogger.debug(LTag.AUTOSENS, bucketedData.toString()) + //aapsLogger.debug(LTag.AUTOSENS, iobCobCalculatorPlugin.getBgReadingsDataTable().toString()) + val notification = Notification(Notification.SEND_LOGFILES, resourceHelper.gs(R.string.sendlogfiles), Notification.LOW) + rxBus.send(EventNewNotification(notification)) + sp.putBoolean("log_AUTOSENS", true) + break } - } catch (e: Exception) { - aapsLogger.error("Unhandled exception", e) - fabricPrivacy.logException(e) - aapsLogger.debug(autosensDataTable.toString()) - aapsLogger.debug(bucketedData.toString()) - aapsLogger.debug(iobCobCalculatorPlugin.bgReadings.toString()) - val notification = Notification(Notification.SEND_LOGFILES, resourceHelper.gs(R.string.sendlogfiles), Notification.LOW) - rxBus.send(EventNewNotification(notification)) - sp.putBoolean("log_AUTOSENS", true) - break - } - } else { - aapsLogger.debug(LTag.AUTOSENS, ">>>>> bucketed_data.size()=" + bucketedData.size + " i=" + i + " hourAgoData=" + "null") - } - } - val recentCarbTreatments = treatmentsPlugin.getCarbTreatments5MinBackFromHistory(bgTime) - for (recentCarbTreatment in recentCarbTreatments) { - autosensData.carbsFromBolus += recentCarbTreatment.carbs - val isAAPSOrWeighted = sensitivityAAPSPlugin.isEnabled() || sensitivityWeightedAveragePlugin.isEnabled() - autosensData.activeCarbsList.add(autosensData.CarbsInPast(recentCarbTreatment, isAAPSOrWeighted)) - autosensData.pastSensitivity += "[" + DecimalFormatter.to0Decimal(recentCarbTreatment.carbs) + "g]" - } - - // if we are absorbing carbs - if (previous != null && previous.cob > 0) { - // calculate sum of min carb impact from all active treatments - var totalMinCarbsImpact = 0.0 - if (sensitivityAAPSPlugin.isEnabled(PluginType.SENSITIVITY) || sensitivityWeightedAveragePlugin.isEnabled(PluginType.SENSITIVITY)) { - //when the impact depends on a max time, sum them up as smaller carb sizes make them smaller - for (ii in autosensData.activeCarbsList.indices) { - val c = autosensData.activeCarbsList[ii] - totalMinCarbsImpact += c.min5minCarbImpact - } - } else { - //Oref sensitivity - totalMinCarbsImpact = sp.getDouble(R.string.key_openapsama_min_5m_carbimpact, SMBDefaults.min_5m_carbimpact) - } - - // figure out how many carbs that represents - // but always assume at least 3mg/dL/5m (default) absorption per active treatment - val ci = max(deviation, totalMinCarbsImpact) - if (ci != deviation) autosensData.failoverToMinAbsorbtionRate = true - autosensData.absorbed = ci * profile.getIc(bgTime) / sens - // and add that to the running total carbsAbsorbed - autosensData.cob = max(previous.cob - autosensData.absorbed, 0.0) - autosensData.substractAbosorbedCarbs() - autosensData.usedMinCarbsImpact = totalMinCarbsImpact - } - val isAAPSOrWeighted = sensitivityAAPSPlugin.isEnabled() || sensitivityWeightedAveragePlugin.isEnabled() - autosensData.removeOldCarbs(bgTime, isAAPSOrWeighted) - autosensData.cob += autosensData.carbsFromBolus - autosensData.deviation = deviation - autosensData.bgi = bgi - autosensData.delta = delta - autosensData.avgDelta = avgDelta - autosensData.avgDeviation = avgDeviation - autosensData.slopeFromMaxDeviation = slopeFromMaxDeviation - autosensData.slopeFromMinDeviation = slopeFromMinDeviation - - // calculate autosens only without COB - if (autosensData.cob <= 0) { - when { - abs(deviation) < Constants.DEVIATION_TO_BE_EQUAL -> { - autosensData.pastSensitivity += "=" - autosensData.validDeviation = true - } - - deviation > 0 -> { - autosensData.pastSensitivity += "+" - autosensData.validDeviation = true - } - - else -> { - autosensData.pastSensitivity += "-" - autosensData.validDeviation = true + // let it here crash on NPE to get more data as i cannot reproduce this bug + val deviationSlope = (ad.avgDeviation - avgDeviation) / (ad.time - bgTime) * 1000 * 60 * 5 + if (ad.avgDeviation > maxDeviation) { + slopeFromMaxDeviation = min(0.0, deviationSlope) + maxDeviation = ad.avgDeviation + } + if (ad.avgDeviation < minDeviation) { + slopeFromMinDeviation = max(0.0, deviationSlope) + minDeviation = ad.avgDeviation + } + past++ } + } catch (e: Exception) { + aapsLogger.error("Unhandled exception", e) + fabricPrivacy.logException(e) + aapsLogger.debug(autosensDataTable.toString()) + aapsLogger.debug(bucketedData.toString()) + //aapsLogger.debug(iobCobCalculatorPlugin.getBgReadingsDataTable().toString()) + val notification = Notification(Notification.SEND_LOGFILES, resourceHelper.gs(R.string.sendlogfiles), Notification.LOW) + rxBus.send(EventNewNotification(notification)) + sp.putBoolean("log_AUTOSENS", true) + break } } else { - autosensData.pastSensitivity += "C" + aapsLogger.debug(LTag.AUTOSENS, ">>>>> bucketed_data.size()=" + bucketedData.size + " i=" + i + " hourAgoData=" + "null") } - previous = autosensData - if (bgTime < DateUtil.now()) autosensDataTable.put(bgTime, autosensData) - aapsLogger.debug(LTag.AUTOSENS, "Running detectSensitivity from: " + dateUtil.dateAndTimeString(oldestTimeWithData) + " to: " + dateUtil.dateAndTimeString(bgTime) + " lastDataTime:" + iobCobCalculatorPlugin.lastDataTime()) - val sensitivity = iobCobCalculatorPlugin.detectSensitivityWithLock(oldestTimeWithData, bgTime) - aapsLogger.debug(LTag.AUTOSENS, "Sensitivity result: $sensitivity") - autosensData.autosensResult = sensitivity - aapsLogger.debug(LTag.AUTOSENS, autosensData.toString()) } + val recentCarbTreatments = repository.getCarbsDataFromTimeToTimeExpanded(bgTime - T.mins(5).msecs(), bgTime, true).blockingGet() + for (recentCarbTreatment in recentCarbTreatments) { + autosensData.carbsFromBolus += recentCarbTreatment.amount + val isAAPSOrWeighted = sensitivityAAPSPlugin.isEnabled() || sensitivityWeightedAveragePlugin.isEnabled() + autosensData.activeCarbsList.add(autosensData.CarbsInPast(recentCarbTreatment, isAAPSOrWeighted)) + autosensData.pastSensitivity += "[" + DecimalFormatter.to0Decimal(recentCarbTreatment.amount) + "g]" + } + + // if we are absorbing carbs + if (previous != null && previous.cob > 0) { + // calculate sum of min carb impact from all active treatments + var totalMinCarbsImpact = 0.0 + if (sensitivityAAPSPlugin.isEnabled(PluginType.SENSITIVITY) || sensitivityWeightedAveragePlugin.isEnabled(PluginType.SENSITIVITY)) { + //when the impact depends on a max time, sum them up as smaller carb sizes make them smaller + for (ii in autosensData.activeCarbsList.indices) { + val c = autosensData.activeCarbsList[ii] + totalMinCarbsImpact += c.min5minCarbImpact + } + } else { + //Oref sensitivity + totalMinCarbsImpact = sp.getDouble(R.string.key_openapsama_min_5m_carbimpact, SMBDefaults.min_5m_carbimpact) + } + + // figure out how many carbs that represents + // but always assume at least 3mg/dL/5m (default) absorption per active treatment + val ci = max(deviation, totalMinCarbsImpact) + if (ci != deviation) autosensData.failoverToMinAbsorbtionRate = true + autosensData.absorbed = ci * profile.getIc(bgTime) / sens + // and add that to the running total carbsAbsorbed + autosensData.cob = max(previous.cob - autosensData.absorbed, 0.0) + autosensData.substractAbosorbedCarbs() + autosensData.usedMinCarbsImpact = totalMinCarbsImpact + } + val isAAPSOrWeighted = sensitivityAAPSPlugin.isEnabled() || sensitivityWeightedAveragePlugin.isEnabled() + autosensData.removeOldCarbs(bgTime, isAAPSOrWeighted) + autosensData.cob += autosensData.carbsFromBolus + autosensData.deviation = deviation + autosensData.bgi = bgi + autosensData.delta = delta + autosensData.avgDelta = avgDelta + autosensData.avgDeviation = avgDeviation + autosensData.slopeFromMaxDeviation = slopeFromMaxDeviation + autosensData.slopeFromMinDeviation = slopeFromMinDeviation + + // calculate autosens only without COB + if (autosensData.cob <= 0) { + when { + abs(deviation) < Constants.DEVIATION_TO_BE_EQUAL -> { + autosensData.pastSensitivity += "=" + autosensData.validDeviation = true + } + + deviation > 0 -> { + autosensData.pastSensitivity += "+" + autosensData.validDeviation = true + } + + else -> { + autosensData.pastSensitivity += "-" + autosensData.validDeviation = true + } + } + } else { + autosensData.pastSensitivity += "C" + } + previous = autosensData + if (bgTime < dateUtil.now()) autosensDataTable.put(bgTime, autosensData) + aapsLogger.debug(LTag.AUTOSENS, "Running detectSensitivity from: " + dateUtil.dateAndTimeString(oldestTimeWithData) + " to: " + dateUtil.dateAndTimeString(bgTime) + " lastDataTime:" + ads.lastDataTime(dateUtil)) + val sensitivity = activePlugin.activeSensitivity.detectSensitivity(ads, oldestTimeWithData, bgTime) + aapsLogger.debug(LTag.AUTOSENS, "Sensitivity result: $sensitivity") + autosensData.autosensResult = sensitivity + aapsLogger.debug(LTag.AUTOSENS, autosensData.toString()) } + iobCobCalculatorPlugin.ads = ads Thread { SystemClock.sleep(1000) rxBus.send(EventAutosensCalculationFinished(cause)) @@ -270,7 +274,6 @@ class IobCobThread @Inject internal constructor( mWakeLock?.release() rxBus.send(EventIobCalculationProgress("")) aapsLogger.debug(LTag.AUTOSENS, "AUTOSENSDATA thread ended: $from") - aapsLogger.debug(LTag.AUTOSENS, "Midnights: " + MidnightTime.log()) profiler.log(LTag.AUTOSENS, "IobCobThread", start) } } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/iob/iobCobCalculator/events/EventAutosensBgLoaded.kt b/app/src/main/java/info/nightscout/androidaps/plugins/iob/iobCobCalculator/events/EventAutosensBgLoaded.kt deleted file mode 100644 index b02e96b67f..0000000000 --- a/app/src/main/java/info/nightscout/androidaps/plugins/iob/iobCobCalculator/events/EventAutosensBgLoaded.kt +++ /dev/null @@ -1,6 +0,0 @@ -package info.nightscout.androidaps.plugins.iob.iobCobCalculator.events - -import info.nightscout.androidaps.events.Event -import info.nightscout.androidaps.events.EventLoop - -class EventAutosensBgLoaded(var cause: Event) : EventLoop() diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/iob/iobCobCalculator/events/EventNewHistoryBgData.kt b/app/src/main/java/info/nightscout/androidaps/plugins/iob/iobCobCalculator/events/EventNewHistoryBgData.kt deleted file mode 100644 index 5f546c2d9f..0000000000 --- a/app/src/main/java/info/nightscout/androidaps/plugins/iob/iobCobCalculator/events/EventNewHistoryBgData.kt +++ /dev/null @@ -1,5 +0,0 @@ -package info.nightscout.androidaps.plugins.iob.iobCobCalculator.events - -import info.nightscout.androidaps.events.Event - -class EventNewHistoryBgData(val timestamp: Long) : Event() \ No newline at end of file diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/iob/iobCobCalculator/events/EventNewHistoryData.kt b/app/src/main/java/info/nightscout/androidaps/plugins/iob/iobCobCalculator/events/EventNewHistoryData.kt index c2372aff83..c842a1dcb7 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/iob/iobCobCalculator/events/EventNewHistoryData.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/iob/iobCobCalculator/events/EventNewHistoryData.kt @@ -1,5 +1,6 @@ package info.nightscout.androidaps.plugins.iob.iobCobCalculator.events +import info.nightscout.androidaps.database.entities.GlucoseValue import info.nightscout.androidaps.events.Event -class EventNewHistoryData(var time: Long) : Event() \ No newline at end of file +class EventNewHistoryData(val oldDataTimestamp: Long, val reloadBgData: Boolean, val newestGlucoseValue : GlucoseValue? = null) : Event() \ No newline at end of file diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/profile/local/LocalProfileFragment.kt b/app/src/main/java/info/nightscout/androidaps/plugins/profile/local/LocalProfileFragment.kt index ccc2c19596..0e5068e419 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/profile/local/LocalProfileFragment.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/profile/local/LocalProfileFragment.kt @@ -12,10 +12,12 @@ import dagger.android.support.DaggerFragment import info.nightscout.androidaps.Constants import info.nightscout.androidaps.R import info.nightscout.androidaps.data.Profile -import info.nightscout.androidaps.database.entities.UserEntry.* +import info.nightscout.androidaps.database.entities.UserEntry.Action +import info.nightscout.androidaps.database.entities.UserEntry.Sources +import info.nightscout.androidaps.database.entities.ValueWithUnit import info.nightscout.androidaps.databinding.LocalprofileFragmentBinding import info.nightscout.androidaps.dialogs.ProfileSwitchDialog -import info.nightscout.androidaps.interfaces.ActivePluginProvider +import info.nightscout.androidaps.interfaces.ActivePlugin import info.nightscout.androidaps.logging.AAPSLogger import info.nightscout.androidaps.logging.UserEntryLogger import info.nightscout.androidaps.plugins.bus.RxBusWrapper @@ -34,7 +36,7 @@ class LocalProfileFragment : DaggerFragment() { @Inject lateinit var aapsLogger: AAPSLogger @Inject lateinit var rxBus: RxBusWrapper @Inject lateinit var resourceHelper: ResourceHelper - @Inject lateinit var activePlugin: ActivePluginProvider + @Inject lateinit var activePlugin: ActivePlugin @Inject lateinit var fabricPrivacy: FabricPrivacy @Inject lateinit var localProfilePlugin: LocalProfilePlugin @Inject lateinit var hardLimits: HardLimits @@ -163,7 +165,7 @@ class LocalProfileFragment : DaggerFragment() { if (localProfilePlugin.isEdited) { activity?.let { OKDialog.show(it, "", resourceHelper.gs(R.string.saveorresetchangesfirst)) } } else { - uel.log(Action.NEW_PROFILE) + uel.log(Action.NEW_PROFILE, Sources.LocalProfile) localProfilePlugin.addNewProfile() build() } @@ -173,7 +175,7 @@ class LocalProfileFragment : DaggerFragment() { if (localProfilePlugin.isEdited) { activity?.let { OKDialog.show(it, "", resourceHelper.gs(R.string.saveorresetchangesfirst)) } } else { - uel.log(Action.CLONE_PROFILE, localProfilePlugin.currentProfile()?.name ?: "") + uel.log(Action.CLONE_PROFILE, Sources.LocalProfile, ValueWithUnit.SimpleString(localProfilePlugin.currentProfile()?.name ?: "")) localProfilePlugin.cloneProfile() build() } @@ -182,7 +184,7 @@ class LocalProfileFragment : DaggerFragment() { binding.profileRemove.setOnClickListener { activity?.let { activity -> OKDialog.showConfirmation(activity, resourceHelper.gs(R.string.deletecurrentprofile), { - uel.log(Action.PROFILE_REMOVED, localProfilePlugin.currentProfile()?.name ?: "") + uel.log(Action.PROFILE_REMOVED, Sources.LocalProfile, ValueWithUnit.SimpleString(localProfilePlugin.currentProfile()?.name ?: "")) localProfilePlugin.removeCurrentProfile() build() }, null) @@ -210,6 +212,7 @@ class LocalProfileFragment : DaggerFragment() { if (!localProfilePlugin.isValidEditState()) { return@setOnClickListener //Should not happen as saveButton should not be visible if not valid } + uel.log(Action.STORE_PROFILE, Sources.LocalProfile, ValueWithUnit.SimpleString(localProfilePlugin.currentProfile()?.name ?: "")) localProfilePlugin.storeSettings(activity) build() } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/profile/local/LocalProfilePlugin.kt b/app/src/main/java/info/nightscout/androidaps/plugins/profile/local/LocalProfilePlugin.kt index 8da1e6b188..939601a596 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/profile/local/LocalProfilePlugin.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/profile/local/LocalProfilePlugin.kt @@ -5,12 +5,10 @@ import dagger.android.HasAndroidInjector import info.nightscout.androidaps.Constants import info.nightscout.androidaps.R import info.nightscout.androidaps.data.Profile -import info.nightscout.androidaps.database.entities.UserEntry.* import info.nightscout.androidaps.events.EventProfileStoreChanged import info.nightscout.androidaps.interfaces.* import info.nightscout.androidaps.logging.AAPSLogger import info.nightscout.androidaps.logging.LTag -import info.nightscout.androidaps.logging.UserEntryLogger import info.nightscout.androidaps.plugins.bus.RxBusWrapper import info.nightscout.androidaps.plugins.general.nsclient.NSUpload import info.nightscout.androidaps.utils.DateUtil @@ -35,7 +33,7 @@ class LocalProfilePlugin @Inject constructor( private val sp: SP, private val profileFunction: ProfileFunction, private val nsUpload: NSUpload, - private val uel: UserEntryLogger + private val dateUtil: DateUtil ) : PluginBase(PluginDescription() .mainType(PluginType.PROFILE) .fragmentClass(LocalProfileFragment::class.java.name) @@ -46,7 +44,7 @@ class LocalProfilePlugin @Inject constructor( .description(R.string.description_profile_local) .setDefault(), aapsLogger, resourceHelper, injector -), ProfileInterface { +), ProfileSource { private var rawProfile: ProfileStore? = null @@ -58,6 +56,7 @@ class LocalProfilePlugin @Inject constructor( } class SingleProfile { + internal var name: String? = null internal var mgdl: Boolean = false internal var dia: Double = Constants.defaultDIA @@ -116,7 +115,6 @@ class LocalProfilePlugin @Inject constructor( createAndStoreConvertedProfile() isEdited = false aapsLogger.debug(LTag.PROFILE, "Storing settings: " + rawProfile?.data.toString()) - uel.log(Action.STORE_PROFILE) rxBus.send(EventProfileStoreChanged()) var namesOK = true profiles.forEach { @@ -205,7 +203,7 @@ class LocalProfilePlugin @Inject constructor( fun copyFrom(profile: Profile, newName: String): SingleProfile { var verifiedName = newName if (rawProfile?.getSpecificProfile(newName) != null) { - verifiedName += " " + DateUtil.now().toString() + verifiedName += " " + dateUtil.now().toString() } val sp = SingleProfile() sp.name = verifiedName @@ -342,7 +340,7 @@ class LocalProfilePlugin @Inject constructor( } } if (numOfProfiles > 0) json.put("defaultProfile", currentProfile()?.name) - json.put("startDate", DateUtil.toISOAsUTC(DateUtil.now())) + json.put("startDate", dateUtil.toISOAsUTC(dateUtil.now())) json.put("store", store) } catch (e: JSONException) { aapsLogger.error("Unhandled exception", e) @@ -351,12 +349,10 @@ class LocalProfilePlugin @Inject constructor( return ProfileStore(injector, json) } - override fun getProfile(): ProfileStore? { - return rawProfile - } + override val profile: ProfileStore? + get() = rawProfile - override fun getProfileName(): String { - return DecimalFormatter.to2Decimal(rawProfile?.getDefaultProfile()?.percentageBasalSum() + override val profileName: String + get() = DecimalFormatter.to2Decimal(rawProfile?.getDefaultProfile()?.percentageBasalSum() ?: 0.0) + "U " - } } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/profile/ns/NSProfileFragment.kt b/app/src/main/java/info/nightscout/androidaps/plugins/profile/ns/NSProfileFragment.kt index 3b0b60768b..d6869ad370 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/profile/ns/NSProfileFragment.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/profile/ns/NSProfileFragment.kt @@ -8,7 +8,9 @@ import android.widget.AdapterView import android.widget.ArrayAdapter import dagger.android.support.DaggerFragment import info.nightscout.androidaps.R -import info.nightscout.androidaps.database.entities.UserEntry.* +import info.nightscout.androidaps.database.entities.ValueWithUnit +import info.nightscout.androidaps.database.entities.UserEntry.Action +import info.nightscout.androidaps.database.entities.UserEntry.Sources import info.nightscout.androidaps.databinding.NsprofileFragmentBinding import info.nightscout.androidaps.interfaces.ProfileFunction import info.nightscout.androidaps.logging.UserEntryLogger @@ -34,6 +36,7 @@ class NSProfileFragment : DaggerFragment() { @Inject lateinit var profileFunction: ProfileFunction @Inject lateinit var nsProfilePlugin: NSProfilePlugin @Inject lateinit var aapsSchedulers: AapsSchedulers + @Inject lateinit var dateUtil: DateUtil @Inject lateinit var uel: UserEntryLogger private var disposable: CompositeDisposable = CompositeDisposable() @@ -62,8 +65,10 @@ class NSProfileFragment : DaggerFragment() { activity?.let { activity -> OKDialog.showConfirmation(activity, resourceHelper.gs(R.string.nsprofile), resourceHelper.gs(R.string.activate_profile) + ": " + name + " ?", Runnable { - uel.log(Action.PROFILE_SWITCH, ValueWithUnit(name, Units.None), ValueWithUnit(100.toInt(), Units.Percent)) - treatmentsPlugin.doProfileSwitch(store, name, 0, 100, 0, DateUtil.now()) + uel.log(Action.PROFILE_SWITCH, Sources.NSProfile, + ValueWithUnit.SimpleString(name), + ValueWithUnit.Percent(100)) + treatmentsPlugin.doProfileSwitch(store, name, 0, 100, 0, dateUtil.now()) }) } } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/profile/ns/NSProfilePlugin.kt b/app/src/main/java/info/nightscout/androidaps/plugins/profile/ns/NSProfilePlugin.kt index e2c3c56608..04998de8a3 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/profile/ns/NSProfilePlugin.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/profile/ns/NSProfilePlugin.kt @@ -3,14 +3,15 @@ package info.nightscout.androidaps.plugins.profile.ns import android.content.Context import androidx.work.Worker import androidx.work.WorkerParameters +import androidx.work.workDataOf import dagger.android.HasAndroidInjector -import info.nightscout.androidaps.Config +import info.nightscout.androidaps.interfaces.Config import info.nightscout.androidaps.R import info.nightscout.androidaps.events.EventProfileStoreChanged import info.nightscout.androidaps.interfaces.PluginBase import info.nightscout.androidaps.interfaces.PluginDescription import info.nightscout.androidaps.interfaces.PluginType -import info.nightscout.androidaps.interfaces.ProfileInterface +import info.nightscout.androidaps.interfaces.ProfileSource import info.nightscout.androidaps.interfaces.ProfileStore import info.nightscout.androidaps.logging.AAPSLogger import info.nightscout.androidaps.logging.LTag @@ -43,9 +44,12 @@ class NSProfilePlugin @Inject constructor( .showInList(!config.NSCLIENT) .description(R.string.description_profile_nightscout), aapsLogger, resourceHelper, injector -), ProfileInterface { +), ProfileSource { - private var profile: ProfileStore? = null + override var profile: ProfileStore? = null + + override val profileName: String? + get() = profile?.getDefaultProfileName() override fun onStart() { super.onStart() @@ -70,13 +74,6 @@ class NSProfilePlugin @Inject constructor( } } - override fun getProfile(): ProfileStore? { - return profile - } - - override fun getProfileName(): String { - return profile!!.getDefaultProfileName()!! - } // cannot be inner class because of needed injection class NSProfileWorker( @@ -96,7 +93,7 @@ class NSProfilePlugin @Inject constructor( override fun doWork(): Result { val profileString = dataWorker.pickupJSONObject(inputData.getLong(DataWorker.STORE_KEY, -1)) - ?: return Result.failure() + ?: return Result.failure(workDataOf("Error" to "missing input data")) nsProfilePlugin.profile = ProfileStore(injector, profileString) nsProfilePlugin.storeNSProfile() if (nsProfilePlugin.isEnabled()) { diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/pump/mdi/MDIPlugin.kt b/app/src/main/java/info/nightscout/androidaps/plugins/pump/mdi/MDIPlugin.kt index ea7b47f332..758bf03ff5 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/pump/mdi/MDIPlugin.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/pump/mdi/MDIPlugin.kt @@ -10,9 +10,9 @@ import info.nightscout.androidaps.logging.AAPSLogger import info.nightscout.androidaps.logging.LTag import info.nightscout.androidaps.plugins.common.ManufacturerType import info.nightscout.androidaps.plugins.pump.common.defs.PumpType -import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin import info.nightscout.androidaps.utils.DateUtil import info.nightscout.androidaps.utils.InstanceId.instanceId +import info.nightscout.androidaps.utils.T import info.nightscout.androidaps.utils.resources.ResourceHelper import org.json.JSONException import org.json.JSONObject @@ -25,14 +25,15 @@ class MDIPlugin @Inject constructor( aapsLogger: AAPSLogger, resourceHelper: ResourceHelper, commandQueue: CommandQueueProvider, - private val treatmentsPlugin: TreatmentsPlugin + private val dateUtil: DateUtil, + private val pumpSync: PumpSync ) : PumpPluginBase(PluginDescription() .mainType(PluginType.PUMP) .pluginIcon(R.drawable.ic_ict) .pluginName(R.string.mdi) .description(R.string.description_pump_mdi), injector, aapsLogger, resourceHelper, commandQueue -), PumpInterface { +), Pump { override val pumpDescription = PumpDescription() @@ -73,12 +74,26 @@ class MDIPlugin @Inject constructor( result.bolusDelivered = detailedBolusInfo.insulin result.carbsDelivered = detailedBolusInfo.carbs result.comment = resourceHelper.gs(R.string.virtualpump_resultok) - treatmentsPlugin.addToHistoryTreatment(detailedBolusInfo, false) + if (detailedBolusInfo.insulin > 0) + pumpSync.syncBolusWithPumpId( + timestamp = detailedBolusInfo.timestamp, + amount = detailedBolusInfo.insulin, + type = detailedBolusInfo.bolusType, + pumpId = dateUtil.now(), + pumpType = PumpType.MDI, + pumpSerial = serialNumber()) + if (detailedBolusInfo.carbs > 0) + pumpSync.syncCarbsWithTimestamp( + timestamp = detailedBolusInfo.timestamp + T.mins(detailedBolusInfo.carbTime.toLong()).msecs(), + amount = detailedBolusInfo.carbs, + pumpId = null, + pumpType = PumpType.MDI, + pumpSerial = serialNumber()) return result } override fun stopBolusDelivering() {} - override fun setTempBasalAbsolute(absoluteRate: Double, durationInMinutes: Int, profile: Profile, enforceNew: Boolean): PumpEnactResult { + override fun setTempBasalAbsolute(absoluteRate: Double, durationInMinutes: Int, profile: Profile, enforceNew: Boolean, tbrType: PumpSync.TemporaryBasalType): PumpEnactResult { val result = PumpEnactResult(injector) result.success = false result.comment = resourceHelper.gs(R.string.pumperror) @@ -86,7 +101,7 @@ class MDIPlugin @Inject constructor( return result } - override fun setTempBasalPercent(percent: Int, durationInMinutes: Int, profile: Profile, enforceNew: Boolean): PumpEnactResult { + override fun setTempBasalPercent(percent: Int, durationInMinutes: Int, profile: Profile, enforceNew: Boolean, tbrType: PumpSync.TemporaryBasalType): PumpEnactResult { val result = PumpEnactResult(injector) result.success = false result.comment = resourceHelper.gs(R.string.pumperror) @@ -127,10 +142,10 @@ class MDIPlugin @Inject constructor( status.put("status", "normal") extended.put("Version", version) extended.put("ActiveProfile", profileName) - status.put("timestamp", DateUtil.toISOString(now)) + status.put("timestamp", dateUtil.toISOString(now)) pump.put("status", status) pump.put("extended", extended) - pump.put("clock", DateUtil.toISOString(now)) + pump.put("clock", dateUtil.toISOString(now)) } catch (e: JSONException) { aapsLogger.error("Exception: ", e) } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/pump/virtual/VirtualPumpFragment.kt b/app/src/main/java/info/nightscout/androidaps/plugins/pump/virtual/VirtualPumpFragment.kt index bdbc298ff5..f2eb4bb5e1 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/pump/virtual/VirtualPumpFragment.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/pump/virtual/VirtualPumpFragment.kt @@ -10,24 +10,29 @@ import info.nightscout.androidaps.R import info.nightscout.androidaps.databinding.VirtualpumpFragmentBinding import info.nightscout.androidaps.events.EventExtendedBolusChange import info.nightscout.androidaps.events.EventTempBasalChange +import info.nightscout.androidaps.interfaces.IobCobCalculator +import info.nightscout.androidaps.interfaces.ProfileFunction import info.nightscout.androidaps.plugins.bus.RxBusWrapper import info.nightscout.androidaps.plugins.pump.virtual.events.EventVirtualPumpUpdateGui -import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin +import info.nightscout.androidaps.utils.DateUtil import info.nightscout.androidaps.utils.FabricPrivacy import info.nightscout.androidaps.utils.T -import io.reactivex.rxkotlin.plusAssign +import info.nightscout.androidaps.extensions.toStringFull import info.nightscout.androidaps.utils.resources.ResourceHelper import info.nightscout.androidaps.utils.rx.AapsSchedulers import io.reactivex.disposables.CompositeDisposable +import io.reactivex.rxkotlin.plusAssign import javax.inject.Inject class VirtualPumpFragment : DaggerFragment() { @Inject lateinit var rxBus: RxBusWrapper @Inject lateinit var resourceHelper: ResourceHelper + @Inject lateinit var dateUtil: DateUtil @Inject lateinit var fabricPrivacy: FabricPrivacy @Inject lateinit var virtualPumpPlugin: VirtualPumpPlugin - @Inject lateinit var treatmentsPlugin: TreatmentsPlugin + @Inject lateinit var profileFunction: ProfileFunction + @Inject lateinit var iobCobCalculator: IobCobCalculator @Inject lateinit var aapsSchedulers: AapsSchedulers private val disposable = CompositeDisposable() @@ -88,10 +93,11 @@ class VirtualPumpFragment : DaggerFragment() { @Synchronized private fun updateGui() { if (_binding == null) return + val profile = profileFunction.getProfile() ?: return binding.basabasalrate.text = resourceHelper.gs(R.string.pump_basebasalrate, virtualPumpPlugin.baseBasalRate) - binding.tempbasal.text = treatmentsPlugin.getTempBasalFromHistory(System.currentTimeMillis())?.toStringFull() + binding.tempbasal.text = iobCobCalculator.getTempBasal(dateUtil.now())?.toStringFull(profile, dateUtil) ?: "" - binding.extendedbolus.text = treatmentsPlugin.getExtendedBolusFromHistory(System.currentTimeMillis())?.toString() + binding.extendedbolus.text = iobCobCalculator.getExtendedBolus(dateUtil.now())?.toStringFull(dateUtil) ?: "" binding.battery.text = resourceHelper.gs(R.string.format_percent, virtualPumpPlugin.batteryPercent) binding.reservoir.text = resourceHelper.gs(R.string.formatinsulinunits, virtualPumpPlugin.reservoirInUnits.toDouble()) diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/pump/virtual/VirtualPumpPlugin.kt b/app/src/main/java/info/nightscout/androidaps/plugins/pump/virtual/VirtualPumpPlugin.kt index 7d72e9deae..b595da0409 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/pump/virtual/VirtualPumpPlugin.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/pump/virtual/VirtualPumpPlugin.kt @@ -4,14 +4,11 @@ import android.os.SystemClock import androidx.preference.PreferenceFragmentCompat import androidx.preference.SwitchPreference import dagger.android.HasAndroidInjector -import info.nightscout.androidaps.Config +import info.nightscout.androidaps.interfaces.Config import info.nightscout.androidaps.R import info.nightscout.androidaps.data.DetailedBolusInfo import info.nightscout.androidaps.data.Profile import info.nightscout.androidaps.data.PumpEnactResult -import info.nightscout.androidaps.db.ExtendedBolus -import info.nightscout.androidaps.db.Source -import info.nightscout.androidaps.db.TemporaryBasal import info.nightscout.androidaps.events.EventPreferenceChange import info.nightscout.androidaps.interfaces.* import info.nightscout.androidaps.logging.AAPSLogger @@ -23,11 +20,13 @@ import info.nightscout.androidaps.plugins.general.overview.events.EventOverviewB import info.nightscout.androidaps.plugins.general.overview.notifications.Notification import info.nightscout.androidaps.plugins.pump.common.defs.PumpType import info.nightscout.androidaps.plugins.pump.virtual.events.EventVirtualPumpUpdateGui -import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin import info.nightscout.androidaps.utils.DateUtil import info.nightscout.androidaps.utils.FabricPrivacy import info.nightscout.androidaps.utils.InstanceId.instanceId +import info.nightscout.androidaps.utils.T import info.nightscout.androidaps.utils.TimeChangeType +import info.nightscout.androidaps.extensions.convertedToAbsolute +import info.nightscout.androidaps.extensions.plannedRemainingMinutes import info.nightscout.androidaps.utils.resources.ResourceHelper import info.nightscout.androidaps.utils.rx.AapsSchedulers import info.nightscout.androidaps.utils.sharedPreferences.SP @@ -49,8 +48,9 @@ open class VirtualPumpPlugin @Inject constructor( private val aapsSchedulers: AapsSchedulers, private val sp: SP, private val profileFunction: ProfileFunction, - private val treatmentsPlugin: TreatmentsPlugin, + private val iobCobCalculator: IobCobCalculator, commandQueue: CommandQueueProvider, + private val pumpSync: PumpSync, private val config: Config, private val dateUtil: DateUtil ) : PumpPluginBase(PluginDescription() @@ -63,7 +63,7 @@ open class VirtualPumpPlugin @Inject constructor( .description(R.string.description_pump_virtual) .setDefault(), injector, aapsLogger, resourceHelper, commandQueue -), PumpInterface { +), Pump { private val disposable = CompositeDisposable() var batteryPercent = 50 @@ -72,29 +72,27 @@ open class VirtualPumpPlugin @Inject constructor( var pumpType: PumpType? = null private set private var lastDataTime: Long = 0 - override val pumpDescription = PumpDescription() - - init { - pumpDescription.isBolusCapable = true - pumpDescription.bolusStep = 0.1 - pumpDescription.isExtendedBolusCapable = true - pumpDescription.extendedBolusStep = 0.05 - pumpDescription.extendedBolusDurationStep = 30.0 - pumpDescription.extendedBolusMaxDuration = 8 * 60.toDouble() - pumpDescription.isTempBasalCapable = true - pumpDescription.tempBasalStyle = PumpDescription.PERCENT or PumpDescription.ABSOLUTE - pumpDescription.maxTempPercent = 500 - pumpDescription.tempPercentStep = 10 - pumpDescription.tempDurationStep = 30 - pumpDescription.tempDurationStep15mAllowed = true - pumpDescription.tempDurationStep30mAllowed = true - pumpDescription.tempMaxDuration = 24 * 60 - pumpDescription.isSetBasalProfileCapable = true - pumpDescription.basalStep = 0.01 - pumpDescription.basalMinimumRate = 0.01 - pumpDescription.isRefillingCapable = true - pumpDescription.storesCarbInfo = false - pumpDescription.is30minBasalRatesCapable = true + override val pumpDescription = PumpDescription().also { + it.isBolusCapable = true + it.bolusStep = 0.1 + it.isExtendedBolusCapable = true + it.extendedBolusStep = 0.05 + it.extendedBolusDurationStep = 30.0 + it.extendedBolusMaxDuration = 8 * 60.toDouble() + it.isTempBasalCapable = true + it.tempBasalStyle = PumpDescription.PERCENT or PumpDescription.ABSOLUTE + it.maxTempPercent = 500 + it.tempPercentStep = 10 + it.tempDurationStep = 30 + it.tempDurationStep15mAllowed = true + it.tempDurationStep30mAllowed = true + it.tempMaxDuration = 24 * 60 + it.isSetBasalProfileCapable = true + it.basalStep = 0.01 + it.basalMinimumRate = 0.01 + it.isRefillingCapable = true + it.storesCarbInfo = false + it.is30minBasalRatesCapable = true } fun getFakingStatus(): Boolean { @@ -154,7 +152,7 @@ open class VirtualPumpPlugin @Inject constructor( override fun setNewBasalProfile(profile: Profile): PumpEnactResult { lastDataTime = System.currentTimeMillis() - // Do nothing here. we are using ConfigBuilderPlugin.getPlugin().getActiveProfile().getProfile(); + // Do nothing here. we are using database profile val result = PumpEnactResult(injector) result.success = true val notification = Notification(Notification.PROFILE_SET_OK, resourceHelper.gs(R.string.profile_set_ok), Notification.INFO, 60) @@ -181,22 +179,21 @@ open class VirtualPumpPlugin @Inject constructor( override fun deliverTreatment(detailedBolusInfo: DetailedBolusInfo): PumpEnactResult { val result = PumpEnactResult(injector) - result.success = true - result.bolusDelivered = detailedBolusInfo.insulin - result.carbsDelivered = detailedBolusInfo.carbs - result.enacted = result.bolusDelivered > 0 || result.carbsDelivered > 0 - result.comment = resourceHelper.gs(R.string.virtualpump_resultok) + .success(true) + .bolusDelivered(detailedBolusInfo.insulin) + .carbsDelivered(detailedBolusInfo.carbs) + .enacted(detailedBolusInfo.insulin > 0 || detailedBolusInfo.carbs > 0) + .comment(resourceHelper.gs(R.string.virtualpump_resultok)) + val bolusingEvent = EventOverviewBolusProgress var delivering = 0.0 while (delivering < detailedBolusInfo.insulin) { SystemClock.sleep(200) - val bolusingEvent = EventOverviewBolusProgress bolusingEvent.status = resourceHelper.gs(R.string.bolusdelivering, delivering) bolusingEvent.percent = min((delivering / detailedBolusInfo.insulin * 100).toInt(), 100) rxBus.send(bolusingEvent) delivering += 0.1 } SystemClock.sleep(200) - val bolusingEvent = EventOverviewBolusProgress bolusingEvent.status = resourceHelper.gs(R.string.bolusdelivered, detailedBolusInfo.insulin) bolusingEvent.percent = 100 rxBus.send(bolusingEvent) @@ -204,17 +201,26 @@ open class VirtualPumpPlugin @Inject constructor( aapsLogger.debug(LTag.PUMP, "Delivering treatment insulin: " + detailedBolusInfo.insulin + "U carbs: " + detailedBolusInfo.carbs + "g " + result) rxBus.send(EventVirtualPumpUpdateGui()) lastDataTime = System.currentTimeMillis() - treatmentsPlugin.addToHistoryTreatment(detailedBolusInfo, false) + if (detailedBolusInfo.insulin > 0) + pumpSync.syncBolusWithPumpId( + timestamp = detailedBolusInfo.timestamp, + amount = detailedBolusInfo.insulin, + type = detailedBolusInfo.bolusType, + pumpId = dateUtil.now(), + pumpType = pumpType ?: PumpType.GENERIC_AAPS, + pumpSerial = serialNumber()) + if (detailedBolusInfo.carbs > 0) + pumpSync.syncCarbsWithTimestamp( + timestamp = detailedBolusInfo.timestamp + T.mins(detailedBolusInfo.carbTime.toLong()).msecs(), + amount = detailedBolusInfo.carbs, + pumpId = null, + pumpType = pumpType ?: PumpType.GENERIC_AAPS, + pumpSerial = serialNumber()) return result } override fun stopBolusDelivering() {} - override fun setTempBasalAbsolute(absoluteRate: Double, durationInMinutes: Int, profile: Profile, enforceNew: Boolean): PumpEnactResult { - val tempBasal = TemporaryBasal(injector) - .date(System.currentTimeMillis()) - .absolute(absoluteRate) - .duration(durationInMinutes) - .source(Source.USER) + override fun setTempBasalAbsolute(absoluteRate: Double, durationInMinutes: Int, profile: Profile, enforceNew: Boolean, tbrType: PumpSync.TemporaryBasalType): PumpEnactResult { val result = PumpEnactResult(injector) result.success = true result.enacted = true @@ -222,19 +228,23 @@ open class VirtualPumpPlugin @Inject constructor( result.absolute = absoluteRate result.duration = durationInMinutes result.comment = resourceHelper.gs(R.string.virtualpump_resultok) - treatmentsPlugin.addToHistoryTempBasal(tempBasal) + pumpSync.syncTemporaryBasalWithPumpId( + timestamp = dateUtil.now(), + rate = absoluteRate, + duration = T.mins(durationInMinutes.toLong()).msecs(), + isAbsolute = true, + type = tbrType, + pumpId = dateUtil.now(), + pumpType = pumpType ?: PumpType.GENERIC_AAPS, + pumpSerial = serialNumber() + ) aapsLogger.debug(LTag.PUMP, "Setting temp basal absolute: $result") rxBus.send(EventVirtualPumpUpdateGui()) lastDataTime = System.currentTimeMillis() return result } - override fun setTempBasalPercent(percent: Int, durationInMinutes: Int, profile: Profile, enforceNew: Boolean): PumpEnactResult { - val tempBasal = TemporaryBasal(injector) - .date(System.currentTimeMillis()) - .percent(percent) - .duration(durationInMinutes) - .source(Source.USER) + override fun setTempBasalPercent(percent: Int, durationInMinutes: Int, profile: Profile, enforceNew: Boolean, tbrType: PumpSync.TemporaryBasalType): PumpEnactResult { val result = PumpEnactResult(injector) result.success = true result.enacted = true @@ -243,7 +253,16 @@ open class VirtualPumpPlugin @Inject constructor( result.isTempCancel = false result.duration = durationInMinutes result.comment = resourceHelper.gs(R.string.virtualpump_resultok) - treatmentsPlugin.addToHistoryTempBasal(tempBasal) + pumpSync.syncTemporaryBasalWithPumpId( + timestamp = dateUtil.now(), + rate = percent.toDouble(), + duration = T.mins(durationInMinutes.toLong()).msecs(), + isAbsolute = false, + type = tbrType, + pumpId = dateUtil.now(), + pumpType = pumpType ?: PumpType.GENERIC_AAPS, + pumpSerial = serialNumber() + ) aapsLogger.debug(LTag.PUMP, "Settings temp basal percent: $result") rxBus.send(EventVirtualPumpUpdateGui()) lastDataTime = System.currentTimeMillis() @@ -253,18 +272,21 @@ open class VirtualPumpPlugin @Inject constructor( override fun setExtendedBolus(insulin: Double, durationInMinutes: Int): PumpEnactResult { val result = cancelExtendedBolus() if (!result.success) return result - val extendedBolus = ExtendedBolus(injector) - .date(System.currentTimeMillis()) - .insulin(insulin) - .durationInMinutes(durationInMinutes) - .source(Source.USER) result.success = true result.enacted = true result.bolusDelivered = insulin result.isTempCancel = false result.duration = durationInMinutes result.comment = resourceHelper.gs(R.string.virtualpump_resultok) - treatmentsPlugin.addToHistoryExtendedBolus(extendedBolus) + pumpSync.syncExtendedBolusWithPumpId( + timestamp = dateUtil.now(), + amount = insulin, + duration = T.mins(durationInMinutes.toLong()).msecs(), + isEmulatingTB = false, + pumpId = dateUtil.now(), + pumpType = pumpType ?: PumpType.GENERIC_AAPS, + pumpSerial = serialNumber() + ) aapsLogger.debug(LTag.PUMP, "Setting extended bolus: $result") rxBus.send(EventVirtualPumpUpdateGui()) lastDataTime = System.currentTimeMillis() @@ -276,11 +298,14 @@ open class VirtualPumpPlugin @Inject constructor( result.success = true result.isTempCancel = true result.comment = resourceHelper.gs(R.string.virtualpump_resultok) - if (treatmentsPlugin.isTempBasalInProgress) { + if (pumpSync.expectedPumpState().temporaryBasal != null) { result.enacted = true - val tempStop = TemporaryBasal(injector).date(System.currentTimeMillis()).source(Source.USER) - treatmentsPlugin.addToHistoryTempBasal(tempStop) - //tempBasal = null; + pumpSync.syncStopTemporaryBasalWithPumpId( + timestamp = dateUtil.now(), + endPumpId = dateUtil.now(), + pumpType = pumpType ?: PumpType.GENERIC_AAPS, + pumpSerial = serialNumber() + ) aapsLogger.debug(LTag.PUMP, "Canceling temp basal: $result") rxBus.send(EventVirtualPumpUpdateGui()) } @@ -290,10 +315,13 @@ open class VirtualPumpPlugin @Inject constructor( override fun cancelExtendedBolus(): PumpEnactResult { val result = PumpEnactResult(injector) - if (treatmentsPlugin.isInHistoryExtendedBolusInProgress) { - val exStop = ExtendedBolus(injector, System.currentTimeMillis()) - exStop.source = Source.USER - treatmentsPlugin.addToHistoryExtendedBolus(exStop) + if (pumpSync.expectedPumpState().extendedBolus != null) { + pumpSync.syncStopExtendedBolusWithPumpId( + timestamp = dateUtil.now(), + endPumpId = dateUtil.now(), + pumpType = pumpType ?: PumpType.GENERIC_AAPS, + pumpSerial = serialNumber() + ) } result.success = true result.enacted = true @@ -322,24 +350,24 @@ open class VirtualPumpPlugin @Inject constructor( extended.put("ActiveProfile", profileName) } catch (ignored: Exception) { } - val tb = treatmentsPlugin.getTempBasalFromHistory(now) + val tb = iobCobCalculator.getTempBasal(now) if (tb != null) { - extended.put("TempBasalAbsoluteRate", tb.tempBasalConvertedToAbsolute(now, profile)) - extended.put("TempBasalStart", dateUtil.dateAndTimeString(tb.date)) + extended.put("TempBasalAbsoluteRate", tb.convertedToAbsolute(now, profile)) + extended.put("TempBasalStart", dateUtil.dateAndTimeString(tb.timestamp)) extended.put("TempBasalRemaining", tb.plannedRemainingMinutes) } - val eb = treatmentsPlugin.getExtendedBolusFromHistory(now) + val eb = iobCobCalculator.getExtendedBolus(now) if (eb != null) { - extended.put("ExtendedBolusAbsoluteRate", eb.absoluteRate()) - extended.put("ExtendedBolusStart", dateUtil.dateAndTimeString(eb.date)) + extended.put("ExtendedBolusAbsoluteRate", eb.rate) + extended.put("ExtendedBolusStart", dateUtil.dateAndTimeString(eb.timestamp)) extended.put("ExtendedBolusRemaining", eb.plannedRemainingMinutes) } - status.put("timestamp", DateUtil.toISOString(now)) + status.put("timestamp", dateUtil.toISOString(now)) pump.put("battery", battery) pump.put("status", status) pump.put("extended", extended) pump.put("reservoir", reservoirInUnits) - pump.put("clock", DateUtil.toISOString(now)) + pump.put("clock", dateUtil.toISOString(now)) } catch (e: JSONException) { aapsLogger.error("Unhandled exception", e) } @@ -347,7 +375,7 @@ open class VirtualPumpPlugin @Inject constructor( } override fun manufacturer(): ManufacturerType { - return pumpDescription.pumpType.manufacturer + return pumpDescription.pumpType.manufacturer ?: ManufacturerType.AndroidAPS } override fun model(): PumpType { @@ -367,7 +395,7 @@ open class VirtualPumpPlugin @Inject constructor( } fun refreshConfiguration() { - val pumpType = sp.getString(R.string.key_virtualpump_type, PumpType.GenericAAPS.description) + val pumpType = sp.getString(R.string.key_virtualpump_type, PumpType.GENERIC_AAPS.description) val pumpTypeNew = PumpType.getByDescription(pumpType) aapsLogger.debug(LTag.PUMP, "Pump in configuration: $pumpType, PumpType object: $pumpTypeNew") if (this.pumpType == pumpTypeNew) return diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/sensitivity/AbstractSensitivityPlugin.kt b/app/src/main/java/info/nightscout/androidaps/plugins/sensitivity/AbstractSensitivityPlugin.kt index 9e826156ee..66b070075d 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/sensitivity/AbstractSensitivityPlugin.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/sensitivity/AbstractSensitivityPlugin.kt @@ -2,12 +2,12 @@ package info.nightscout.androidaps.plugins.sensitivity import dagger.android.HasAndroidInjector import info.nightscout.androidaps.R -import info.nightscout.androidaps.interfaces.IobCobCalculatorInterface import info.nightscout.androidaps.interfaces.PluginBase import info.nightscout.androidaps.interfaces.PluginDescription -import info.nightscout.androidaps.interfaces.SensitivityInterface +import info.nightscout.androidaps.interfaces.Sensitivity import info.nightscout.androidaps.logging.AAPSLogger import info.nightscout.androidaps.logging.LTag +import info.nightscout.androidaps.plugins.iob.iobCobCalculator.AutosensDataStore import info.nightscout.androidaps.plugins.iob.iobCobCalculator.AutosensResult import info.nightscout.androidaps.utils.Round import info.nightscout.androidaps.utils.SafeParse @@ -22,9 +22,9 @@ abstract class AbstractSensitivityPlugin( aapsLogger: AAPSLogger, resourceHelper: ResourceHelper, val sp: SP -) : PluginBase(pluginDescription, aapsLogger, resourceHelper, injector), SensitivityInterface { +) : PluginBase(pluginDescription, aapsLogger, resourceHelper, injector), Sensitivity { - abstract override fun detectSensitivity(plugin: IobCobCalculatorInterface, fromTime: Long, toTime: Long): AutosensResult + abstract override fun detectSensitivity(ads: AutosensDataStore, fromTime: Long, toTime: Long): AutosensResult fun fillResult(ratio: Double, carbsAbsorbed: Double, pastSensitivity: String, ratioLimit: String, sensResult: String, deviationsArraySize: Int): AutosensResult { @@ -46,11 +46,11 @@ abstract class AbstractSensitivityPlugin( //If not-excluded data <= MIN_HOURS -> don't do Autosens //If not-excluded data >= MIN_HOURS_FULL_AUTOSENS -> full Autosens //Between MIN_HOURS and MIN_HOURS_FULL_AUTOSENS: gradually increase autosens - val autosensContrib = (min(max(SensitivityInterface.MIN_HOURS, deviationsArraySize / 12.0), - SensitivityInterface.MIN_HOURS_FULL_AUTOSENS) - SensitivityInterface.MIN_HOURS) / (SensitivityInterface.MIN_HOURS_FULL_AUTOSENS - SensitivityInterface.MIN_HOURS) + val autosensContrib = (min(max(Sensitivity.MIN_HOURS, deviationsArraySize / 12.0), + Sensitivity.MIN_HOURS_FULL_AUTOSENS) - Sensitivity.MIN_HOURS) / (Sensitivity.MIN_HOURS_FULL_AUTOSENS - Sensitivity.MIN_HOURS) ratio = autosensContrib * (ratio - 1) + 1 if (autosensContrib != 1.0) { - ratioLimit += "(" + deviationsArraySize + " of " + SensitivityInterface.MIN_HOURS_FULL_AUTOSENS * 12 + " values) " + ratioLimit += "(" + deviationsArraySize + " of " + Sensitivity.MIN_HOURS_FULL_AUTOSENS * 12 + " values) " } if (ratio != rawRatio) { ratioLimit += "Ratio limited from $rawRatio to $ratio" diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/sensitivity/SensitivityAAPSPlugin.kt b/app/src/main/java/info/nightscout/androidaps/plugins/sensitivity/SensitivityAAPSPlugin.kt index 127045ebd0..9eee2864e0 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/sensitivity/SensitivityAAPSPlugin.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/sensitivity/SensitivityAAPSPlugin.kt @@ -7,18 +7,18 @@ import info.nightscout.androidaps.data.Profile import info.nightscout.androidaps.database.AppRepository import info.nightscout.androidaps.database.entities.TherapyEvent import info.nightscout.androidaps.db.ProfileSwitch +import info.nightscout.androidaps.extensions.isEvent5minBack import info.nightscout.androidaps.interfaces.DatabaseHelperInterface -import info.nightscout.androidaps.interfaces.IobCobCalculatorInterface import info.nightscout.androidaps.interfaces.PluginDescription import info.nightscout.androidaps.interfaces.PluginType import info.nightscout.androidaps.interfaces.ProfileFunction -import info.nightscout.androidaps.interfaces.SensitivityInterface.SensitivityType +import info.nightscout.androidaps.interfaces.Sensitivity.SensitivityType import info.nightscout.androidaps.logging.AAPSLogger import info.nightscout.androidaps.logging.LTag +import info.nightscout.androidaps.plugins.iob.iobCobCalculator.AutosensDataStore import info.nightscout.androidaps.plugins.iob.iobCobCalculator.AutosensResult -import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorPlugin.Companion.percentile +import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorPlugin import info.nightscout.androidaps.utils.DateUtil -import info.nightscout.androidaps.utils.extensions.isEvent5minBack import info.nightscout.androidaps.utils.resources.ResourceHelper import info.nightscout.androidaps.utils.sharedPreferences.SP import org.json.JSONException @@ -30,10 +30,10 @@ import kotlin.math.roundToInt @Singleton open class SensitivityAAPSPlugin @Inject constructor( - injector: HasAndroidInjector?, - aapsLogger: AAPSLogger?, - resourceHelper: ResourceHelper?, - sp: SP?, + injector: HasAndroidInjector, + aapsLogger: AAPSLogger, + resourceHelper: ResourceHelper, + sp: SP, private val profileFunction: ProfileFunction, private val dateUtil: DateUtil, private val databaseHelper: DatabaseHelperInterface, @@ -45,11 +45,10 @@ open class SensitivityAAPSPlugin @Inject constructor( .shortName(R.string.sensitivity_shortname) .preferencesId(R.xml.pref_absorption_aaps) .description(R.string.description_sensitivity_aaps), - injector!!, aapsLogger!!, resourceHelper!!, sp!! + injector, aapsLogger, resourceHelper, sp ) { - override fun detectSensitivity(plugin: IobCobCalculatorInterface, fromTime: Long, toTime: Long): AutosensResult { - val autosensDataTable = plugin.getAutosensDataTable() + override fun detectSensitivity(ads: AutosensDataStore, fromTime: Long, toTime: Long): AutosensResult { val age = sp.getString(R.string.key_age, "") var defaultHours = 24 if (age == resourceHelper.gs(R.string.key_adult)) defaultHours = 24 @@ -61,13 +60,13 @@ open class SensitivityAAPSPlugin @Inject constructor( aapsLogger.error("No profile") return AutosensResult() } - if (autosensDataTable.size() < 4) { - aapsLogger.debug(LTag.AUTOSENS, "No autosens data available. lastDataTime=" + plugin.lastDataTime()) + if (ads.autosensDataTable.size() < 4) { + aapsLogger.debug(LTag.AUTOSENS, "No autosens data available. lastDataTime=" + ads.lastDataTime(dateUtil)) return AutosensResult() } - val current = plugin.getAutosensData(toTime) // this is running inside lock already + val current = ads.getAutosensDataAtTime(toTime) // this is running inside lock already if (current == null) { - aapsLogger.debug(LTag.AUTOSENS, "No autosens data available. toTime: " + dateUtil.dateAndTimeString(toTime) + " lastDataTime: " + plugin.lastDataTime()) + aapsLogger.debug(LTag.AUTOSENS, "No autosens data available. toTime: " + dateUtil.dateAndTimeString(toTime) + " lastDataTime: " + ads.lastDataTime(dateUtil)) return AutosensResult() } val siteChanges = repository.getTherapyEventDataFromTime(fromTime, TherapyEvent.Type.CANNULA_CHANGE, true).blockingGet() @@ -75,8 +74,8 @@ open class SensitivityAAPSPlugin @Inject constructor( val deviationsArray: MutableList = ArrayList() var pastSensitivity = "" var index = 0 - while (index < autosensDataTable.size()) { - val autosensData = autosensDataTable.valueAt(index) + while (index < ads.autosensDataTable.size()) { + val autosensData = ads.autosensDataTable.valueAt(index) if (autosensData.time < fromTime) { index++ continue @@ -116,7 +115,7 @@ open class SensitivityAAPSPlugin @Inject constructor( val sensResult: String aapsLogger.debug(LTag.AUTOSENS, "Records: $index $pastSensitivity") Arrays.sort(deviations) - val percentile = percentile(deviations, 0.50) + val percentile = IobCobCalculatorPlugin.percentile(deviations, 0.50) val basalOff = percentile * (60.0 / 5.0) / sens val ratio = 1 + basalOff / profile.maxDailyBasal sensResult = when { diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/sensitivity/SensitivityOref1Plugin.kt b/app/src/main/java/info/nightscout/androidaps/plugins/sensitivity/SensitivityOref1Plugin.kt index 9e5860de44..828646c354 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/sensitivity/SensitivityOref1Plugin.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/sensitivity/SensitivityOref1Plugin.kt @@ -7,19 +7,19 @@ import info.nightscout.androidaps.data.Profile import info.nightscout.androidaps.database.AppRepository import info.nightscout.androidaps.database.entities.TherapyEvent import info.nightscout.androidaps.db.ProfileSwitch +import info.nightscout.androidaps.extensions.isEvent5minBack import info.nightscout.androidaps.interfaces.DatabaseHelperInterface -import info.nightscout.androidaps.interfaces.IobCobCalculatorInterface import info.nightscout.androidaps.interfaces.PluginDescription import info.nightscout.androidaps.interfaces.PluginType import info.nightscout.androidaps.interfaces.ProfileFunction -import info.nightscout.androidaps.interfaces.SensitivityInterface.SensitivityType +import info.nightscout.androidaps.interfaces.Sensitivity.SensitivityType import info.nightscout.androidaps.logging.AAPSLogger import info.nightscout.androidaps.logging.LTag import info.nightscout.androidaps.plugins.aps.openAPSSMB.SMBDefaults +import info.nightscout.androidaps.plugins.iob.iobCobCalculator.AutosensDataStore import info.nightscout.androidaps.plugins.iob.iobCobCalculator.AutosensResult -import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorPlugin.Companion.percentile +import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorPlugin import info.nightscout.androidaps.utils.DateUtil -import info.nightscout.androidaps.utils.extensions.isEvent5minBack import info.nightscout.androidaps.utils.resources.ResourceHelper import info.nightscout.androidaps.utils.sharedPreferences.SP import org.json.JSONException @@ -31,10 +31,10 @@ import kotlin.math.roundToInt @Singleton open class SensitivityOref1Plugin @Inject constructor( - injector: HasAndroidInjector?, - aapsLogger: AAPSLogger?, - resourceHelper: ResourceHelper?, - sp: SP?, + injector: HasAndroidInjector, + aapsLogger: AAPSLogger, + resourceHelper: ResourceHelper, + sp: SP, private val profileFunction: ProfileFunction, private val dateUtil: DateUtil, private val databaseHelper: DatabaseHelperInterface, @@ -48,27 +48,26 @@ open class SensitivityOref1Plugin @Inject constructor( .preferencesId(R.xml.pref_absorption_oref1) .description(R.string.description_sensitivity_oref1) .setDefault(), - injector!!, aapsLogger!!, resourceHelper!!, sp!! + injector, aapsLogger, resourceHelper, sp ) { - override fun detectSensitivity(plugin: IobCobCalculatorInterface, fromTime: Long, toTime: Long): AutosensResult { + override fun detectSensitivity(ads: AutosensDataStore, fromTime: Long, toTime: Long): AutosensResult { // todo this method is called from the IobCobCalculatorPlugin, which leads to a circular // dependency, this should be avoided - val autosensDataTable = plugin.getAutosensDataTable() val profile = profileFunction.getProfile() if (profile == null) { aapsLogger.error("No profile") return AutosensResult() } - if (autosensDataTable.size() < 4) { - aapsLogger.debug(LTag.AUTOSENS, "No autosens data available. lastDataTime=" + plugin.lastDataTime()) + if (ads.autosensDataTable.size() < 4) { + aapsLogger.debug(LTag.AUTOSENS, "No autosens data available. lastDataTime=" + ads.lastDataTime(dateUtil)) return AutosensResult() } // the current - val current = plugin.getAutosensData(toTime) // this is running inside lock already + val current = ads.getAutosensDataAtTime(toTime) // this is running inside lock already if (current == null) { - aapsLogger.debug(LTag.AUTOSENS, "No autosens data available. toTime: " + dateUtil.dateAndTimeString(toTime) + " lastDataTime: " + plugin.lastDataTime()) + aapsLogger.debug(LTag.AUTOSENS, "No autosens data available. toTime: " + dateUtil.dateAndTimeString(toTime) + " lastDataTime: " + ads.lastDataTime(dateUtil)) return AutosensResult() } val siteChanges = repository.getTherapyEventDataFromTime(fromTime, TherapyEvent.Type.CANNULA_CHANGE, true).blockingGet() @@ -85,8 +84,8 @@ open class SensitivityOref1Plugin @Inject constructor( val ratioLimitArray = mutableListOf("", "") val hoursDetection = listOf(8.0, 24.0) var index = 0 - while (index < autosensDataTable.size()) { - val autosensData = autosensDataTable.valueAt(index) + while (index < ads.autosensDataTable.size()) { + val autosensData = ads.autosensDataTable.valueAt(index) if (autosensData.time < fromTime) { index++ continue @@ -106,6 +105,7 @@ open class SensitivityOref1Plugin @Inject constructor( if (isEvent5minBack(siteChanges, autosensData.time)) { deviationsArray.clear() pastSensitivity += "(SITECHANGE)" + pastSensitivity += "(SITECHANGE)" } // reset deviations after profile switch @@ -162,8 +162,8 @@ open class SensitivityOref1Plugin @Inject constructor( val sens = profile.isfMgdl aapsLogger.debug(LTag.AUTOSENS, "Records: $index $pastSensitivity") Arrays.sort(deviations) - val pSensitive = percentile(deviations, 0.50) - val pResistant = percentile(deviations, 0.50) + val pSensitive = IobCobCalculatorPlugin.percentile(deviations, 0.50) + val pResistant = IobCobCalculatorPlugin.percentile(deviations, 0.50) var basalOff = 0.0 when { pSensitive < 0 -> { // sensitive diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/sensitivity/SensitivityWeightedAveragePlugin.kt b/app/src/main/java/info/nightscout/androidaps/plugins/sensitivity/SensitivityWeightedAveragePlugin.kt index f875f9f44c..8da207dd06 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/sensitivity/SensitivityWeightedAveragePlugin.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/sensitivity/SensitivityWeightedAveragePlugin.kt @@ -8,17 +8,17 @@ import info.nightscout.androidaps.data.Profile import info.nightscout.androidaps.database.AppRepository import info.nightscout.androidaps.database.entities.TherapyEvent import info.nightscout.androidaps.db.ProfileSwitch +import info.nightscout.androidaps.extensions.isEvent5minBack import info.nightscout.androidaps.interfaces.DatabaseHelperInterface -import info.nightscout.androidaps.interfaces.IobCobCalculatorInterface import info.nightscout.androidaps.interfaces.PluginDescription import info.nightscout.androidaps.interfaces.PluginType import info.nightscout.androidaps.interfaces.ProfileFunction -import info.nightscout.androidaps.interfaces.SensitivityInterface.SensitivityType +import info.nightscout.androidaps.interfaces.Sensitivity.SensitivityType import info.nightscout.androidaps.logging.AAPSLogger import info.nightscout.androidaps.logging.LTag +import info.nightscout.androidaps.plugins.iob.iobCobCalculator.AutosensDataStore import info.nightscout.androidaps.plugins.iob.iobCobCalculator.AutosensResult import info.nightscout.androidaps.utils.DateUtil -import info.nightscout.androidaps.utils.extensions.isEvent5minBack import info.nightscout.androidaps.utils.resources.ResourceHelper import info.nightscout.androidaps.utils.sharedPreferences.SP import org.json.JSONException @@ -47,21 +47,20 @@ open class SensitivityWeightedAveragePlugin @Inject constructor( injector, aapsLogger, resourceHelper, sp ) { - override fun detectSensitivity(plugin: IobCobCalculatorInterface, fromTime: Long, toTime: Long): AutosensResult { - val autosensDataTable = plugin.getAutosensDataTable() + override fun detectSensitivity(ads: AutosensDataStore, fromTime: Long, toTime: Long): AutosensResult { val age = sp.getString(R.string.key_age, "") var defaultHours = 24 if (age == resourceHelper.gs(R.string.key_adult)) defaultHours = 24 if (age == resourceHelper.gs(R.string.key_teenage)) defaultHours = 4 if (age == resourceHelper.gs(R.string.key_child)) defaultHours = 4 val hoursForDetection = sp.getInt(R.string.key_openapsama_autosens_period, defaultHours) - if (autosensDataTable.size() < 4) { - aapsLogger.debug(LTag.AUTOSENS, "No autosens data available. lastDataTime=" + plugin.lastDataTime()) + if (ads.autosensDataTable.size() < 4) { + aapsLogger.debug(LTag.AUTOSENS, "No autosens data available. lastDataTime=" + ads.lastDataTime(dateUtil)) return AutosensResult() } - val current = plugin.getAutosensData(toTime) // this is running inside lock already + val current = ads.getAutosensDataAtTime(toTime) // this is running inside lock already if (current == null) { - aapsLogger.debug(LTag.AUTOSENS, "No autosens data available. toTime: " + dateUtil.dateAndTimeString(toTime) + " lastDataTime: " + plugin.lastDataTime()) + aapsLogger.debug(LTag.AUTOSENS, "No autosens data available. toTime: " + dateUtil.dateAndTimeString(toTime) + " lastDataTime: " + ads.lastDataTime(dateUtil)) return AutosensResult() } val profile = profileFunction.getProfile() @@ -74,8 +73,8 @@ open class SensitivityWeightedAveragePlugin @Inject constructor( var pastSensitivity = "" var index = 0 val data = LongSparseArray() - while (index < autosensDataTable.size()) { - val autosensData = autosensDataTable.valueAt(index) + while (index < ads.autosensDataTable.size()) { + val autosensData = ads.autosensDataTable.valueAt(index) if (autosensData.time < fromTime) { index++ continue diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/source/BGSourceFragment.kt b/app/src/main/java/info/nightscout/androidaps/plugins/source/BGSourceFragment.kt index a889ea38ba..b4d334206e 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/source/BGSourceFragment.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/source/BGSourceFragment.kt @@ -10,8 +10,10 @@ import androidx.recyclerview.widget.RecyclerView import dagger.android.support.DaggerFragment import info.nightscout.androidaps.R import info.nightscout.androidaps.database.AppRepository +import info.nightscout.androidaps.database.entities.ValueWithUnit import info.nightscout.androidaps.database.entities.GlucoseValue -import info.nightscout.androidaps.database.entities.UserEntry.* +import info.nightscout.androidaps.database.entities.UserEntry.Action +import info.nightscout.androidaps.database.entities.UserEntry.Sources import info.nightscout.androidaps.database.transactions.InvalidateGlucoseValueTransaction import info.nightscout.androidaps.databinding.BgsourceFragmentBinding import info.nightscout.androidaps.databinding.BgsourceItemBinding @@ -24,9 +26,11 @@ import info.nightscout.androidaps.utils.DateUtil import info.nightscout.androidaps.utils.FabricPrivacy import info.nightscout.androidaps.utils.T import info.nightscout.androidaps.utils.alertDialogs.OKDialog -import info.nightscout.androidaps.utils.extensions.directionToIcon -import info.nightscout.androidaps.utils.extensions.toVisibility -import info.nightscout.androidaps.utils.extensions.valueToUnitsString +import info.nightscout.androidaps.extensions.directionToIcon +import info.nightscout.androidaps.extensions.toVisibility +import info.nightscout.androidaps.extensions.valueToUnitsString +import info.nightscout.androidaps.interfaces.ActivePlugin +import info.nightscout.androidaps.interfaces.PluginBase import info.nightscout.androidaps.utils.resources.ResourceHelper import info.nightscout.androidaps.utils.rx.AapsSchedulers import io.reactivex.disposables.CompositeDisposable @@ -45,6 +49,7 @@ class BGSourceFragment : DaggerFragment() { @Inject lateinit var repository: AppRepository @Inject lateinit var aapsSchedulers: AapsSchedulers @Inject lateinit var uel: UserEntryLogger + @Inject lateinit var activePlugin: ActivePlugin private val disposable = CompositeDisposable() private val millsToThePast = T.hours(12).msecs() @@ -129,7 +134,19 @@ class BGSourceFragment : DaggerFragment() { activity?.let { activity -> val text = dateUtil.dateAndTimeString(glucoseValue.timestamp) + "\n" + glucoseValue.valueToUnitsString(profileFunction.getUnits()) OKDialog.showConfirmation(activity, resourceHelper.gs(R.string.removerecord), text, Runnable { - uel.log(Action.BG_REMOVED, ValueWithUnit(glucoseValue.timestamp, Units.Timestamp)) + val source = when((activePlugin.activeBgSource as PluginBase).pluginDescription.pluginName) { + R.string.dexcom_app_patched -> Sources.Dexcom + R.string.eversense -> Sources.Eversense + R.string.Glimp -> Sources.Glimp + R.string.MM640g -> Sources.MM640g + R.string.nsclientbg -> Sources.NSClientSource + R.string.poctech -> Sources.PocTech + R.string.tomato -> Sources.Tomato + R.string.xdrip -> Sources.Xdrip + else -> Sources.Unknown + } + uel.log(Action.BG_REMOVED, source, + ValueWithUnit.Timestamp(glucoseValue.timestamp)) disposable += repository.runTransaction(InvalidateGlucoseValueTransaction(glucoseValue.id)).subscribe() }) } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/source/DexcomPlugin.kt b/app/src/main/java/info/nightscout/androidaps/plugins/source/DexcomPlugin.kt index 71a2a0ce65..d28aa3fa4f 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/source/DexcomPlugin.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/source/DexcomPlugin.kt @@ -6,29 +6,31 @@ import android.content.pm.PackageManager import androidx.core.content.ContextCompat import androidx.work.Worker import androidx.work.WorkerParameters +import androidx.work.workDataOf import dagger.android.HasAndroidInjector -import info.nightscout.androidaps.Config +import info.nightscout.androidaps.interfaces.Config import info.nightscout.androidaps.R import info.nightscout.androidaps.activities.RequestDexcomPermissionActivity import info.nightscout.androidaps.database.AppRepository import info.nightscout.androidaps.database.entities.GlucoseValue import info.nightscout.androidaps.database.entities.TherapyEvent +import info.nightscout.androidaps.database.entities.UserEntry.Action +import info.nightscout.androidaps.database.entities.UserEntry.Sources +import info.nightscout.androidaps.database.entities.ValueWithUnit import info.nightscout.androidaps.database.transactions.CgmSourceTransaction -import info.nightscout.androidaps.interfaces.BgSourceInterface +import info.nightscout.androidaps.interfaces.BgSource import info.nightscout.androidaps.interfaces.PluginBase import info.nightscout.androidaps.interfaces.PluginDescription import info.nightscout.androidaps.interfaces.PluginType import info.nightscout.androidaps.logging.AAPSLogger import info.nightscout.androidaps.logging.LTag -import info.nightscout.androidaps.plugins.general.nsclient.NSUpload +import info.nightscout.androidaps.logging.UserEntryLogger import info.nightscout.androidaps.receivers.DataWorker import info.nightscout.androidaps.utils.DateUtil import info.nightscout.androidaps.utils.T import info.nightscout.androidaps.utils.XDripBroadcast import info.nightscout.androidaps.utils.resources.ResourceHelper import info.nightscout.androidaps.utils.sharedPreferences.SP -import io.reactivex.disposables.CompositeDisposable -import io.reactivex.rxkotlin.plusAssign import javax.inject.Inject import javax.inject.Singleton @@ -37,6 +39,7 @@ class DexcomPlugin @Inject constructor( injector: HasAndroidInjector, resourceHelper: ResourceHelper, aapsLogger: AAPSLogger, + private val sp: SP, private val dexcomMediator: DexcomMediator, config: Config ) : PluginBase(PluginDescription() @@ -48,9 +51,7 @@ class DexcomPlugin @Inject constructor( .preferencesId(R.xml.pref_bgsourcedexcom) .description(R.string.description_source_dexcom), aapsLogger, resourceHelper, injector -), BgSourceInterface { - - private val disposable = CompositeDisposable() +), BgSource { init { if (!config.NSCLIENT) { @@ -62,16 +63,17 @@ class DexcomPlugin @Inject constructor( return true } + override fun shouldUploadToNs(glucoseValue: GlucoseValue): Boolean = + (glucoseValue.sourceSensor == GlucoseValue.SourceSensor.DEXCOM_G6_NATIVE || + glucoseValue.sourceSensor == GlucoseValue.SourceSensor.DEXCOM_G5_NATIVE || + glucoseValue.sourceSensor == GlucoseValue.SourceSensor.DEXCOM_NATIVE_UNKNOWN) + && sp.getBoolean(R.string.key_dexcomg5_nsupload, false) + override fun onStart() { super.onStart() dexcomMediator.requestPermissionIfNeeded() } - override fun onStop() { - disposable.clear() - super.onStop() - } - // cannot be inner class because of needed injection class DexcomWorker( context: Context, @@ -81,11 +83,12 @@ class DexcomPlugin @Inject constructor( @Inject lateinit var aapsLogger: AAPSLogger @Inject lateinit var injector: HasAndroidInjector @Inject lateinit var dexcomPlugin: DexcomPlugin - @Inject lateinit var nsUpload: NSUpload @Inject lateinit var sp: SP + @Inject lateinit var dateUtil: DateUtil @Inject lateinit var dataWorker: DataWorker @Inject lateinit var broadcastToXDrip: XDripBroadcast @Inject lateinit var repository: AppRepository + @Inject lateinit var uel: UserEntryLogger init { (context.applicationContext as HasAndroidInjector).androidInjector().inject(this) @@ -94,9 +97,9 @@ class DexcomPlugin @Inject constructor( override fun doWork(): Result { var ret = Result.success() - if (!dexcomPlugin.isEnabled(PluginType.BGSOURCE)) return Result.failure() + if (!dexcomPlugin.isEnabled(PluginType.BGSOURCE)) return Result.success() val bundle = dataWorker.pickupBundle(inputData.getLong(DataWorker.STORE_KEY, -1)) - ?: return Result.failure() + ?: return Result.failure(workDataOf("Error" to "missing input data")) try { val sourceSensor = when (bundle.getString("sensorType") ?: "") { "G6" -> GlucoseValue.SourceSensor.DEXCOM_G6_NATIVE @@ -104,7 +107,7 @@ class DexcomPlugin @Inject constructor( else -> GlucoseValue.SourceSensor.DEXCOM_NATIVE_UNKNOWN } val glucoseValuesBundle = bundle.getBundle("glucoseValues") - ?: return Result.failure() + ?: return Result.failure(workDataOf("Error" to "missing glucoseValues")) val glucoseValues = mutableListOf() for (i in 0 until glucoseValuesBundle.size()) { val glucoseValueBundle = glucoseValuesBundle.getBundle(i.toString())!! @@ -122,7 +125,7 @@ class DexcomPlugin @Inject constructor( for (i in 0 until meters.size()) { meters.getBundle(i.toString())?.let { val timestamp = it.getLong("timestamp") * 1000 - val now = DateUtil.now() + val now = dateUtil.now() if (timestamp > now - T.months(1).msecs() && timestamp < now) { calibrations.add(CgmSourceTransaction.Calibration( timestamp = it.getLong("timestamp") * 1000, @@ -138,40 +141,39 @@ class DexcomPlugin @Inject constructor( } else { null } - dexcomPlugin.disposable += repository.runTransactionForResult(CgmSourceTransaction(glucoseValues, calibrations, sensorStartTime)).subscribe({ result -> - result.inserted.forEach { - broadcastToXDrip(it) - if (sp.getBoolean(R.string.key_dexcomg5_nsupload, false)) { - nsUpload.uploadBg(it, sourceSensor.text) - } - aapsLogger.debug(LTag.BGSOURCE, "Inserted bg $it") + repository.runTransactionForResult(CgmSourceTransaction(glucoseValues, calibrations, sensorStartTime)) + .doOnError { + aapsLogger.error(LTag.DATABASE, "Error while saving values from Dexcom App", it) + ret = Result.failure(workDataOf("Error" to it)) } - result.updated.forEach { - broadcastToXDrip(it) - if (sp.getBoolean(R.string.key_dexcomg5_nsupload, false)) { - nsUpload.updateBg(it, sourceSensor.text) + .blockingGet() + .also { result -> + result.inserted.forEach { + broadcastToXDrip(it) + aapsLogger.debug(LTag.DATABASE, "Inserted bg $it") } - aapsLogger.debug(LTag.BGSOURCE, "Updated bg $it") - } - result.sensorInsertionsInserted.forEach { - if (sp.getBoolean(R.string.key_dexcomg5_nsupload, false)) { - nsUpload.uploadEvent(it) + result.updated.forEach { + broadcastToXDrip(it) + aapsLogger.debug(LTag.DATABASE, "Updated bg $it") } - aapsLogger.debug(LTag.BGSOURCE, "Inserted sensor insertion $it") - } - result.calibrationsInserted.forEach { - if (sp.getBoolean(R.string.key_dexcomg5_nsupload, false)) { - nsUpload.uploadEvent(it) + result.sensorInsertionsInserted.forEach { + uel.log(Action.CAREPORTAL, + Sources.BG, + ValueWithUnit.Timestamp(it.timestamp), + ValueWithUnit.TherapyEventType(it.type)) + aapsLogger.debug(LTag.DATABASE, "Inserted sensor insertion $it") + } + result.calibrationsInserted.forEach { + uel.log(Action.CAREPORTAL, + Sources.BG, + ValueWithUnit.Timestamp(it.timestamp), + ValueWithUnit.TherapyEventType(it.type)) + aapsLogger.debug(LTag.DATABASE, "Inserted calibration $it") } - aapsLogger.debug(LTag.BGSOURCE, "Inserted calibration $it") } - }, { - aapsLogger.error("Error while saving values from Dexcom App", it) - ret = Result.failure() - }) } catch (e: Exception) { aapsLogger.error("Error while processing intent from Dexcom App", e) - ret = Result.failure() + ret = Result.failure(workDataOf("Error" to e)) } return ret } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/source/EversensePlugin.kt b/app/src/main/java/info/nightscout/androidaps/plugins/source/EversensePlugin.kt index f585fbfff5..c6d0467c78 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/source/EversensePlugin.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/source/EversensePlugin.kt @@ -3,20 +3,20 @@ package info.nightscout.androidaps.plugins.source import android.content.Context import androidx.work.Worker import androidx.work.WorkerParameters +import androidx.work.workDataOf import dagger.android.HasAndroidInjector import info.nightscout.androidaps.R import info.nightscout.androidaps.database.AppRepository import info.nightscout.androidaps.database.entities.GlucoseValue import info.nightscout.androidaps.database.entities.TherapyEvent import info.nightscout.androidaps.database.transactions.CgmSourceTransaction -import info.nightscout.androidaps.database.transactions.InsertTherapyEventIfNewTransaction -import info.nightscout.androidaps.interfaces.BgSourceInterface +import info.nightscout.androidaps.database.transactions.InsertIfNewByTimestampTherapyEventTransaction +import info.nightscout.androidaps.interfaces.BgSource import info.nightscout.androidaps.interfaces.PluginBase import info.nightscout.androidaps.interfaces.PluginDescription import info.nightscout.androidaps.interfaces.PluginType import info.nightscout.androidaps.logging.AAPSLogger import info.nightscout.androidaps.logging.LTag -import info.nightscout.androidaps.plugins.general.nsclient.NSUpload import info.nightscout.androidaps.receivers.DataWorker import info.nightscout.androidaps.utils.DateUtil import info.nightscout.androidaps.utils.XDripBroadcast @@ -30,7 +30,8 @@ import javax.inject.Singleton class EversensePlugin @Inject constructor( injector: HasAndroidInjector, resourceHelper: ResourceHelper, - aapsLogger: AAPSLogger + aapsLogger: AAPSLogger, + private val sp: SP ) : PluginBase(PluginDescription() .mainType(PluginType.BGSOURCE) .fragmentClass(BGSourceFragment::class.java.name) @@ -40,10 +41,13 @@ class EversensePlugin @Inject constructor( .preferencesId(R.xml.pref_bgsource) .description(R.string.description_source_eversense), aapsLogger, resourceHelper, injector -), BgSourceInterface { +), BgSource { override var sensorBatteryLevel = -1 + override fun shouldUploadToNs(glucoseValue: GlucoseValue): Boolean = + glucoseValue.sourceSensor == GlucoseValue.SourceSensor.EVERSENSE && sp.getBoolean(R.string.key_dexcomg5_nsupload, false) + // cannot be inner class because of needed injection class EversenseWorker( context: Context, @@ -53,8 +57,6 @@ class EversensePlugin @Inject constructor( @Inject lateinit var injector: HasAndroidInjector @Inject lateinit var eversensePlugin: EversensePlugin @Inject lateinit var aapsLogger: AAPSLogger - @Inject lateinit var sp: SP - @Inject lateinit var nsUpload: NSUpload @Inject lateinit var dateUtil: DateUtil @Inject lateinit var dataWorker: DataWorker @Inject lateinit var repository: AppRepository @@ -67,9 +69,9 @@ class EversensePlugin @Inject constructor( override fun doWork(): Result { var ret = Result.success() - if (!eversensePlugin.isEnabled(PluginType.BGSOURCE)) return Result.failure() + if (!eversensePlugin.isEnabled(PluginType.BGSOURCE)) return Result.success() val bundle = dataWorker.pickupBundle(inputData.getLong(DataWorker.STORE_KEY, -1)) - ?: return Result.failure() + ?: return Result.failure(workDataOf("Error" to "missing input data")) if (bundle.containsKey("currentCalibrationPhase")) aapsLogger.debug(LTag.BGSOURCE, "currentCalibrationPhase: " + bundle.getString("currentCalibrationPhase")) if (bundle.containsKey("placementModeInProgress")) aapsLogger.debug(LTag.BGSOURCE, "placementModeInProgress: " + bundle.getBoolean("placementModeInProgress")) if (bundle.containsKey("glucoseLevel")) aapsLogger.debug(LTag.BGSOURCE, "glucoseLevel: " + bundle.getInt("glucoseLevel")) @@ -109,16 +111,14 @@ class EversensePlugin @Inject constructor( ) repository.runTransactionForResult(CgmSourceTransaction(glucoseValues, emptyList(), null)) .doOnError { - aapsLogger.error("Error while saving values from Eversense App", it) - ret = Result.failure() + aapsLogger.error(LTag.DATABASE, "Error while saving values from Eversense App", it) + ret = Result.failure(workDataOf("Error" to it)) } .blockingGet() .also { savedValues -> savedValues.inserted.forEach { broadcastToXDrip(it) - if (sp.getBoolean(R.string.key_dexcomg5_nsupload, false)) - nsUpload.uploadBg(it, GlucoseValue.SourceSensor.EVERSENSE.text) - aapsLogger.debug(LTag.BGSOURCE, "Inserted bg $it") + aapsLogger.debug(LTag.DATABASE, "Inserted bg $it") } } } @@ -132,7 +132,7 @@ class EversensePlugin @Inject constructor( aapsLogger.debug(LTag.BGSOURCE, "calibrationTimestamps" + Arrays.toString(calibrationTimestamps)) aapsLogger.debug(LTag.BGSOURCE, "calibrationRecordNumbers" + Arrays.toString(calibrationRecordNumbers)) for (i in calibrationGlucoseLevels.indices) { - repository.runTransactionForResult(InsertTherapyEventIfNewTransaction( + repository.runTransactionForResult(InsertIfNewByTimestampTherapyEventTransaction( timestamp = calibrationTimestamps[i], type = TherapyEvent.Type.FINGER_STICK_BG_VALUE, glucose = calibrationGlucoseLevels[i].toDouble(), @@ -141,15 +141,12 @@ class EversensePlugin @Inject constructor( enteredBy = "AndroidAPS-Eversense" )) .doOnError { - aapsLogger.error(LTag.BGSOURCE, "Error while saving therapy event", it) - ret = Result.failure() + aapsLogger.error(LTag.DATABASE, "Error while saving therapy event", it) + ret = Result.failure(workDataOf("Error" to it)) } .blockingGet() .also { result -> - result.inserted.forEach { - nsUpload.uploadEvent(it) - aapsLogger.debug(LTag.BGSOURCE, "Inserted bg $it") - } + result.inserted.forEach { aapsLogger.debug(LTag.DATABASE, "Inserted therapy event $it") } } } } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/source/GlimpPlugin.kt b/app/src/main/java/info/nightscout/androidaps/plugins/source/GlimpPlugin.kt index c61e2a4065..dcd6690163 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/source/GlimpPlugin.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/source/GlimpPlugin.kt @@ -3,18 +3,18 @@ package info.nightscout.androidaps.plugins.source import android.content.Context import androidx.work.Worker import androidx.work.WorkerParameters +import androidx.work.workDataOf import dagger.android.HasAndroidInjector import info.nightscout.androidaps.R import info.nightscout.androidaps.database.AppRepository import info.nightscout.androidaps.database.entities.GlucoseValue import info.nightscout.androidaps.database.transactions.CgmSourceTransaction -import info.nightscout.androidaps.interfaces.BgSourceInterface +import info.nightscout.androidaps.interfaces.BgSource import info.nightscout.androidaps.interfaces.PluginBase import info.nightscout.androidaps.interfaces.PluginDescription import info.nightscout.androidaps.interfaces.PluginType import info.nightscout.androidaps.logging.AAPSLogger import info.nightscout.androidaps.logging.LTag -import info.nightscout.androidaps.plugins.general.nsclient.NSUpload import info.nightscout.androidaps.utils.XDripBroadcast import info.nightscout.androidaps.utils.resources.ResourceHelper import info.nightscout.androidaps.utils.sharedPreferences.SP @@ -25,7 +25,8 @@ import javax.inject.Singleton class GlimpPlugin @Inject constructor( injector: HasAndroidInjector, resourceHelper: ResourceHelper, - aapsLogger: AAPSLogger + aapsLogger: AAPSLogger, + private val sp: SP ) : PluginBase(PluginDescription() .mainType(PluginType.BGSOURCE) .fragmentClass(BGSourceFragment::class.java.name) @@ -34,7 +35,7 @@ class GlimpPlugin @Inject constructor( .preferencesId(R.xml.pref_bgsource) .description(R.string.description_source_glimp), aapsLogger, resourceHelper, injector -), BgSourceInterface { +), BgSource { // cannot be inner class because of needed injection class GlimpWorker( @@ -47,8 +48,6 @@ class GlimpPlugin @Inject constructor( @Inject lateinit var aapsLogger: AAPSLogger @Inject lateinit var repository: AppRepository @Inject lateinit var broadcastToXDrip: XDripBroadcast - @Inject lateinit var sp: SP - @Inject lateinit var nsUpload: NSUpload init { (context.applicationContext as HasAndroidInjector).androidInjector().inject(this) @@ -57,7 +56,7 @@ class GlimpPlugin @Inject constructor( override fun doWork(): Result { var ret = Result.success() - if (!glimpPlugin.isEnabled(PluginType.BGSOURCE)) return Result.failure() + if (!glimpPlugin.isEnabled(PluginType.BGSOURCE)) return Result.success() aapsLogger.debug(LTag.BGSOURCE, "Received Glimp Data: $inputData}") val glucoseValues = mutableListOf() glucoseValues += CgmSourceTransaction.TransactionGlucoseValue( @@ -70,19 +69,21 @@ class GlimpPlugin @Inject constructor( ) repository.runTransactionForResult(CgmSourceTransaction(glucoseValues, emptyList(), null)) .doOnError { - aapsLogger.error("Error while saving values from Glimp App", it) - ret = Result.failure() + aapsLogger.error(LTag.DATABASE, "Error while saving values from Glimp App", it) + ret = Result.failure(workDataOf("Error" to it)) } .blockingGet() .also { savedValues -> savedValues.inserted.forEach { broadcastToXDrip(it) - if (sp.getBoolean(R.string.key_dexcomg5_nsupload, false)) - nsUpload.uploadBg(it, GlucoseValue.SourceSensor.GLIMP.text) - aapsLogger.debug(LTag.BGSOURCE, "Inserted bg $it") + aapsLogger.debug(LTag.DATABASE, "Inserted bg $it") } } return ret } } + + override fun shouldUploadToNs(glucoseValue: GlucoseValue): Boolean = + glucoseValue.sourceSensor == GlucoseValue.SourceSensor.GLIMP && sp.getBoolean(R.string.key_dexcomg5_nsupload, false) + } \ No newline at end of file diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/source/MM640gPlugin.kt b/app/src/main/java/info/nightscout/androidaps/plugins/source/MM640gPlugin.kt index 1bb431e59b..41d4defeeb 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/source/MM640gPlugin.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/source/MM640gPlugin.kt @@ -3,18 +3,18 @@ package info.nightscout.androidaps.plugins.source import android.content.Context import androidx.work.Worker import androidx.work.WorkerParameters +import androidx.work.workDataOf import dagger.android.HasAndroidInjector import info.nightscout.androidaps.R import info.nightscout.androidaps.database.AppRepository import info.nightscout.androidaps.database.entities.GlucoseValue import info.nightscout.androidaps.database.transactions.CgmSourceTransaction -import info.nightscout.androidaps.interfaces.BgSourceInterface +import info.nightscout.androidaps.interfaces.BgSource import info.nightscout.androidaps.interfaces.PluginBase import info.nightscout.androidaps.interfaces.PluginDescription import info.nightscout.androidaps.interfaces.PluginType import info.nightscout.androidaps.logging.AAPSLogger import info.nightscout.androidaps.logging.LTag -import info.nightscout.androidaps.plugins.general.nsclient.NSUpload import info.nightscout.androidaps.receivers.DataWorker import info.nightscout.androidaps.utils.DateUtil import info.nightscout.androidaps.utils.XDripBroadcast @@ -29,7 +29,8 @@ import javax.inject.Singleton class MM640gPlugin @Inject constructor( injector: HasAndroidInjector, resourceHelper: ResourceHelper, - aapsLogger: AAPSLogger + aapsLogger: AAPSLogger, + private val sp: SP ) : PluginBase(PluginDescription() .mainType(PluginType.BGSOURCE) .fragmentClass(BGSourceFragment::class.java.name) @@ -37,7 +38,7 @@ class MM640gPlugin @Inject constructor( .pluginName(R.string.MM640g) .description(R.string.description_source_mm640g), aapsLogger, resourceHelper, injector -), BgSourceInterface { +), BgSource { // cannot be inner class because of needed injection class MM640gWorker( @@ -48,8 +49,6 @@ class MM640gPlugin @Inject constructor( @Inject lateinit var mM640gPlugin: MM640gPlugin @Inject lateinit var injector: HasAndroidInjector @Inject lateinit var aapsLogger: AAPSLogger - @Inject lateinit var sp: SP - @Inject lateinit var nsUpload: NSUpload @Inject lateinit var dateUtil: DateUtil @Inject lateinit var dataWorker: DataWorker @Inject lateinit var repository: AppRepository @@ -62,8 +61,8 @@ class MM640gPlugin @Inject constructor( override fun doWork(): Result { var ret = Result.success() - if (!mM640gPlugin.isEnabled(PluginType.BGSOURCE)) return Result.failure() - val collection = inputData.getString("collection") ?: return Result.failure() + if (!mM640gPlugin.isEnabled(PluginType.BGSOURCE)) return Result.success() + val collection = inputData.getString("collection") ?: return Result.failure(workDataOf("Error" to "missing collection")) if (collection == "entries") { val data = inputData.getString("data") aapsLogger.debug(LTag.BGSOURCE, "Received MM640g Data: $data") @@ -88,25 +87,27 @@ class MM640gPlugin @Inject constructor( } repository.runTransactionForResult(CgmSourceTransaction(glucoseValues, emptyList(), null)) .doOnError { - aapsLogger.error("Error while saving values from Eversense App", it) - ret = Result.failure() + aapsLogger.error(LTag.DATABASE, "Error while saving values from Eversense App", it) + ret = Result.failure(workDataOf("Error" to it)) } .blockingGet() .also { savedValues -> - savedValues.all().forEach { - broadcastToXDrip(it) - if (sp.getBoolean(R.string.key_dexcomg5_nsupload, false)) - nsUpload.uploadBg(it, GlucoseValue.SourceSensor.MM_600_SERIES.text) - aapsLogger.debug(LTag.BGSOURCE, "Inserted bg $it") + savedValues.all().forEach { + broadcastToXDrip(it) + aapsLogger.debug(LTag.DATABASE, "Inserted bg $it") + } } - } } catch (e: JSONException) { aapsLogger.error("Exception: ", e) - ret = Result.failure() + ret = Result.failure(workDataOf("Error" to e)) } } } return ret } } + + override fun shouldUploadToNs(glucoseValue: GlucoseValue): Boolean = + glucoseValue.sourceSensor == GlucoseValue.SourceSensor.MM_600_SERIES && sp.getBoolean(R.string.key_dexcomg5_nsupload, false) + } \ No newline at end of file diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/source/NSClientSourcePlugin.kt b/app/src/main/java/info/nightscout/androidaps/plugins/source/NSClientSourcePlugin.kt index b885e3b545..4866cc7f9e 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/source/NSClientSourcePlugin.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/source/NSClientSourcePlugin.kt @@ -3,13 +3,14 @@ package info.nightscout.androidaps.plugins.source import android.content.Context import androidx.work.Worker import androidx.work.WorkerParameters +import androidx.work.workDataOf import dagger.android.HasAndroidInjector -import info.nightscout.androidaps.Config +import info.nightscout.androidaps.interfaces.Config import info.nightscout.androidaps.R import info.nightscout.androidaps.database.AppRepository import info.nightscout.androidaps.database.entities.GlucoseValue import info.nightscout.androidaps.database.transactions.CgmSourceTransaction -import info.nightscout.androidaps.interfaces.BgSourceInterface +import info.nightscout.androidaps.interfaces.BgSource import info.nightscout.androidaps.interfaces.PluginBase import info.nightscout.androidaps.interfaces.PluginDescription import info.nightscout.androidaps.interfaces.PluginType @@ -17,7 +18,6 @@ import info.nightscout.androidaps.logging.AAPSLogger import info.nightscout.androidaps.logging.LTag import info.nightscout.androidaps.plugins.bus.RxBusWrapper import info.nightscout.androidaps.plugins.general.nsclient.NSClientPlugin -import info.nightscout.androidaps.plugins.general.nsclient.NSUpload import info.nightscout.androidaps.plugins.general.nsclient.data.NSSgv import info.nightscout.androidaps.plugins.general.overview.events.EventDismissNotification import info.nightscout.androidaps.plugins.general.overview.notifications.Notification @@ -44,7 +44,7 @@ class NSClientSourcePlugin @Inject constructor( .pluginName(R.string.nsclientbg) .description(R.string.description_source_ns_client), aapsLogger, resourceHelper, injector -), BgSourceInterface { +), BgSource { private var lastBGTimeStamp: Long = 0 private var isAdvancedFilteringEnabled = false @@ -61,6 +61,8 @@ class NSClientSourcePlugin @Inject constructor( return isAdvancedFilteringEnabled } + override fun shouldUploadToNs(glucoseValue: GlucoseValue): Boolean = false + private fun detectSource(glucoseValue: GlucoseValue) { if (glucoseValue.timestamp > lastBGTimeStamp) { isAdvancedFilteringEnabled = arrayOf( @@ -85,7 +87,6 @@ class NSClientSourcePlugin @Inject constructor( @Inject lateinit var aapsLogger: AAPSLogger @Inject lateinit var sp: SP @Inject lateinit var rxBus: RxBusWrapper - @Inject lateinit var nsUpload: NSUpload @Inject lateinit var dateUtil: DateUtil @Inject lateinit var dataWorker: DataWorker @Inject lateinit var repository: AppRepository @@ -103,7 +104,7 @@ class NSClientSourcePlugin @Inject constructor( timestamp = sgv.mills ?: return null, value = sgv.mgdl?.toDouble() ?: return null, noise = null, - raw = sgv.filtered?.toDouble() ?: sgv.mgdl?.toDouble(), + raw = sgv.filtered?.toDouble() ?: sgv.mgdl?.toDouble(), trendArrow = GlucoseValue.TrendArrow.fromString(sgv.direction), nightscoutId = sgv.id, sourceSensor = GlucoseValue.SourceSensor.fromString(sgv.device) @@ -114,10 +115,10 @@ class NSClientSourcePlugin @Inject constructor( override fun doWork(): Result { var ret = Result.success() - if (!nsClientSourcePlugin.isEnabled() && !sp.getBoolean(R.string.key_ns_autobackfill, true) && !dexcomPlugin.isEnabled()) return Result.failure() + if (!nsClientSourcePlugin.isEnabled() && !sp.getBoolean(R.string.key_ns_autobackfill, true) && !dexcomPlugin.isEnabled()) return Result.success() val sgvs = dataWorker.pickupJSONArray(inputData.getLong(DataWorker.STORE_KEY, -1)) - ?: return Result.failure() + ?: return Result.failure(workDataOf("Error" to "missing input data")) try { var latestDateInReceivedData: Long = 0 @@ -126,12 +127,12 @@ class NSClientSourcePlugin @Inject constructor( val glucoseValues = mutableListOf() for (i in 0 until sgvs.length()) { val sgv = toGv(sgvs.getJSONObject(i)) ?: continue - if (sgv.timestamp < dateUtil._now() && sgv.timestamp > latestDateInReceivedData) latestDateInReceivedData = sgv.timestamp + if (sgv.timestamp < dateUtil.now() && sgv.timestamp > latestDateInReceivedData) latestDateInReceivedData = sgv.timestamp glucoseValues += sgv } // Was that sgv more less 5 mins ago ? - if (T.msecs(dateUtil._now() - latestDateInReceivedData).mins() < 5L) { + if (T.msecs(dateUtil.now() - latestDateInReceivedData).mins() < 5L) { rxBus.send(EventDismissNotification(Notification.NS_ALARM)) rxBus.send(EventDismissNotification(Notification.NS_URGENT_ALARM)) } @@ -140,25 +141,25 @@ class NSClientSourcePlugin @Inject constructor( repository.runTransactionForResult(CgmSourceTransaction(glucoseValues, emptyList(), null, !nsClientSourcePlugin.isEnabled())) .doOnError { - aapsLogger.error("Error while saving values from NSClient App", it) - ret = Result.failure() + aapsLogger.error(LTag.DATABASE, "Error while saving values from NSClient App", it) + ret = Result.failure(workDataOf("Error" to it)) } .blockingGet() .also { result -> result.updated.forEach { broadcastToXDrip(it) nsClientSourcePlugin.detectSource(it) - aapsLogger.debug(LTag.BGSOURCE, "Updated bg $it") + aapsLogger.debug(LTag.DATABASE, "Updated bg $it") } result.inserted.forEach { broadcastToXDrip(it) nsClientSourcePlugin.detectSource(it) - aapsLogger.debug(LTag.BGSOURCE, "Inserted bg $it") + aapsLogger.debug(LTag.DATABASE, "Inserted bg $it") } } } catch (e: Exception) { aapsLogger.error("Unhandled exception", e) - ret = Result.failure() + ret = Result.failure(workDataOf("Error" to e)) } // Objectives 0 sp.putBoolean(R.string.key_ObjectivesbgIsAvailableInNS, true) diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/source/PoctechPlugin.kt b/app/src/main/java/info/nightscout/androidaps/plugins/source/PoctechPlugin.kt index 09c5204309..bcec10bd5d 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/source/PoctechPlugin.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/source/PoctechPlugin.kt @@ -3,19 +3,19 @@ package info.nightscout.androidaps.plugins.source import android.content.Context import androidx.work.Worker import androidx.work.WorkerParameters +import androidx.work.workDataOf import dagger.android.HasAndroidInjector import info.nightscout.androidaps.Constants import info.nightscout.androidaps.R import info.nightscout.androidaps.database.AppRepository import info.nightscout.androidaps.database.entities.GlucoseValue import info.nightscout.androidaps.database.transactions.CgmSourceTransaction -import info.nightscout.androidaps.interfaces.BgSourceInterface +import info.nightscout.androidaps.interfaces.BgSource import info.nightscout.androidaps.interfaces.PluginBase import info.nightscout.androidaps.interfaces.PluginDescription import info.nightscout.androidaps.interfaces.PluginType import info.nightscout.androidaps.logging.AAPSLogger import info.nightscout.androidaps.logging.LTag -import info.nightscout.androidaps.plugins.general.nsclient.NSUpload import info.nightscout.androidaps.utils.JsonHelper.safeGetString import info.nightscout.androidaps.utils.XDripBroadcast import info.nightscout.androidaps.utils.resources.ResourceHelper @@ -29,7 +29,8 @@ import javax.inject.Singleton class PoctechPlugin @Inject constructor( injector: HasAndroidInjector, resourceHelper: ResourceHelper, - aapsLogger: AAPSLogger + aapsLogger: AAPSLogger, + private val sp: SP ) : PluginBase(PluginDescription() .mainType(PluginType.BGSOURCE) .fragmentClass(BGSourceFragment::class.java.name) @@ -38,7 +39,7 @@ class PoctechPlugin @Inject constructor( .preferencesId(R.xml.pref_bgsource) .description(R.string.description_source_poctech), aapsLogger, resourceHelper, injector -), BgSourceInterface { +), BgSource { // cannot be inner class because of needed injection class PoctechWorker( @@ -49,8 +50,6 @@ class PoctechPlugin @Inject constructor( @Inject lateinit var injector: HasAndroidInjector @Inject lateinit var poctechPlugin: PoctechPlugin @Inject lateinit var aapsLogger: AAPSLogger - @Inject lateinit var sp: SP - @Inject lateinit var nsUpload: NSUpload @Inject lateinit var repository: AppRepository @Inject lateinit var broadcastToXDrip: XDripBroadcast @@ -61,7 +60,7 @@ class PoctechPlugin @Inject constructor( override fun doWork(): Result { var ret = Result.success() - if (!poctechPlugin.isEnabled(PluginType.BGSOURCE)) return Result.failure() + if (!poctechPlugin.isEnabled(PluginType.BGSOURCE)) return Result.success() aapsLogger.debug(LTag.BGSOURCE, "Received Poctech Data $inputData") try { val glucoseValues = mutableListOf() @@ -81,23 +80,25 @@ class PoctechPlugin @Inject constructor( } repository.runTransactionForResult(CgmSourceTransaction(glucoseValues, emptyList(), null)) .doOnError { - aapsLogger.error("Error while saving values from Poctech App", it) - ret = Result.failure() + aapsLogger.error(LTag.DATABASE, "Error while saving values from Poctech App", it) + ret = Result.failure(workDataOf("Error" to it)) } .blockingGet() .also { savedValues -> savedValues.inserted.forEach { broadcastToXDrip(it) - if (sp.getBoolean(R.string.key_dexcomg5_nsupload, false)) - nsUpload.uploadBg(it, GlucoseValue.SourceSensor.POCTECH_NATIVE.text) - aapsLogger.debug(LTag.BGSOURCE, "Inserted bg $it") + aapsLogger.debug(LTag.DATABASE, "Inserted bg $it") } } } catch (e: JSONException) { aapsLogger.error("Exception: ", e) - ret = Result.failure() + ret = Result.failure(workDataOf("Error" to e)) } return ret } } + + override fun shouldUploadToNs(glucoseValue: GlucoseValue): Boolean = + glucoseValue.sourceSensor == GlucoseValue.SourceSensor.POCTECH_NATIVE && sp.getBoolean(R.string.key_dexcomg5_nsupload, false) + } \ No newline at end of file diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/source/RandomBgPlugin.kt b/app/src/main/java/info/nightscout/androidaps/plugins/source/RandomBgPlugin.kt index aa776557ae..06c7822036 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/source/RandomBgPlugin.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/source/RandomBgPlugin.kt @@ -7,19 +7,17 @@ import info.nightscout.androidaps.R import info.nightscout.androidaps.database.AppRepository import info.nightscout.androidaps.database.entities.GlucoseValue import info.nightscout.androidaps.database.transactions.CgmSourceTransaction -import info.nightscout.androidaps.interfaces.BgSourceInterface +import info.nightscout.androidaps.interfaces.BgSource import info.nightscout.androidaps.interfaces.PluginBase import info.nightscout.androidaps.interfaces.PluginDescription import info.nightscout.androidaps.interfaces.PluginType import info.nightscout.androidaps.logging.AAPSLogger import info.nightscout.androidaps.logging.LTag -import info.nightscout.androidaps.plugins.general.nsclient.NSUpload import info.nightscout.androidaps.plugins.pump.virtual.VirtualPumpPlugin import info.nightscout.androidaps.utils.DateUtil import info.nightscout.androidaps.utils.T import info.nightscout.androidaps.utils.XDripBroadcast import info.nightscout.androidaps.utils.buildHelper.BuildHelper -import info.nightscout.androidaps.utils.extensions.isRunningTest import info.nightscout.androidaps.utils.resources.ResourceHelper import info.nightscout.androidaps.utils.sharedPreferences.SP import io.reactivex.disposables.CompositeDisposable @@ -38,7 +36,6 @@ class RandomBgPlugin @Inject constructor( private val virtualPumpPlugin: VirtualPumpPlugin, private val buildHelper: BuildHelper, private val sp: SP, - private val nsUpload: NSUpload, private val dateUtil: DateUtil, private val repository: AppRepository, private val xDripBroadcast: XDripBroadcast @@ -51,7 +48,7 @@ class RandomBgPlugin @Inject constructor( .preferencesId(R.xml.pref_bgsource) .description(R.string.description_source_randombg), aapsLogger, resourceHelper, injector -), BgSourceInterface { +), BgSource { private val loopHandler: Handler = Handler(HandlerThread(RandomBgPlugin::class.java.simpleName + "Handler").also { it.start() }.looper) private lateinit var refreshLoop: Runnable @@ -59,12 +56,15 @@ class RandomBgPlugin @Inject constructor( companion object { const val interval = 5L // minutes + const val min = 70 // mgdl + const val max = 190 // mgdl + const val period = 90.0 // minutes } init { refreshLoop = Runnable { - handleNewData() loopHandler.postDelayed(refreshLoop, T.mins(interval).msecs()) + handleNewData() } } @@ -74,6 +74,9 @@ class RandomBgPlugin @Inject constructor( return true } + override fun shouldUploadToNs(glucoseValue: GlucoseValue): Boolean = + glucoseValue.sourceSensor == GlucoseValue.SourceSensor.RANDOM && sp.getBoolean(R.string.key_dexcomg5_nsupload, false) + override fun onStart() { super.onStart() loopHandler.postDelayed(refreshLoop, T.mins(interval).msecs()) @@ -86,37 +89,33 @@ class RandomBgPlugin @Inject constructor( } override fun specialEnableCondition(): Boolean { - return isRunningTest() || virtualPumpPlugin.isEnabled(PluginType.PUMP) && buildHelper.isEngineeringMode() +// return isRunningTest() || virtualPumpPlugin.isEnabled(PluginType.PUMP) && buildHelper.isEngineeringMode() + return true } private fun handleNewData() { if (!isEnabled(PluginType.BGSOURCE)) return - val min = 70 - val max = 190 val cal = GregorianCalendar() val currentMinute = cal.get(Calendar.MINUTE) + (cal.get(Calendar.HOUR_OF_DAY) % 2) * 60 - val bgMgdl = min + ((max - min) + (max - min) * sin(currentMinute / 120.0 * 2 * PI)) / 2 + val bgMgdl = min + ((max - min) + (max - min) * sin(currentMinute / period * 2 * PI)) / 2 val glucoseValues = mutableListOf() glucoseValues += CgmSourceTransaction.TransactionGlucoseValue( - timestamp = dateUtil._now(), + timestamp = dateUtil.now(), value = bgMgdl, raw = 0.0, noise = null, trendArrow = GlucoseValue.TrendArrow.NONE, sourceSensor = GlucoseValue.SourceSensor.RANDOM ) - disposable += repository.runTransactionForResult(CgmSourceTransaction(glucoseValues, emptyList(), null)).subscribe({ savedValues -> - savedValues.inserted.forEach { - xDripBroadcast(it) - if (sp.getBoolean(R.string.key_dexcomg5_nsupload, false)) - nsUpload.uploadBg(it, GlucoseValue.SourceSensor.RANDOM.text) - aapsLogger.debug(LTag.BGSOURCE, "Inserted bg $it") - } - }, { - aapsLogger.error(LTag.BGSOURCE, "Error while saving values from Random plugin", it) - }) - aapsLogger.debug(LTag.BGSOURCE, "Generated BG: $bgMgdl ${Date()}") + disposable += repository.runTransactionForResult(CgmSourceTransaction(glucoseValues, emptyList(), null)) + .subscribe({ savedValues -> + savedValues.inserted.forEach { + xDripBroadcast(it) + aapsLogger.debug(LTag.DATABASE, "Inserted bg $it") + } + }, { aapsLogger.error(LTag.DATABASE, "Error while saving values from Random plugin", it) } + ) } } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/source/TomatoPlugin.kt b/app/src/main/java/info/nightscout/androidaps/plugins/source/TomatoPlugin.kt index db1710d6e2..bbcc7ccc49 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/source/TomatoPlugin.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/source/TomatoPlugin.kt @@ -3,18 +3,18 @@ package info.nightscout.androidaps.plugins.source import android.content.Context import androidx.work.Worker import androidx.work.WorkerParameters +import androidx.work.workDataOf import dagger.android.HasAndroidInjector import info.nightscout.androidaps.R import info.nightscout.androidaps.database.AppRepository import info.nightscout.androidaps.database.entities.GlucoseValue import info.nightscout.androidaps.database.transactions.CgmSourceTransaction -import info.nightscout.androidaps.interfaces.BgSourceInterface +import info.nightscout.androidaps.interfaces.BgSource import info.nightscout.androidaps.interfaces.PluginBase import info.nightscout.androidaps.interfaces.PluginDescription import info.nightscout.androidaps.interfaces.PluginType import info.nightscout.androidaps.logging.AAPSLogger import info.nightscout.androidaps.logging.LTag -import info.nightscout.androidaps.plugins.general.nsclient.NSUpload import info.nightscout.androidaps.utils.XDripBroadcast import info.nightscout.androidaps.utils.resources.ResourceHelper import info.nightscout.androidaps.utils.sharedPreferences.SP @@ -25,7 +25,8 @@ import javax.inject.Singleton class TomatoPlugin @Inject constructor( injector: HasAndroidInjector, resourceHelper: ResourceHelper, - aapsLogger: AAPSLogger + aapsLogger: AAPSLogger, + private val sp: SP ) : PluginBase(PluginDescription() .mainType(PluginType.BGSOURCE) .fragmentClass(BGSourceFragment::class.java.name) @@ -35,7 +36,7 @@ class TomatoPlugin @Inject constructor( .shortName(R.string.tomato_short) .description(R.string.description_source_tomato), aapsLogger, resourceHelper, injector -), BgSourceInterface { +), BgSource { // cannot be inner class because of needed injection class TomatoWorker( @@ -47,7 +48,6 @@ class TomatoPlugin @Inject constructor( @Inject lateinit var tomatoPlugin: TomatoPlugin @Inject lateinit var aapsLogger: AAPSLogger @Inject lateinit var sp: SP - @Inject lateinit var nsUpload: NSUpload @Inject lateinit var repository: AppRepository @Inject lateinit var broadcastToXDrip: XDripBroadcast @@ -59,7 +59,7 @@ class TomatoPlugin @Inject constructor( override fun doWork(): Result { var ret = Result.success() - if (!tomatoPlugin.isEnabled(PluginType.BGSOURCE)) return Result.failure() + if (!tomatoPlugin.isEnabled(PluginType.BGSOURCE)) return Result.success() val glucoseValues = mutableListOf() glucoseValues += CgmSourceTransaction.TransactionGlucoseValue( timestamp = inputData.getLong("com.fanqies.tomatofn.Extras.Time", 0), @@ -71,19 +71,21 @@ class TomatoPlugin @Inject constructor( ) repository.runTransactionForResult(CgmSourceTransaction(glucoseValues, emptyList(), null)) .doOnError { - aapsLogger.error("Error while saving values from Tomato App", it) - ret = Result.failure() + aapsLogger.error(LTag.DATABASE, "Error while saving values from Tomato App", it) + ret = Result.failure(workDataOf("Error" to it)) } .blockingGet() .also { savedValues -> savedValues.inserted.forEach { broadcastToXDrip(it) - if (sp.getBoolean(R.string.key_dexcomg5_nsupload, false)) - nsUpload.uploadBg(it, GlucoseValue.SourceSensor.LIBRE_1_TOMATO.text) - aapsLogger.debug(LTag.BGSOURCE, "Inserted bg $it") + aapsLogger.debug(LTag.DATABASE, "Inserted bg $it") } } return ret } } + + override fun shouldUploadToNs(glucoseValue: GlucoseValue): Boolean = + glucoseValue.sourceSensor == GlucoseValue.SourceSensor.LIBRE_1_TOMATO && sp.getBoolean(R.string.key_dexcomg5_nsupload, false) + } \ No newline at end of file diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/source/XdripPlugin.kt b/app/src/main/java/info/nightscout/androidaps/plugins/source/XdripPlugin.kt index 3862e9f6d5..be7df833e9 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/source/XdripPlugin.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/source/XdripPlugin.kt @@ -3,12 +3,13 @@ package info.nightscout.androidaps.plugins.source import android.content.Context import androidx.work.Worker import androidx.work.WorkerParameters +import androidx.work.workDataOf import dagger.android.HasAndroidInjector import info.nightscout.androidaps.R import info.nightscout.androidaps.database.AppRepository import info.nightscout.androidaps.database.entities.GlucoseValue import info.nightscout.androidaps.database.transactions.CgmSourceTransaction -import info.nightscout.androidaps.interfaces.BgSourceInterface +import info.nightscout.androidaps.interfaces.BgSource import info.nightscout.androidaps.interfaces.PluginBase import info.nightscout.androidaps.interfaces.PluginDescription import info.nightscout.androidaps.interfaces.PluginType @@ -32,11 +33,13 @@ class XdripPlugin @Inject constructor( .pluginName(R.string.xdrip) .description(R.string.description_source_xdrip), aapsLogger, resourceHelper, injector -), BgSourceInterface { +), BgSource { private var advancedFiltering = false override var sensorBatteryLevel = -1 + override fun shouldUploadToNs(glucoseValue: GlucoseValue): Boolean = false + override fun advancedFilteringSupported(): Boolean { return advancedFiltering } @@ -70,9 +73,9 @@ class XdripPlugin @Inject constructor( override fun doWork(): Result { var ret = Result.success() - if (!xdripPlugin.isEnabled(PluginType.BGSOURCE)) return Result.failure() + if (!xdripPlugin.isEnabled(PluginType.BGSOURCE)) return Result.success() val bundle = dataWorker.pickupBundle(inputData.getLong(DataWorker.STORE_KEY, -1)) - ?: return Result.failure() + ?: return Result.failure(workDataOf("Error" to "missing input data")) aapsLogger.debug(LTag.BGSOURCE, "Received xDrip data: $bundle") val glucoseValues = mutableListOf() @@ -87,14 +90,14 @@ class XdripPlugin @Inject constructor( ) repository.runTransactionForResult(CgmSourceTransaction(glucoseValues, emptyList(), null)) .doOnError { - aapsLogger.error(LTag.BGSOURCE, "Error while saving values from Eversense App", it) - ret = Result.failure() + aapsLogger.error(LTag.DATABASE, "Error while saving values from Xdrip", it) + ret = Result.failure(workDataOf("Error" to it)) } .blockingGet() .also { savedValues -> savedValues.all().forEach { xdripPlugin.detectSource(it) - aapsLogger.debug(LTag.BGSOURCE, "Inserted bg $it") + aapsLogger.debug(LTag.DATABASE, "Inserted bg $it") } } xdripPlugin.sensorBatteryLevel = bundle.getInt(Intents.EXTRA_SENSOR_BATTERY, -1) diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/treatments/CarbsGenerator.kt b/app/src/main/java/info/nightscout/androidaps/plugins/treatments/CarbsGenerator.kt deleted file mode 100644 index 7f9dbc94c3..0000000000 --- a/app/src/main/java/info/nightscout/androidaps/plugins/treatments/CarbsGenerator.kt +++ /dev/null @@ -1,60 +0,0 @@ -package info.nightscout.androidaps.plugins.treatments - -import android.content.Context -import info.nightscout.androidaps.R -import info.nightscout.androidaps.activities.ErrorHelperActivity -import info.nightscout.androidaps.data.DetailedBolusInfo -import info.nightscout.androidaps.database.entities.TherapyEvent -import info.nightscout.androidaps.db.Source -import info.nightscout.androidaps.interfaces.ActivePluginProvider -import info.nightscout.androidaps.interfaces.CommandQueueProvider -import info.nightscout.androidaps.queue.Callback -import info.nightscout.androidaps.utils.DateUtil -import info.nightscout.androidaps.utils.T -import info.nightscout.androidaps.utils.resources.ResourceHelper -import javax.inject.Inject -import javax.inject.Singleton -import kotlin.math.roundToInt - -@Singleton -class CarbsGenerator @Inject constructor( - private val resourceHelper: ResourceHelper, - private val activePlugin: ActivePluginProvider, - private val commandQueue: CommandQueueProvider, - private val context: Context -) { - - fun generateCarbs(amount: Int, startTime: Long, duration: Int, notes: String) { - var remainingCarbs = amount.toLong() - val ticks = duration * 4 //duration guaranteed to be integer greater zero - for (i in 0 until ticks) { - val carbTime = startTime + i * 15 * 60 * 1000 - val smallCarbAmount = (1.0 * remainingCarbs / (ticks - i)).roundToInt() //on last iteration (ticks-i) is 1 -> smallCarbAmount == remainingCarbs - remainingCarbs -= smallCarbAmount.toLong() - if (smallCarbAmount > 0) createCarb(smallCarbAmount, carbTime, TherapyEvent.Type.MEAL_BOLUS.text, notes) - } - } - - fun createCarb(carbs: Int, time: Long, eventType: String, notes: String) { - val carbInfo = DetailedBolusInfo() - carbInfo.date = time - carbInfo.eventType = eventType - carbInfo.carbs = carbs.toDouble() - carbInfo.context = context - carbInfo.source = Source.USER - carbInfo.notes = notes - if (activePlugin.activePump.pumpDescription.storesCarbInfo && carbInfo.date <= DateUtil.now() && carbInfo.date > DateUtil.now() - T.mins(2).msecs()) { - commandQueue.bolus(carbInfo, object : Callback() { - override fun run() { - if (!result.success) { - ErrorHelperActivity.runAlarm(context, result.comment, resourceHelper.gs(R.string.treatmentdeliveryerror), R.raw.boluserror) - } - } - }) - } else { - // Don't send to pump if it is in the future or more than 5 minutes in the past - // as pumps might return those as as "now" when reading the history. - activePlugin.activeTreatments.addToHistoryTreatment(carbInfo, false) - } - } -} \ No newline at end of file diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/treatments/TreatmentService.java b/app/src/main/java/info/nightscout/androidaps/plugins/treatments/TreatmentService.java index a4f85e3882..3619e209f6 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/treatments/TreatmentService.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/treatments/TreatmentService.java @@ -17,28 +17,19 @@ import com.j256.ormlite.table.TableUtils; import org.apache.commons.lang3.StringUtils; import org.jetbrains.annotations.NotNull; -import org.json.JSONException; -import org.json.JSONObject; import java.sql.SQLException; -import java.util.ArrayList; import java.util.List; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ScheduledFuture; -import java.util.concurrent.TimeUnit; import javax.inject.Inject; import dagger.android.HasAndroidInjector; import info.nightscout.androidaps.db.DatabaseHelper; -import info.nightscout.androidaps.db.ICallback; import info.nightscout.androidaps.db.Source; import info.nightscout.androidaps.db.Treatment; -import info.nightscout.androidaps.events.Event; -import info.nightscout.androidaps.events.EventNsTreatment; -import info.nightscout.androidaps.events.EventReloadTreatmentData; -import info.nightscout.androidaps.events.EventTreatmentChange; import info.nightscout.androidaps.interfaces.DatabaseHelperInterface; import info.nightscout.androidaps.interfaces.TreatmentServiceInterface; import info.nightscout.androidaps.interfaces.UpdateReturn; @@ -46,14 +37,9 @@ import info.nightscout.androidaps.logging.AAPSLogger; import info.nightscout.androidaps.logging.LTag; import info.nightscout.androidaps.plugins.bus.RxBusWrapper; import info.nightscout.androidaps.plugins.general.openhumans.OpenHumansUploader; -import info.nightscout.androidaps.plugins.iob.iobCobCalculator.events.EventNewHistoryData; import info.nightscout.androidaps.plugins.pump.medtronic.MedtronicPumpPlugin; -import info.nightscout.androidaps.plugins.pump.medtronic.data.MedtronicHistoryData; -import info.nightscout.androidaps.utils.DateUtil; import info.nightscout.androidaps.utils.FabricPrivacy; -import info.nightscout.androidaps.utils.JsonHelper; import info.nightscout.androidaps.utils.rx.AapsSchedulers; -import io.reactivex.disposables.CompositeDisposable; /** @@ -70,29 +56,10 @@ public class TreatmentService extends OrmLiteBaseService impleme @Inject OpenHumansUploader openHumansUploader; @Inject AapsSchedulers aapsSchedulers; - private final CompositeDisposable disposable = new CompositeDisposable(); - - private static final ScheduledExecutorService treatmentEventWorker = Executors.newSingleThreadScheduledExecutor(); - private static ScheduledFuture scheduledTreatmentEventPost = null; - public TreatmentService(HasAndroidInjector injector) { injector.androidInjector().inject(this); onCreate(); dbInitialize(); - disposable.add(rxBus - .toObservable(EventNsTreatment.class) - .observeOn(aapsSchedulers.getIo()) - .subscribe(event -> { - int mode = event.getMode(); - JSONObject payload = event.getPayload(); - - if (mode == EventNsTreatment.Companion.getADD() || mode == EventNsTreatment.Companion.getUPDATE()) { - this.createTreatmentFromJsonIfNotExists(payload); - } else { // EventNsTreatment.REMOVE - this.deleteNS(payload); - } - }, fabricPrivacy::logException) - ); } /** @@ -215,94 +182,6 @@ public class TreatmentService extends OrmLiteBaseService impleme } } - public void resetTreatments() { - try { - TableUtils.dropTable(this.getConnectionSource(), Treatment.class, true); - TableUtils.createTableIfNotExists(this.getConnectionSource(), Treatment.class); - DatabaseHelper.updateEarliestDataChange(0); - } catch (SQLException e) { - aapsLogger.error("Unhandled exception", e); - } - scheduleTreatmentChange(null, true); - } - - - /** - * A place to centrally register events to be posted, if any data changed. - * This should be implemented in an abstract service-class. - *

- * We do need to make sure, that ICallback is extended to be able to handle multiple - * events, or handle a list of events. - *

- * on some methods the earliestDataChange event is handled separatly, in that it is checked if it is - * set to null by another event already (eg. scheduleExtendedBolusChange). - * - * @param event - * @param eventWorker - * @param callback - */ - private void scheduleEvent(final Event event, ScheduledExecutorService eventWorker, - final ICallback callback) { - - class PostRunnable implements Runnable { - public void run() { - aapsLogger.debug(LTag.DATATREATMENTS, "Firing EventReloadTreatmentData"); - rxBus.send(event); - if (DatabaseHelper.earliestDataChange != null) { - aapsLogger.debug(LTag.DATATREATMENTS, "Firing EventNewHistoryData"); - rxBus.send(new EventNewHistoryData(DatabaseHelper.earliestDataChange)); - } - DatabaseHelper.earliestDataChange = null; - callback.setPost(null); - } - } - // prepare task for execution in 1 sec - // cancel waiting task to prevent sending multiple posts - ScheduledFuture scheduledFuture = callback.getPost(); - if (scheduledFuture != null) - scheduledFuture.cancel(false); - Runnable task = new PostRunnable(); - final int sec = 1; - callback.setPost(eventWorker.schedule(task, sec, TimeUnit.SECONDS)); - } - - /** - * Schedule a foodChange Event. - */ - public void scheduleTreatmentChange(@Nullable final Treatment treatment, boolean runImmediately) { - if (runImmediately) { - aapsLogger.debug(LTag.DATATREATMENTS, "Firing EventReloadTreatmentData"); - rxBus.send(new EventReloadTreatmentData(new EventTreatmentChange(treatment))); - if (DatabaseHelper.earliestDataChange != null) { - aapsLogger.debug(LTag.DATATREATMENTS, "Firing EventNewHistoryData"); - rxBus.send(new EventNewHistoryData(DatabaseHelper.earliestDataChange)); - } - DatabaseHelper.earliestDataChange = null; - } else { - this.scheduleEvent(new EventReloadTreatmentData(new EventTreatmentChange(treatment)), treatmentEventWorker, new ICallback() { - @Override - public void setPost(ScheduledFuture post) { - scheduledTreatmentEventPost = post; - } - - @Override - public ScheduledFuture getPost() { - return scheduledTreatmentEventPost; - } - }); - } - } - - public List getTreatmentData() { - try { - return this.getDao().queryForAll(); - } catch (SQLException e) { - aapsLogger.error("Unhandled exception", e); - } - - return new ArrayList<>(); - } - public long count() { try { return this.getDao().countOf(); @@ -326,28 +205,9 @@ public class TreatmentService extends OrmLiteBaseService impleme "unit": "ml" } */ - public void createTreatmentFromJsonIfNotExists(JSONObject json) { - try { - Treatment treatment = Treatment.createFromJson(json); - if (treatment != null) { - - if (MedtronicHistoryData.doubleBolusDebug) - aapsLogger.debug(LTag.DATATREATMENTS, "DoubleBolusDebug: createTreatmentFromJsonIfNotExists:: medtronicPump={}", medtronicPumpPlugin.isEnabled()); - - if (!medtronicPumpPlugin.isEnabled()) - createOrUpdate(treatment); - else - createOrUpdateMedtronic(treatment, true); - } else - aapsLogger.error("Date is null: " + treatment.toString()); - } catch (JSONException e) { - aapsLogger.error("Unhandled exception", e); - } - } - - // return true if new record is created public UpdateReturn createOrUpdate(Treatment treatment) { + /* if (treatment != null && treatment.source == Source.NONE) { aapsLogger.error("Coder error: source is not set for treatment: " + treatment, new Exception()); //FabricPrivacy.logException(new Exception("Coder error: source is not set for treatment: " + treatment)); @@ -470,12 +330,13 @@ public class TreatmentService extends OrmLiteBaseService impleme } catch (SQLException e) { aapsLogger.error("Unhandled exception", e); } + */ return new UpdateReturn(false, false); } @NotNull public UpdateReturn createOrUpdateMedtronic(@NotNull Treatment treatment, boolean fromNightScout) { - +/* if (MedtronicHistoryData.doubleBolusDebug) aapsLogger.debug(LTag.DATATREATMENTS, "DoubleBolusDebug: createOrUpdateMedtronic:: originalTreatment={}, fromNightScout={}", treatment, fromNightScout); @@ -524,6 +385,8 @@ public class TreatmentService extends OrmLiteBaseService impleme } catch (SQLException e) { aapsLogger.error("Unhandled SQL exception: {}", e.getMessage(), e); } + + */ return new UpdateReturn(false, false); } @@ -654,107 +517,6 @@ public class TreatmentService extends OrmLiteBaseService impleme } } - /** - * Returns the newest record with insulin > 0 - */ - @Nullable - public Treatment getLastBolus(boolean excludeSMB) { - try { - QueryBuilder queryBuilder = getDao().queryBuilder(); - Where where = queryBuilder.where(); - where.gt("insulin", 0); - where.and().le("date", DateUtil.now()); - where.and().eq("isValid", true); - if (excludeSMB) where.and().eq("isSMB", false); - queryBuilder.orderBy("date", false); - queryBuilder.limit(1L); - - List result = getDao().query(queryBuilder.prepare()); - if (result.isEmpty()) - return null; - return result.get(0); - } catch (SQLException e) { - throw new RuntimeException(e); - } - } - - /** - * Returns the newest record with carbs > 0 - */ - @Nullable - public Treatment getLastCarb() { - try { - QueryBuilder queryBuilder = getDao().queryBuilder(); - Where where = queryBuilder.where(); - where.gt("carbs", 0); - where.and().le("date", DateUtil.now()); - where.and().eq("isValid", true); - queryBuilder.orderBy("date", false); - queryBuilder.limit(1L); - - List result = getDao().query(queryBuilder.prepare()); - if (result.isEmpty()) - return null; - return result.get(0); - } catch (SQLException e) { - throw new RuntimeException(e); - } - } - - public void deleteNS(JSONObject json) { - String _id = JsonHelper.safeGetString(json, "_id"); - if (_id != null && !_id.isEmpty()) - this.deleteByNSId(_id); - } - - /** - * deletes an entry by its NS Id. - *

- * Basically a convenience method for findByNSId and delete. - * - * @param _id - */ - private void deleteByNSId(String _id) { - Treatment stored = findByNSId(_id); - if (stored != null) { - aapsLogger.debug(LTag.DATATREATMENTS, "Removing Treatment record from database: " + stored.toString()); - try { - getDao().delete(stored); - } catch (SQLException e) { - aapsLogger.error("Unhandled exception", e); - } - DatabaseHelper.updateEarliestDataChange(stored.date); - this.scheduleTreatmentChange(stored, false); - } - } - - /** - * deletes the treatment and sends the treatmentChange Event - *

- * should be moved ot a Service - * - * @param treatment - */ - public void delete(Treatment treatment) { - try { - getDao().delete(treatment); - DatabaseHelper.updateEarliestDataChange(treatment.date); - this.scheduleTreatmentChange(treatment, true); - } catch (SQLException e) { - aapsLogger.error("Unhandled exception", e); - } - } - - public void update(Treatment treatment) { - try { - getDao().update(treatment); - DatabaseHelper.updateEarliestDataChange(treatment.date); - } catch (SQLException e) { - aapsLogger.error("Unhandled exception", e); - } - scheduleTreatmentChange(treatment, true); - } - /** * finds treatment by its NS Id. * @@ -784,40 +546,6 @@ public class TreatmentService extends OrmLiteBaseService impleme return null; } - public List getTreatmentDataFromTime(long mills, boolean ascending) { - try { - TreatmentDaoWrapper daoTreatments = getDao(); - List treatments; - QueryBuilder queryBuilder = daoTreatments.queryBuilder(); - queryBuilder.orderBy("date", ascending); - Where where = queryBuilder.where(); - where.ge("date", mills); - PreparedQuery preparedQuery = queryBuilder.prepare(); - treatments = daoTreatments.query(preparedQuery); - return treatments; - } catch (SQLException e) { - aapsLogger.error("Unhandled exception", e); - } - return new ArrayList<>(); - } - - public List getTreatmentDataFromTime(long from, long to, boolean ascending) { - try { - TreatmentDaoWrapper daoTreatments = getDao(); - List treatments; - QueryBuilder queryBuilder = daoTreatments.queryBuilder(); - queryBuilder.orderBy("date", ascending); - Where where = queryBuilder.where(); - where.between("date", from, to); - PreparedQuery preparedQuery = queryBuilder.prepare(); - treatments = daoTreatments.query(preparedQuery); - return treatments; - } catch (SQLException e) { - aapsLogger.error("Unhandled exception", e); - } - return new ArrayList<>(); - } - @Nullable @Override public IBinder onBind(Intent intent) { diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/treatments/TreatmentsFragment.kt b/app/src/main/java/info/nightscout/androidaps/plugins/treatments/TreatmentsFragment.kt index 6115ce9185..9de459f622 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/treatments/TreatmentsFragment.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/treatments/TreatmentsFragment.kt @@ -10,13 +10,14 @@ import dagger.android.support.DaggerFragment import info.nightscout.androidaps.R import info.nightscout.androidaps.databinding.TreatmentsFragmentBinding import info.nightscout.androidaps.events.EventExtendedBolusChange -import info.nightscout.androidaps.interfaces.ActivePluginProvider -import info.nightscout.androidaps.interfaces.ConfigInterface +import info.nightscout.androidaps.interfaces.ActivePlugin +import info.nightscout.androidaps.interfaces.IobCobCalculator import info.nightscout.androidaps.plugins.bus.RxBusWrapper import info.nightscout.androidaps.plugins.treatments.fragments.* +import info.nightscout.androidaps.utils.DateUtil import info.nightscout.androidaps.utils.FabricPrivacy import info.nightscout.androidaps.utils.buildHelper.BuildHelper -import info.nightscout.androidaps.utils.extensions.toVisibility +import info.nightscout.androidaps.extensions.toVisibility import info.nightscout.androidaps.utils.resources.ResourceHelper import info.nightscout.androidaps.utils.rx.AapsSchedulers import io.reactivex.disposables.CompositeDisposable @@ -28,10 +29,11 @@ class TreatmentsFragment : DaggerFragment() { @Inject lateinit var rxBus: RxBusWrapper @Inject lateinit var resourceHelper: ResourceHelper @Inject lateinit var fabricPrivacy: FabricPrivacy - @Inject lateinit var activePlugin: ActivePluginProvider - @Inject lateinit var treatmentsPlugin: TreatmentsPlugin + @Inject lateinit var activePlugin: ActivePlugin + @Inject lateinit var iobCobCalculator: IobCobCalculator @Inject lateinit var aapsSchedulers: AapsSchedulers @Inject lateinit var buildHelper: BuildHelper + @Inject lateinit var dateUtil: DateUtil private val disposable = CompositeDisposable() @@ -51,7 +53,7 @@ class TreatmentsFragment : DaggerFragment() { binding.extendedBoluses.visibility = (buildHelper.isEngineeringMode() && !activePlugin.activePump.isFakingTempsByExtendedBoluses).toVisibility() binding.treatments.setOnClickListener { - setFragment(TreatmentsBolusFragment()) + setFragment(TreatmentsBolusCarbsFragment()) setBackgroundColorOnSelected(it) } binding.extendedBoluses.setOnClickListener { @@ -78,7 +80,7 @@ class TreatmentsFragment : DaggerFragment() { setFragment(TreatmentsUserEntryFragment()) setBackgroundColorOnSelected(it) } - setFragment(TreatmentsBolusFragment()) + setFragment(TreatmentsBolusCarbsFragment()) setBackgroundColorOnSelected(binding.treatments) } @@ -125,6 +127,6 @@ class TreatmentsFragment : DaggerFragment() { private fun updateGui() { if (_binding == null) return - binding.extendedBoluses.visibility = (activePlugin.activePump.pumpDescription.isExtendedBolusCapable || treatmentsPlugin.extendedBolusesFromHistory.size() > 0).toVisibility() + binding.extendedBoluses.visibility = (activePlugin.activePump.pumpDescription.isExtendedBolusCapable || iobCobCalculator.getExtendedBolus(dateUtil.now()) != null).toVisibility() } } \ No newline at end of file diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/treatments/TreatmentsPlugin.java b/app/src/main/java/info/nightscout/androidaps/plugins/treatments/TreatmentsPlugin.java index c91aac3c9c..94673a29b6 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/treatments/TreatmentsPlugin.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/treatments/TreatmentsPlugin.java @@ -1,15 +1,12 @@ package info.nightscout.androidaps.plugins.treatments; import android.content.Context; -import android.os.Bundle; import androidx.annotation.NonNull; import androidx.annotation.Nullable; -import com.google.firebase.analytics.FirebaseAnalytics; - -import java.util.ArrayList; import java.util.List; +import java.util.stream.Collectors; import javax.inject.Inject; import javax.inject.Singleton; @@ -17,13 +14,7 @@ import javax.inject.Singleton; import dagger.android.HasAndroidInjector; import info.nightscout.androidaps.Constants; import info.nightscout.androidaps.R; -import info.nightscout.androidaps.activities.ErrorHelperActivity; import info.nightscout.androidaps.data.DetailedBolusInfo; -import info.nightscout.androidaps.data.Intervals; -import info.nightscout.androidaps.data.Iob; -import info.nightscout.androidaps.data.IobTotal; -import info.nightscout.androidaps.data.NonOverlappingIntervals; -import info.nightscout.androidaps.data.Profile; import info.nightscout.androidaps.data.ProfileIntervals; import info.nightscout.androidaps.database.AppRepository; import info.nightscout.androidaps.db.ExtendedBolus; @@ -32,32 +23,23 @@ import info.nightscout.androidaps.db.Source; import info.nightscout.androidaps.db.TemporaryBasal; import info.nightscout.androidaps.db.Treatment; import info.nightscout.androidaps.events.EventReloadProfileSwitchData; -import info.nightscout.androidaps.events.EventReloadTempBasalData; -import info.nightscout.androidaps.events.EventReloadTreatmentData; -import info.nightscout.androidaps.interfaces.ActivePluginProvider; +import info.nightscout.androidaps.interfaces.ActivePlugin; import info.nightscout.androidaps.interfaces.DatabaseHelperInterface; import info.nightscout.androidaps.interfaces.PluginBase; import info.nightscout.androidaps.interfaces.PluginDescription; import info.nightscout.androidaps.interfaces.PluginType; import info.nightscout.androidaps.interfaces.ProfileFunction; import info.nightscout.androidaps.interfaces.ProfileStore; -import info.nightscout.androidaps.interfaces.PumpInterface; import info.nightscout.androidaps.interfaces.TreatmentServiceInterface; import info.nightscout.androidaps.interfaces.TreatmentsInterface; -import info.nightscout.androidaps.interfaces.UpdateReturn; -import info.nightscout.androidaps.interfaces.UploadQueueInterface; import info.nightscout.androidaps.logging.AAPSLogger; import info.nightscout.androidaps.logging.LTag; import info.nightscout.androidaps.plugins.bus.RxBusWrapper; import info.nightscout.androidaps.plugins.general.nsclient.NSUpload; import info.nightscout.androidaps.plugins.general.overview.events.EventDismissNotification; import info.nightscout.androidaps.plugins.general.overview.notifications.Notification; -import info.nightscout.androidaps.plugins.iob.iobCobCalculator.AutosensResult; -import info.nightscout.androidaps.plugins.pump.medtronic.MedtronicPumpPlugin; -import info.nightscout.androidaps.plugins.pump.medtronic.data.MedtronicHistoryData; import info.nightscout.androidaps.utils.DateUtil; import info.nightscout.androidaps.utils.FabricPrivacy; -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; @@ -72,9 +54,8 @@ public class TreatmentsPlugin extends PluginBase implements TreatmentsInterface private final RxBusWrapper rxBus; private final ResourceHelper resourceHelper; private final ProfileFunction profileFunction; - private final ActivePluginProvider activePlugin; + private final ActivePlugin activePlugin; private final NSUpload nsUpload; - private final UploadQueueInterface uploadQueue; private final FabricPrivacy fabricPrivacy; private final DateUtil dateUtil; private final DatabaseHelperInterface databaseHelper; @@ -84,12 +65,6 @@ public class TreatmentsPlugin extends PluginBase implements TreatmentsInterface protected TreatmentServiceInterface service; - private IobTotal lastTreatmentCalculation; - private IobTotal lastTempBasalsCalculation; - - private final ArrayList treatments = new ArrayList<>(); - private final Intervals tempBasals = new NonOverlappingIntervals<>(); - private final Intervals extendedBoluses = new NonOverlappingIntervals<>(); private final ProfileIntervals profiles = new ProfileIntervals<>(); @Inject @@ -102,11 +77,10 @@ public class TreatmentsPlugin extends PluginBase implements TreatmentsInterface Context context, SP sp, ProfileFunction profileFunction, - ActivePluginProvider activePlugin, + ActivePlugin activePlugin, NSUpload nsUpload, FabricPrivacy fabricPrivacy, DateUtil dateUtil, - UploadQueueInterface uploadQueue, DatabaseHelperInterface databaseHelper, AppRepository repository ) { @@ -131,7 +105,6 @@ public class TreatmentsPlugin extends PluginBase implements TreatmentsInterface this.fabricPrivacy = fabricPrivacy; this.dateUtil = dateUtil; this.nsUpload = nsUpload; - this.uploadQueue = uploadQueue; this.databaseHelper = databaseHelper; this.repository = repository; } @@ -141,34 +114,12 @@ public class TreatmentsPlugin extends PluginBase implements TreatmentsInterface this.service = new TreatmentService(getInjector()); initializeData(range()); super.onStart(); - disposable.add(rxBus - .toObservable(EventReloadTreatmentData.class) - .observeOn(aapsSchedulers.getIo()) - .subscribe(event -> { - getAapsLogger().debug(LTag.DATATREATMENTS, "EventReloadTreatmentData"); - initializeTreatmentData(range()); - initializeExtendedBolusData(range()); - updateTotalIOBTreatments(); - rxBus.send(event.getNext()); - }, - fabricPrivacy::logException - )); disposable.add(rxBus .toObservable(EventReloadProfileSwitchData.class) .observeOn(aapsSchedulers.getIo()) .subscribe(event -> initializeProfileSwitchData(range()), fabricPrivacy::logException )); - disposable.add(rxBus - .toObservable(EventReloadTempBasalData.class) - .observeOn(aapsSchedulers.getIo()) - .subscribe(event -> { - getAapsLogger().debug(LTag.DATATREATMENTS, "EventReloadTempBasalData"); - initializeTempBasalData(range()); - updateTotalIOBTempBasals(); - }, - fabricPrivacy::logException - )); } @Override @@ -190,115 +141,32 @@ public class TreatmentsPlugin extends PluginBase implements TreatmentsInterface } public void initializeData(long range) { - initializeTempBasalData(range); - initializeTreatmentData(range); - initializeExtendedBolusData(range); initializeProfileSwitchData(range); } - private void initializeTreatmentData(long range) { - getAapsLogger().debug(LTag.DATATREATMENTS, "initializeTreatmentData"); - synchronized (treatments) { - treatments.clear(); - treatments.addAll(getService().getTreatmentDataFromTime(DateUtil.now() - range, false)); - } - } - - private void initializeTempBasalData(long range) { - getAapsLogger().debug(LTag.DATATREATMENTS, "initializeTempBasalData"); - synchronized (tempBasals) { - tempBasals.reset().add(databaseHelper.getTemporaryBasalsDataFromTime(DateUtil.now() - range, false)); - } - - } - - private void initializeExtendedBolusData(long range) { - getAapsLogger().debug(LTag.DATATREATMENTS, "initializeExtendedBolusData"); - synchronized (extendedBoluses) { - extendedBoluses.reset().add(databaseHelper.getExtendedBolusDataFromTime(DateUtil.now() - range, false)); - } - - } - private void initializeProfileSwitchData(long range) { getAapsLogger().debug(LTag.DATATREATMENTS, "initializeProfileSwitchData"); synchronized (profiles) { - profiles.reset().add(databaseHelper.getProfileSwitchData(DateUtil.now() - range, false)); + profiles.reset().add(databaseHelper.getProfileSwitchData(dateUtil.now() - range, false)); } } - @Override - public IobTotal getLastCalculationTreatments() { - return lastTreatmentCalculation; - } - - @Override - public IobTotal getCalculationToTimeTreatments(long time) { - IobTotal total = new IobTotal(time); - - Profile profile = profileFunction.getProfile(); - if (profile == null) - return total; - - PumpInterface pumpInterface = activePlugin.getActivePump(); - - double dia = profile.getDia(); - - synchronized (treatments) { - for (int pos = 0; pos < treatments.size(); pos++) { - Treatment t = treatments.get(pos); - if (!t.isValid) continue; - if (t.date > time) continue; - Iob tIOB = t.iobCalc(time, dia); - total.iob += tIOB.getIobContrib(); - total.activity += tIOB.getActivityContrib(); - if (t.insulin > 0 && t.date > total.lastBolusTime) - total.lastBolusTime = t.date; - if (!t.isSMB) { - // instead of dividing the DIA that only worked on the bilinear curves, - // multiply the time the treatment is seen active. - long timeSinceTreatment = time - t.date; - long snoozeTime = t.date + (long) (timeSinceTreatment * sp.getDouble(R.string.key_openapsama_bolussnooze_dia_divisor, 2.0)); - Iob bIOB = t.iobCalc(snoozeTime, dia); - total.bolussnooze += bIOB.getIobContrib(); - } - } - } - - if (!pumpInterface.isFakingTempsByExtendedBoluses()) - synchronized (extendedBoluses) { - for (int pos = 0; pos < extendedBoluses.size(); pos++) { - ExtendedBolus e = extendedBoluses.get(pos); - if (e.date > time) continue; - IobTotal calc = e.iobCalc(time, profile); - total.plus(calc); - } - } - return total; - } - - @Override - public void updateTotalIOBTreatments() { - lastTreatmentCalculation = getCalculationToTimeTreatments(System.currentTimeMillis()); - } - - @Override - public List getTreatmentsFromHistory() { - synchronized (treatments) { - return new ArrayList<>(treatments); - } - } - - /** * Returns all Treatments after specified timestamp. Also returns invalid entries (required to - * map "Fill Canula" entries to history (and not to add double bolus for it) + * map "Fill Cannula" entries to history (and not to add double bolus for it) * * @param fromTimestamp * @return */ + @Deprecated @Override public List getTreatmentsFromHistoryAfterTimestamp(long fromTimestamp) { + return repository.getBolusesIncludingInvalidFromTimeToTime(fromTimestamp, dateUtil.now(), true) + .blockingGet() + .stream() + .map(bolus -> new Treatment(getInjector(), bolus)) + .collect(Collectors.toList()); +/* List in5minback = new ArrayList<>(); long time = System.currentTimeMillis(); @@ -306,29 +174,15 @@ public class TreatmentsPlugin extends PluginBase implements TreatmentsInterface // getAapsLogger().debug(MedtronicHistoryData.doubleBolusDebug, LTag.DATATREATMENTS, "DoubleBolusDebug: AllTreatmentsInDb: " + new GsonBuilder().excludeFieldsWithoutExposeAnnotation().create().toJson(treatments)); for (Treatment t : treatments) { - if (t.date <= time && t.date >= fromTimestamp) + if (t.date >= fromTimestamp && t.date <= time) in5minback.add(t); } // getAapsLogger().debug(MedtronicHistoryData.doubleBolusDebug, LTag.DATATREATMENTS, "DoubleBolusDebug: FilteredTreatments: AfterTime={}, Items={} " + fromTimestamp + " " + new GsonBuilder().excludeFieldsWithoutExposeAnnotation().create().toJson(in5minback)); return in5minback; } +*/ } - - - @Override - public List getCarbTreatments5MinBackFromHistory(long time) { - List in5minback = new ArrayList<>(); - synchronized (treatments) { - for (Treatment t : treatments) { - if (!t.isValid) - continue; - if (t.date <= time && t.date > time - 5 * 60 * 1000 && t.carbs > 0) - in5minback.add(t); - } - return in5minback; - } - } - +/* @Override public long getLastBolusTime() { Treatment last = getService().getLastBolus(false); @@ -364,205 +218,14 @@ public class TreatmentsPlugin extends PluginBase implements TreatmentsInterface } - @Override - public boolean isInHistoryRealTempBasalInProgress() { - return getRealTempBasalFromHistory(System.currentTimeMillis()) != null; - } - - @Override - public TemporaryBasal getRealTempBasalFromHistory(long time) { - synchronized (tempBasals) { - return tempBasals.getValueByInterval(time); - } - } - - @Override - public boolean isTempBasalInProgress() { - return getTempBasalFromHistory(System.currentTimeMillis()) != null; - } - - @Override public void removeTempBasal(TemporaryBasal tempBasal) { - String tempBasalId = tempBasal._id; - if (NSUpload.isIdValid(tempBasalId)) { - nsUpload.removeCareportalEntryFromNS(tempBasalId); - } else { - uploadQueue.removeByMongoId("dbAdd", tempBasalId); - } - databaseHelper.delete(tempBasal); - } - - @Override - public boolean isInHistoryExtendedBolusInProgress() { - return getExtendedBolusFromHistory(System.currentTimeMillis()) != null; //TODO: crosscheck here - } - - @Override - public IobTotal getLastCalculationTempBasals() { - return lastTempBasalsCalculation; - } - - @Override - public IobTotal getCalculationToTimeTempBasals(long time) { - return getCalculationToTimeTempBasals(time, false, 0); - } - - public IobTotal getCalculationToTimeTempBasals(long time, boolean truncate, long truncateTime) { - IobTotal total = new IobTotal(time); - - PumpInterface pumpInterface = activePlugin.getActivePump(); - - synchronized (tempBasals) { - for (int pos = 0; pos < tempBasals.size(); pos++) { - TemporaryBasal t = tempBasals.get(pos); - if (t.date > time) continue; - IobTotal calc; - Profile profile = profileFunction.getProfile(t.date); - if (profile == null) continue; - if (truncate && t.end() > truncateTime) { - TemporaryBasal dummyTemp = new TemporaryBasal(getInjector()); - dummyTemp.copyFrom(t); - dummyTemp.cutEndTo(truncateTime); - calc = dummyTemp.iobCalc(time, profile); - } else { - calc = t.iobCalc(time, profile); - } - //log.debug("BasalIOB " + new Date(time) + " >>> " + calc.basaliob); - total.plus(calc); - } - } - if (pumpInterface.isFakingTempsByExtendedBoluses()) { - IobTotal totalExt = new IobTotal(time); - synchronized (extendedBoluses) { - for (int pos = 0; pos < extendedBoluses.size(); pos++) { - ExtendedBolus e = extendedBoluses.get(pos); - if (e.date > time) continue; - IobTotal calc; - Profile profile = profileFunction.getProfile(e.date); - if (profile == null) continue; - if (truncate && e.end() > truncateTime) { - ExtendedBolus dummyExt = new ExtendedBolus(getInjector()); - dummyExt.copyFrom(e); - dummyExt.cutEndTo(truncateTime); - calc = dummyExt.iobCalc(time, profile); - } else { - calc = e.iobCalc(time, profile); - } - totalExt.plus(calc); - } - } - // Convert to basal iob - totalExt.basaliob = totalExt.iob; - totalExt.iob = 0d; - totalExt.netbasalinsulin = totalExt.extendedBolusInsulin; - totalExt.hightempinsulin = totalExt.extendedBolusInsulin; - total.plus(totalExt); - } - return total; - } - - public IobTotal getAbsoluteIOBTempBasals(long time) { - IobTotal total = new IobTotal(time); - - for (long i = time - range(); i < time; i += T.mins(5).msecs()) { - Profile profile = profileFunction.getProfile(i); - if (profile == null) continue; - double basal = profile.getBasal(i); - TemporaryBasal runningTBR = getTempBasalFromHistory(i); - double running = basal; - if (runningTBR != null) { - running = runningTBR.tempBasalConvertedToAbsolute(i, profile); - } - Treatment treatment = new Treatment(getInjector()); - treatment.date = i; - treatment.insulin = running * 5.0 / 60.0; // 5 min chunk - Iob iob = treatment.iobCalc(time, profile.getDia()); - total.basaliob += iob.getIobContrib(); - total.activity += iob.getActivityContrib(); - } - return total; - } - - public IobTotal getCalculationToTimeTempBasals(long time, long truncateTime, AutosensResult lastAutosensResult, boolean exercise_mode, int half_basal_exercise_target, boolean isTempTarget) { - IobTotal total = new IobTotal(time); - - PumpInterface pumpInterface = activePlugin.getActivePump(); - - synchronized (tempBasals) { - for (int pos = 0; pos < tempBasals.size(); pos++) { - TemporaryBasal t = tempBasals.get(pos); - if (t.date > time) continue; - IobTotal calc; - Profile profile = profileFunction.getProfile(t.date); - if (profile == null) continue; - if (t.end() > truncateTime) { - TemporaryBasal dummyTemp = new TemporaryBasal(getInjector()); - dummyTemp.copyFrom(t); - dummyTemp.cutEndTo(truncateTime); - calc = dummyTemp.iobCalc(time, profile, lastAutosensResult, exercise_mode, half_basal_exercise_target, isTempTarget); - } else { - calc = t.iobCalc(time, profile, lastAutosensResult, exercise_mode, half_basal_exercise_target, isTempTarget); - } - //log.debug("BasalIOB " + new Date(time) + " >>> " + calc.basaliob); - total.plus(calc); - } - } - if (pumpInterface.isFakingTempsByExtendedBoluses()) { - IobTotal totalExt = new IobTotal(time); - synchronized (extendedBoluses) { - for (int pos = 0; pos < extendedBoluses.size(); pos++) { - ExtendedBolus e = extendedBoluses.get(pos); - if (e.date > time) continue; - IobTotal calc; - Profile profile = profileFunction.getProfile(e.date); - if (profile == null) continue; - if (e.end() > truncateTime) { - ExtendedBolus dummyExt = new ExtendedBolus(getInjector()); - dummyExt.copyFrom(e); - dummyExt.cutEndTo(truncateTime); - calc = dummyExt.iobCalc(time, profile, lastAutosensResult, exercise_mode, half_basal_exercise_target, isTempTarget); - } else { - calc = e.iobCalc(time, profile, lastAutosensResult, exercise_mode, half_basal_exercise_target, isTempTarget); - } - totalExt.plus(calc); - } - } - // Convert to basal iob - totalExt.basaliob = totalExt.iob; - totalExt.iob = 0d; - totalExt.netbasalinsulin = totalExt.extendedBolusInsulin; - totalExt.hightempinsulin = totalExt.extendedBolusInsulin; - total.plus(totalExt); - } - return total; - } - - @Override - public void updateTotalIOBTempBasals() { - lastTempBasalsCalculation = getCalculationToTimeTempBasals(DateUtil.now()); - } - - @Nullable - @Override - public TemporaryBasal getTempBasalFromHistory(long time) { - TemporaryBasal tb = getRealTempBasalFromHistory(time); - if (tb != null) - return tb; - ExtendedBolus eb = getExtendedBolusFromHistory(time); - if (eb != null && activePlugin.getActivePump().isFakingTempsByExtendedBoluses()) - return new TemporaryBasal(eb); - return null; - } - - @Override - public ExtendedBolus getExtendedBolusFromHistory(long time) { - synchronized (extendedBoluses) { - return extendedBoluses.getValueByInterval(time); - } - } + */ + @Deprecated @Override public boolean addToHistoryExtendedBolus(ExtendedBolus extendedBolus) { + throw new IllegalStateException("Migrate to new DB"); //log.debug("Adding new ExtentedBolus record" + extendedBolus.log()); + /* boolean newRecordCreated = databaseHelper.createOrUpdate(extendedBolus); if (newRecordCreated) { if (extendedBolus.durationInMinutes == 0) { @@ -576,26 +239,14 @@ public class TreatmentsPlugin extends PluginBase implements TreatmentsInterface nsUpload.uploadExtendedBolus(extendedBolus); } return newRecordCreated; + */ } - @Override - @NonNull - public Intervals getExtendedBolusesFromHistory() { - synchronized (extendedBoluses) { - return new NonOverlappingIntervals<>(extendedBoluses); - } - } - - @Override - @NonNull - public NonOverlappingIntervals getTemporaryBasalsFromHistory() { - synchronized (tempBasals) { - return new NonOverlappingIntervals<>(tempBasals); - } - } - + @Deprecated @Override public boolean addToHistoryTempBasal(TemporaryBasal tempBasal) { + throw new IllegalStateException("Migrate to new DB"); +/* //log.debug("Adding new TemporaryBasal record" + tempBasal.toString()); boolean newRecordCreated = databaseHelper.createOrUpdate(tempBasal); if (newRecordCreated) { @@ -607,32 +258,41 @@ public class TreatmentsPlugin extends PluginBase implements TreatmentsInterface nsUpload.uploadTempBasalStartPercent(tempBasal, profileFunction.getProfile(tempBasal.date)); } return newRecordCreated; + */ } + @Deprecated public TreatmentUpdateReturn createOrUpdateMedtronic(Treatment treatment, boolean fromNightScout) { + throw new IllegalStateException("Migrate to new DB"); +/* UpdateReturn resultRecord = getService().createOrUpdateMedtronic(treatment, fromNightScout); return new TreatmentUpdateReturn(resultRecord.getSuccess(), resultRecord.getNewRecord()); + */ } // return true if new record is created + @Deprecated @Override public boolean addToHistoryTreatment(DetailedBolusInfo detailedBolusInfo, boolean allowUpdate) { + throw new IllegalStateException("Migrate to new DB"); +/* boolean medtronicPump = activePlugin.getActivePump() instanceof MedtronicPumpPlugin; getAapsLogger().debug(MedtronicHistoryData.doubleBolusDebug, LTag.DATATREATMENTS, "DoubleBolusDebug: addToHistoryTreatment::isMedtronicPump={} " + medtronicPump); Treatment treatment = new Treatment(); - treatment.date = detailedBolusInfo.date; - treatment.source = detailedBolusInfo.source; - treatment.pumpId = detailedBolusInfo.pumpId; + treatment.date = detailedBolusInfo.timestamp; + treatment.source = (detailedBolusInfo.getPumpType() == PumpType.USER) ? Source.USER : Source.PUMP; + treatment.pumpId = detailedBolusInfo.getBolusPumpId() != null ? detailedBolusInfo.getBolusPumpId() : 0; treatment.insulin = detailedBolusInfo.insulin; - treatment.isValid = detailedBolusInfo.isValid; - treatment.isSMB = detailedBolusInfo.isSMB; + treatment.isValid = detailedBolusInfo.getBolusType() != DetailedBolusInfo.BolusType.PRIMING; + treatment.isSMB = detailedBolusInfo.getBolusType() == DetailedBolusInfo.BolusType.SMB; if (detailedBolusInfo.carbTime == 0) treatment.carbs = detailedBolusInfo.carbs; treatment.mealBolus = treatment.carbs > 0; - treatment.boluscalc = detailedBolusInfo.boluscalc != null ? detailedBolusInfo.boluscalc.toString() : null; + // treatment.boluscalc = detailedBolusInfo.boluscalc != null ? detailedBolusInfo.boluscalc.toString() : null; + treatment.boluscalc = null; UpdateReturn creatOrUpdateResult; getAapsLogger().debug(medtronicPump && MedtronicHistoryData.doubleBolusDebug, LTag.DATATREATMENTS, "DoubleBolusDebug: addToHistoryTreatment::treatment={} " + treatment); @@ -647,9 +307,9 @@ public class TreatmentsPlugin extends PluginBase implements TreatmentsInterface if (detailedBolusInfo.carbTime != 0) { Treatment carbsTreatment = new Treatment(); - carbsTreatment.source = detailedBolusInfo.source; - carbsTreatment.pumpId = detailedBolusInfo.pumpId; // but this should never happen - carbsTreatment.date = detailedBolusInfo.date + detailedBolusInfo.carbTime * 60 * 1000L + 1000L; // add 1 sec to make them different records + carbsTreatment.source = (detailedBolusInfo.getPumpType() == PumpType.USER) ? Source.USER : Source.PUMP; + carbsTreatment.pumpId = detailedBolusInfo.getCarbsPumpId() != null ? detailedBolusInfo.getCarbsPumpId() : 0; // but this should never happen + carbsTreatment.date = detailedBolusInfo.timestamp + detailedBolusInfo.carbTime * 60 * 1000L + 1000L; // add 1 sec to make them different records carbsTreatment.carbs = detailedBolusInfo.carbs; getAapsLogger().debug(medtronicPump && MedtronicHistoryData.doubleBolusDebug, LTag.DATATREATMENTS, "DoubleBolusDebug: carbTime!=0, creating second treatment. CarbsTreatment={}" + carbsTreatment); @@ -660,7 +320,7 @@ public class TreatmentsPlugin extends PluginBase implements TreatmentsInterface getService().createOrUpdateMedtronic(carbsTreatment, false); //log.debug("Adding new Treatment record" + carbsTreatment); } - if (newRecordCreated && detailedBolusInfo.isValid) + if (newRecordCreated && detailedBolusInfo.getBolusType() != DetailedBolusInfo.BolusType.PRIMING) nsUpload.uploadTreatmentRecord(detailedBolusInfo); if (!allowUpdate && !creatOrUpdateResult.getSuccess()) { @@ -677,25 +337,7 @@ public class TreatmentsPlugin extends PluginBase implements TreatmentsInterface } return newRecordCreated; - } - - @Override - public long oldestDataAvailable() { - long oldestTime = System.currentTimeMillis(); - synchronized (tempBasals) { - if (tempBasals.size() > 0) - oldestTime = Math.min(oldestTime, tempBasals.get(0).date); - } - synchronized (extendedBoluses) { - if (extendedBoluses.size() > 0) - oldestTime = Math.min(oldestTime, extendedBoluses.get(0).date); - } - synchronized (treatments) { - if (treatments.size() > 0) - oldestTime = Math.min(oldestTime, treatments.get(treatments.size() - 1).date); - } - oldestTime -= 15 * 60 * 1000L; // allow 15 min before - return oldestTime; + */ } @Override @@ -718,7 +360,7 @@ public class TreatmentsPlugin extends PluginBase implements TreatmentsInterface //log.debug("Adding new TemporaryBasal record" + profileSwitch.log()); rxBus.send(new EventDismissNotification(Notification.PROFILE_SWITCH_MISSING)); databaseHelper.createOrUpdate(profileSwitch); - nsUpload.uploadProfileSwitch(profileSwitch, profileSwitch.date); + nsUpload.uploadProfileSwitch(profileSwitch, profileSwitch.date, dateUtil); } @Override @@ -738,7 +380,7 @@ public class TreatmentsPlugin extends PluginBase implements TreatmentsInterface profileSwitch.source = Source.USER; profileSwitch.profileName = profileFunction.getProfileName(System.currentTimeMillis(), false, false); profileSwitch.profileJson = profileFunction.getProfile().getData().toString(); - profileSwitch.profilePlugin = activePlugin.getActiveProfileInterface().getClass().getName(); + profileSwitch.profilePlugin = activePlugin.getActiveProfileSource().getClass().getName(); profileSwitch.durationInMinutes = duration; profileSwitch.isCPP = percentage != 100 || timeShift != 0; profileSwitch.timeshift = timeShift; diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/treatments/fragments/TreatmentsBolusCarbsFragment.kt b/app/src/main/java/info/nightscout/androidaps/plugins/treatments/fragments/TreatmentsBolusCarbsFragment.kt new file mode 100644 index 0000000000..4af296892d --- /dev/null +++ b/app/src/main/java/info/nightscout/androidaps/plugins/treatments/fragments/TreatmentsBolusCarbsFragment.kt @@ -0,0 +1,377 @@ +package info.nightscout.androidaps.plugins.treatments.fragments + +import android.graphics.Paint +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.recyclerview.widget.LinearLayoutManager +import androidx.recyclerview.widget.RecyclerView +import dagger.android.support.DaggerFragment +import info.nightscout.androidaps.R +import info.nightscout.androidaps.database.AppRepository +import info.nightscout.androidaps.database.entities.Bolus +import info.nightscout.androidaps.database.entities.BolusCalculatorResult +import info.nightscout.androidaps.database.entities.Carbs +import info.nightscout.androidaps.database.entities.UserEntry.Action +import info.nightscout.androidaps.database.entities.UserEntry.Sources +import info.nightscout.androidaps.database.entities.ValueWithUnit +import info.nightscout.androidaps.database.transactions.InvalidateBolusCalculatorResultTransaction +import info.nightscout.androidaps.database.transactions.InvalidateBolusTransaction +import info.nightscout.androidaps.database.transactions.InvalidateCarbsTransaction +import info.nightscout.androidaps.databinding.TreatmentsBolusCarbsFragmentBinding +import info.nightscout.androidaps.databinding.TreatmentsBolusCarbsItemBinding +import info.nightscout.androidaps.dialogs.WizardInfoDialog +import info.nightscout.androidaps.events.EventAutosensCalculationFinished +import info.nightscout.androidaps.events.EventTreatmentChange +import info.nightscout.androidaps.interfaces.ActivePlugin +import info.nightscout.androidaps.interfaces.ProfileFunction +import info.nightscout.androidaps.logging.AAPSLogger +import info.nightscout.androidaps.logging.LTag +import info.nightscout.androidaps.logging.UserEntryLogger +import info.nightscout.androidaps.plugins.bus.RxBusWrapper +import info.nightscout.androidaps.plugins.general.nsclient.events.EventNSClientRestart +import info.nightscout.androidaps.plugins.treatments.events.EventTreatmentUpdateGui +import info.nightscout.androidaps.utils.DateUtil +import info.nightscout.androidaps.utils.FabricPrivacy +import info.nightscout.androidaps.utils.T +import info.nightscout.androidaps.utils.alertDialogs.OKDialog +import info.nightscout.androidaps.utils.buildHelper.BuildHelper +import info.nightscout.androidaps.extensions.iobCalc +import info.nightscout.androidaps.extensions.toVisibility +import info.nightscout.androidaps.plugins.iob.iobCobCalculator.events.EventNewHistoryData +import info.nightscout.androidaps.utils.resources.ResourceHelper +import info.nightscout.androidaps.utils.rx.AapsSchedulers +import info.nightscout.androidaps.utils.sharedPreferences.SP +import io.reactivex.Completable +import io.reactivex.disposables.CompositeDisposable +import io.reactivex.rxkotlin.plusAssign +import io.reactivex.rxkotlin.subscribeBy +import java.util.concurrent.TimeUnit +import javax.inject.Inject + +class TreatmentsBolusCarbsFragment : DaggerFragment() { + + @Inject lateinit var rxBus: RxBusWrapper + @Inject lateinit var sp: SP + @Inject lateinit var aapsLogger: AAPSLogger + @Inject lateinit var resourceHelper: ResourceHelper + @Inject lateinit var fabricPrivacy: FabricPrivacy + @Inject lateinit var profileFunction: ProfileFunction + @Inject lateinit var dateUtil: DateUtil + @Inject lateinit var buildHelper: BuildHelper + @Inject lateinit var aapsSchedulers: AapsSchedulers + @Inject lateinit var uel: UserEntryLogger + @Inject lateinit var repository: AppRepository + @Inject lateinit var activePlugin: ActivePlugin + + class MealLink( + val bolus: Bolus? = null, + val carbs: Carbs? = null, + val bolusCalculatorResult: BolusCalculatorResult? = null + ) + + private val disposable = CompositeDisposable() + + private val millsToThePast = T.days(30).msecs() + + private var _binding: TreatmentsBolusCarbsFragmentBinding? = null + + // This property is only valid between onCreateView and + // onDestroyView. + private val binding get() = _binding!! + + override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View = + TreatmentsBolusCarbsFragmentBinding.inflate(inflater, container, false).also { _binding = it }.root + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + binding.recyclerview.setHasFixedSize(true) + binding.recyclerview.layoutManager = LinearLayoutManager(view.context) + + binding.refreshFromNightscout.setOnClickListener { + activity?.let { activity -> + OKDialog.showConfirmation(activity, resourceHelper.gs(R.string.refresheventsfromnightscout) + "?") { + uel.log(Action.TREATMENTS_NS_REFRESH, Sources.Treatments) + disposable += + Completable.fromAction { + repository.deleteAllBolusCalculatorResults() + repository.deleteAllBoluses() + repository.deleteAllCarbs() + } + .subscribeOn(aapsSchedulers.io) + .observeOn(aapsSchedulers.main) + .subscribeBy( + onError = { aapsLogger.error("Error removing entries", it) }, + onComplete = { + rxBus.send(EventTreatmentChange()) + rxBus.send(EventNewHistoryData(0, false)) } + ) + rxBus.send(EventNSClientRestart()) + } + } + } + binding.deleteFutureTreatments.setOnClickListener { + activity?.let { activity -> + OKDialog.showConfirmation(activity, resourceHelper.gs(R.string.overview_treatment_label), resourceHelper.gs(R.string.deletefuturetreatments) + "?", Runnable { + uel.log(Action.DELETE_FUTURE_TREATMENTS, Sources.Treatments) + repository + .getBolusesDataFromTime(dateUtil.now(), false) + .observeOn(aapsSchedulers.main) + .subscribe { list -> + list.forEach { bolus -> + disposable += repository.runTransactionForResult(InvalidateBolusTransaction(bolus.id)) + .subscribe( + { result -> result.invalidated.forEach { aapsLogger.debug(LTag.DATABASE, "Invalidated bolus $it") } }, + { aapsLogger.error(LTag.DATABASE, "Error while invalidating bolus", it) } + ) + } + } + repository + .getCarbsDataFromTime(dateUtil.now(), false) + .observeOn(aapsSchedulers.main) + .subscribe { list -> + list.forEach { carb -> + disposable += repository.runTransactionForResult(InvalidateCarbsTransaction(carb.id)) + .subscribe( + { result -> result.invalidated.forEach { aapsLogger.debug(LTag.DATABASE, "Invalidated carbs $it") } }, + { aapsLogger.error(LTag.DATABASE, "Error while invalidating carbs", it) } + ) + } + } + repository + .getBolusCalculatorResultsDataFromTime(dateUtil.now(), false) + .observeOn(aapsSchedulers.main) + .subscribe { list -> + list.forEach { bolusCalc -> + disposable += repository.runTransactionForResult(InvalidateBolusCalculatorResultTransaction(bolusCalc.id)) + .subscribe( + { result -> result.invalidated.forEach { aapsLogger.debug(LTag.DATABASE, "Invalidated bolusCalculatorResult $it") } }, + { aapsLogger.error(LTag.DATABASE, "Error while invalidating bolusCalculatorResult", it) } + ) + } + } + binding.deleteFutureTreatments.visibility = View.GONE + }) + } + } + val nsUploadOnly = sp.getBoolean(R.string.key_ns_upload_only, true) || !buildHelper.isEngineeringMode() + if (nsUploadOnly) binding.refreshFromNightscout.visibility = View.GONE + binding.showInvalidated.setOnCheckedChangeListener { _, _ -> + rxBus.send(EventTreatmentUpdateGui()) + } + } + + private fun bolusMealLinksWithInvalid(now: Long) = repository + .getBolusesIncludingInvalidFromTime(now - millsToThePast, false) + .map { bolus -> bolus.map { MealLink(bolus = it) } } + + private fun carbsMealLinksWithInvalid(now: Long) = repository + .getCarbsIncludingInvalidFromTime(now - millsToThePast, false) + .map { carb -> carb.map { MealLink(carbs = it) } } + + private fun calcResultMealLinksWithInvalid(now: Long) = repository + .getBolusCalculatorResultsIncludingInvalidFromTime(now - millsToThePast, false) + .map { calc -> calc.map { MealLink(bolusCalculatorResult = it) } } + + private fun bolusMealLinks(now: Long) = repository + .getBolusesDataFromTime(now - millsToThePast, false) + .map { bolus -> bolus.map { MealLink(bolus = it) } } + + private fun carbsMealLinks(now: Long) = repository + .getCarbsDataFromTime(now - millsToThePast, false) + .map { carb -> carb.map { MealLink(carbs = it) } } + + private fun calcResultMealLinks(now: Long) = repository + .getBolusCalculatorResultsDataFromTime(now - millsToThePast, false) + .map { calc -> calc.map { MealLink(bolusCalculatorResult = it) } } + + fun swapAdapter() { + val now = System.currentTimeMillis() + + if (binding.showInvalidated.isChecked) + disposable += carbsMealLinksWithInvalid(now) + .zipWith(bolusMealLinksWithInvalid(now)) { first, second -> first + second } + .zipWith(calcResultMealLinksWithInvalid(now)) { first, second -> first + second } + .map { ml -> + ml.sortedByDescending { + it.carbs?.timestamp ?: it.bolus?.timestamp + ?: it.bolusCalculatorResult?.timestamp + } + } + .observeOn(aapsSchedulers.main) + .subscribe { list -> + binding.recyclerview.swapAdapter(RecyclerViewAdapter(list), true) + binding.deleteFutureTreatments.visibility = list.isNotEmpty().toVisibility() + } + else + disposable += carbsMealLinks(now) + .zipWith(bolusMealLinks(now)) { first, second -> first + second } + .zipWith(calcResultMealLinks(now)) { first, second -> first + second } + .map { ml -> + ml.sortedByDescending { + it.carbs?.timestamp ?: it.bolus?.timestamp + ?: it.bolusCalculatorResult?.timestamp + } + } + .observeOn(aapsSchedulers.main) + .subscribe { list -> + binding.recyclerview.swapAdapter(RecyclerViewAdapter(list), true) + binding.deleteFutureTreatments.visibility = list.isNotEmpty().toVisibility() + } + + } + + @Synchronized + override fun onResume() { + super.onResume() + swapAdapter() + disposable += rxBus + .toObservable(EventTreatmentChange::class.java) + .observeOn(aapsSchedulers.main) + .debounce(1L, TimeUnit.SECONDS) + .subscribe({ swapAdapter() }, fabricPrivacy::logException) + disposable += rxBus + .toObservable(EventTreatmentUpdateGui::class.java) // TODO join with above + .observeOn(aapsSchedulers.io) + .debounce(1L, TimeUnit.SECONDS) + .subscribe({ swapAdapter() }, fabricPrivacy::logException) + disposable += rxBus + .toObservable(EventAutosensCalculationFinished::class.java) + .observeOn(aapsSchedulers.main) + .debounce(1L, TimeUnit.SECONDS) + .subscribe({ swapAdapter() }, fabricPrivacy::logException) + } + + @Synchronized + override fun onPause() { + super.onPause() + disposable.clear() + } + + @Synchronized + override fun onDestroyView() { + super.onDestroyView() + binding.recyclerview.adapter = null // avoid leaks + _binding = null + } + + inner class RecyclerViewAdapter internal constructor(var mealLinks: List) : RecyclerView.Adapter() { + + override fun onCreateViewHolder(viewGroup: ViewGroup, viewType: Int): MealLinkLoadedViewHolder { + val v = LayoutInflater.from(viewGroup.context).inflate(R.layout.treatments_bolus_carbs_item, viewGroup, false) + return MealLinkLoadedViewHolder(v) + } + + override fun onBindViewHolder(holder: MealLinkLoadedViewHolder, position: Int) { + val profile = profileFunction.getProfile() ?: return + val ml = mealLinks[position] + + // Metadata + holder.binding.metadataLayout.visibility = (ml.bolusCalculatorResult != null && (ml.bolusCalculatorResult.isValid || binding.showInvalidated.isChecked)).toVisibility() + ml.bolusCalculatorResult?.let { bolusCalculatorResult -> + holder.binding.date.text = dateUtil.dateAndTimeString(bolusCalculatorResult.timestamp) + } + + // Bolus + holder.binding.bolusLayout.visibility = (ml.bolus != null && (ml.bolus.isValid || binding.showInvalidated.isChecked)).toVisibility() + ml.bolus?.let { bolus -> + holder.binding.bolusDate.text = dateUtil.timeString(bolus.timestamp) + holder.binding.insulin.text = resourceHelper.gs(R.string.formatinsulinunits, bolus.amount) + holder.binding.bolusNs.visibility = (bolus.interfaceIDs.nightscoutId != null).toVisibility() + holder.binding.bolusPump.visibility = (bolus.interfaceIDs.pumpId != null).toVisibility() + holder.binding.bolusInvalid.visibility = bolus.isValid.not().toVisibility() + val iob = bolus.iobCalc(activePlugin, System.currentTimeMillis(), profile.dia) + holder.binding.iob.text = resourceHelper.gs(R.string.formatinsulinunits, iob.iobContrib) + if (iob.iobContrib != 0.0) holder.binding.iob.setTextColor(resourceHelper.gc(R.color.colorActive)) else holder.binding.iob.setTextColor(holder.binding.carbs.currentTextColor) + if (bolus.timestamp > dateUtil.now()) holder.binding.date.setTextColor(resourceHelper.gc(R.color.colorScheduled)) else holder.binding.date.setTextColor(holder.binding.carbs.currentTextColor) + holder.binding.mealOrCorrection.text = + when (ml.bolus.type) { + Bolus.Type.SMB -> "SMB" + Bolus.Type.NORMAL -> resourceHelper.gs(R.string.mealbolus) + Bolus.Type.PRIMING -> resourceHelper.gs(R.string.prime) + } + } + // Carbs + holder.binding.carbsLayout.visibility = (ml.carbs != null && (ml.carbs.isValid || binding.showInvalidated.isChecked)).toVisibility() + ml.carbs?.let { carbs -> + holder.binding.carbsDate.text = dateUtil.timeString(carbs.timestamp) + holder.binding.carbs.text = resourceHelper.gs(R.string.format_carbs, carbs.amount.toInt()) + holder.binding.carbsDuration.text = if (carbs.duration > 0) resourceHelper.gs(R.string.format_mins, T.msecs(carbs.duration).mins().toInt()) else "" + holder.binding.carbsNs.visibility = (carbs.interfaceIDs.nightscoutId != null).toVisibility() + holder.binding.carbsPump.visibility = (carbs.interfaceIDs.pumpId != null).toVisibility() + holder.binding.carbsInvalid.visibility = carbs.isValid.not().toVisibility() + } + + holder.binding.bolusRemove.visibility = (ml.bolus?.isValid == true).toVisibility() + holder.binding.carbsRemove.visibility = (ml.carbs?.isValid == true).toVisibility() + holder.binding.bolusRemove.tag = ml + holder.binding.carbsRemove.tag = ml + holder.binding.calculation.tag = ml + } + + override fun getItemCount(): Int { + return mealLinks.size + } + + inner class MealLinkLoadedViewHolder internal constructor(view: View) : RecyclerView.ViewHolder(view) { + + val binding = TreatmentsBolusCarbsItemBinding.bind(view) + + init { + binding.calculation.setOnClickListener { + val mealLinkLoaded = it.tag as MealLink + mealLinkLoaded.bolusCalculatorResult?.let { bolusCalculatorResult -> + WizardInfoDialog().also { wizardDialog -> + wizardDialog.setData(bolusCalculatorResult) + wizardDialog.show(childFragmentManager, "WizardInfoDialog") + } + } + } + binding.calculation.paintFlags = binding.calculation.paintFlags or Paint.UNDERLINE_TEXT_FLAG + binding.bolusRemove.setOnClickListener { ml -> + val bolus = (ml.tag as MealLink?)?.bolus ?: return@setOnClickListener + activity?.let { activity -> + val text = resourceHelper.gs(R.string.configbuilder_insulin) + ": " + + resourceHelper.gs(R.string.formatinsulinunits, bolus.amount) + "\n" + + resourceHelper.gs(R.string.date) + ": " + dateUtil.dateAndTimeString(bolus.timestamp) + OKDialog.showConfirmation(activity, resourceHelper.gs(R.string.removerecord), text, Runnable { + uel.log( + Action.BOLUS_REMOVED, Sources.Treatments, + ValueWithUnit.Timestamp(bolus.timestamp), + ValueWithUnit.Insulin(bolus.amount) + //ValueWithUnit.Gram(mealLinkLoaded.carbs.toInt()) + ) + disposable += repository.runTransactionForResult(InvalidateBolusTransaction(bolus.id)) + .subscribe( + { result -> result.invalidated.forEach { aapsLogger.debug(LTag.DATABASE, "Invalidated bolus $it") } }, + { aapsLogger.error(LTag.DATABASE, "Error while invalidating bolus", it) } + ) + }) + } + } + binding.bolusRemove.paintFlags = binding.bolusRemove.paintFlags or Paint.UNDERLINE_TEXT_FLAG + binding.carbsRemove.setOnClickListener { ml -> + val carb = (ml.tag as MealLink?)?.carbs ?: return@setOnClickListener + activity?.let { activity -> + val text = resourceHelper.gs(R.string.carbs) + ": " + + resourceHelper.gs(R.string.carbs) + ": " + resourceHelper.gs(R.string.format_carbs, carb.amount.toInt()) + "\n" + + resourceHelper.gs(R.string.date) + ": " + dateUtil.dateAndTimeString(carb.timestamp) + OKDialog.showConfirmation(activity, resourceHelper.gs(R.string.removerecord), text, Runnable { + uel.log( + Action.CARBS_REMOVED, Sources.Treatments, + ValueWithUnit.Timestamp(carb.timestamp), + ValueWithUnit.Gram(carb.amount.toInt())) + disposable += repository.runTransactionForResult(InvalidateCarbsTransaction(carb.id)) + .subscribe( + { result -> result.invalidated.forEach { aapsLogger.debug(LTag.DATABASE, "Invalidated carbs $it") } }, + { aapsLogger.error(LTag.DATABASE, "Error while invalidating carbs", it) } + ) + }) + } + } + binding.carbsRemove.paintFlags = binding.carbsRemove.paintFlags or Paint.UNDERLINE_TEXT_FLAG + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/treatments/fragments/TreatmentsBolusFragment.kt b/app/src/main/java/info/nightscout/androidaps/plugins/treatments/fragments/TreatmentsBolusFragment.kt deleted file mode 100644 index 5b53f9a757..0000000000 --- a/app/src/main/java/info/nightscout/androidaps/plugins/treatments/fragments/TreatmentsBolusFragment.kt +++ /dev/null @@ -1,210 +0,0 @@ -package info.nightscout.androidaps.plugins.treatments.fragments - -import android.graphics.Paint -import android.os.Bundle -import android.view.LayoutInflater -import android.view.View -import android.view.ViewGroup -import androidx.recyclerview.widget.LinearLayoutManager -import androidx.recyclerview.widget.RecyclerView -import dagger.android.support.DaggerFragment -import info.nightscout.androidaps.R -import info.nightscout.androidaps.database.entities.UserEntry.* -import info.nightscout.androidaps.databinding.TreatmentsBolusFragmentBinding -import info.nightscout.androidaps.databinding.TreatmentsBolusItemBinding -import info.nightscout.androidaps.db.Source -import info.nightscout.androidaps.db.Treatment -import info.nightscout.androidaps.dialogs.WizardInfoDialog -import info.nightscout.androidaps.events.EventTreatmentChange -import info.nightscout.androidaps.interfaces.ProfileFunction -import info.nightscout.androidaps.logging.UserEntryLogger -import info.nightscout.androidaps.plugins.bus.RxBusWrapper -import info.nightscout.androidaps.plugins.general.nsclient.NSUpload -import info.nightscout.androidaps.plugins.general.nsclient.events.EventNSClientRestart -import info.nightscout.androidaps.events.EventAutosensCalculationFinished -import info.nightscout.androidaps.interfaces.UploadQueueInterface -import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin -import info.nightscout.androidaps.plugins.treatments.fragments.TreatmentsBolusFragment.RecyclerViewAdapter.TreatmentsViewHolder -import info.nightscout.androidaps.utils.DateUtil -import info.nightscout.androidaps.utils.FabricPrivacy -import info.nightscout.androidaps.utils.alertDialogs.OKDialog -import info.nightscout.androidaps.utils.buildHelper.BuildHelper -import info.nightscout.androidaps.utils.resources.ResourceHelper -import info.nightscout.androidaps.utils.rx.AapsSchedulers -import info.nightscout.androidaps.utils.sharedPreferences.SP -import io.reactivex.disposables.CompositeDisposable -import javax.inject.Inject - -class TreatmentsBolusFragment : DaggerFragment() { - - private val disposable = CompositeDisposable() - - @Inject lateinit var rxBus: RxBusWrapper - @Inject lateinit var sp: SP - @Inject lateinit var resourceHelper: ResourceHelper - @Inject lateinit var fabricPrivacy: FabricPrivacy - @Inject lateinit var treatmentsPlugin: TreatmentsPlugin - @Inject lateinit var profileFunction: ProfileFunction - @Inject lateinit var nsUpload: NSUpload - @Inject lateinit var uploadQueue: UploadQueueInterface - @Inject lateinit var dateUtil: DateUtil - @Inject lateinit var buildHelper: BuildHelper - @Inject lateinit var aapsSchedulers: AapsSchedulers - @Inject lateinit var uel: UserEntryLogger - - private var _binding: TreatmentsBolusFragmentBinding? = null - - // This property is only valid between onCreateView and - // onDestroyView. - private val binding get() = _binding!! - - override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View = - TreatmentsBolusFragmentBinding.inflate(inflater, container, false).also { _binding = it }.root - - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { - super.onViewCreated(view, savedInstanceState) - binding.recyclerview.setHasFixedSize(true) - binding.recyclerview.layoutManager = LinearLayoutManager(view.context) - binding.recyclerview.adapter = RecyclerViewAdapter(treatmentsPlugin.treatmentsFromHistory) - binding.refreshFromNightscout.setOnClickListener { - activity?.let { activity -> - OKDialog.showConfirmation(activity, resourceHelper.gs(R.string.refresheventsfromnightscout) + "?") { - uel.log(Action.TREATMENTS_NS_REFRESH) - treatmentsPlugin.service.resetTreatments() - rxBus.send(EventNSClientRestart()) - } - } - } - binding.deleteFutureTreatments.setOnClickListener { - activity?.let { activity -> - OKDialog.showConfirmation(activity, resourceHelper.gs(R.string.overview_treatment_label), resourceHelper.gs(R.string.deletefuturetreatments) + "?", Runnable { - uel.log(Action.DELETE_FUTURE_TREATMENTS) - val futureTreatments = treatmentsPlugin.service.getTreatmentDataFromTime(DateUtil.now() + 1000, true) - for (treatment in futureTreatments) { - if (NSUpload.isIdValid(treatment._id)) - nsUpload.removeCareportalEntryFromNS(treatment._id) - else - uploadQueue.removeByMongoId("dbAdd", treatment._id) - treatmentsPlugin.service.delete(treatment) - } - updateGui() - }) - } - } - val nsUploadOnly = sp.getBoolean(R.string.key_ns_upload_only, true) || !buildHelper.isEngineeringMode() - if (nsUploadOnly) binding.refreshFromNightscout.visibility = View.GONE - } - - @Synchronized - override fun onResume() { - super.onResume() - disposable.add(rxBus - .toObservable(EventTreatmentChange::class.java) - .observeOn(aapsSchedulers.main) - .subscribe({ updateGui() }, fabricPrivacy::logException) - ) - disposable.add(rxBus - .toObservable(EventAutosensCalculationFinished::class.java) - .observeOn(aapsSchedulers.main) - .subscribe({ updateGui() }, fabricPrivacy::logException) - ) - updateGui() - } - - @Synchronized - override fun onPause() { - super.onPause() - disposable.clear() - } - - @Synchronized - override fun onDestroyView() { - super.onDestroyView() - _binding = null - } - - inner class RecyclerViewAdapter internal constructor(var treatments: List) : RecyclerView.Adapter() { - - override fun onCreateViewHolder(viewGroup: ViewGroup, viewType: Int): TreatmentsViewHolder { - val v = LayoutInflater.from(viewGroup.context).inflate(R.layout.treatments_bolus_item, viewGroup, false) - return TreatmentsViewHolder(v) - } - - override fun onBindViewHolder(holder: TreatmentsViewHolder, position: Int) { - val profile = profileFunction.getProfile() ?: return - val t = treatments[position] - holder.binding.date.text = dateUtil.dateAndTimeString(t.date) - holder.binding.insulin.text = resourceHelper.gs(R.string.formatinsulinunits, t.insulin) - holder.binding.carbs.text = resourceHelper.gs(R.string.format_carbs, t.carbs.toInt()) - val iob = t.iobCalc(System.currentTimeMillis(), profile.dia) - holder.binding.iob.text = resourceHelper.gs(R.string.formatinsulinunits, iob.iobContrib) - holder.binding.mealOrCorrection.text = if (t.isSMB) "SMB" else if (t.mealBolus) resourceHelper.gs(R.string.mealbolus) else resourceHelper.gs(R.string.correctionbous) - holder.binding.pump.visibility = if (t.source == Source.PUMP) View.VISIBLE else View.GONE - holder.binding.ns.visibility = if (NSUpload.isIdValid(t._id)) View.VISIBLE else View.GONE - holder.binding.invalid.visibility = if (t.isValid) View.GONE else View.VISIBLE - if (iob.iobContrib != 0.0) holder.binding.iob.setTextColor(resourceHelper.gc(R.color.colorActive)) else holder.binding.iob.setTextColor(holder.binding.carbs.currentTextColor) - if (t.date > DateUtil.now()) holder.binding.date.setTextColor(resourceHelper.gc(R.color.colorScheduled)) else holder.binding.date.setTextColor(holder.binding.carbs.currentTextColor) - holder.binding.remove.tag = t - holder.binding.calculation.tag = t - holder.binding.calculation.visibility = if (t.getBoluscalc() == null) View.INVISIBLE else View.VISIBLE - } - - override fun getItemCount(): Int { - return treatments.size - } - - inner class TreatmentsViewHolder internal constructor(view: View) : RecyclerView.ViewHolder(view) { - - val binding = TreatmentsBolusItemBinding.bind(view) - - init { - binding.calculation.setOnClickListener { - val treatment = it.tag as Treatment - if (treatment.getBoluscalc() != null) { - val wizardDialog = WizardInfoDialog() - wizardDialog.setData(treatment.getBoluscalc()!!) - wizardDialog.show(childFragmentManager, "WizardInfoDialog") - } - } - binding.calculation.paintFlags = binding.calculation.paintFlags or Paint.UNDERLINE_TEXT_FLAG - binding.remove.setOnClickListener { - val treatment = it.tag as Treatment? ?: return@setOnClickListener - activity?.let { activity -> - val text = resourceHelper.gs(R.string.configbuilder_insulin) + ": " + - resourceHelper.gs(R.string.formatinsulinunits, treatment.insulin) + "\n" + - resourceHelper.gs(R.string.carbs) + ": " + resourceHelper.gs(R.string.format_carbs, treatment.carbs.toInt()) + "\n" + - resourceHelper.gs(R.string.date) + ": " + dateUtil.dateAndTimeString(treatment.date) - OKDialog.showConfirmation(activity, resourceHelper.gs(R.string.removerecord), text, Runnable { - uel.log(Action.TREATMENT_REMOVED, ValueWithUnit(treatment.date, Units.Timestamp), ValueWithUnit(treatment.insulin, Units.U, treatment.insulin != 0.0), ValueWithUnit(treatment.carbs.toInt(), Units.G, treatment.carbs != 0.0)) - if (treatment.source == Source.PUMP) { - treatment.isValid = false - treatmentsPlugin.service.update(treatment) - } else { - if (NSUpload.isIdValid(treatment._id)) - nsUpload.removeCareportalEntryFromNS(treatment._id) - else - uploadQueue.removeByMongoId("dbAdd", treatment._id) - treatmentsPlugin.service.delete(treatment) - } - updateGui() - }) - } - } - binding.remove.paintFlags = binding.remove.paintFlags or Paint.UNDERLINE_TEXT_FLAG - } - } - } - - private fun updateGui() { - if (_binding == null) return - binding.recyclerview.swapAdapter(RecyclerViewAdapter(treatmentsPlugin.treatmentsFromHistory), false) - if (treatmentsPlugin.lastCalculationTreatments != null) { - binding.iobTotal.text = resourceHelper.gs(R.string.formatinsulinunits, treatmentsPlugin.lastCalculationTreatments.iob) - binding.iobActivityTotal.text = resourceHelper.gs(R.string.formatinsulinunits, treatmentsPlugin.lastCalculationTreatments.activity) - } - if (treatmentsPlugin.service.getTreatmentDataFromTime(DateUtil.now() + 1000, true).isNotEmpty()) - binding.deleteFutureTreatments.visibility = View.VISIBLE - else - binding.deleteFutureTreatments.visibility = View.GONE - } -} \ No newline at end of file diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/treatments/fragments/TreatmentsCareportalFragment.kt b/app/src/main/java/info/nightscout/androidaps/plugins/treatments/fragments/TreatmentsCareportalFragment.kt index 666c38eb9c..4c90c80e08 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/treatments/fragments/TreatmentsCareportalFragment.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/treatments/fragments/TreatmentsCareportalFragment.kt @@ -10,19 +10,19 @@ import androidx.recyclerview.widget.RecyclerView import dagger.android.support.DaggerFragment import info.nightscout.androidaps.R import info.nightscout.androidaps.database.AppRepository +import info.nightscout.androidaps.database.entities.ValueWithUnit import info.nightscout.androidaps.database.entities.TherapyEvent +import info.nightscout.androidaps.database.entities.UserEntry.Action +import info.nightscout.androidaps.database.entities.UserEntry.Sources import info.nightscout.androidaps.database.transactions.InvalidateAAPSStartedTherapyEventTransaction import info.nightscout.androidaps.database.transactions.InvalidateTherapyEventTransaction -import info.nightscout.androidaps.database.entities.UserEntry.* import info.nightscout.androidaps.databinding.TreatmentsCareportalFragmentBinding import info.nightscout.androidaps.databinding.TreatmentsCareportalItemBinding import info.nightscout.androidaps.events.EventTherapyEventChange -import info.nightscout.androidaps.interfaces.UploadQueueInterface import info.nightscout.androidaps.logging.AAPSLogger import info.nightscout.androidaps.logging.LTag import info.nightscout.androidaps.logging.UserEntryLogger import info.nightscout.androidaps.plugins.bus.RxBusWrapper -import info.nightscout.androidaps.plugins.general.nsclient.NSUpload import info.nightscout.androidaps.plugins.general.nsclient.events.EventNSClientRestart import info.nightscout.androidaps.plugins.treatments.events.EventTreatmentUpdateGui import info.nightscout.androidaps.plugins.treatments.fragments.TreatmentsCareportalFragment.RecyclerViewAdapter.TherapyEventsViewHolder @@ -32,7 +32,7 @@ import info.nightscout.androidaps.utils.T import info.nightscout.androidaps.utils.Translator import info.nightscout.androidaps.utils.alertDialogs.OKDialog import info.nightscout.androidaps.utils.buildHelper.BuildHelper -import info.nightscout.androidaps.utils.extensions.toVisibility +import info.nightscout.androidaps.extensions.toVisibility import info.nightscout.androidaps.utils.resources.ResourceHelper import info.nightscout.androidaps.utils.rx.AapsSchedulers import info.nightscout.androidaps.utils.sharedPreferences.SP @@ -51,8 +51,6 @@ class TreatmentsCareportalFragment : DaggerFragment() { @Inject lateinit var resourceHelper: ResourceHelper @Inject lateinit var fabricPrivacy: FabricPrivacy @Inject lateinit var translator: Translator - @Inject lateinit var nsUpload: NSUpload - @Inject lateinit var uploadQueue: UploadQueueInterface @Inject lateinit var dateUtil: DateUtil @Inject lateinit var buildHelper: BuildHelper @Inject lateinit var aapsSchedulers: AapsSchedulers @@ -79,7 +77,7 @@ class TreatmentsCareportalFragment : DaggerFragment() { binding.refreshFromNightscout.setOnClickListener { activity?.let { activity -> OKDialog.showConfirmation(activity, resourceHelper.gs(R.string.careportal), resourceHelper.gs(R.string.refresheventsfromnightscout) + " ?", Runnable { - uel.log(Action.CAREPORTAL_NS_REFRESH) + uel.log(Action.CAREPORTAL_NS_REFRESH, Sources.Treatments) disposable += Completable.fromAction { repository.deleteAllTherapyEventsEntries() } .subscribeOn(aapsSchedulers.io) .observeOn(aapsSchedulers.main) @@ -94,19 +92,12 @@ class TreatmentsCareportalFragment : DaggerFragment() { binding.removeAndroidapsStartedEvents.setOnClickListener { activity?.let { activity -> OKDialog.showConfirmation(activity, resourceHelper.gs(R.string.careportal), resourceHelper.gs(R.string.careportal_removestartedevents), Runnable { - uel.log(Action.RESTART_EVENTS_REMOVED) - // val events = databaseHelper.getCareportalEvents(false) - repository.runTransactionForResult(InvalidateAAPSStartedTherapyEventTransaction()) - .subscribe({ result -> - result.invalidated.forEach { event -> - if (NSUpload.isIdValid(event.interfaceIDs.nightscoutId)) - nsUpload.removeCareportalEntryFromNS(event.interfaceIDs.nightscoutId) - else - uploadQueue.removeByMongoId("dbAdd", event.timestamp.toString()) - } - }, { - aapsLogger.error(LTag.BGSOURCE, "Error while invalidating therapy event", it) - }) + uel.log(Action.RESTART_EVENTS_REMOVED, Sources.Treatments) + repository.runTransactionForResult(InvalidateAAPSStartedTherapyEventTransaction(resourceHelper.gs(R.string.androidaps_start))) + .subscribe( + { result -> result.invalidated.forEach { aapsLogger.debug(LTag.DATABASE, "Invalidated therapy event $it") } }, + { aapsLogger.error(LTag.DATABASE, "Error while invalidating therapy event", it) } + ) }, null) } } @@ -120,28 +111,28 @@ class TreatmentsCareportalFragment : DaggerFragment() { fun swapAdapter() { val now = System.currentTimeMillis() - if (binding.showInvalidated.isChecked) - repository - .getTherapyEventDataIncludingInvalidFromTime(now - millsToThePast, false) - .observeOn(aapsSchedulers.main) - .subscribe { list -> binding.recyclerview.swapAdapter(RecyclerViewAdapter(list), true) } - else - repository - .getTherapyEventDataFromTime(now - millsToThePast, false) - .observeOn(aapsSchedulers.main) - .subscribe { list -> binding.recyclerview.swapAdapter(RecyclerViewAdapter(list), true) } + disposable += + if (binding.showInvalidated.isChecked) + repository + .getTherapyEventDataIncludingInvalidFromTime(now - millsToThePast, false) + .observeOn(aapsSchedulers.main) + .subscribe { list -> binding.recyclerview.swapAdapter(RecyclerViewAdapter(list), true) } + else + repository + .getTherapyEventDataFromTime(now - millsToThePast, false) + .observeOn(aapsSchedulers.main) + .subscribe { list -> binding.recyclerview.swapAdapter(RecyclerViewAdapter(list), true) } } @Synchronized override fun onResume() { super.onResume() swapAdapter() - disposable.add(rxBus + disposable += rxBus .toObservable(EventTherapyEventChange::class.java) .observeOn(aapsSchedulers.main) .debounce(1L, TimeUnit.SECONDS) .subscribe({ swapAdapter() }, fabricPrivacy::logException) - ) disposable += rxBus .toObservable(EventTreatmentUpdateGui::class.java) // TODO join with above .observeOn(aapsSchedulers.io) @@ -174,9 +165,9 @@ class TreatmentsCareportalFragment : DaggerFragment() { holder.binding.ns.visibility = (therapyEvent.interfaceIDs.nightscoutId != null).toVisibility() holder.binding.invalid.visibility = therapyEvent.isValid.not().toVisibility() holder.binding.date.text = dateUtil.dateAndTimeString(therapyEvent.timestamp) - holder.binding.duration.text = if (therapyEvent.duration == 0L) "" else DateUtil.niceTimeScalar(therapyEvent.duration, resourceHelper) + holder.binding.duration.text = if (therapyEvent.duration == 0L) "" else dateUtil.niceTimeScalar(therapyEvent.duration, resourceHelper) holder.binding.note.text = therapyEvent.note - holder.binding.type.text = translator.translate(therapyEvent.type.text) + holder.binding.type.text = translator.translate(therapyEvent.type) holder.binding.remove.tag = therapyEvent } @@ -192,19 +183,19 @@ class TreatmentsCareportalFragment : DaggerFragment() { binding.remove.setOnClickListener { v: View -> val therapyEvent = v.tag as TherapyEvent activity?.let { activity -> - val text = resourceHelper.gs(R.string.eventtype) + ": " + translator.translate(therapyEvent.type.text) + "\n" + - resourceHelper.gs(R.string.notes_label) + ": " + (therapyEvent.note ?: "") + "\n" + + val text = resourceHelper.gs(R.string.eventtype) + ": " + translator.translate(therapyEvent.type) + "\n" + + resourceHelper.gs(R.string.notes_label) + ": " + (therapyEvent.note + ?: "") + "\n" + resourceHelper.gs(R.string.date) + ": " + dateUtil.dateAndTimeString(therapyEvent.timestamp) OKDialog.showConfirmation(activity, resourceHelper.gs(R.string.removerecord), text, Runnable { - uel.log(Action.CAREPORTAL_REMOVED, therapyEvent.note , ValueWithUnit(therapyEvent.timestamp, Units.Timestamp), ValueWithUnit(therapyEvent.type.text, Units.TherapyEvent)) + uel.log(Action.CAREPORTAL_REMOVED, Sources.Treatments, therapyEvent.note , + ValueWithUnit.Timestamp(therapyEvent.timestamp), + ValueWithUnit.TherapyEventType(therapyEvent.type)) disposable += repository.runTransactionForResult(InvalidateTherapyEventTransaction(therapyEvent.id)) - .subscribe({ - val id = therapyEvent.interfaceIDs.nightscoutId - if (NSUpload.isIdValid(id)) nsUpload.removeCareportalEntryFromNS(id) - else uploadQueue.removeByMongoId("dbAdd", therapyEvent.timestamp.toString()) - }, { - aapsLogger.error(LTag.BGSOURCE, "Error while invalidating therapy event", it) - }) + .subscribe( + { result -> result.invalidated.forEach { aapsLogger.debug(LTag.DATABASE, "Invalidated therapy event $it") } }, + { aapsLogger.error(LTag.DATABASE, "Error while invalidating therapy event", it) } + ) }, null) } } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/treatments/fragments/TreatmentsExtendedBolusesFragment.kt b/app/src/main/java/info/nightscout/androidaps/plugins/treatments/fragments/TreatmentsExtendedBolusesFragment.kt index bbecd9b5bd..5e52467f5e 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/treatments/fragments/TreatmentsExtendedBolusesFragment.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/treatments/fragments/TreatmentsExtendedBolusesFragment.kt @@ -11,45 +11,52 @@ import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.RecyclerView import dagger.android.support.DaggerFragment import info.nightscout.androidaps.R -import info.nightscout.androidaps.data.Intervals -import info.nightscout.androidaps.database.entities.UserEntry.* +import info.nightscout.androidaps.database.AppRepository +import info.nightscout.androidaps.database.entities.ExtendedBolus +import info.nightscout.androidaps.database.entities.UserEntry.Action +import info.nightscout.androidaps.database.entities.UserEntry.Sources +import info.nightscout.androidaps.database.interfaces.end +import info.nightscout.androidaps.database.transactions.InvalidateExtendedBolusTransaction import info.nightscout.androidaps.databinding.TreatmentsExtendedbolusFragmentBinding import info.nightscout.androidaps.databinding.TreatmentsExtendedbolusItemBinding -import info.nightscout.androidaps.db.ExtendedBolus -import info.nightscout.androidaps.db.Source -import info.nightscout.androidaps.events.EventAutosensCalculationFinished import info.nightscout.androidaps.events.EventExtendedBolusChange -import info.nightscout.androidaps.interfaces.ActivePluginProvider -import info.nightscout.androidaps.interfaces.DatabaseHelperInterface +import info.nightscout.androidaps.extensions.iobCalc +import info.nightscout.androidaps.extensions.isInProgress +import info.nightscout.androidaps.extensions.toVisibility +import info.nightscout.androidaps.interfaces.ActivePlugin import info.nightscout.androidaps.interfaces.ProfileFunction -import info.nightscout.androidaps.interfaces.UploadQueueInterface +import info.nightscout.androidaps.logging.AAPSLogger +import info.nightscout.androidaps.logging.LTag import info.nightscout.androidaps.logging.UserEntryLogger import info.nightscout.androidaps.plugins.bus.RxBusWrapper -import info.nightscout.androidaps.plugins.general.nsclient.NSUpload import info.nightscout.androidaps.plugins.treatments.fragments.TreatmentsExtendedBolusesFragment.RecyclerViewAdapter.ExtendedBolusesViewHolder import info.nightscout.androidaps.utils.DateUtil import info.nightscout.androidaps.utils.FabricPrivacy +import info.nightscout.androidaps.utils.T import info.nightscout.androidaps.utils.alertDialogs.OKDialog import info.nightscout.androidaps.utils.resources.ResourceHelper import info.nightscout.androidaps.utils.rx.AapsSchedulers import io.reactivex.disposables.CompositeDisposable +import io.reactivex.rxkotlin.plusAssign +import java.util.concurrent.TimeUnit import javax.inject.Inject class TreatmentsExtendedBolusesFragment : DaggerFragment() { private val disposable = CompositeDisposable() - @Inject lateinit var activePlugin: ActivePluginProvider + private val millsToThePast = T.days(30).msecs() + + @Inject lateinit var activePlugin: ActivePlugin @Inject lateinit var rxBus: RxBusWrapper @Inject lateinit var resourceHelper: ResourceHelper + @Inject lateinit var aapsLogger: AAPSLogger @Inject lateinit var fabricPrivacy: FabricPrivacy - @Inject lateinit var nsUpload: NSUpload - @Inject lateinit var uploadQueue: UploadQueueInterface @Inject lateinit var profileFunction: ProfileFunction @Inject lateinit var dateUtil: DateUtil @Inject lateinit var aapsSchedulers: AapsSchedulers - @Inject lateinit var databaseHelper: DatabaseHelperInterface @Inject lateinit var uel: UserEntryLogger + @Inject lateinit var repository: AppRepository private var _binding: TreatmentsExtendedbolusFragmentBinding? = null @@ -58,18 +65,54 @@ class TreatmentsExtendedBolusesFragment : DaggerFragment() { private val binding get() = _binding!! override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, - savedInstanceState: Bundle?): View { - _binding = TreatmentsExtendedbolusFragmentBinding.inflate(inflater, container, false) - return binding.root - } + savedInstanceState: Bundle?): View = + TreatmentsExtendedbolusFragmentBinding.inflate(inflater, container, false).also { _binding = it }.root override fun onViewCreated(view: View, savedInstanceState: Bundle?) { binding.recyclerview.setHasFixedSize(true) binding.recyclerview.layoutManager = LinearLayoutManager(view.context) - binding.recyclerview.adapter = RecyclerViewAdapter(activePlugin.activeTreatments.extendedBolusesFromHistory) } - private inner class RecyclerViewAdapter(private var extendedBolusList: Intervals) : RecyclerView.Adapter() { + fun swapAdapter() { + val now = System.currentTimeMillis() + if (binding.showInvalidated.isChecked) + repository + .getExtendedBolusDataIncludingInvalidFromTime(now - millsToThePast, false) + .observeOn(aapsSchedulers.main) + .subscribe { list -> binding.recyclerview.swapAdapter(RecyclerViewAdapter(list), true) } + else + repository + .getExtendedBolusDataFromTime(now - millsToThePast, false) + .observeOn(aapsSchedulers.main) + .subscribe { list -> binding.recyclerview.swapAdapter(RecyclerViewAdapter(list), true) } + } + + @Synchronized + override fun onResume() { + super.onResume() + swapAdapter() + + disposable += rxBus + .toObservable(EventExtendedBolusChange::class.java) + .observeOn(aapsSchedulers.io) + .debounce(1L, TimeUnit.SECONDS) + .subscribe({ swapAdapter() }, fabricPrivacy::logException) + } + + @Synchronized + override fun onPause() { + super.onPause() + disposable.clear() + } + + @Synchronized + override fun onDestroyView() { + super.onDestroyView() + binding.recyclerview.adapter = null // avoid leaks + _binding = null + } + + private inner class RecyclerViewAdapter(private var extendedBolusList: List) : RecyclerView.Adapter() { override fun onCreateViewHolder(viewGroup: ViewGroup, viewType: Int): ExtendedBolusesViewHolder { val v = LayoutInflater.from(viewGroup.context).inflate(R.layout.treatments_extendedbolus_item, viewGroup, false) @@ -77,38 +120,29 @@ class TreatmentsExtendedBolusesFragment : DaggerFragment() { } override fun onBindViewHolder(holder: ExtendedBolusesViewHolder, position: Int) { - val extendedBolus = extendedBolusList.getReversed(position) - holder.binding.ph.visibility = if (extendedBolus.source == Source.PUMP) View.VISIBLE else View.GONE - holder.binding.ns.visibility = if (NSUpload.isIdValid(extendedBolus._id)) View.VISIBLE else View.GONE - if (extendedBolus.isEndingEvent) { - holder.binding.date.text = dateUtil.dateAndTimeString(extendedBolus.date) - holder.binding.duration.text = resourceHelper.gs(R.string.cancel) - holder.binding.insulin.text = "" - holder.binding.realDuration.text = "" - holder.binding.iob.text = "" - holder.binding.insulinSoFar.text = "" - holder.binding.ratio.text = "" + val extendedBolus = extendedBolusList[position] + holder.binding.ns.visibility = (extendedBolus.interfaceIDs.nightscoutId != null).toVisibility() + holder.binding.ph.visibility = (extendedBolus.interfaceIDs.pumpId != null).toVisibility() + holder.binding.invalid.visibility = extendedBolus.isValid.not().toVisibility() + @SuppressLint("SetTextI18n") + if (extendedBolus.isInProgress(dateUtil)) { + holder.binding.date.text = dateUtil.dateAndTimeString(extendedBolus.timestamp) + holder.binding.date.setTextColor(resourceHelper.gc(R.color.colorActive)) } else { - @SuppressLint("SetTextI18n") - if (extendedBolus.isInProgress) holder.binding.date.text = dateUtil.dateAndTimeString(extendedBolus.date) - else holder.binding.date.text = dateUtil.dateAndTimeString(extendedBolus.date) + " - " + dateUtil.timeString(extendedBolus.end()) - val profile = profileFunction.getProfile(extendedBolus.date) - holder.binding.duration.text = resourceHelper.gs(R.string.format_mins, extendedBolus.durationInMinutes) - holder.binding.insulin.text = resourceHelper.gs(R.string.formatinsulinunits, extendedBolus.insulin) - holder.binding.realDuration.text = resourceHelper.gs(R.string.format_mins, extendedBolus.realDuration) - val iob = extendedBolus.iobCalc(System.currentTimeMillis(), profile) - holder.binding.iob.text = resourceHelper.gs(R.string.formatinsulinunits, iob.iob) - holder.binding.insulinSoFar.text = resourceHelper.gs(R.string.formatinsulinunits, extendedBolus.insulinSoFar()) - holder.binding.ratio.text = resourceHelper.gs(R.string.pump_basebasalrate, extendedBolus.absoluteRate()) - if (extendedBolus.isInProgress) holder.binding.date.setTextColor(resourceHelper.gc(R.color.colorActive)) else holder.binding.date.setTextColor(holder.binding.insulin.currentTextColor) - if (iob.iob != 0.0) holder.binding.iob.setTextColor(resourceHelper.gc(R.color.colorActive)) else holder.binding.iob.setTextColor(holder.binding.insulin.currentTextColor) + holder.binding.date.text = dateUtil.dateAndTimeString(extendedBolus.timestamp) + " - " + dateUtil.timeString(extendedBolus.end) + holder.binding.date.setTextColor(holder.binding.insulin.currentTextColor) } + val profile = profileFunction.getProfile(extendedBolus.timestamp) ?: return + holder.binding.duration.text = resourceHelper.gs(R.string.format_mins, T.msecs(extendedBolus.duration).mins()) + holder.binding.insulin.text = resourceHelper.gs(R.string.formatinsulinunits, extendedBolus.amount) + val iob = extendedBolus.iobCalc(System.currentTimeMillis(), profile, activePlugin.activeInsulin) + holder.binding.iob.text = resourceHelper.gs(R.string.formatinsulinunits, iob.iob) + holder.binding.ratio.text = resourceHelper.gs(R.string.pump_basebasalrate, extendedBolus.rate) + if (iob.iob != 0.0) holder.binding.iob.setTextColor(resourceHelper.gc(R.color.colorActive)) else holder.binding.iob.setTextColor(holder.binding.insulin.currentTextColor) holder.binding.remove.tag = extendedBolus } - override fun getItemCount(): Int { - return extendedBolusList.size() - } + override fun getItemCount(): Int = extendedBolusList.size inner class ExtendedBolusesViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { @@ -117,17 +151,17 @@ class TreatmentsExtendedBolusesFragment : DaggerFragment() { init { binding.remove.setOnClickListener { v: View -> val extendedBolus = v.tag as ExtendedBolus - context?.let { - OKDialog.showConfirmation(it, resourceHelper.gs(R.string.removerecord), + context?.let { context -> + OKDialog.showConfirmation(context, resourceHelper.gs(R.string.removerecord), """ ${resourceHelper.gs(R.string.extended_bolus)} - ${resourceHelper.gs(R.string.date)}: ${dateUtil.dateAndTimeString(extendedBolus.date)} + ${resourceHelper.gs(R.string.date)}: ${dateUtil.dateAndTimeString(extendedBolus.timestamp)} """.trimIndent(), { _: DialogInterface, _: Int -> - uel.log(Action.EXTENDED_BOLUS_REMOVED) - val id = extendedBolus._id - if (NSUpload.isIdValid(id)) nsUpload.removeCareportalEntryFromNS(id) - else uploadQueue.removeByMongoId("dbAdd", id) - databaseHelper.delete(extendedBolus) + uel.log(Action.EXTENDED_BOLUS_REMOVED, Sources.Treatments) + disposable += repository.runTransactionForResult(InvalidateExtendedBolusTransaction(extendedBolus.id)) + .subscribe( + { aapsLogger.debug(LTag.DATABASE, "Removed extended bolus $extendedBolus") }, + { aapsLogger.error(LTag.DATABASE, "Error while invalidating extended bolus", it) }) }, null) } } @@ -136,35 +170,4 @@ class TreatmentsExtendedBolusesFragment : DaggerFragment() { } } - - @Synchronized override fun onResume() { - super.onResume() - disposable.add(rxBus - .toObservable(EventExtendedBolusChange::class.java) - .observeOn(aapsSchedulers.main) - .subscribe({ updateGui() }, fabricPrivacy::logException) - ) - disposable.add(rxBus - .toObservable(EventAutosensCalculationFinished::class.java) - .observeOn(aapsSchedulers.main) - .subscribe({ updateGui() }, fabricPrivacy::logException) - ) - updateGui() - } - - @Synchronized override fun onPause() { - super.onPause() - disposable.clear() - } - - @Synchronized - override fun onDestroyView() { - super.onDestroyView() - _binding = null - } - - private fun updateGui() { - if (_binding == null) return - binding.recyclerview.swapAdapter(RecyclerViewAdapter(activePlugin.activeTreatments.extendedBolusesFromHistory), false) - } } \ No newline at end of file diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/treatments/fragments/TreatmentsProfileSwitchFragment.kt b/app/src/main/java/info/nightscout/androidaps/plugins/treatments/fragments/TreatmentsProfileSwitchFragment.kt index c7b667b2fd..b05dfb2b40 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/treatments/fragments/TreatmentsProfileSwitchFragment.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/treatments/fragments/TreatmentsProfileSwitchFragment.kt @@ -9,7 +9,9 @@ import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.RecyclerView import dagger.android.support.DaggerFragment import info.nightscout.androidaps.R -import info.nightscout.androidaps.database.entities.UserEntry.* +import info.nightscout.androidaps.database.entities.ValueWithUnit +import info.nightscout.androidaps.database.entities.UserEntry.Action +import info.nightscout.androidaps.database.entities.UserEntry.Sources import info.nightscout.androidaps.databinding.TreatmentsProfileswitchFragmentBinding import info.nightscout.androidaps.databinding.TreatmentsProfileswitchItemBinding import info.nightscout.androidaps.db.ProfileSwitch @@ -30,7 +32,7 @@ import info.nightscout.androidaps.utils.FabricPrivacy import info.nightscout.androidaps.utils.T import info.nightscout.androidaps.utils.alertDialogs.OKDialog import info.nightscout.androidaps.utils.buildHelper.BuildHelper -import info.nightscout.androidaps.utils.extensions.toVisibility +import info.nightscout.androidaps.extensions.toVisibility import info.nightscout.androidaps.utils.resources.ResourceHelper import info.nightscout.androidaps.utils.rx.AapsSchedulers import info.nightscout.androidaps.utils.sharedPreferences.SP @@ -67,11 +69,11 @@ class TreatmentsProfileSwitchFragment : DaggerFragment() { super.onViewCreated(view, savedInstanceState) binding.recyclerview.setHasFixedSize(true) binding.recyclerview.layoutManager = LinearLayoutManager(view.context) - binding.recyclerview.adapter = RecyclerProfileViewAdapter(databaseHelper.getProfileSwitchData(DateUtil.now() - T.days(30).msecs(), false)) + binding.recyclerview.adapter = RecyclerProfileViewAdapter(databaseHelper.getProfileSwitchData(dateUtil.now() - T.days(30).msecs(), false)) binding.refreshFromNightscout.setOnClickListener { activity?.let { activity -> - uel.log(Action.PROFILE_SWITCH_NS_REFRESH) + uel.log(Action.PROFILE_SWITCH_NS_REFRESH, Sources.Treatments) OKDialog.showConfirmation(activity, resourceHelper.gs(R.string.refresheventsfromnightscout) + "?") { databaseHelper.resetProfileSwitch() rxBus.send(EventNSClientRestart()) @@ -106,7 +108,7 @@ class TreatmentsProfileSwitchFragment : DaggerFragment() { fun updateGUI() { if (_binding == null) return - binding.recyclerview.swapAdapter(RecyclerProfileViewAdapter(databaseHelper.getProfileSwitchData(DateUtil.now() - T.days(30).msecs(), false)), false) + binding.recyclerview.swapAdapter(RecyclerProfileViewAdapter(databaseHelper.getProfileSwitchData(dateUtil.now() - T.days(30).msecs(), false)), false) } inner class RecyclerProfileViewAdapter(private var profileSwitchList: List) : RecyclerView.Adapter() { @@ -148,7 +150,8 @@ class TreatmentsProfileSwitchFragment : DaggerFragment() { OKDialog.showConfirmation(activity, resourceHelper.gs(R.string.removerecord), resourceHelper.gs(R.string.careportal_profileswitch) + ": " + profileSwitch.profileName + "\n" + resourceHelper.gs(R.string.date) + ": " + dateUtil.dateAndTimeString(profileSwitch.date), Runnable { - uel.log(Action.PROFILE_SWITCH_REMOVED, profileSwitch.profileName, ValueWithUnit(profileSwitch.date, Units.Timestamp)) + uel.log(Action.PROFILE_SWITCH_REMOVED, Sources.Treatments, profileSwitch.profileName, + ValueWithUnit.Timestamp(profileSwitch.date)) val id = profileSwitch._id if (NSUpload.isIdValid(id)) nsUpload.removeCareportalEntryFromNS(id) else uploadQueue.removeByMongoId("dbAdd", id) @@ -161,7 +164,10 @@ class TreatmentsProfileSwitchFragment : DaggerFragment() { val profileSwitch = it.tag as ProfileSwitch OKDialog.showConfirmation(activity, resourceHelper.gs(R.string.careportal_profileswitch), resourceHelper.gs(R.string.copytolocalprofile) + "\n" + profileSwitch.customizedName + "\n" + dateUtil.dateAndTimeString(profileSwitch.date), Runnable { profileSwitch.profileObject?.let { - uel.log(Action.PROFILE_SWITCH_CLONED, ValueWithUnit(profileSwitch.date, Units.Timestamp), ValueWithUnit(profileSwitch.profileName, Units.None)) + uel.log(Action.PROFILE_SWITCH_CLONED, Sources.Treatments, + profileSwitch.customizedName + " " + dateUtil.dateAndTimeString(profileSwitch.date).replace(".", "_"), + ValueWithUnit.Timestamp(profileSwitch.date), + ValueWithUnit.SimpleString(profileSwitch.profileName)) val nonCustomized = it.convertToNonCustomizedProfile() if (nonCustomized.isValid(resourceHelper.gs(R.string.careportal_profileswitch, false))) { localProfilePlugin.addProfile(localProfilePlugin.copyFrom(nonCustomized, profileSwitch.customizedName + " " + dateUtil.dateAndTimeString(profileSwitch.date).replace(".", "_"))) diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/treatments/fragments/TreatmentsTempTargetFragment.kt b/app/src/main/java/info/nightscout/androidaps/plugins/treatments/fragments/TreatmentsTempTargetFragment.kt index 74fa9c95db..78ead608b6 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/treatments/fragments/TreatmentsTempTargetFragment.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/treatments/fragments/TreatmentsTempTargetFragment.kt @@ -13,8 +13,10 @@ import dagger.android.support.DaggerFragment import info.nightscout.androidaps.R import info.nightscout.androidaps.database.AppRepository import info.nightscout.androidaps.database.ValueWrapper +import info.nightscout.androidaps.database.entities.ValueWithUnit import info.nightscout.androidaps.database.entities.TemporaryTarget -import info.nightscout.androidaps.database.entities.UserEntry.* +import info.nightscout.androidaps.database.entities.UserEntry.Action +import info.nightscout.androidaps.database.entities.UserEntry.Sources import info.nightscout.androidaps.database.interfaces.end import info.nightscout.androidaps.database.transactions.InvalidateTemporaryTargetTransaction import info.nightscout.androidaps.databinding.TreatmentsTemptargetFragmentBinding @@ -26,7 +28,6 @@ import info.nightscout.androidaps.logging.AAPSLogger import info.nightscout.androidaps.logging.LTag import info.nightscout.androidaps.logging.UserEntryLogger import info.nightscout.androidaps.plugins.bus.RxBusWrapper -import info.nightscout.androidaps.plugins.general.nsclient.NSUpload import info.nightscout.androidaps.plugins.general.nsclient.events.EventNSClientRestart import info.nightscout.androidaps.plugins.treatments.events.EventTreatmentUpdateGui import info.nightscout.androidaps.plugins.treatments.fragments.TreatmentsTempTargetFragment.RecyclerViewAdapter.TempTargetsViewHolder @@ -36,10 +37,10 @@ import info.nightscout.androidaps.utils.T import info.nightscout.androidaps.utils.Translator import info.nightscout.androidaps.utils.alertDialogs.OKDialog import info.nightscout.androidaps.utils.buildHelper.BuildHelper -import info.nightscout.androidaps.utils.extensions.friendlyDescription -import info.nightscout.androidaps.utils.extensions.highValueToUnitsToString -import info.nightscout.androidaps.utils.extensions.lowValueToUnitsToString -import info.nightscout.androidaps.utils.extensions.toVisibility +import info.nightscout.androidaps.extensions.friendlyDescription +import info.nightscout.androidaps.extensions.highValueToUnitsToString +import info.nightscout.androidaps.extensions.lowValueToUnitsToString +import info.nightscout.androidaps.extensions.toVisibility import info.nightscout.androidaps.utils.resources.ResourceHelper import info.nightscout.androidaps.utils.rx.AapsSchedulers import info.nightscout.androidaps.utils.sharedPreferences.SP @@ -57,7 +58,6 @@ class TreatmentsTempTargetFragment : DaggerFragment() { @Inject lateinit var aapsLogger: AAPSLogger @Inject lateinit var profileFunction: ProfileFunction @Inject lateinit var resourceHelper: ResourceHelper - @Inject lateinit var nsUpload: NSUpload @Inject lateinit var uploadQueue: UploadQueueInterface @Inject lateinit var fabricPrivacy: FabricPrivacy @Inject lateinit var translator: Translator @@ -86,7 +86,7 @@ class TreatmentsTempTargetFragment : DaggerFragment() { binding.refreshFromNightscout.setOnClickListener { context?.let { context -> OKDialog.showConfirmation(context, resourceHelper.gs(R.string.refresheventsfromnightscout) + " ?", { - uel.log(Action.TT_NS_REFRESH) + uel.log(Action.TT_NS_REFRESH, Sources.Treatments) disposable += Completable.fromAction { repository.deleteAllTempTargetEntries() } .subscribeOn(aapsSchedulers.io) .observeOn(aapsSchedulers.main) @@ -151,9 +151,9 @@ class TreatmentsTempTargetFragment : DaggerFragment() { _binding = null } - inner class RecyclerViewAdapter internal constructor(private var tempTargetList: List) : RecyclerView.Adapter() { + private inner class RecyclerViewAdapter internal constructor(private var tempTargetList: List) : RecyclerView.Adapter() { - private val dbRecord = repository.getTemporaryTargetActiveAt(dateUtil._now()).blockingGet() + private val dbRecord = repository.getTemporaryTargetActiveAt(dateUtil.now()).blockingGet() private val currentlyActiveTarget = if (dbRecord is ValueWrapper.Existing) dbRecord.value else null override fun onCreateViewHolder(viewGroup: ViewGroup, viewType: Int): TempTargetsViewHolder = @@ -170,12 +170,12 @@ class TreatmentsTempTargetFragment : DaggerFragment() { holder.binding.duration.text = resourceHelper.gs(R.string.format_mins, T.msecs(tempTarget.duration).mins()) holder.binding.low.text = tempTarget.lowValueToUnitsToString(units) holder.binding.high.text = tempTarget.highValueToUnitsToString(units) - holder.binding.reason.text = translator.translate(tempTarget.reason.text) + holder.binding.reason.text = translator.translate(tempTarget.reason) holder.binding.date.setTextColor( when { - tempTarget.id == currentlyActiveTarget?.id -> resourceHelper.gc(R.color.colorActive) - tempTarget.timestamp > DateUtil.now() -> resourceHelper.gc(R.color.colorScheduled) - else -> holder.binding.reasonColon.currentTextColor + tempTarget.id == currentlyActiveTarget?.id -> resourceHelper.gc(R.color.colorActive) + tempTarget.timestamp > dateUtil.now() -> resourceHelper.gc(R.color.colorScheduled) + else -> holder.binding.reasonColon.currentTextColor }) holder.binding.remove.tag = tempTarget } @@ -196,15 +196,16 @@ class TreatmentsTempTargetFragment : DaggerFragment() { ${dateUtil.dateAndTimeString(tempTarget.timestamp)} """.trimIndent(), { _: DialogInterface?, _: Int -> - uel.log(Action.TT_REMOVED, ValueWithUnit(tempTarget.timestamp, Units.Timestamp), ValueWithUnit(tempTarget.reason.text, Units.TherapyEvent), ValueWithUnit(tempTarget.lowTarget, Units.Mg_Dl), ValueWithUnit(tempTarget.highTarget, Units.Mg_Dl, tempTarget.lowTarget != tempTarget.highTarget), ValueWithUnit(tempTarget.duration.toInt(), Units.M)) + uel.log(Action.TT_REMOVED, Sources.Treatments, + ValueWithUnit.Timestamp(tempTarget.timestamp), + ValueWithUnit.TherapyEventTTReason(tempTarget.reason), + ValueWithUnit.Mgdl(tempTarget.lowTarget), + ValueWithUnit.Mgdl(tempTarget.highTarget).takeIf { tempTarget.lowTarget != tempTarget.highTarget }, + ValueWithUnit.Minute(TimeUnit.MILLISECONDS.toMinutes(tempTarget.duration).toInt())) disposable += repository.runTransactionForResult(InvalidateTemporaryTargetTransaction(tempTarget.id)) - .subscribe({ - val id = tempTarget.interfaceIDs.nightscoutId - if (NSUpload.isIdValid(id)) nsUpload.removeCareportalEntryFromNS(id) - else uploadQueue.removeByMongoId("dbAdd", tempTarget.timestamp.toString()) - }, { - aapsLogger.error(LTag.BGSOURCE, "Error while invalidating temporary target", it) - }) + .subscribe( + { aapsLogger.debug(LTag.DATABASE, "Removed temp target $tempTarget") }, + { aapsLogger.error(LTag.DATABASE, "Error while invalidating temporary target", it) }) }, null) } } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/treatments/fragments/TreatmentsTemporaryBasalsFragment.kt b/app/src/main/java/info/nightscout/androidaps/plugins/treatments/fragments/TreatmentsTemporaryBasalsFragment.kt index 365c5ae4c2..d0ee9dcd5b 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/treatments/fragments/TreatmentsTemporaryBasalsFragment.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/treatments/fragments/TreatmentsTemporaryBasalsFragment.kt @@ -10,44 +10,60 @@ import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.RecyclerView import dagger.android.support.DaggerFragment import info.nightscout.androidaps.R -import info.nightscout.androidaps.data.Intervals import info.nightscout.androidaps.data.IobTotal +import info.nightscout.androidaps.database.AppRepository +import info.nightscout.androidaps.database.entities.TemporaryBasal import info.nightscout.androidaps.database.entities.UserEntry.* +import info.nightscout.androidaps.database.entities.UserEntry.Action +import info.nightscout.androidaps.database.entities.UserEntry.Sources +import info.nightscout.androidaps.database.entities.ValueWithUnit +import info.nightscout.androidaps.database.interfaces.end +import info.nightscout.androidaps.database.transactions.InvalidateTemporaryBasalTransaction import info.nightscout.androidaps.databinding.TreatmentsTempbasalsFragmentBinding import info.nightscout.androidaps.databinding.TreatmentsTempbasalsItemBinding -import info.nightscout.androidaps.db.Source -import info.nightscout.androidaps.db.TemporaryBasal +import info.nightscout.androidaps.events.EventAutosensCalculationFinished import info.nightscout.androidaps.events.EventTempBasalChange -import info.nightscout.androidaps.interfaces.ActivePluginProvider +import info.nightscout.androidaps.extensions.iobCalc +import info.nightscout.androidaps.extensions.toStringFull +import info.nightscout.androidaps.extensions.toTemporaryBasal +import info.nightscout.androidaps.extensions.toVisibility +import info.nightscout.androidaps.interfaces.ActivePlugin import info.nightscout.androidaps.interfaces.ProfileFunction +import info.nightscout.androidaps.logging.AAPSLogger +import info.nightscout.androidaps.logging.LTag import info.nightscout.androidaps.logging.UserEntryLogger import info.nightscout.androidaps.plugins.bus.RxBusWrapper -import info.nightscout.androidaps.plugins.general.nsclient.NSUpload -import info.nightscout.androidaps.events.EventAutosensCalculationFinished import info.nightscout.androidaps.plugins.treatments.fragments.TreatmentsTemporaryBasalsFragment.RecyclerViewAdapter.TempBasalsViewHolder import info.nightscout.androidaps.utils.DateUtil import info.nightscout.androidaps.utils.FabricPrivacy +import info.nightscout.androidaps.utils.T import info.nightscout.androidaps.utils.alertDialogs.OKDialog import info.nightscout.androidaps.utils.resources.ResourceHelper import info.nightscout.androidaps.utils.rx.AapsSchedulers import io.reactivex.disposables.CompositeDisposable +import io.reactivex.rxkotlin.plusAssign import javax.inject.Inject +import kotlin.math.abs class TreatmentsTemporaryBasalsFragment : DaggerFragment() { private val disposable = CompositeDisposable() + @Inject lateinit var aapsLogger: AAPSLogger @Inject lateinit var rxBus: RxBusWrapper @Inject lateinit var resourceHelper: ResourceHelper @Inject lateinit var fabricPrivacy: FabricPrivacy - @Inject lateinit var activePlugin: ActivePluginProvider + @Inject lateinit var activePlugin: ActivePlugin @Inject lateinit var profileFunction: ProfileFunction @Inject lateinit var dateUtil: DateUtil @Inject lateinit var aapsSchedulers: AapsSchedulers @Inject lateinit var uel: UserEntryLogger + @Inject lateinit var repository: AppRepository private var _binding: TreatmentsTempbasalsFragmentBinding? = null + private val millsToThePast = T.days(30).msecs() + // This property is only valid between onCreateView and // onDestroyView. private val binding get() = _binding!! @@ -59,23 +75,67 @@ class TreatmentsTemporaryBasalsFragment : DaggerFragment() { super.onViewCreated(view, savedInstanceState) binding.recyclerview.setHasFixedSize(true) binding.recyclerview.layoutManager = LinearLayoutManager(view.context) - binding.recyclerview.adapter = RecyclerViewAdapter(activePlugin.activeTreatments.temporaryBasalsFromHistory) + } + + private fun tempBasalsWithInvalid(now: Long) = repository + .getTemporaryBasalsDataIncludingInvalidFromTime(now - millsToThePast, false) + + private fun tempBasals(now: Long) = repository + .getTemporaryBasalsDataFromTime(now - millsToThePast, false) + + private fun extendedBolusesWithInvalid(now: Long) = repository + .getExtendedBolusDataIncludingInvalidFromTime(now - millsToThePast, false) + .map { eb -> eb.map { profileFunction.getProfile(it.timestamp)?.let { profile -> it.toTemporaryBasal(profile) } } } + + private fun extendedBoluses(now: Long) = repository + .getExtendedBolusDataFromTime(now - millsToThePast, false) + .map { eb -> eb.map { profileFunction.getProfile(it.timestamp)?.let { profile -> it.toTemporaryBasal(profile) } } } + + fun swapAdapter() { + val now = System.currentTimeMillis() + disposable += + if (activePlugin.activePump.isFakingTempsByExtendedBoluses) { + if (binding.showInvalidated.isChecked) + tempBasalsWithInvalid(now) + .zipWith(extendedBolusesWithInvalid(now)) { first, second -> first + second } + .map { list -> list.filterNotNull() } + .map { list -> list.sortedByDescending { it.timestamp } } + .observeOn(aapsSchedulers.main) + .subscribe { list -> binding.recyclerview.swapAdapter(RecyclerViewAdapter(list), true) } + else + tempBasals(now) + .zipWith(extendedBoluses(now)) { first, second -> first + second } + .map { list -> list.filterNotNull() } + .map { list -> list.sortedByDescending { it.timestamp } } + .observeOn(aapsSchedulers.main) + .subscribe { list -> binding.recyclerview.swapAdapter(RecyclerViewAdapter(list), true) } + } else { + if (binding.showInvalidated.isChecked) + tempBasalsWithInvalid(now) + .observeOn(aapsSchedulers.main) + .subscribe { list -> binding.recyclerview.swapAdapter(RecyclerViewAdapter(list), true) } + else + tempBasals(now) + .observeOn(aapsSchedulers.main) + .subscribe { list -> binding.recyclerview.swapAdapter(RecyclerViewAdapter(list), true) } + } + } @Synchronized override fun onResume() { super.onResume() - disposable.add(rxBus + swapAdapter() + + disposable += rxBus .toObservable(EventTempBasalChange::class.java) .observeOn(aapsSchedulers.main) - .subscribe({ updateGui() }, fabricPrivacy::logException) - ) - disposable.add(rxBus + .subscribe({ swapAdapter() }, fabricPrivacy::logException) + + disposable += rxBus .toObservable(EventAutosensCalculationFinished::class.java) .observeOn(aapsSchedulers.main) - .subscribe({ updateGui() }, fabricPrivacy::logException) - ) - updateGui() + .subscribe({ swapAdapter() }, fabricPrivacy::logException) } @Synchronized @@ -87,69 +147,46 @@ class TreatmentsTemporaryBasalsFragment : DaggerFragment() { @Synchronized override fun onDestroyView() { super.onDestroyView() + binding.recyclerview.adapter = null // avoid leaks _binding = null } - inner class RecyclerViewAdapter internal constructor(private var tempBasalList: Intervals) : RecyclerView.Adapter() { + inner class RecyclerViewAdapter internal constructor(private var tempBasalList: List) : RecyclerView.Adapter() { override fun onCreateViewHolder(viewGroup: ViewGroup, viewType: Int): TempBasalsViewHolder = TempBasalsViewHolder(LayoutInflater.from(viewGroup.context).inflate(R.layout.treatments_tempbasals_item, viewGroup, false)) override fun onBindViewHolder(holder: TempBasalsViewHolder, position: Int) { - val tempBasal = tempBasalList.getReversed(position) - holder.binding.ph.visibility = if (tempBasal.source == Source.PUMP) View.VISIBLE else View.GONE - holder.binding.ns.visibility = if (NSUpload.isIdValid(tempBasal._id)) View.VISIBLE else View.GONE - if (tempBasal.isEndingEvent) { - holder.binding.date.text = dateUtil.dateAndTimeString(tempBasal.date) - holder.binding.duration.text = resourceHelper.gs(R.string.cancel) - holder.binding.absolute.text = "" - holder.binding.percent.text = "" - holder.binding.realDuration.text = "" - holder.binding.iob.text = "" - holder.binding.netInsulin.text = "" - holder.binding.netRatio.text = "" - holder.binding.extendedFlag.visibility = View.GONE - holder.binding.iob.setTextColor(holder.binding.netRatio.currentTextColor) + val tempBasal = tempBasalList[position] + holder.binding.ns.visibility = (tempBasal.interfaceIDs.nightscoutId != null).toVisibility() + holder.binding.invalid.visibility = tempBasal.isValid.not().toVisibility() + holder.binding.ph.visibility = (tempBasal.interfaceIDs.pumpId != null).toVisibility() + if (tempBasal.isInProgress) { + holder.binding.date.text = dateUtil.dateAndTimeString(tempBasal.timestamp) + holder.binding.date.setTextColor(resourceHelper.gc(R.color.colorActive)) } else { - if (tempBasal.isInProgress) { - holder.binding.date.text = dateUtil.dateAndTimeString(tempBasal.date) - holder.binding.date.setTextColor(resourceHelper.gc(R.color.colorActive)) - } else { - holder.binding.date.text = dateUtil.dateAndTimeRangeString(tempBasal.date, tempBasal.end()) - holder.binding.date.setTextColor(holder.binding.netRatio.currentTextColor) - } - holder.binding.duration.text = resourceHelper.gs(R.string.format_mins, tempBasal.durationInMinutes) - if (tempBasal.isAbsolute) { - val profile = profileFunction.getProfile(tempBasal.date) - if (profile != null) { - holder.binding.absolute.text = resourceHelper.gs(R.string.pump_basebasalrate, tempBasal.tempBasalConvertedToAbsolute(tempBasal.date, profile)) - holder.binding.percent.text = "" - } else { - holder.binding.absolute.text = resourceHelper.gs(R.string.noprofile) - holder.binding.percent.text = "" - } - } else { - holder.binding.absolute.text = "" - holder.binding.percent.text = resourceHelper.gs(R.string.format_percent, tempBasal.percentRate) - } - holder.binding.realDuration.text = resourceHelper.gs(R.string.format_mins, tempBasal.realDuration) - val now = DateUtil.now() - var iob = IobTotal(now) - val profile = profileFunction.getProfile(now) - if (profile != null) iob = tempBasal.iobCalc(now, profile) - holder.binding.iob.text = resourceHelper.gs(R.string.formatinsulinunits, iob.basaliob) - holder.binding.netInsulin.text = resourceHelper.gs(R.string.formatinsulinunits, iob.netInsulin) - holder.binding.netRatio.text = resourceHelper.gs(R.string.pump_basebasalrate, iob.netRatio) - holder.binding.extendedFlag.visibility = View.GONE - if (iob.basaliob != 0.0) holder.binding.iob.setTextColor(resourceHelper.gc(R.color.colorActive)) else holder.binding.iob.setTextColor(holder.binding.netRatio.currentTextColor) + holder.binding.date.text = dateUtil.dateAndTimeRangeString(tempBasal.timestamp, tempBasal.end) + holder.binding.date.setTextColor(holder.binding.duration.currentTextColor) } + holder.binding.duration.text = resourceHelper.gs(R.string.format_mins, T.msecs(tempBasal.duration).mins()) + if (tempBasal.isAbsolute) holder.binding.rate.text = resourceHelper.gs(R.string.pump_basebasalrate, tempBasal.rate) + else holder.binding.rate.text = resourceHelper.gs(R.string.format_percent, tempBasal.rate.toInt()) + val now = dateUtil.now() + var iob = IobTotal(now) + val profile = profileFunction.getProfile(now) + if (profile != null) iob = tempBasal.iobCalc(now, profile, activePlugin.activeInsulin) + holder.binding.iob.text = resourceHelper.gs(R.string.formatinsulinunits, iob.basaliob) + holder.binding.extendedFlag.visibility = (tempBasal.type == TemporaryBasal.Type.FAKE_EXTENDED).toVisibility() + holder.binding.suspendFlag.visibility = (tempBasal.type == TemporaryBasal.Type.PUMP_SUSPEND).toVisibility() + holder.binding.emulatedSuspendFlag.visibility = (tempBasal.type == TemporaryBasal.Type.EMULATED_PUMP_SUSPEND).toVisibility() + holder.binding.superBolusFlag.visibility = (tempBasal.type == TemporaryBasal.Type.SUPERBOLUS).toVisibility() + if (abs(iob.basaliob) > 0.01) holder.binding.iob.setTextColor(resourceHelper.gc(R.color.colorActive)) else holder.binding.iob.setTextColor(holder.binding.duration.currentTextColor) holder.binding.remove.tag = tempBasal } - override fun getItemCount(): Int { - return tempBasalList.size() - } + override fun getItemCount(): Int = tempBasalList.size + @Deprecated("remove remove functionality after finish") inner class TempBasalsViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { val binding = TreatmentsTempbasalsItemBinding.bind(itemView) @@ -157,15 +194,21 @@ class TreatmentsTemporaryBasalsFragment : DaggerFragment() { init { binding.remove.setOnClickListener { v: View -> val tempBasal = v.tag as TemporaryBasal + val profile = profileFunction.getProfile(dateUtil.now()) + ?: return@setOnClickListener context?.let { OKDialog.showConfirmation(it, resourceHelper.gs(R.string.removerecord), """ - ${resourceHelper.gs(R.string.tempbasal_label)}: ${tempBasal.toStringFull()} - ${resourceHelper.gs(R.string.date)}: ${dateUtil.dateAndTimeString(tempBasal.date)} + ${resourceHelper.gs(R.string.tempbasal_label)}: ${tempBasal.toStringFull(profile, dateUtil)} + ${resourceHelper.gs(R.string.date)}: ${dateUtil.dateAndTimeString(tempBasal.timestamp)} """.trimIndent(), { _: DialogInterface?, _: Int -> - uel.log(Action.TT_REMOVED, ValueWithUnit(tempBasal.date, Units.Timestamp)) - activePlugin.activeTreatments.removeTempBasal(tempBasal) + uel.log(Action.TEMP_BASAL_REMOVED, Sources.Treatments, + ValueWithUnit.Timestamp(tempBasal.timestamp)) + disposable += repository.runTransactionForResult(InvalidateTemporaryBasalTransaction(tempBasal.id)) + .subscribe( + { aapsLogger.debug(LTag.DATABASE, "Removed temporary basal $tempBasal") }, + { aapsLogger.error(LTag.DATABASE, "Error while invalidating temporary basal", it) }) }, null) } } @@ -174,11 +217,4 @@ class TreatmentsTemporaryBasalsFragment : DaggerFragment() { } } - - private fun updateGui() { - if (_binding == null) return - binding.recyclerview.swapAdapter(RecyclerViewAdapter(activePlugin.activeTreatments.temporaryBasalsFromHistory), false) - val tempBasalsCalculation = activePlugin.activeTreatments.lastCalculationTempBasals - if (tempBasalsCalculation != null) binding.totalTempIob.text = resourceHelper.gs(R.string.formatinsulinunits, tempBasalsCalculation.basaliob) - } } \ No newline at end of file diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/treatments/fragments/TreatmentsUserEntryFragment.kt b/app/src/main/java/info/nightscout/androidaps/plugins/treatments/fragments/TreatmentsUserEntryFragment.kt index 5a7c6432f1..9bbc46d63b 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/treatments/fragments/TreatmentsUserEntryFragment.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/treatments/fragments/TreatmentsUserEntryFragment.kt @@ -7,27 +7,29 @@ import android.view.ViewGroup import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.RecyclerView import dagger.android.support.DaggerFragment -import info.nightscout.androidaps.Constants import info.nightscout.androidaps.R import info.nightscout.androidaps.database.AppRepository import info.nightscout.androidaps.database.entities.UserEntry -import info.nightscout.androidaps.database.entities.UserEntry.* +import info.nightscout.androidaps.database.entities.UserEntry.Action +import info.nightscout.androidaps.database.entities.UserEntry.Sources import info.nightscout.androidaps.databinding.TreatmentsUserEntryFragmentBinding import info.nightscout.androidaps.databinding.TreatmentsUserEntryItemBinding import info.nightscout.androidaps.events.EventPreferenceChange -import info.nightscout.androidaps.interfaces.ImportExportPrefsInterface +import info.nightscout.androidaps.interfaces.ImportExportPrefs import info.nightscout.androidaps.interfaces.ProfileFunction import info.nightscout.androidaps.logging.UserEntryLogger import info.nightscout.androidaps.plugins.bus.RxBusWrapper +import info.nightscout.androidaps.plugins.treatments.events.EventTreatmentUpdateGui import info.nightscout.androidaps.utils.DateUtil -import info.nightscout.androidaps.utils.DecimalFormatter import info.nightscout.androidaps.utils.FabricPrivacy +import info.nightscout.androidaps.utils.T import info.nightscout.androidaps.utils.Translator +import info.nightscout.androidaps.utils.userEntry.UserEntryPresentationHelper import info.nightscout.androidaps.utils.alertDialogs.OKDialog -import info.nightscout.androidaps.utils.extensions.* import info.nightscout.androidaps.utils.resources.ResourceHelper import info.nightscout.androidaps.utils.rx.AapsSchedulers import io.reactivex.disposables.CompositeDisposable +import java.util.concurrent.TimeUnit import javax.inject.Inject class TreatmentsUserEntryFragment : DaggerFragment() { @@ -40,11 +42,15 @@ class TreatmentsUserEntryFragment : DaggerFragment() { @Inject lateinit var fabricPrivacy: FabricPrivacy @Inject lateinit var rxBus: RxBusWrapper @Inject lateinit var translator: Translator - @Inject lateinit var importExportPrefs: ImportExportPrefsInterface + @Inject lateinit var importExportPrefs: ImportExportPrefs @Inject lateinit var uel: UserEntryLogger + @Inject lateinit var userEntryPresentationHelper: UserEntryPresentationHelper private val disposable = CompositeDisposable() + private val millsToThePastFiltered = T.days(30).msecs() + private val millsToThePastUnFiltered = T.days(3).msecs() + private var _binding: TreatmentsUserEntryFragmentBinding? = null // This property is only valid between onCreateView and @@ -61,20 +67,30 @@ class TreatmentsUserEntryFragment : DaggerFragment() { binding.ueExportToXml.setOnClickListener { activity?.let { activity -> OKDialog.showConfirmation(activity, resourceHelper.gs(R.string.ue_export_to_csv) + "?") { - uel.log(Action.EXPORT_CSV) + uel.log(Action.EXPORT_CSV, Sources.Treatments) importExportPrefs.exportUserEntriesCsv(activity, repository.getAllUserEntries()) } } } - + binding.showLoop.setOnCheckedChangeListener { _, _ -> + rxBus.send(EventTreatmentUpdateGui()) + } } fun swapAdapter() { - disposable.add( repository - .getAllUserEntries() - .observeOn(aapsSchedulers.main) - .subscribe { list -> binding.recyclerview.swapAdapter(UserEntryAdapter(list), true) } - ) + val now = System.currentTimeMillis() + if (binding.showLoop.isChecked) + disposable.add( repository + .getUserEntryDataFromTime(now - millsToThePastUnFiltered) + .observeOn(aapsSchedulers.main) + .subscribe { list -> binding.recyclerview.swapAdapter(UserEntryAdapter(list), true) } + ) + else + disposable.add( repository + .getUserEntryFilteredDataFromTime(now - millsToThePastFiltered) + .observeOn(aapsSchedulers.main) + .subscribe { list -> binding.recyclerview.swapAdapter(UserEntryAdapter(list), true) } + ) } @Synchronized @@ -86,6 +102,11 @@ class TreatmentsUserEntryFragment : DaggerFragment() { .toObservable(EventPreferenceChange::class.java) .observeOn(aapsSchedulers.io) .subscribe({ swapAdapter() }, fabricPrivacy::logException)) + disposable.add(rxBus + .toObservable(EventTreatmentUpdateGui::class.java) + .observeOn(aapsSchedulers.io) + .debounce(1L, TimeUnit.SECONDS) + .subscribe({ swapAdapter() }, fabricPrivacy::logException)) } @Synchronized @@ -111,44 +132,13 @@ class TreatmentsUserEntryFragment : DaggerFragment() { override fun onBindViewHolder(holder: UserEntryViewHolder, position: Int) { val current = entries[position] holder.binding.date.text = dateUtil.dateAndTimeAndSecondsString(current.timestamp) - holder.binding.action.text = translator.translate(current.action.name) - holder.binding.action.setTextColor(resourceHelper.gc(current.action.colorGroup.colorId())) - if (current.s != "") { - holder.binding.s.text = current.s - holder.binding.s.visibility = View.VISIBLE - } else - holder.binding.s.visibility = View.GONE - var valuesWithUnitString = "" - var rStringParam = 0 - val separator = " " - for(v in current.values) { - if (rStringParam >0) - rStringParam-- - else - when (v.unit) { - Units.Timestamp -> valuesWithUnitString += dateUtil.dateAndTimeAndSecondsString(v.lValue) + separator - Units.TherapyEvent -> valuesWithUnitString += translator.translate(v.sValue) + separator - Units.R_String -> { - rStringParam = v.lValue.toInt() - when (rStringParam) { // - 0 -> valuesWithUnitString += resourceHelper.gs(v.iValue) + separator - 1 -> valuesWithUnitString += resourceHelper.gs(v.iValue, current.values[current.values.indexOf(v)+1].value()) + separator - 2 -> valuesWithUnitString += resourceHelper.gs(v.iValue, current.values[current.values.indexOf(v)+1].value(), current.values[current.values.indexOf(v)+2].value()) + separator - 3 -> valuesWithUnitString += resourceHelper.gs(v.iValue, current.values[current.values.indexOf(v)+1].value(), current.values[current.values.indexOf(v)+2].value(), current.values[current.values.indexOf(v)+3].value()) + separator - 4 -> rStringParam = 0 - } - } - Units.Mg_Dl -> valuesWithUnitString += if (profileFunction.getUnits()==Constants.MGDL) DecimalFormatter.to0Decimal(v.dValue) + translator.translate(Units.Mg_Dl.name) + separator else DecimalFormatter.to1Decimal(v.dValue/Constants.MMOLL_TO_MGDL) + translator.translate(Units.Mmol_L.name) + separator - Units.Mmol_L -> valuesWithUnitString += if (profileFunction.getUnits()==Constants.MGDL) DecimalFormatter.to0Decimal(v.dValue*Constants.MMOLL_TO_MGDL) + translator.translate(Units.Mg_Dl.name) + separator else DecimalFormatter.to1Decimal(v.dValue) + translator.translate(Units.Mmol_L.name) + separator - Units.U_H, Units.U - -> valuesWithUnitString += DecimalFormatter.to2Decimal(v.dValue) + translator.translate(v.unit.name) + separator - Units.G, Units.M, Units.H, Units.Percent - -> valuesWithUnitString += v.iValue.toString() + translator.translate(v.unit.name) + separator - else -> valuesWithUnitString += if (v.iValue != 0 || v.sValue != "") { v.value().toString() + separator } else "" - } - } - holder.binding.values.text = valuesWithUnitString.trim() - holder.binding.values.visibility = if (current.values.size > 0) View.VISIBLE else View.GONE + holder.binding.action.text = userEntryPresentationHelper.actionToColoredString(current.action) + holder.binding.s.text = current.note + holder.binding.s.visibility = if (current.note != "") View.VISIBLE else View.GONE + holder.binding.iconSource.setImageResource(userEntryPresentationHelper.iconId(current.source)) + holder.binding.iconSource.visibility = View.VISIBLE + holder.binding.values.text = userEntryPresentationHelper.listToPresentationString(current.values) + holder.binding.values.visibility = if (holder.binding.values.text != "") View.VISIBLE else View.GONE } inner class UserEntryViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { @@ -157,6 +147,6 @@ class TreatmentsUserEntryFragment : DaggerFragment() { } override fun getItemCount(): Int = entries.size - } + } \ No newline at end of file diff --git a/app/src/main/java/info/nightscout/androidaps/queue/CommandQueue.kt b/app/src/main/java/info/nightscout/androidaps/queue/CommandQueue.kt index aeb00da0fa..3dc312fd79 100644 --- a/app/src/main/java/info/nightscout/androidaps/queue/CommandQueue.kt +++ b/app/src/main/java/info/nightscout/androidaps/queue/CommandQueue.kt @@ -13,14 +13,16 @@ import info.nightscout.androidaps.activities.ErrorHelperActivity import info.nightscout.androidaps.data.DetailedBolusInfo import info.nightscout.androidaps.data.Profile import info.nightscout.androidaps.data.PumpEnactResult +import info.nightscout.androidaps.database.AppRepository import info.nightscout.androidaps.dialogs.BolusProgressDialog import info.nightscout.androidaps.events.EventBolusRequested import info.nightscout.androidaps.events.EventNewBasalProfile import info.nightscout.androidaps.events.EventProfileNeedsUpdate -import info.nightscout.androidaps.interfaces.ActivePluginProvider +import info.nightscout.androidaps.interfaces.ActivePlugin import info.nightscout.androidaps.interfaces.CommandQueueProvider import info.nightscout.androidaps.interfaces.Constraint import info.nightscout.androidaps.interfaces.ProfileFunction +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 @@ -31,6 +33,7 @@ import info.nightscout.androidaps.plugins.general.overview.events.EventNewNotifi import info.nightscout.androidaps.plugins.general.overview.notifications.Notification import info.nightscout.androidaps.queue.commands.* import info.nightscout.androidaps.queue.commands.Command.CommandType +import info.nightscout.androidaps.utils.DateUtil import info.nightscout.androidaps.utils.FabricPrivacy import info.nightscout.androidaps.utils.HtmlHelper import info.nightscout.androidaps.utils.buildHelper.BuildHelper @@ -38,51 +41,12 @@ import info.nightscout.androidaps.utils.resources.ResourceHelper import info.nightscout.androidaps.utils.rx.AapsSchedulers import info.nightscout.androidaps.utils.sharedPreferences.SP import io.reactivex.disposables.CompositeDisposable +import io.reactivex.rxkotlin.plusAssign +import io.reactivex.rxkotlin.subscribeBy import java.util.* import javax.inject.Inject import javax.inject.Singleton -/** - * Created by mike on 08.11.2017. - * - * - * DATA FLOW: - * --------- - * - * - * (request) - > ConfigBuilder.getCommandQueue().bolus(...) - * - * - * app no longer waits for result but passes Callback - * - * - * request is added to queue, if another request of the same type already exists in queue, it's removed prior adding - * but if request of the same type is currently executed (probably important only for bolus which is running long time), new request is declined - * new QueueThread is created and started if current if finished - * CommandReadStatus is added automatically before command if queue is empty - * - * - * biggest change is we don't need exec pump commands in Handler because it's finished immediately - * command queueing if not realized by stacking in different Handlers and threads anymore but by internal queue with better control - * - * - * QueueThread calls ConfigBuilder#connect which is passed to getActivePump().connect - * connect should be executed on background and return immediately. afterwards isConnecting() is expected to be true - * - * - * while isConnecting() == true GUI is updated by posting connection progress - * - * - * if connect is successful: isConnected() becomes true, isConnecting() becomes false - * CommandQueue starts calling execute() of commands. execute() is expected to be blocking (return after finish). - * callback with result is called after finish automatically - * if connect failed: isConnected() becomes false, isConnecting() becomes false - * connect() is called again - * - * - * when queue is empty, disconnect is called - */ - @Singleton open class CommandQueue @Inject constructor( private val injector: HasAndroidInjector, @@ -92,10 +56,12 @@ open class CommandQueue @Inject constructor( private val resourceHelper: ResourceHelper, private val constraintChecker: ConstraintChecker, private val profileFunction: ProfileFunction, - private val activePlugin: Lazy, + private val activePlugin: Lazy, private val context: Context, private val sp: SP, private val buildHelper: BuildHelper, + private val dateUtil: DateUtil, + private val repository: AppRepository, private val fabricPrivacy: FabricPrivacy ) : CommandQueueProvider { @@ -209,7 +175,7 @@ open class CommandQueue @Inject constructor( override fun independentConnect(reason: String, callback: Callback?) { aapsLogger.debug(LTag.PUMPQUEUE, "Starting new queue") - val tempCommandQueue = CommandQueue(injector, aapsLogger, rxBus, aapsSchedulers, resourceHelper, constraintChecker, profileFunction, activePlugin, context, sp, buildHelper, fabricPrivacy) + val tempCommandQueue = CommandQueue(injector, aapsLogger, rxBus, aapsSchedulers, resourceHelper, constraintChecker, profileFunction, activePlugin, context, sp, buildHelper, dateUtil, repository, fabricPrivacy) tempCommandQueue.readStatus(reason, callback) } @@ -229,13 +195,40 @@ open class CommandQueue @Inject constructor( // returns true if command is queued @Synchronized override fun bolus(detailedBolusInfo: DetailedBolusInfo, callback: Callback?): Boolean { - var type = if (detailedBolusInfo.isSMB) CommandType.SMB_BOLUS else CommandType.BOLUS + // Check if pump store carbs + // If not, it's not necessary add command to the queue and initiate connection + // Assuming carbs in the future and carbs with duration are NOT stores anyway + if ((detailedBolusInfo.carbs > 0) && + (!activePlugin.get().activePump.pumpDescription.storesCarbInfo || + detailedBolusInfo.carbsDuration != 0L || + (detailedBolusInfo.carbsTimestamp ?: detailedBolusInfo.timestamp) > dateUtil.now()) + ) { + disposable += repository.runTransactionForResult(detailedBolusInfo.insertCarbsTransaction()) + .subscribeBy( + onSuccess = { result -> + result.inserted.forEach { aapsLogger.debug(LTag.DATABASE, "Inserted carbs $it") } + callback?.result(PumpEnactResult(injector).enacted(false).success(true))?.run() + + }, + onError = { + aapsLogger.error(LTag.DATABASE, "Error while saving carbs", it) + callback?.result(PumpEnactResult(injector).enacted(false).success(false))?.run() + } + ) + // Do not process carbs anymore + detailedBolusInfo.carbs = 0.0 + // if no insulin just exit + if (detailedBolusInfo.insulin == 0.0) return true + + } + var type = if (detailedBolusInfo.bolusType == DetailedBolusInfo.BolusType.SMB) CommandType.SMB_BOLUS else CommandType.BOLUS if (type == CommandType.SMB_BOLUS) { if (isRunning(CommandType.BOLUS) || isRunning(CommandType.SMB_BOLUS) || bolusInQueue()) { aapsLogger.debug(LTag.PUMPQUEUE, "Rejecting SMB since a bolus is queue/running") return false } - if (detailedBolusInfo.lastKnownBolusTime < activePlugin.get().activeTreatments.lastBolusTime) { + val lastBolusTime = repository.getLastBolusRecord()?.timestamp ?: 0L + if (detailedBolusInfo.lastKnownBolusTime < lastBolusTime) { aapsLogger.debug(LTag.PUMPQUEUE, "Rejecting bolus, another bolus was issued since request time") return false } @@ -256,7 +249,7 @@ open class CommandQueue @Inject constructor( detailedBolusInfo.insulin = constraintChecker.applyBolusConstraints(Constraint(detailedBolusInfo.insulin)).value() detailedBolusInfo.carbs = constraintChecker.applyCarbsConstraints(Constraint(detailedBolusInfo.carbs.toInt())).value().toDouble() // add new command to queue - if (detailedBolusInfo.isSMB) { + if (detailedBolusInfo.bolusType == DetailedBolusInfo.BolusType.SMB) { add(CommandSMBBolus(injector, detailedBolusInfo, callback)) } else { add(CommandBolus(injector, detailedBolusInfo, callback, type)) @@ -297,7 +290,7 @@ open class CommandQueue @Inject constructor( } // returns true if command is queued - override fun tempBasalAbsolute(absoluteRate: Double, durationInMinutes: Int, enforceNew: Boolean, profile: Profile, callback: Callback?): Boolean { + override fun tempBasalAbsolute(absoluteRate: Double, durationInMinutes: Int, enforceNew: Boolean, profile: Profile, tbrType: PumpSync.TemporaryBasalType, callback: Callback?): Boolean { if (!enforceNew && isRunning(CommandType.TEMPBASAL)) { callback?.result(executingNowError())?.run() return false @@ -306,13 +299,13 @@ open class CommandQueue @Inject constructor( removeAll(CommandType.TEMPBASAL) val rateAfterConstraints = constraintChecker.applyBasalConstraints(Constraint(absoluteRate), profile).value() // add new command to queue - add(CommandTempBasalAbsolute(injector, rateAfterConstraints, durationInMinutes, enforceNew, profile, callback)) + add(CommandTempBasalAbsolute(injector, rateAfterConstraints, durationInMinutes, enforceNew, profile, tbrType, callback)) notifyAboutNewCommand() return true } // returns true if command is queued - override fun tempBasalPercent(percent: Int, durationInMinutes: Int, enforceNew: Boolean, profile: Profile, callback: Callback?): Boolean { + override fun tempBasalPercent(percent: Int, durationInMinutes: Int, enforceNew: Boolean, profile: Profile, tbrType: PumpSync.TemporaryBasalType, callback: Callback?): Boolean { if (!enforceNew && isRunning(CommandType.TEMPBASAL)) { callback?.result(executingNowError())?.run() return false @@ -321,7 +314,7 @@ open class CommandQueue @Inject constructor( removeAll(CommandType.TEMPBASAL) val percentAfterConstraints = constraintChecker.applyBasalPercentConstraints(Constraint(percent), profile).value() // add new command to queue - add(CommandTempBasalPercent(injector, percentAfterConstraints, durationInMinutes, enforceNew, profile, callback)) + add(CommandTempBasalPercent(injector, percentAfterConstraints, durationInMinutes, enforceNew, profile, tbrType, callback)) notifyAboutNewCommand() return true } diff --git a/app/src/main/java/info/nightscout/androidaps/queue/QueueThread.kt b/app/src/main/java/info/nightscout/androidaps/queue/QueueThread.kt index c1b4fa7aa5..34b64b8501 100644 --- a/app/src/main/java/info/nightscout/androidaps/queue/QueueThread.kt +++ b/app/src/main/java/info/nightscout/androidaps/queue/QueueThread.kt @@ -7,7 +7,7 @@ import android.os.SystemClock import info.nightscout.androidaps.Constants import info.nightscout.androidaps.R import info.nightscout.androidaps.events.EventPumpStatusChanged -import info.nightscout.androidaps.interfaces.ActivePluginProvider +import info.nightscout.androidaps.interfaces.ActivePlugin import info.nightscout.androidaps.logging.AAPSLogger import info.nightscout.androidaps.logging.LTag import info.nightscout.androidaps.plugins.bus.RxBusWrapper @@ -22,7 +22,7 @@ class QueueThread internal constructor( context: Context, private val aapsLogger: AAPSLogger, private val rxBus: RxBusWrapper, - private val activePlugin: ActivePluginProvider, + private val activePlugin: ActivePlugin, private val resourceHelper: ResourceHelper, private val sp: SP ) : Thread() { diff --git a/app/src/main/java/info/nightscout/androidaps/queue/commands/CommandBolus.kt b/app/src/main/java/info/nightscout/androidaps/queue/commands/CommandBolus.kt index 084eb12609..e8d779634e 100644 --- a/app/src/main/java/info/nightscout/androidaps/queue/commands/CommandBolus.kt +++ b/app/src/main/java/info/nightscout/androidaps/queue/commands/CommandBolus.kt @@ -4,7 +4,7 @@ import dagger.android.HasAndroidInjector import info.nightscout.androidaps.R import info.nightscout.androidaps.data.DetailedBolusInfo import info.nightscout.androidaps.dialogs.BolusProgressDialog -import info.nightscout.androidaps.interfaces.ActivePluginProvider +import info.nightscout.androidaps.interfaces.ActivePlugin import info.nightscout.androidaps.logging.LTag import info.nightscout.androidaps.plugins.bus.RxBusWrapper import info.nightscout.androidaps.plugins.general.overview.events.EventDismissBolusProgressIfRunning @@ -19,7 +19,7 @@ class CommandBolus( ) : Command(injector, type, callback) { @Inject lateinit var rxBus: RxBusWrapper - @Inject lateinit var activePlugin: ActivePluginProvider + @Inject lateinit var activePlugin: ActivePlugin override fun execute() { val r = activePlugin.activePump.deliverTreatment(detailedBolusInfo) diff --git a/app/src/main/java/info/nightscout/androidaps/queue/commands/CommandCancelExtendedBolus.kt b/app/src/main/java/info/nightscout/androidaps/queue/commands/CommandCancelExtendedBolus.kt index 40f9dfb972..c15d0e7914 100644 --- a/app/src/main/java/info/nightscout/androidaps/queue/commands/CommandCancelExtendedBolus.kt +++ b/app/src/main/java/info/nightscout/androidaps/queue/commands/CommandCancelExtendedBolus.kt @@ -1,7 +1,7 @@ package info.nightscout.androidaps.queue.commands import dagger.android.HasAndroidInjector -import info.nightscout.androidaps.interfaces.ActivePluginProvider +import info.nightscout.androidaps.interfaces.ActivePlugin import info.nightscout.androidaps.logging.LTag import info.nightscout.androidaps.queue.Callback import javax.inject.Inject @@ -11,7 +11,7 @@ class CommandCancelExtendedBolus constructor( callback: Callback? ) : Command(injector, CommandType.EXTENDEDBOLUS, callback) { - @Inject lateinit var activePlugin: ActivePluginProvider + @Inject lateinit var activePlugin: ActivePlugin override fun execute() { val r = activePlugin.activePump.cancelExtendedBolus() diff --git a/app/src/main/java/info/nightscout/androidaps/queue/commands/CommandCancelTempBasal.kt b/app/src/main/java/info/nightscout/androidaps/queue/commands/CommandCancelTempBasal.kt index ff7182df9a..79835a9ecd 100644 --- a/app/src/main/java/info/nightscout/androidaps/queue/commands/CommandCancelTempBasal.kt +++ b/app/src/main/java/info/nightscout/androidaps/queue/commands/CommandCancelTempBasal.kt @@ -1,7 +1,7 @@ package info.nightscout.androidaps.queue.commands import dagger.android.HasAndroidInjector -import info.nightscout.androidaps.interfaces.ActivePluginProvider +import info.nightscout.androidaps.interfaces.ActivePlugin import info.nightscout.androidaps.logging.LTag import info.nightscout.androidaps.queue.Callback import javax.inject.Inject @@ -12,7 +12,7 @@ class CommandCancelTempBasal( callback: Callback? ) : Command(injector, CommandType.TEMPBASAL, callback) { - @Inject lateinit var activePlugin: ActivePluginProvider + @Inject lateinit var activePlugin: ActivePlugin override fun execute() { val r = activePlugin.activePump.cancelTempBasal(enforceNew) diff --git a/app/src/main/java/info/nightscout/androidaps/queue/commands/CommandCustomCommand.kt b/app/src/main/java/info/nightscout/androidaps/queue/commands/CommandCustomCommand.kt index f0df2754d3..e9f058ece9 100644 --- a/app/src/main/java/info/nightscout/androidaps/queue/commands/CommandCustomCommand.kt +++ b/app/src/main/java/info/nightscout/androidaps/queue/commands/CommandCustomCommand.kt @@ -1,7 +1,7 @@ package info.nightscout.androidaps.queue.commands import dagger.android.HasAndroidInjector -import info.nightscout.androidaps.interfaces.ActivePluginProvider +import info.nightscout.androidaps.interfaces.ActivePlugin import info.nightscout.androidaps.logging.LTag import info.nightscout.androidaps.queue.Callback import javax.inject.Inject @@ -12,7 +12,7 @@ class CommandCustomCommand( callback: Callback? ) : Command(injector, CommandType.CUSTOM_COMMAND, callback) { - @Inject lateinit var activePlugin: ActivePluginProvider + @Inject lateinit var activePlugin: ActivePlugin override fun execute() { val result = activePlugin.activePump.executeCustomCommand(customCommand) diff --git a/app/src/main/java/info/nightscout/androidaps/queue/commands/CommandExtendedBolus.kt b/app/src/main/java/info/nightscout/androidaps/queue/commands/CommandExtendedBolus.kt index 2e81520ee4..c1c67bfac4 100644 --- a/app/src/main/java/info/nightscout/androidaps/queue/commands/CommandExtendedBolus.kt +++ b/app/src/main/java/info/nightscout/androidaps/queue/commands/CommandExtendedBolus.kt @@ -1,7 +1,7 @@ package info.nightscout.androidaps.queue.commands import dagger.android.HasAndroidInjector -import info.nightscout.androidaps.interfaces.ActivePluginProvider +import info.nightscout.androidaps.interfaces.ActivePlugin import info.nightscout.androidaps.logging.LTag import info.nightscout.androidaps.queue.Callback import javax.inject.Inject @@ -13,7 +13,7 @@ class CommandExtendedBolus constructor( callback: Callback? ) : Command(injector, CommandType.EXTENDEDBOLUS, callback) { - @Inject lateinit var activePlugin: ActivePluginProvider + @Inject lateinit var activePlugin: ActivePlugin override fun execute() { val r = activePlugin.activePump.setExtendedBolus(insulin, durationInMinutes) diff --git a/app/src/main/java/info/nightscout/androidaps/queue/commands/CommandInsightSetTBROverNotification.kt b/app/src/main/java/info/nightscout/androidaps/queue/commands/CommandInsightSetTBROverNotification.kt index 7cf02fed74..ab8b8bd3e2 100644 --- a/app/src/main/java/info/nightscout/androidaps/queue/commands/CommandInsightSetTBROverNotification.kt +++ b/app/src/main/java/info/nightscout/androidaps/queue/commands/CommandInsightSetTBROverNotification.kt @@ -1,7 +1,7 @@ package info.nightscout.androidaps.queue.commands import dagger.android.HasAndroidInjector -import info.nightscout.androidaps.interfaces.ActivePluginProvider +import info.nightscout.androidaps.interfaces.ActivePlugin import info.nightscout.androidaps.plugins.pump.insight.LocalInsightPlugin import info.nightscout.androidaps.queue.Callback import javax.inject.Inject @@ -12,7 +12,7 @@ class CommandInsightSetTBROverNotification constructor( callback: Callback? ) : Command(injector, CommandType.INSIGHT_SET_TBR_OVER_ALARM, callback) { - @Inject lateinit var activePlugin: ActivePluginProvider + @Inject lateinit var activePlugin: ActivePlugin override fun execute() { val pump = activePlugin.activePump diff --git a/app/src/main/java/info/nightscout/androidaps/queue/commands/CommandLoadEvents.kt b/app/src/main/java/info/nightscout/androidaps/queue/commands/CommandLoadEvents.kt index 7f09441ecc..f959eff033 100644 --- a/app/src/main/java/info/nightscout/androidaps/queue/commands/CommandLoadEvents.kt +++ b/app/src/main/java/info/nightscout/androidaps/queue/commands/CommandLoadEvents.kt @@ -1,8 +1,8 @@ package info.nightscout.androidaps.queue.commands import dagger.android.HasAndroidInjector -import info.nightscout.androidaps.interfaces.ActivePluginProvider -import info.nightscout.androidaps.interfaces.DanaRInterface +import info.nightscout.androidaps.interfaces.ActivePlugin +import info.nightscout.androidaps.interfaces.Dana import info.nightscout.androidaps.logging.LTag import info.nightscout.androidaps.queue.Callback import javax.inject.Inject @@ -12,12 +12,12 @@ class CommandLoadEvents( callback: Callback? ) : Command(injector, CommandType.LOAD_EVENTS, callback) { - @Inject lateinit var activePlugin: ActivePluginProvider + @Inject lateinit var activePlugin: ActivePlugin override fun execute() { val pump = activePlugin.activePump - if (pump is DanaRInterface) { - val danaPump = pump as DanaRInterface + if (pump is Dana) { + val danaPump = pump as Dana val r = danaPump.loadEvents() aapsLogger.debug(LTag.PUMPQUEUE, "Result success: ${r.success} enacted: ${r.enacted}") callback?.result(r)?.run() diff --git a/app/src/main/java/info/nightscout/androidaps/queue/commands/CommandLoadHistory.kt b/app/src/main/java/info/nightscout/androidaps/queue/commands/CommandLoadHistory.kt index fb7f455ed4..431b4fe12e 100644 --- a/app/src/main/java/info/nightscout/androidaps/queue/commands/CommandLoadHistory.kt +++ b/app/src/main/java/info/nightscout/androidaps/queue/commands/CommandLoadHistory.kt @@ -1,8 +1,8 @@ package info.nightscout.androidaps.queue.commands import dagger.android.HasAndroidInjector -import info.nightscout.androidaps.interfaces.ActivePluginProvider -import info.nightscout.androidaps.interfaces.DanaRInterface +import info.nightscout.androidaps.interfaces.ActivePlugin +import info.nightscout.androidaps.interfaces.Dana import info.nightscout.androidaps.logging.LTag import info.nightscout.androidaps.queue.Callback import javax.inject.Inject @@ -13,12 +13,12 @@ class CommandLoadHistory( callback: Callback? ) : Command(injector, CommandType.LOAD_HISTORY, callback) { - @Inject lateinit var activePlugin: ActivePluginProvider + @Inject lateinit var activePlugin: ActivePlugin override fun execute() { val pump = activePlugin.activePump - if (pump is DanaRInterface) { - val danaPump = pump as DanaRInterface + if (pump is Dana) { + val danaPump = pump as Dana val r = danaPump.loadHistory(type) aapsLogger.debug(LTag.PUMPQUEUE, "Result success: " + r.success + " enacted: " + r.enacted) callback?.result(r)?.run() diff --git a/app/src/main/java/info/nightscout/androidaps/queue/commands/CommandLoadTDDs.kt b/app/src/main/java/info/nightscout/androidaps/queue/commands/CommandLoadTDDs.kt index 9bf4a1ab7d..a38ab32962 100644 --- a/app/src/main/java/info/nightscout/androidaps/queue/commands/CommandLoadTDDs.kt +++ b/app/src/main/java/info/nightscout/androidaps/queue/commands/CommandLoadTDDs.kt @@ -1,7 +1,7 @@ package info.nightscout.androidaps.queue.commands import dagger.android.HasAndroidInjector -import info.nightscout.androidaps.interfaces.ActivePluginProvider +import info.nightscout.androidaps.interfaces.ActivePlugin import info.nightscout.androidaps.logging.LTag import info.nightscout.androidaps.queue.Callback import javax.inject.Inject @@ -11,7 +11,7 @@ class CommandLoadTDDs( callback: Callback? ) : Command(injector, CommandType.LOAD_TDD, callback) { - @Inject lateinit var activePlugin: ActivePluginProvider + @Inject lateinit var activePlugin: ActivePlugin override fun execute() { val pump = activePlugin.activePump diff --git a/app/src/main/java/info/nightscout/androidaps/queue/commands/CommandReadStatus.kt b/app/src/main/java/info/nightscout/androidaps/queue/commands/CommandReadStatus.kt index 052ad8a515..096178b06e 100644 --- a/app/src/main/java/info/nightscout/androidaps/queue/commands/CommandReadStatus.kt +++ b/app/src/main/java/info/nightscout/androidaps/queue/commands/CommandReadStatus.kt @@ -2,7 +2,7 @@ package info.nightscout.androidaps.queue.commands import dagger.android.HasAndroidInjector import info.nightscout.androidaps.data.PumpEnactResult -import info.nightscout.androidaps.interfaces.ActivePluginProvider +import info.nightscout.androidaps.interfaces.ActivePlugin import info.nightscout.androidaps.logging.LTag import info.nightscout.androidaps.queue.Callback import info.nightscout.androidaps.utils.LocalAlertUtils @@ -15,7 +15,7 @@ class CommandReadStatus( callback: Callback? ) : Command(injector, CommandType.READSTATUS, callback) { - @Inject lateinit var activePlugin: ActivePluginProvider + @Inject lateinit var activePlugin: ActivePlugin @Inject lateinit var localAlertUtils: LocalAlertUtils override fun execute() { diff --git a/app/src/main/java/info/nightscout/androidaps/queue/commands/CommandSMBBolus.kt b/app/src/main/java/info/nightscout/androidaps/queue/commands/CommandSMBBolus.kt index f18ae1db9f..d43493059b 100644 --- a/app/src/main/java/info/nightscout/androidaps/queue/commands/CommandSMBBolus.kt +++ b/app/src/main/java/info/nightscout/androidaps/queue/commands/CommandSMBBolus.kt @@ -4,7 +4,7 @@ import dagger.android.HasAndroidInjector import info.nightscout.androidaps.R import info.nightscout.androidaps.data.DetailedBolusInfo import info.nightscout.androidaps.data.PumpEnactResult -import info.nightscout.androidaps.interfaces.ActivePluginProvider +import info.nightscout.androidaps.interfaces.ActivePlugin import info.nightscout.androidaps.logging.LTag import info.nightscout.androidaps.queue.Callback import info.nightscout.androidaps.utils.DateUtil @@ -18,19 +18,19 @@ class CommandSMBBolus( ) : Command(injector, CommandType.SMB_BOLUS, callback) { @Inject lateinit var dateUtil: DateUtil - @Inject lateinit var activePlugin: ActivePluginProvider + @Inject lateinit var activePlugin: ActivePlugin override fun execute() { val r: PumpEnactResult - val lastBolusTime = activePlugin.activeTreatments.lastBolusTime - if (lastBolusTime != 0L && lastBolusTime + T.mins(3).msecs() > DateUtil.now()) { + val lastBolusTime = repository.getLastBolusRecord()?.timestamp ?: 0L + if (lastBolusTime != 0L && lastBolusTime + T.mins(3).msecs() > dateUtil.now()) { aapsLogger.debug(LTag.PUMPQUEUE, "SMB requested but still in 3 min interval") r = PumpEnactResult(injector).enacted(false).success(false).comment("SMB requested but still in 3 min interval") - } else if (detailedBolusInfo.deliverAt != 0L && detailedBolusInfo.deliverAt + T.mins(1).msecs() > System.currentTimeMillis()) { + } else if (detailedBolusInfo.deliverAtTheLatest != 0L && detailedBolusInfo.deliverAtTheLatest + T.mins(1).msecs() > System.currentTimeMillis()) { r = activePlugin.activePump.deliverTreatment(detailedBolusInfo) } else { r = PumpEnactResult(injector).enacted(false).success(false).comment("SMB request too old") - aapsLogger.debug(LTag.PUMPQUEUE, "SMB bolus canceled. deliverAt: " + dateUtil.dateAndTimeString(detailedBolusInfo.deliverAt)) + aapsLogger.debug(LTag.PUMPQUEUE, "SMB bolus canceled. deliverAt: " + dateUtil.dateAndTimeString(detailedBolusInfo.deliverAtTheLatest)) } aapsLogger.debug(LTag.PUMPQUEUE, "Result success: ${r.success} enacted: ${r.enacted}") callback?.result(r)?.run() diff --git a/app/src/main/java/info/nightscout/androidaps/queue/commands/CommandSetProfile.kt b/app/src/main/java/info/nightscout/androidaps/queue/commands/CommandSetProfile.kt index 89521346fe..d7798782ab 100644 --- a/app/src/main/java/info/nightscout/androidaps/queue/commands/CommandSetProfile.kt +++ b/app/src/main/java/info/nightscout/androidaps/queue/commands/CommandSetProfile.kt @@ -5,7 +5,7 @@ import info.nightscout.androidaps.R import info.nightscout.androidaps.data.Profile import info.nightscout.androidaps.data.PumpEnactResult import info.nightscout.androidaps.db.Source -import info.nightscout.androidaps.interfaces.ActivePluginProvider +import info.nightscout.androidaps.interfaces.ActivePlugin import info.nightscout.androidaps.interfaces.CommandQueueProvider import info.nightscout.androidaps.interfaces.PluginType import info.nightscout.androidaps.logging.LTag @@ -20,7 +20,7 @@ class CommandSetProfile constructor( ) : Command(injector, CommandType.BASAL_PROFILE, callback) { @Inject lateinit var smsCommunicatorPlugin: SmsCommunicatorPlugin - @Inject lateinit var activePlugin: ActivePluginProvider + @Inject lateinit var activePlugin: ActivePlugin @Inject lateinit var commandQueue: CommandQueueProvider override fun execute() { diff --git a/app/src/main/java/info/nightscout/androidaps/queue/commands/CommandSetUserSettings.kt b/app/src/main/java/info/nightscout/androidaps/queue/commands/CommandSetUserSettings.kt index c63d32fc1c..abefe7e00e 100644 --- a/app/src/main/java/info/nightscout/androidaps/queue/commands/CommandSetUserSettings.kt +++ b/app/src/main/java/info/nightscout/androidaps/queue/commands/CommandSetUserSettings.kt @@ -1,8 +1,8 @@ package info.nightscout.androidaps.queue.commands import dagger.android.HasAndroidInjector -import info.nightscout.androidaps.interfaces.ActivePluginProvider -import info.nightscout.androidaps.interfaces.DanaRInterface +import info.nightscout.androidaps.interfaces.ActivePlugin +import info.nightscout.androidaps.interfaces.Dana import info.nightscout.androidaps.logging.LTag import info.nightscout.androidaps.queue.Callback import javax.inject.Inject @@ -12,11 +12,11 @@ class CommandSetUserSettings( callback: Callback? ) : Command(injector, CommandType.SET_USER_SETTINGS, callback) { - @Inject lateinit var activePlugin: ActivePluginProvider + @Inject lateinit var activePlugin: ActivePlugin override fun execute() { val pump = activePlugin.activePump - if (pump is DanaRInterface) { + if (pump is Dana) { val r = pump.setUserOptions() aapsLogger.debug(LTag.PUMPQUEUE, "Result success: ${r.success} enacted: ${r.enacted}") callback?.result(r)?.run() diff --git a/app/src/main/java/info/nightscout/androidaps/queue/commands/CommandStartPump.kt b/app/src/main/java/info/nightscout/androidaps/queue/commands/CommandStartPump.kt index da911775bf..8987208bab 100644 --- a/app/src/main/java/info/nightscout/androidaps/queue/commands/CommandStartPump.kt +++ b/app/src/main/java/info/nightscout/androidaps/queue/commands/CommandStartPump.kt @@ -1,7 +1,7 @@ package info.nightscout.androidaps.queue.commands import dagger.android.HasAndroidInjector -import info.nightscout.androidaps.interfaces.ActivePluginProvider +import info.nightscout.androidaps.interfaces.ActivePlugin import info.nightscout.androidaps.plugins.pump.insight.LocalInsightPlugin import info.nightscout.androidaps.queue.Callback import javax.inject.Inject @@ -11,7 +11,7 @@ class CommandStartPump( callback: Callback? ) : Command(injector, CommandType.START_PUMP, callback) { - @Inject lateinit var activePlugin: ActivePluginProvider + @Inject lateinit var activePlugin: ActivePlugin override fun execute() { val pump = activePlugin.activePump diff --git a/app/src/main/java/info/nightscout/androidaps/queue/commands/CommandStopPump.kt b/app/src/main/java/info/nightscout/androidaps/queue/commands/CommandStopPump.kt index 1f0390e97f..894573f435 100644 --- a/app/src/main/java/info/nightscout/androidaps/queue/commands/CommandStopPump.kt +++ b/app/src/main/java/info/nightscout/androidaps/queue/commands/CommandStopPump.kt @@ -1,7 +1,7 @@ package info.nightscout.androidaps.queue.commands import dagger.android.HasAndroidInjector -import info.nightscout.androidaps.interfaces.ActivePluginProvider +import info.nightscout.androidaps.interfaces.ActivePlugin import info.nightscout.androidaps.plugins.pump.insight.LocalInsightPlugin import info.nightscout.androidaps.queue.Callback import javax.inject.Inject @@ -11,7 +11,7 @@ class CommandStopPump( callback: Callback? ) : Command(injector, CommandType.STOP_PUMP, callback) { - @Inject lateinit var activePlugin: ActivePluginProvider + @Inject lateinit var activePlugin: ActivePlugin override fun execute() { val pump = activePlugin.activePump diff --git a/app/src/main/java/info/nightscout/androidaps/queue/commands/CommandTempBasalAbsolute.kt b/app/src/main/java/info/nightscout/androidaps/queue/commands/CommandTempBasalAbsolute.kt index 488aa3bb7f..316acb74bc 100644 --- a/app/src/main/java/info/nightscout/androidaps/queue/commands/CommandTempBasalAbsolute.kt +++ b/app/src/main/java/info/nightscout/androidaps/queue/commands/CommandTempBasalAbsolute.kt @@ -2,7 +2,8 @@ package info.nightscout.androidaps.queue.commands import dagger.android.HasAndroidInjector import info.nightscout.androidaps.data.Profile -import info.nightscout.androidaps.interfaces.ActivePluginProvider +import info.nightscout.androidaps.interfaces.ActivePlugin +import info.nightscout.androidaps.interfaces.PumpSync import info.nightscout.androidaps.logging.LTag import info.nightscout.androidaps.queue.Callback import javax.inject.Inject @@ -13,13 +14,14 @@ class CommandTempBasalAbsolute( private val durationInMinutes: Int, private val enforceNew: Boolean, private val profile: Profile, + private val tbrType: PumpSync.TemporaryBasalType, callback: Callback? ) : Command(injector, CommandType.TEMPBASAL, callback) { - @Inject lateinit var activePlugin: ActivePluginProvider + @Inject lateinit var activePlugin: ActivePlugin override fun execute() { - val r = activePlugin.activePump.setTempBasalAbsolute(absoluteRate, durationInMinutes, profile, enforceNew) + val r = activePlugin.activePump.setTempBasalAbsolute(absoluteRate, durationInMinutes, profile, enforceNew, tbrType) aapsLogger.debug(LTag.PUMPQUEUE, "Result rate: $absoluteRate durationInMinutes: $durationInMinutes success: ${r.success} enacted: ${r.enacted}") callback?.result(r)?.run() } diff --git a/app/src/main/java/info/nightscout/androidaps/queue/commands/CommandTempBasalPercent.kt b/app/src/main/java/info/nightscout/androidaps/queue/commands/CommandTempBasalPercent.kt index 8bfdbb73b7..215886b35a 100644 --- a/app/src/main/java/info/nightscout/androidaps/queue/commands/CommandTempBasalPercent.kt +++ b/app/src/main/java/info/nightscout/androidaps/queue/commands/CommandTempBasalPercent.kt @@ -2,7 +2,8 @@ package info.nightscout.androidaps.queue.commands import dagger.android.HasAndroidInjector import info.nightscout.androidaps.data.Profile -import info.nightscout.androidaps.interfaces.ActivePluginProvider +import info.nightscout.androidaps.interfaces.ActivePlugin +import info.nightscout.androidaps.interfaces.PumpSync import info.nightscout.androidaps.logging.LTag import info.nightscout.androidaps.queue.Callback import javax.inject.Inject @@ -13,13 +14,14 @@ class CommandTempBasalPercent( private val durationInMinutes: Int, private val enforceNew: Boolean, private val profile: Profile, + private val tbrType: PumpSync.TemporaryBasalType, callback: Callback? ) : Command(injector, CommandType.TEMPBASAL, callback) { - @Inject lateinit var activePlugin: ActivePluginProvider + @Inject lateinit var activePlugin: ActivePlugin override fun execute() { - val r = activePlugin.activePump.setTempBasalPercent(percent, durationInMinutes, profile, enforceNew) + val r = activePlugin.activePump.setTempBasalPercent(percent, durationInMinutes, profile, enforceNew, tbrType) aapsLogger.debug(LTag.PUMPQUEUE, "Result percent: $percent durationInMinutes: $durationInMinutes success: ${r.success} enacted: ${r.enacted}") callback?.result(r)?.run() } diff --git a/app/src/main/java/info/nightscout/androidaps/receivers/DataReceiver.kt b/app/src/main/java/info/nightscout/androidaps/receivers/DataReceiver.kt index 89a869837f..eb1c5f1837 100644 --- a/app/src/main/java/info/nightscout/androidaps/receivers/DataReceiver.kt +++ b/app/src/main/java/info/nightscout/androidaps/receivers/DataReceiver.kt @@ -26,7 +26,7 @@ open class DataReceiver : DaggerBroadcastReceiver() { override fun onReceive(context: Context, intent: Intent) { super.onReceive(context, intent) val bundle = intent.extras ?: return - aapsLogger.debug(LTag.DATASERVICE, "onReceive ${intent.action} ${BundleLogger.log(bundle)}") + aapsLogger.debug(LTag.DATABASE, "onReceive ${intent.action} ${BundleLogger.log(bundle)}") when (intent.action) { diff --git a/app/src/main/java/info/nightscout/androidaps/receivers/DataWorker.kt b/app/src/main/java/info/nightscout/androidaps/receivers/DataWorker.kt index d46491b15e..fed3db6598 100644 --- a/app/src/main/java/info/nightscout/androidaps/receivers/DataWorker.kt +++ b/app/src/main/java/info/nightscout/androidaps/receivers/DataWorker.kt @@ -32,6 +32,12 @@ class DataWorker @Inject constructor( return value as Bundle? } + @Synchronized fun pickupObject(key: Long): Any? { + val value = store[key] + store.remove(key) + return value + } + @Synchronized fun pickupString(key: Long): String? { val value = store[key] store.remove(key) 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..92294f2053 100644 --- a/app/src/main/java/info/nightscout/androidaps/receivers/KeepAliveReceiver.kt +++ b/app/src/main/java/info/nightscout/androidaps/receivers/KeepAliveReceiver.kt @@ -3,23 +3,30 @@ 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.interfaces.Config +import info.nightscout.androidaps.database.AppRepository import info.nightscout.androidaps.events.EventProfileNeedsUpdate -import info.nightscout.androidaps.interfaces.ActivePluginProvider +import info.nightscout.androidaps.extensions.buildDeviceStatus +import info.nightscout.androidaps.interfaces.ActivePlugin import info.nightscout.androidaps.interfaces.CommandQueueProvider +import info.nightscout.androidaps.interfaces.IobCobCalculator import info.nightscout.androidaps.interfaces.ProfileFunction 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.iob.iobCobCalculator.IobCobCalculatorPlugin +import info.nightscout.androidaps.plugins.configBuilder.RunningConfiguration import info.nightscout.androidaps.queue.commands.Command import info.nightscout.androidaps.utils.DateUtil import info.nightscout.androidaps.utils.FabricPrivacy @@ -31,42 +38,110 @@ 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 iobCobCalculator: IobCobCalculator + @Inject lateinit var loopPlugin: LoopPlugin + @Inject lateinit var dateUtil: DateUtil + @Inject lateinit var activePlugin: ActivePlugin + @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() || iobCobCalculator.ads.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, iobCobCalculator, 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/java/info/nightscout/androidaps/receivers/TimeDateOrTZChangeReceiver.kt b/app/src/main/java/info/nightscout/androidaps/receivers/TimeDateOrTZChangeReceiver.kt index bcf3091c86..51bf087cd0 100644 --- a/app/src/main/java/info/nightscout/androidaps/receivers/TimeDateOrTZChangeReceiver.kt +++ b/app/src/main/java/info/nightscout/androidaps/receivers/TimeDateOrTZChangeReceiver.kt @@ -4,8 +4,8 @@ import android.content.Context import android.content.Intent import com.google.gson.Gson import dagger.android.DaggerBroadcastReceiver -import info.nightscout.androidaps.interfaces.ActivePluginProvider -import info.nightscout.androidaps.interfaces.PumpInterface +import info.nightscout.androidaps.interfaces.ActivePlugin +import info.nightscout.androidaps.interfaces.Pump import info.nightscout.androidaps.logging.AAPSLogger import info.nightscout.androidaps.logging.BundleLogger import info.nightscout.androidaps.logging.LTag @@ -15,7 +15,7 @@ import javax.inject.Inject class TimeDateOrTZChangeReceiver : DaggerBroadcastReceiver() { @Inject lateinit var aapsLogger: AAPSLogger - @Inject lateinit var activePlugin: ActivePluginProvider + @Inject lateinit var activePlugin: ActivePlugin val gson: Gson = Gson() private var isDST = false @@ -37,7 +37,7 @@ class TimeDateOrTZChangeReceiver : DaggerBroadcastReceiver() { override fun onReceive(context: Context, intent: Intent) { super.onReceive(context, intent) val action = intent.action - val activePump: PumpInterface = activePlugin.activePump + val activePump: Pump = activePlugin.activePump aapsLogger.debug(LTag.PUMP, "TimeDateOrTZChangeReceiver::Date, Time and/or TimeZone changed. [action={}]", action) aapsLogger.debug(LTag.PUMP, "TimeDateOrTZChangeReceiver::Intent::{}", BundleLogger.log(intent.extras)) diff --git a/app/src/main/java/info/nightscout/androidaps/setupwizard/SWDefinition.kt b/app/src/main/java/info/nightscout/androidaps/setupwizard/SWDefinition.kt index 600a4842e3..7c83af9360 100644 --- a/app/src/main/java/info/nightscout/androidaps/setupwizard/SWDefinition.kt +++ b/app/src/main/java/info/nightscout/androidaps/setupwizard/SWDefinition.kt @@ -7,19 +7,13 @@ import android.net.Uri import android.provider.Settings import androidx.appcompat.app.AppCompatActivity import dagger.android.HasAndroidInjector -import info.nightscout.androidaps.Config import info.nightscout.androidaps.Constants import info.nightscout.androidaps.R import info.nightscout.androidaps.dialogs.ProfileSwitchDialog import info.nightscout.androidaps.events.EventPumpStatusChanged -import info.nightscout.androidaps.interfaces.ActivePluginProvider -import info.nightscout.androidaps.interfaces.CommandQueueProvider -import info.nightscout.androidaps.interfaces.ImportExportPrefsInterface -import info.nightscout.androidaps.interfaces.PluginType -import info.nightscout.androidaps.interfaces.ProfileFunction +import info.nightscout.androidaps.interfaces.* import info.nightscout.androidaps.plugins.aps.loop.LoopPlugin import info.nightscout.androidaps.plugins.bus.RxBusWrapper -import info.nightscout.androidaps.plugins.configBuilder.ConfigBuilderPlugin import info.nightscout.androidaps.plugins.constraints.objectives.ObjectivesFragment import info.nightscout.androidaps.plugins.constraints.objectives.ObjectivesPlugin import info.nightscout.androidaps.plugins.general.nsclient.NSClientPlugin @@ -36,6 +30,7 @@ import info.nightscout.androidaps.setupwizard.elements.* import info.nightscout.androidaps.setupwizard.events.EventSWUpdate import info.nightscout.androidaps.utils.AndroidPermission import info.nightscout.androidaps.utils.CryptoUtil +import info.nightscout.androidaps.utils.buildHelper.ConfigImpl import info.nightscout.androidaps.utils.extensions.isRunningTest import info.nightscout.androidaps.utils.resources.ResourceHelper import info.nightscout.androidaps.utils.sharedPreferences.SP @@ -52,17 +47,17 @@ class SWDefinition @Inject constructor( private val sp: SP, private val profileFunction: ProfileFunction, private val localProfilePlugin: LocalProfilePlugin, - private val activePlugin: ActivePluginProvider, + private val activePlugin: ActivePlugin, private val commandQueue: CommandQueueProvider, private val objectivesPlugin: ObjectivesPlugin, - private val configBuilderPlugin: ConfigBuilderPlugin, + private val configBuilder: ConfigBuilder, private val loopPlugin: LoopPlugin, private val nsClientPlugin: NSClientPlugin, private val nsProfilePlugin: NSProfilePlugin, - private val importExportPrefs: ImportExportPrefsInterface, + private val importExportPrefs: ImportExportPrefs, private val androidPermission: AndroidPermission, private val cryptoUtil: CryptoUtil, - private val config: Config + private val config: ConfigImpl ) { lateinit var activity: AppCompatActivity @@ -174,7 +169,7 @@ class SWDefinition @Inject constructor( .add(SWButton(injector) .text(R.string.enable_nsclient) .action { - configBuilderPlugin.performPluginSwitch(nsClientPlugin, true, PluginType.GENERAL) + configBuilder.performPluginSwitch(nsClientPlugin, true, PluginType.GENERAL) rxBus.send(EventSWUpdate(true)) } .visibility { !nsClientPlugin.isEnabled(PluginType.GENERAL) }) @@ -274,13 +269,13 @@ class SWDefinition @Inject constructor( .add(SWFragment(injector, this) .add(NSProfileFragment())) .validator { nsProfilePlugin.profile != null && nsProfilePlugin.profile!!.getDefaultProfile() != null && nsProfilePlugin.profile!!.getDefaultProfile()!!.isValid("StartupWizard") } - .visibility { nsProfilePlugin.isEnabled(PluginType.PROFILE) } + .visibility { nsProfilePlugin.isEnabled() } private val screenLocalProfile = SWScreen(injector, R.string.localprofile) .skippable(false) .add(SWFragment(injector, this) .add(LocalProfileFragment())) .validator { localProfilePlugin.profile?.getDefaultProfile()?.isValid("StartupWizard") == true } - .visibility { localProfilePlugin.isEnabled(PluginType.PROFILE) } + .visibility { localProfilePlugin.isEnabled() } private val screenProfileSwitch = SWScreen(injector, R.string.careportal_profileswitch) .skippable(false) .add(SWInfoText(injector) @@ -360,7 +355,7 @@ class SWDefinition @Inject constructor( .add(SWButton(injector) .text(R.string.enableloop) .action { - configBuilderPlugin.performPluginSwitch(loopPlugin, true, PluginType.LOOP) + configBuilder.performPluginSwitch(loopPlugin, true, PluginType.LOOP) rxBus.send(EventSWUpdate(true)) } .visibility { !loopPlugin.isEnabled(PluginType.LOOP) }) diff --git a/app/src/main/java/info/nightscout/androidaps/skins/SkinButtonsOn.kt b/app/src/main/java/info/nightscout/androidaps/skins/SkinButtonsOn.kt index 829c1e6d63..8c3595d069 100644 --- a/app/src/main/java/info/nightscout/androidaps/skins/SkinButtonsOn.kt +++ b/app/src/main/java/info/nightscout/androidaps/skins/SkinButtonsOn.kt @@ -1,6 +1,6 @@ package info.nightscout.androidaps.skins -import info.nightscout.androidaps.Config +import info.nightscout.androidaps.interfaces.Config import info.nightscout.androidaps.R import javax.inject.Inject import javax.inject.Singleton diff --git a/app/src/main/java/info/nightscout/androidaps/skins/SkinClassic.kt b/app/src/main/java/info/nightscout/androidaps/skins/SkinClassic.kt index 3e27443e74..a6ae3b51b9 100644 --- a/app/src/main/java/info/nightscout/androidaps/skins/SkinClassic.kt +++ b/app/src/main/java/info/nightscout/androidaps/skins/SkinClassic.kt @@ -3,7 +3,7 @@ package info.nightscout.androidaps.skins import android.util.DisplayMetrics import android.view.View import android.widget.LinearLayout -import info.nightscout.androidaps.Config +import info.nightscout.androidaps.interfaces.Config import info.nightscout.androidaps.R import javax.inject.Inject import javax.inject.Singleton diff --git a/app/src/main/java/info/nightscout/androidaps/skins/SkinLargeDisplay.kt b/app/src/main/java/info/nightscout/androidaps/skins/SkinLargeDisplay.kt index 62764b00bc..751e0b3ad0 100644 --- a/app/src/main/java/info/nightscout/androidaps/skins/SkinLargeDisplay.kt +++ b/app/src/main/java/info/nightscout/androidaps/skins/SkinLargeDisplay.kt @@ -3,7 +3,7 @@ package info.nightscout.androidaps.skins import android.util.DisplayMetrics import android.view.View import android.widget.LinearLayout -import info.nightscout.androidaps.Config +import info.nightscout.androidaps.interfaces.Config import info.nightscout.androidaps.R import javax.inject.Inject import javax.inject.Singleton diff --git a/app/src/main/java/info/nightscout/androidaps/skins/SkinLowRes.kt b/app/src/main/java/info/nightscout/androidaps/skins/SkinLowRes.kt index c2fbc2aba1..c4384db93b 100644 --- a/app/src/main/java/info/nightscout/androidaps/skins/SkinLowRes.kt +++ b/app/src/main/java/info/nightscout/androidaps/skins/SkinLowRes.kt @@ -3,7 +3,7 @@ package info.nightscout.androidaps.skins import android.util.DisplayMetrics import android.view.View import android.widget.LinearLayout -import info.nightscout.androidaps.Config +import info.nightscout.androidaps.interfaces.Config import info.nightscout.androidaps.R import javax.inject.Inject import javax.inject.Singleton diff --git a/app/src/main/java/info/nightscout/androidaps/utils/ActivityMonitor.kt b/app/src/main/java/info/nightscout/androidaps/utils/ActivityMonitor.kt index 7364bef9a5..313d82308b 100644 --- a/app/src/main/java/info/nightscout/androidaps/utils/ActivityMonitor.kt +++ b/app/src/main/java/info/nightscout/androidaps/utils/ActivityMonitor.kt @@ -16,7 +16,8 @@ import javax.inject.Singleton class ActivityMonitor @Inject constructor( private var aapsLogger: AAPSLogger, private val resourceHelper: ResourceHelper, - private var sp: SP + private val sp: SP, + private val dateUtil: DateUtil ) : Application.ActivityLifecycleCallbacks { override fun onActivityPaused(activity: Activity?) { @@ -26,10 +27,10 @@ class ActivityMonitor @Inject constructor( aapsLogger.debug(LTag.UI, "onActivityPaused: $name resumed == 0") return } - val elapsed = DateUtil.now() - resumed + val elapsed = dateUtil.now() - resumed val total = sp.getLong("Monitor_" + name + "_total", 0) if (total == 0L) { - sp.putLong("Monitor_" + name + "_start", DateUtil.now()) + sp.putLong("Monitor_" + name + "_start", dateUtil.now()) } sp.putLong("Monitor_" + name + "_total", total + elapsed) aapsLogger.debug(LTag.UI, "onActivityPaused: $name elapsed=$elapsed total=${total + elapsed}") @@ -38,7 +39,7 @@ class ActivityMonitor @Inject constructor( override fun onActivityResumed(activity: Activity?) { val name = activity?.javaClass?.simpleName ?: return aapsLogger.debug(LTag.UI, "onActivityResumed: $name") - sp.putLong("Monitor_" + name + "_" + "resumed", DateUtil.now()) + sp.putLong("Monitor_" + name + "_" + "resumed", dateUtil.now()) } override fun onActivityStarted(activity: Activity?) { @@ -63,9 +64,9 @@ class ActivityMonitor @Inject constructor( if (key.startsWith("Monitor") && key.endsWith("total")) { val v = if (value is Long) value else SafeParse.stringToLong(value as String) val activity = key.split("_")[1].replace("Activity", "") - val duration = DateUtil.niceTimeScalar(v as Long, resourceHelper) + val duration = dateUtil.niceTimeScalar(v as Long, resourceHelper) val start = sp.getLong(key.replace("total", "start"), 0) - val days = T.msecs(DateUtil.now() - start).days() + val days = T.msecs(dateUtil.now() - start).days() result += resourceHelper.gs(R.string.activitymonitorformat, activity, duration, days) } return result diff --git a/app/src/main/java/info/nightscout/androidaps/utils/HardLimits.kt b/app/src/main/java/info/nightscout/androidaps/utils/HardLimits.kt index 95bd7983ae..0389b34283 100644 --- a/app/src/main/java/info/nightscout/androidaps/utils/HardLimits.kt +++ b/app/src/main/java/info/nightscout/androidaps/utils/HardLimits.kt @@ -2,11 +2,14 @@ package info.nightscout.androidaps.utils import android.content.Context import info.nightscout.androidaps.R +import info.nightscout.androidaps.database.AppRepository +import info.nightscout.androidaps.database.transactions.InsertTherapyEventAnnouncementTransaction import info.nightscout.androidaps.logging.AAPSLogger import info.nightscout.androidaps.plugins.bus.RxBusWrapper -import info.nightscout.androidaps.plugins.general.nsclient.NSUpload import info.nightscout.androidaps.utils.resources.ResourceHelper import info.nightscout.androidaps.utils.sharedPreferences.SP +import io.reactivex.disposables.CompositeDisposable +import io.reactivex.rxkotlin.plusAssign import javax.inject.Inject import javax.inject.Singleton import kotlin.math.max @@ -19,9 +22,11 @@ class HardLimits @Inject constructor( private val sp: SP, private val resourceHelper: ResourceHelper, private val context: Context, - private val nsUpload: NSUpload + private val repository: AppRepository ) { + private val disposable = CompositeDisposable() + companion object { private const val CHILD = 0 @@ -88,7 +93,7 @@ class HardLimits @Inject constructor( msg += ".\n" msg += String.format(resourceHelper.gs(R.string.valuelimitedto), value, newValue) aapsLogger.error(msg) - nsUpload.uploadError(msg) + disposable += repository.runTransaction(InsertTherapyEventAnnouncementTransaction(msg)).subscribe() ToastUtils.showToastInUiThread(context, rxBus, msg, R.raw.error) } return newValue diff --git a/app/src/main/java/info/nightscout/androidaps/utils/JSONFormatter.java b/app/src/main/java/info/nightscout/androidaps/utils/JSONFormatter.java deleted file mode 100644 index dae7f61252..0000000000 --- a/app/src/main/java/info/nightscout/androidaps/utils/JSONFormatter.java +++ /dev/null @@ -1,126 +0,0 @@ -package info.nightscout.androidaps.utils; - -import android.text.Html; -import android.text.Spanned; - -import org.json.JSONArray; -import org.json.JSONException; -import org.json.JSONObject; -import org.slf4j.Logger; - -import java.util.Iterator; -import java.util.Date; -import java.text.SimpleDateFormat; -import java.text.DateFormat; - -import info.nightscout.androidaps.logging.StacktraceLoggerWrapper; - -/** - * Created by mike on 11.07.2016. - */ -public class JSONFormatter { - private static final Logger log = StacktraceLoggerWrapper.getLogger(JSONFormatter.class); - - public static Spanned format(final String jsonString) { - final JsonVisitor visitor = new JsonVisitor(1, '\t'); - try { - if (jsonString.equals("undefined")) - return HtmlHelper.INSTANCE.fromHtml("undefined"); - else if (jsonString.getBytes()[0] == '[') - return HtmlHelper.INSTANCE.fromHtml(visitor.visit(new JSONArray(jsonString), 0)); - else - return HtmlHelper.INSTANCE.fromHtml(visitor.visit(new JSONObject(jsonString), 0)); - } catch (JSONException e) { - log.error("Unhandled exception", e); - return HtmlHelper.INSTANCE.fromHtml(""); - } - } - - public static Spanned format(final JSONObject object) { - final JsonVisitor visitor = new JsonVisitor(1, '\t'); - try { - return HtmlHelper.INSTANCE.fromHtml(visitor.visit(object, 0)); - } catch (JSONException e) { - log.error("Unhandled exception", e); - return HtmlHelper.INSTANCE.fromHtml(""); - } - } - - private static class JsonVisitor { - private final int indentationSize; - private final char indentationChar; - - public JsonVisitor(final int indentationSize, final char indentationChar) { - this.indentationSize = indentationSize; - this.indentationChar = indentationChar; - } - - private String visit(final JSONArray array, final int indent) throws JSONException { - String ret = ""; - final int length = array.length(); - if (length == 0) { - } else { - ret += write("[", indent); - for (int i = 0; i < length; i++) { - ret += visit(array.get(i), indent); - } - ret += write("]", indent); - } - return ret; - } - - private String visit(final JSONObject obj, final int indent) throws JSONException { - String ret = ""; - final int length = obj.length(); - if (length == 0) { - } else { - final Iterator keys = obj.keys(); - while (keys.hasNext()) { - final String key = keys.next(); - ret += write("" + key + ": ", indent); - ret += visit(obj.get(key), indent + 1); - ret += "
"; - } - } - return ret; - } - - private String visit(final Object object, final int indent) throws JSONException { - String ret = ""; - Long n; - if (object instanceof JSONArray) { - ret += visit((JSONArray) object, indent); - } else if (object instanceof JSONObject) { - ret += "
" + visit((JSONObject) object, indent); - } else { - if (object instanceof String) { - ret += write("\"" + ((String) object).replace("<", "<").replace(">", ">") + "\"", indent); - } else { - // try to detect Date as milliseconds - if (object instanceof Long) { - n = (Long) object; - if (n > 1580000000000L && n < 2000000000000L) { // from 2020.01.26 to 2033.05.18 it is with high probability a date object - Date date = new Date(n); - DateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); - ret += write(formatter.format(date), indent); - } else { - ret += write(String.valueOf(object), indent); - } - } else { - ret += write(String.valueOf(object), indent); - } - } - } - return ret; - } - - private String write(final String data, final int indent) { - String ret = ""; - for (int i = 0; i < (indent * indentationSize); i++) { - ret += indentationChar; - } - ret += data; - return ret; - } - } -} diff --git a/app/src/main/java/info/nightscout/androidaps/utils/JSONFormatter.kt b/app/src/main/java/info/nightscout/androidaps/utils/JSONFormatter.kt new file mode 100644 index 0000000000..7d5247c885 --- /dev/null +++ b/app/src/main/java/info/nightscout/androidaps/utils/JSONFormatter.kt @@ -0,0 +1,113 @@ +package info.nightscout.androidaps.utils + +import android.text.Spanned +import info.nightscout.androidaps.logging.AAPSLogger +import info.nightscout.androidaps.utils.HtmlHelper.fromHtml +import org.json.JSONArray +import org.json.JSONException +import org.json.JSONObject +import java.text.DateFormat +import java.text.SimpleDateFormat +import java.util.* +import javax.inject.Inject +import javax.inject.Singleton + +@Singleton +class JSONFormatter @Inject constructor( + private val aapsLogger: AAPSLogger +) { + + fun format(jsonString: String?): Spanned { + jsonString ?: return fromHtml("") + val visitor = JsonVisitor(1, '\t') + return try { + when { + jsonString == "undefined" -> fromHtml("undefined") + jsonString.toByteArray()[0] == '['.toByte() -> fromHtml(visitor.visit(JSONArray(jsonString), 0)) + else -> fromHtml(visitor.visit(JSONObject(jsonString), 0)) + } + } catch (e: JSONException) { + aapsLogger.error("Unhandled exception", e) + fromHtml("") + } + } + + fun format(jsonObject: JSONObject?): Spanned { + jsonObject ?: return fromHtml("") + val visitor = JsonVisitor(1, '\t') + return try { + fromHtml(visitor.visit(jsonObject, 0)) + } catch (e: JSONException) { + aapsLogger.error("Unhandled exception", e) + fromHtml("") + } + } + + private class JsonVisitor(private val indentationSize: Int, private val indentationChar: Char) { + + fun visit(array: JSONArray, indent: Int): String { + var ret = "" + val length = array.length() + if (length != 0) { + ret += write("[", indent) + for (i in 0 until length) { + ret += visit(array[i], indent) + } + ret += write("]", indent) + } + return ret + } + + fun visit(obj: JSONObject, indent: Int): String { + var ret = "" + val length = obj.length() + if (length != 0) { + val keys = obj.keys() + while (keys.hasNext()) { + val key = keys.next() + ret += write("$key: ", indent) + ret += visit(obj[key], indent + 1) + ret += "
" + } + } + return ret + } + + private fun visit(any: Any, indent: Int): String { + var ret = "" + val n: Long + if (any is JSONArray) { + ret += visit(any, indent) + } else if (any is JSONObject) { + ret += "
" + visit(any, indent) + } else { + if (any is String) { + ret += write("\"" + any.replace("<", "<").replace(">", ">") + "\"", indent) + } else { + // try to detect Date as milliseconds + if (any is Long) { + n = any + ret += if (n in 1580000000001..1999999999999) { // from 2020.01.26 to 2033.05.18 it is with high probability a date object + val formatter: DateFormat = SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.getDefault()) + write(formatter.format(Date(n)), indent) + } else { + write(any.toString(), indent) + } + } else { + ret += write(any.toString(), indent) + } + } + } + return ret + } + + private fun write(data: String, indent: Int): String { + var ret = "" + for (i in 0 until indent * indentationSize) { + ret += indentationChar + } + ret += data + return ret + } + } +} \ No newline at end of file diff --git a/app/src/main/java/info/nightscout/androidaps/utils/LocalAlertUtils.kt b/app/src/main/java/info/nightscout/androidaps/utils/LocalAlertUtils.kt index 908f759f41..a8bdb9e92b 100644 --- a/app/src/main/java/info/nightscout/androidaps/utils/LocalAlertUtils.kt +++ b/app/src/main/java/info/nightscout/androidaps/utils/LocalAlertUtils.kt @@ -1,21 +1,24 @@ package info.nightscout.androidaps.utils -import info.nightscout.androidaps.Config +import info.nightscout.androidaps.interfaces.Config import info.nightscout.androidaps.Constants import info.nightscout.androidaps.R -import info.nightscout.androidaps.interfaces.ActivePluginProvider +import info.nightscout.androidaps.database.AppRepository +import info.nightscout.androidaps.database.transactions.InsertTherapyEventAnnouncementTransaction +import info.nightscout.androidaps.interfaces.ActivePlugin +import info.nightscout.androidaps.interfaces.IobCobCalculator import info.nightscout.androidaps.interfaces.ProfileFunction import info.nightscout.androidaps.logging.AAPSLogger import info.nightscout.androidaps.logging.LTag import info.nightscout.androidaps.plugins.bus.RxBusWrapper -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 import info.nightscout.androidaps.plugins.general.overview.notifications.Notification import info.nightscout.androidaps.plugins.general.smsCommunicator.SmsCommunicatorPlugin -import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorPlugin import info.nightscout.androidaps.utils.resources.ResourceHelper import info.nightscout.androidaps.utils.sharedPreferences.SP +import io.reactivex.disposables.CompositeDisposable +import io.reactivex.rxkotlin.plusAssign import javax.inject.Inject import javax.inject.Singleton import kotlin.math.min @@ -29,15 +32,17 @@ class LocalAlertUtils @Inject constructor( private val sp: SP, private val rxBus: RxBusWrapper, private val resourceHelper: ResourceHelper, - private val activePlugin: ActivePluginProvider, + private val activePlugin: ActivePlugin, private val profileFunction: ProfileFunction, - private val iobCobCalculatorPlugin: IobCobCalculatorPlugin, + private val iobCobCalculator: IobCobCalculator, private val smsCommunicatorPlugin: SmsCommunicatorPlugin, private val config: Config, - private val nsUpload: NSUpload, + private val repository: AppRepository, private val dateUtil: DateUtil ) { + private val disposable = CompositeDisposable() + private fun missedReadingsThreshold(): Long { return T.mins(sp.getInt(R.string.key_missed_bg_readings_threshold_minutes, Constants.DEFAULT_MISSED_BG_READINGS_THRESHOLD_MINUTES).toLong()).msecs() } @@ -55,7 +60,7 @@ class LocalAlertUtils @Inject constructor( sp.putLong("nextPumpDisconnectedAlarm", System.currentTimeMillis() + pumpUnreachableThreshold()) rxBus.send(EventNewNotification(Notification(Notification.PUMP_UNREACHABLE, resourceHelper.gs(R.string.pump_unreachable), Notification.URGENT).also { it.soundId = R.raw.alarm })) if (sp.getBoolean(R.string.key_ns_create_announcements_from_errors, true)) - nsUpload.uploadError(resourceHelper.gs(R.string.pump_unreachable)) + disposable += repository.runTransaction(InsertTherapyEventAnnouncementTransaction(resourceHelper.gs(R.string.pump_unreachable))).subscribe() } if (sp.getBoolean(R.string.key_smscommunicator_report_pump_ureachable, true)) smsCommunicatorPlugin.sendNotificationToAllNumbers(resourceHelper.gs(R.string.pump_unreachable)) @@ -105,7 +110,7 @@ class LocalAlertUtils @Inject constructor( } fun checkStaleBGAlert() { - val bgReading = iobCobCalculatorPlugin.lastBg() + val bgReading = iobCobCalculator.ads.lastBg() if (sp.getBoolean(R.string.key_enable_missed_bg_readings_alert, false) && bgReading != null && bgReading.timestamp + missedReadingsThreshold() < System.currentTimeMillis() && sp.getLong("nextMissedReadingsAlarm", 0L) < System.currentTimeMillis()) { val n = Notification(Notification.BG_READINGS_MISSED, resourceHelper.gs(R.string.missed_bg_readings), Notification.URGENT) @@ -113,7 +118,7 @@ class LocalAlertUtils @Inject constructor( sp.putLong("nextMissedReadingsAlarm", System.currentTimeMillis() + missedReadingsThreshold()) rxBus.send(EventNewNotification(n)) if (sp.getBoolean(R.string.key_ns_create_announcements_from_errors, true)) { - nsUpload.uploadError(n.text) + n.text?.let { disposable += repository.runTransaction(InsertTherapyEventAnnouncementTransaction(it)).subscribe() } } } } diff --git a/app/src/main/java/info/nightscout/androidaps/utils/NumberPickerVertical.java b/app/src/main/java/info/nightscout/androidaps/utils/NumberPickerVertical.java deleted file mode 100644 index 5244c5c4ce..0000000000 --- a/app/src/main/java/info/nightscout/androidaps/utils/NumberPickerVertical.java +++ /dev/null @@ -1,26 +0,0 @@ -package info.nightscout.androidaps.utils; - -import android.content.Context; -import android.util.AttributeSet; -import android.view.LayoutInflater; - -import info.nightscout.androidaps.R; -import info.nightscout.androidaps.utils.ui.NumberPicker; - -/** - * Created by mike on 28.06.2016. - */ -public class NumberPickerVertical extends NumberPicker { - public NumberPickerVertical(Context context) { - super(context); - } - - public NumberPickerVertical(Context context, AttributeSet attrs) { - super(context, attrs); - } - - @Override - protected void inflate(Context context) { - LayoutInflater.from(context).inflate(R.layout.number_picker_layout_vertical, this, true); - } - } diff --git a/app/src/main/java/info/nightscout/androidaps/utils/NumberPickerVertical.kt b/app/src/main/java/info/nightscout/androidaps/utils/NumberPickerVertical.kt new file mode 100644 index 0000000000..5e7a0d7e90 --- /dev/null +++ b/app/src/main/java/info/nightscout/androidaps/utils/NumberPickerVertical.kt @@ -0,0 +1,17 @@ +package info.nightscout.androidaps.utils + +import android.content.Context +import android.util.AttributeSet +import android.view.LayoutInflater +import info.nightscout.androidaps.R +import info.nightscout.androidaps.utils.ui.NumberPicker + +class NumberPickerVertical : NumberPicker { + + constructor(context: Context?) : super(context) + constructor(context: Context?, attrs: AttributeSet?) : super(context, attrs) + + override fun inflate(context: Context) { + LayoutInflater.from(context).inflate(R.layout.number_picker_layout_vertical, this, true) + } +} \ No newline at end of file diff --git a/app/src/main/java/info/nightscout/androidaps/utils/PercentageSplitter.java b/app/src/main/java/info/nightscout/androidaps/utils/PercentageSplitter.java deleted file mode 100644 index b3f8156cfe..0000000000 --- a/app/src/main/java/info/nightscout/androidaps/utils/PercentageSplitter.java +++ /dev/null @@ -1,22 +0,0 @@ -package info.nightscout.androidaps.utils; - -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -/** - * Created by mike on 22.12.2017. - */ - -public class PercentageSplitter { - // Matches "Profile name (200%,-2h)", "Profile name (50%) - private static final Pattern splitPattern = Pattern.compile("(.+)\\(\\d+%(,-?\\d+h)?\\)"); - - /** Removes the suffix for percentage and timeshift from a profile name. This is the inverse of what - * {@link info.nightscout.androidaps.db.ProfileSwitch#getCustomizedName()} does. - * Since the customized name is used for the PS upload to NS, this is needed get the original profile name - * when retrieving the PS from NS again. */ - public static String pureName(String name) { - Matcher percentageMatch = splitPattern.matcher(name); - return percentageMatch.find() ? percentageMatch.group(1).trim() : name; - } -} diff --git a/app/src/main/java/info/nightscout/androidaps/utils/PercentageSplitter.kt b/app/src/main/java/info/nightscout/androidaps/utils/PercentageSplitter.kt new file mode 100644 index 0000000000..38288c8256 --- /dev/null +++ b/app/src/main/java/info/nightscout/androidaps/utils/PercentageSplitter.kt @@ -0,0 +1,21 @@ +package info.nightscout.androidaps.utils + +import info.nightscout.androidaps.utils.PercentageSplitter +import java.util.regex.Pattern + +object PercentageSplitter { + + // Matches "Profile name (200%,-2h)", "Profile name (50%) + private val splitPattern = Pattern.compile("(.+)\\(\\d+%(,-?\\d+h)?\\)") + + /** + * Removes the suffix for percentage and timeshift from a profile name. This is the inverse of what + * [info.nightscout.androidaps.db.ProfileSwitch.getCustomizedName] does. + * Since the customized name is used for the PS upload to NS, this is needed get the original profile name + * when retrieving the PS from NS again. + */ + fun pureName(name: String): String { + val percentageMatch = splitPattern.matcher(name) + return if (percentageMatch.find()) percentageMatch.group(1).trim { it <= ' ' } else name + } +} \ No newline at end of file diff --git a/app/src/main/java/info/nightscout/androidaps/utils/SPBackupAgent.java b/app/src/main/java/info/nightscout/androidaps/utils/SPBackupAgent.java deleted file mode 100644 index 098b90c5d1..0000000000 --- a/app/src/main/java/info/nightscout/androidaps/utils/SPBackupAgent.java +++ /dev/null @@ -1,17 +0,0 @@ -package info.nightscout.androidaps.utils; - -import android.app.backup.BackupAgentHelper; -import android.app.backup.SharedPreferencesBackupHelper; - -public class SPBackupAgent extends BackupAgentHelper { - - @Override - public void onCreate() { - // API 24 - final String PREFS = getApplicationContext().getPackageName() + "_preferences"; - final String PREFS_BACKUP_KEY = "SP"; - SharedPreferencesBackupHelper helper = - new SharedPreferencesBackupHelper(this, PREFS); - addHelper(PREFS_BACKUP_KEY, helper); - } -} \ No newline at end of file diff --git a/app/src/main/java/info/nightscout/androidaps/utils/SPBackupAgent.kt b/app/src/main/java/info/nightscout/androidaps/utils/SPBackupAgent.kt new file mode 100644 index 0000000000..bf3a4a5516 --- /dev/null +++ b/app/src/main/java/info/nightscout/androidaps/utils/SPBackupAgent.kt @@ -0,0 +1,16 @@ +package info.nightscout.androidaps.utils + +import android.app.backup.BackupAgentHelper +import android.app.backup.SharedPreferencesBackupHelper + +@Suppress("LocalVariableName") +class SPBackupAgent : BackupAgentHelper() { + + override fun onCreate() { + // API 24 + val PREFS = applicationContext.packageName + "_preferences" + val PREFS_BACKUP_KEY = "SP" + val helper = SharedPreferencesBackupHelper(this, PREFS) + addHelper(PREFS_BACKUP_KEY, helper) + } +} \ No newline at end of file diff --git a/app/src/main/java/info/nightscout/androidaps/utils/TimeListEdit.java b/app/src/main/java/info/nightscout/androidaps/utils/TimeListEdit.java index af6fd3e742..33a24e3244 100644 --- a/app/src/main/java/info/nightscout/androidaps/utils/TimeListEdit.java +++ b/app/src/main/java/info/nightscout/androidaps/utils/TimeListEdit.java @@ -95,7 +95,6 @@ public class TimeListEdit { LinearLayout.LayoutParams llp = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT); llp.setMargins(0, 5, 0, 5); textlabel.setLayoutParams(llp); - //textlabel.setBackgroundColor(ContextCompat.getColor(MainApp.instance(), R.color.linearBlockBackground)); TextViewCompat.setTextAppearance(textlabel, android.R.style.TextAppearance_Medium); layout.addView(textlabel); diff --git a/app/src/main/java/info/nightscout/androidaps/utils/alertDialogs/PrefImportSummaryDialog.kt b/app/src/main/java/info/nightscout/androidaps/utils/alertDialogs/PrefImportSummaryDialog.kt index 976feb9ed1..7a2aa6f513 100644 --- a/app/src/main/java/info/nightscout/androidaps/utils/alertDialogs/PrefImportSummaryDialog.kt +++ b/app/src/main/java/info/nightscout/androidaps/utils/alertDialogs/PrefImportSummaryDialog.kt @@ -20,7 +20,7 @@ import info.nightscout.androidaps.R import info.nightscout.androidaps.plugins.general.maintenance.formats.Prefs import info.nightscout.androidaps.plugins.general.maintenance.formats.PrefsStatus import info.nightscout.androidaps.utils.ToastUtils -import info.nightscout.androidaps.utils.extensions.runOnUiThread +import info.nightscout.androidaps.extensions.runOnUiThread import java.util.* object PrefImportSummaryDialog { diff --git a/app/src/main/java/info/nightscout/androidaps/utils/alertDialogs/TwoMessagesAlertDialog.kt b/app/src/main/java/info/nightscout/androidaps/utils/alertDialogs/TwoMessagesAlertDialog.kt index c3049a3597..b8bc6466a2 100644 --- a/app/src/main/java/info/nightscout/androidaps/utils/alertDialogs/TwoMessagesAlertDialog.kt +++ b/app/src/main/java/info/nightscout/androidaps/utils/alertDialogs/TwoMessagesAlertDialog.kt @@ -9,7 +9,7 @@ import android.view.View import android.widget.TextView import androidx.annotation.DrawableRes import info.nightscout.androidaps.R -import info.nightscout.androidaps.utils.extensions.runOnUiThread +import info.nightscout.androidaps.extensions.runOnUiThread object TwoMessagesAlertDialog { diff --git a/app/src/main/java/info/nightscout/androidaps/utils/androidNotification/NotificationHolder.kt b/app/src/main/java/info/nightscout/androidaps/utils/androidNotification/NotificationHolderImpl.kt similarity index 85% rename from app/src/main/java/info/nightscout/androidaps/utils/androidNotification/NotificationHolder.kt rename to app/src/main/java/info/nightscout/androidaps/utils/androidNotification/NotificationHolderImpl.kt index 72dbb6430f..dfe9ed21c4 100644 --- a/app/src/main/java/info/nightscout/androidaps/utils/androidNotification/NotificationHolder.kt +++ b/app/src/main/java/info/nightscout/androidaps/utils/androidNotification/NotificationHolderImpl.kt @@ -9,18 +9,18 @@ import androidx.core.app.NotificationCompat import androidx.core.app.TaskStackBuilder import info.nightscout.androidaps.MainActivity import info.nightscout.androidaps.core.R -import info.nightscout.androidaps.interfaces.IconsProviderInterface -import info.nightscout.androidaps.interfaces.NotificationHolderInterface +import info.nightscout.androidaps.interfaces.IconsProvider +import info.nightscout.androidaps.interfaces.NotificationHolder import info.nightscout.androidaps.utils.resources.ResourceHelper import javax.inject.Inject import javax.inject.Singleton @Singleton -class NotificationHolder @Inject constructor( +class NotificationHolderImpl @Inject constructor( resourceHelper: ResourceHelper, context: Context, - iconsProvider: IconsProviderInterface -) : NotificationHolderInterface { + iconsProvider: IconsProvider +) : NotificationHolder { override val channelID = "AndroidAPS-Ongoing" override val notificationID = 4711 diff --git a/app/src/main/java/info/nightscout/androidaps/utils/buildHelper/BuildHelper.kt b/app/src/main/java/info/nightscout/androidaps/utils/buildHelper/BuildHelper.kt index 2eafc12ebb..0cb6b5c772 100644 --- a/app/src/main/java/info/nightscout/androidaps/utils/buildHelper/BuildHelper.kt +++ b/app/src/main/java/info/nightscout/androidaps/utils/buildHelper/BuildHelper.kt @@ -1,7 +1,7 @@ package info.nightscout.androidaps.utils.buildHelper import info.nightscout.androidaps.BuildConfig -import info.nightscout.androidaps.Config +import info.nightscout.androidaps.interfaces.Config import info.nightscout.androidaps.plugins.general.maintenance.LoggerUtils import java.io.File import javax.inject.Inject diff --git a/app/src/main/java/info/nightscout/androidaps/Config.kt b/app/src/main/java/info/nightscout/androidaps/utils/buildHelper/ConfigImpl.kt similarity index 77% rename from app/src/main/java/info/nightscout/androidaps/Config.kt rename to app/src/main/java/info/nightscout/androidaps/utils/buildHelper/ConfigImpl.kt index a598adc440..1f8ee377c5 100644 --- a/app/src/main/java/info/nightscout/androidaps/Config.kt +++ b/app/src/main/java/info/nightscout/androidaps/utils/buildHelper/ConfigImpl.kt @@ -1,12 +1,13 @@ -package info.nightscout.androidaps +package info.nightscout.androidaps.utils.buildHelper import android.os.Build -import info.nightscout.androidaps.interfaces.ConfigInterface +import info.nightscout.androidaps.BuildConfig +import info.nightscout.androidaps.interfaces.Config import javax.inject.Inject import javax.inject.Singleton @Singleton -class Config @Inject constructor() : ConfigInterface { +class ConfigImpl @Inject constructor() : Config { override val SUPPORTEDNSVERSION = 1002 // 0.10.00 override val APS = BuildConfig.FLAVOR == "full" diff --git a/app/src/main/java/info/nightscout/androidaps/utils/extensions/DoubleToSignedString.kt b/app/src/main/java/info/nightscout/androidaps/utils/extensions/DoubleToSignedString.kt index af942b871e..bbad911a7c 100644 --- a/app/src/main/java/info/nightscout/androidaps/utils/extensions/DoubleToSignedString.kt +++ b/app/src/main/java/info/nightscout/androidaps/utils/extensions/DoubleToSignedString.kt @@ -1,9 +1,9 @@ package info.nightscout.androidaps.utils.extensions -import info.nightscout.androidaps.interfaces.PumpInterface +import info.nightscout.androidaps.interfaces.Pump import info.nightscout.androidaps.utils.DecimalFormatter -fun Double.toSignedString(pump: PumpInterface): String { +fun Double.toSignedString(pump: Pump): String { val formatted = DecimalFormatter.toPumpSupportedBolus(this, pump) return if (this > 0) "+$formatted" else formatted } diff --git a/app/src/main/java/info/nightscout/androidaps/utils/extensions/GlucoseValueUtils.kt b/app/src/main/java/info/nightscout/androidaps/utils/extensions/GlucoseValueUtils.kt deleted file mode 100644 index b02ba88e39..0000000000 --- a/app/src/main/java/info/nightscout/androidaps/utils/extensions/GlucoseValueUtils.kt +++ /dev/null @@ -1,13 +0,0 @@ -package info.nightscout.androidaps.utils.extensions - -import info.nightscout.androidaps.Constants -import info.nightscout.androidaps.database.entities.GlucoseValue -import info.nightscout.androidaps.utils.DecimalFormatter - -fun GlucoseValue.valueToUnits(units: String): Double = - if (units == Constants.MGDL) value - else value * Constants.MGDL_TO_MMOLL - -fun GlucoseValue.valueToUnitsString(units: String): String = - if (units == Constants.MGDL) DecimalFormatter.to0Decimal(value) - else DecimalFormatter.to1Decimal(value * Constants.MGDL_TO_MMOLL) diff --git a/app/src/main/java/info/nightscout/androidaps/utils/resources/IconsProvider.kt b/app/src/main/java/info/nightscout/androidaps/utils/resources/IconsProviderImplementation.kt similarity index 73% rename from app/src/main/java/info/nightscout/androidaps/utils/resources/IconsProvider.kt rename to app/src/main/java/info/nightscout/androidaps/utils/resources/IconsProviderImplementation.kt index beab1f4330..74f39d3572 100644 --- a/app/src/main/java/info/nightscout/androidaps/utils/resources/IconsProvider.kt +++ b/app/src/main/java/info/nightscout/androidaps/utils/resources/IconsProviderImplementation.kt @@ -1,13 +1,13 @@ package info.nightscout.androidaps.utils.resources import info.nightscout.androidaps.R -import info.nightscout.androidaps.interfaces.ConfigInterface -import info.nightscout.androidaps.interfaces.IconsProviderInterface +import info.nightscout.androidaps.interfaces.Config +import info.nightscout.androidaps.interfaces.IconsProvider import javax.inject.Inject import javax.inject.Singleton @Singleton -class IconsProvider @Inject constructor(private val config: ConfigInterface) : IconsProviderInterface { +class IconsProviderImplementation @Inject constructor(private val config: Config) : IconsProvider { override fun getIcon(): Int = when { diff --git a/app/src/main/java/info/nightscout/androidaps/utils/stats/TddCalculator.kt b/app/src/main/java/info/nightscout/androidaps/utils/stats/TddCalculator.kt index b9da317bc6..80ffb03bad 100644 --- a/app/src/main/java/info/nightscout/androidaps/utils/stats/TddCalculator.kt +++ b/app/src/main/java/info/nightscout/androidaps/utils/stats/TddCalculator.kt @@ -1,83 +1,66 @@ package info.nightscout.androidaps.utils.stats -import android.content.Context import android.text.Spanned import android.util.LongSparseArray -import dagger.android.HasAndroidInjector import info.nightscout.androidaps.R import info.nightscout.androidaps.database.AppRepository +import info.nightscout.androidaps.database.entities.Bolus import info.nightscout.androidaps.db.TDD -import info.nightscout.androidaps.interfaces.ActivePluginProvider -import info.nightscout.androidaps.interfaces.DatabaseHelperInterface +import info.nightscout.androidaps.interfaces.ActivePlugin +import info.nightscout.androidaps.interfaces.IobCobCalculator import info.nightscout.androidaps.interfaces.ProfileFunction -import info.nightscout.androidaps.interfaces.UploadQueueInterface import info.nightscout.androidaps.logging.AAPSLogger import info.nightscout.androidaps.logging.LTag -import info.nightscout.androidaps.plugins.bus.RxBusWrapper -import info.nightscout.androidaps.plugins.general.nsclient.NSUpload -import info.nightscout.androidaps.plugins.treatments.TreatmentService -import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin import info.nightscout.androidaps.utils.DateUtil -import info.nightscout.androidaps.utils.FabricPrivacy import info.nightscout.androidaps.utils.HtmlHelper import info.nightscout.androidaps.utils.MidnightTime import info.nightscout.androidaps.utils.T +import info.nightscout.androidaps.extensions.convertedToAbsolute import info.nightscout.androidaps.utils.resources.ResourceHelper -import info.nightscout.androidaps.utils.rx.AapsSchedulers -import info.nightscout.androidaps.utils.sharedPreferences.SP import javax.inject.Inject class TddCalculator @Inject constructor( - injector: HasAndroidInjector, - aapsLogger: AAPSLogger, - rxBus: RxBusWrapper, - resourceHelper: ResourceHelper, - context: Context, - aapsSchedulers: AapsSchedulers, - sp: SP, - private val activePlugin: ActivePluginProvider, + private val aapsLogger: AAPSLogger, + private val resourceHelper: ResourceHelper, + private val activePlugin: ActivePlugin, private val profileFunction: ProfileFunction, - fabricPrivacy: FabricPrivacy, - nsUpload: NSUpload, private val dateUtil: DateUtil, - uploadQueue: UploadQueueInterface, - databaseHelper: DatabaseHelperInterface, - repository: AppRepository -) : TreatmentsPlugin(injector, aapsLogger, rxBus, aapsSchedulers, resourceHelper, context, sp, profileFunction, activePlugin, nsUpload, fabricPrivacy, dateUtil, uploadQueue, databaseHelper, repository) { - - init { - service = TreatmentService(injector) // plugin is not started - } + private val iobCobCalculator: IobCobCalculator, + private val repository: AppRepository +) { fun calculate(days: Long): LongSparseArray { - val range = T.days(days + 1).msecs() - val startTime = MidnightTime.calc(DateUtil.now() - T.days(days).msecs()) - val endTime = MidnightTime.calc(DateUtil.now()) - initializeData(range) + val startTime = MidnightTime.calc(dateUtil.now() - T.days(days).msecs()) + val endTime = MidnightTime.calc(dateUtil.now()) val result = LongSparseArray() - for (t in treatmentsFromHistory) { - if (!t.isValid) continue - if (t.date < startTime || t.date > endTime) continue - val midnight = MidnightTime.calc(t.date) + repository.getBolusesDataFromTimeToTime(startTime, endTime, true).blockingGet() + .filter { it.type != Bolus.Type.PRIMING } + .forEach { t -> + val midnight = MidnightTime.calc(t.timestamp) + val tdd = result[midnight] ?: TDD(midnight, 0.0, 0.0, 0.0) + tdd.bolus += t.amount + result.put(midnight, tdd) + } + repository.getCarbsDataFromTimeToTimeExpanded(startTime, endTime, true).blockingGet().forEach { t -> + val midnight = MidnightTime.calc(t.timestamp) val tdd = result[midnight] ?: TDD(midnight, 0.0, 0.0, 0.0) - tdd.bolus += t.insulin - tdd.carbs += t.carbs + tdd.carbs += t.amount result.put(midnight, tdd) } for (t in startTime until endTime step T.mins(5).msecs()) { val midnight = MidnightTime.calc(t) val tdd = result[midnight] ?: TDD(midnight, 0.0, 0.0, 0.0) - val tbr = getTempBasalFromHistory(t) - val profile = profileFunction.getProfile(t, this) ?: continue - val absoluteRate = tbr?.tempBasalConvertedToAbsolute(t, profile) ?: profile.getBasal(t) + val tbr = iobCobCalculator.getTempBasalIncludingConvertedExtended(t) + val profile = profileFunction.getProfile(t) ?: continue + val absoluteRate = tbr?.convertedToAbsolute(t, profile) ?: profile.getBasal(t) tdd.basal += absoluteRate / 60.0 * 5.0 if (!activePlugin.activePump.isFakingTempsByExtendedBoluses) { // they are not included in TBRs - val eb = getExtendedBolusFromHistory(t) - val absoluteEbRate = eb?.absoluteRate() ?: 0.0 + val eb = iobCobCalculator.getExtendedBolus(t) + val absoluteEbRate = eb?.rate ?: 0.0 tdd.bolus += absoluteEbRate / 60.0 * 5.0 } result.put(midnight, tdd) diff --git a/app/src/main/java/info/nightscout/androidaps/utils/stats/TirCalculator.kt b/app/src/main/java/info/nightscout/androidaps/utils/stats/TirCalculator.kt index d1f7c74bf1..eaa702f63f 100644 --- a/app/src/main/java/info/nightscout/androidaps/utils/stats/TirCalculator.kt +++ b/app/src/main/java/info/nightscout/androidaps/utils/stats/TirCalculator.kt @@ -26,8 +26,8 @@ class TirCalculator @Inject constructor( fun calculate(days: Long, lowMgdl: Double, highMgdl: Double): LongSparseArray { if (lowMgdl < 39) throw RuntimeException("Low below 39") if (lowMgdl > highMgdl) throw RuntimeException("Low > High") - val startTime = MidnightTime.calc(DateUtil.now() - T.days(days).msecs()) - val endTime = MidnightTime.calc(DateUtil.now()) + val startTime = MidnightTime.calc(dateUtil.now() - T.days(days).msecs()) + val endTime = MidnightTime.calc(dateUtil.now()) val bgReadings = repository.compatGetBgReadingsDataFromTime(startTime, endTime, true).blockingGet() val result = LongSparseArray() diff --git a/app/src/main/java/info/nightscout/androidaps/utils/wizard/BolusWizard.kt b/app/src/main/java/info/nightscout/androidaps/utils/wizard/BolusWizard.kt index 05c441b369..528a09b440 100644 --- a/app/src/main/java/info/nightscout/androidaps/utils/wizard/BolusWizard.kt +++ b/app/src/main/java/info/nightscout/androidaps/utils/wizard/BolusWizard.kt @@ -5,15 +5,18 @@ import android.content.Intent import android.text.Spanned import com.google.common.base.Joiner import dagger.android.HasAndroidInjector -import info.nightscout.androidaps.Config +import info.nightscout.androidaps.interfaces.Config import info.nightscout.androidaps.R import info.nightscout.androidaps.activities.ErrorHelperActivity import info.nightscout.androidaps.data.DetailedBolusInfo import info.nightscout.androidaps.data.Profile +import info.nightscout.androidaps.database.AppRepository +import info.nightscout.androidaps.database.entities.BolusCalculatorResult +import info.nightscout.androidaps.database.entities.ValueWithUnit import info.nightscout.androidaps.database.entities.TemporaryTarget -import info.nightscout.androidaps.database.entities.TherapyEvent -import info.nightscout.androidaps.database.entities.UserEntry.* -import info.nightscout.androidaps.db.Source +import info.nightscout.androidaps.database.entities.UserEntry.Action +import info.nightscout.androidaps.database.entities.UserEntry.Sources +import info.nightscout.androidaps.database.transactions.InsertOrUpdateBolusCalculatorResultTransaction import info.nightscout.androidaps.events.EventRefreshOverview import info.nightscout.androidaps.interfaces.* import info.nightscout.androidaps.logging.AAPSLogger @@ -24,7 +27,6 @@ import info.nightscout.androidaps.plugins.bus.RxBusWrapper import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker import info.nightscout.androidaps.plugins.iob.iobCobCalculator.GlucoseStatus import info.nightscout.androidaps.plugins.iob.iobCobCalculator.GlucoseStatusProvider -import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorPlugin import info.nightscout.androidaps.queue.Callback import info.nightscout.androidaps.utils.CarbTimer import info.nightscout.androidaps.utils.DateUtil @@ -32,11 +34,11 @@ import info.nightscout.androidaps.utils.HtmlHelper import info.nightscout.androidaps.utils.Round import info.nightscout.androidaps.utils.T import info.nightscout.androidaps.utils.alertDialogs.OKDialog -import info.nightscout.androidaps.utils.extensions.formatColor +import info.nightscout.androidaps.extensions.formatColor import info.nightscout.androidaps.utils.resources.ResourceHelper import info.nightscout.androidaps.utils.sharedPreferences.SP -import org.json.JSONException -import org.json.JSONObject +import io.reactivex.disposables.CompositeDisposable +import io.reactivex.rxkotlin.plusAssign import java.util.* import javax.inject.Inject import kotlin.math.abs @@ -51,15 +53,18 @@ class BolusWizard @Inject constructor( @Inject lateinit var sp: SP @Inject lateinit var profileFunction: ProfileFunction @Inject lateinit var constraintChecker: ConstraintChecker - @Inject lateinit var activePlugin: ActivePluginProvider + @Inject lateinit var activePlugin: ActivePlugin @Inject lateinit var commandQueue: CommandQueueProvider @Inject lateinit var loopPlugin: LoopPlugin - @Inject lateinit var iobCobCalculatorPlugin: IobCobCalculatorPlugin + @Inject lateinit var iobCobCalculator: IobCobCalculator @Inject lateinit var dateUtil: DateUtil @Inject lateinit var config: Config @Inject lateinit var uel: UserEntryLogger @Inject lateinit var carbTimer: CarbTimer @Inject lateinit var glucoseStatusProvider: GlucoseStatusProvider + @Inject lateinit var repository: AppRepository + + private val disposable = CompositeDisposable() init { injector.androidInjector().inject(this) @@ -114,7 +119,7 @@ class BolusWizard @Inject constructor( var cob: Double = 0.0 var bg: Double = 0.0 private var correction: Double = 0.0 - private var percentageCorrection: Double = 0.0 + private var percentageCorrection: Int = 0 private var useBg: Boolean = false private var useCob: Boolean = false private var includeBolusIOB: Boolean = false @@ -125,6 +130,7 @@ class BolusWizard @Inject constructor( private var useAlarm = false var notes: String = "" private var carbTime: Int = 0 + private var quickWizard: Boolean = true @JvmOverloads fun doCalc(profile: Profile, @@ -134,7 +140,7 @@ class BolusWizard @Inject constructor( cob: Double, bg: Double, correction: Double, - percentageCorrection: Double = 100.0, + percentageCorrection: Int = 100, useBg: Boolean, useCob: Boolean, includeBolusIOB: Boolean, @@ -144,7 +150,8 @@ class BolusWizard @Inject constructor( useTrend: Boolean, useAlarm: Boolean, notes: String = "", - carbTime: Int = 0 + carbTime: Int = 0, + quickWizard: Boolean = false ): BolusWizard { this.profile = profile @@ -165,6 +172,7 @@ class BolusWizard @Inject constructor( this.useAlarm = useAlarm this.notes = notes this.carbTime = carbTime + this.quickWizard = quickWizard // Insulin from BG sens = Profile.fromMgdlToUnits(profile.isfMgdl, profileFunction.getUnits()) @@ -199,10 +207,8 @@ class BolusWizard @Inject constructor( // Insulin from IOB // IOB calculation - activePlugin.activeTreatments.updateTotalIOBTreatments() - val bolusIob = activePlugin.activeTreatments.lastCalculationTreatments.round() - activePlugin.activeTreatments.updateTotalIOBTempBasals() - val basalIob = activePlugin.activeTreatments.lastCalculationTempBasals.round() + val bolusIob = iobCobCalculator.calculateIobFromBolus().round() + val basalIob = iobCobCalculator.calculateIobFromTempBasalsIncludingConvertedExtended().round() insulinFromBolusIOB = if (includeBolusIOB) -bolusIob.iob else 0.0 insulinFromBasalIOB = if (includeBasalIOB) -basalIob.basaliob else 0.0 @@ -241,53 +247,45 @@ class BolusWizard @Inject constructor( return this } - @Suppress("SpellCheckingInspection") - private fun nsJSON(): JSONObject { - val bolusCalcJSON = JSONObject() - try { - bolusCalcJSON.put("profile", profileName) - bolusCalcJSON.put("notes", notes) - bolusCalcJSON.put("eventTime", DateUtil.toISOString(Date())) - bolusCalcJSON.put("targetBGLow", targetBGLow) - bolusCalcJSON.put("targetBGHigh", targetBGHigh) - bolusCalcJSON.put("isf", sens) - bolusCalcJSON.put("ic", ic) - bolusCalcJSON.put("iob", -(insulinFromBolusIOB + insulinFromBasalIOB)) - bolusCalcJSON.put("bolusiob", insulinFromBolusIOB) - bolusCalcJSON.put("basaliob", insulinFromBasalIOB) - bolusCalcJSON.put("bolusiobused", includeBolusIOB) - bolusCalcJSON.put("basaliobused", includeBasalIOB) - bolusCalcJSON.put("bg", bg) - bolusCalcJSON.put("insulinbg", insulinFromBG) - bolusCalcJSON.put("insulinbgused", useBg) - bolusCalcJSON.put("bgdiff", bgDiff) - bolusCalcJSON.put("insulincarbs", insulinFromCarbs) - bolusCalcJSON.put("carbs", carbs) - bolusCalcJSON.put("cob", cob) - bolusCalcJSON.put("cobused", useCob) - bolusCalcJSON.put("insulincob", insulinFromCOB) - bolusCalcJSON.put("othercorrection", correction) - bolusCalcJSON.put("insulinsuperbolus", insulinFromSuperBolus) - bolusCalcJSON.put("insulintrend", insulinFromTrend) - bolusCalcJSON.put("insulin", calculatedTotalInsulin) - bolusCalcJSON.put("superbolusused", useSuperBolus) - bolusCalcJSON.put("insulinsuperbolus", insulinFromSuperBolus) - bolusCalcJSON.put("trendused", useTrend) - bolusCalcJSON.put("insulintrend", insulinFromTrend) - bolusCalcJSON.put("trend", trend) - bolusCalcJSON.put("ttused", useTT) - bolusCalcJSON.put("percentageCorrection", percentageCorrection) - } catch (e: JSONException) { - aapsLogger.error("Unhandled exception", e) - } - return bolusCalcJSON - } + private fun createBolusCalculatorResult(): BolusCalculatorResult = + BolusCalculatorResult( + timestamp = dateUtil.now(), + targetBGLow = targetBGLow, + targetBGHigh = targetBGHigh, + isf = sens, + ic = ic, + bolusIOB = insulinFromBolusIOB, + wasBolusIOBUsed = includeBolusIOB, + basalIOB = insulinFromBasalIOB, + wasBasalIOBUsed = includeBasalIOB, + glucoseValue = bg, + wasGlucoseUsed = useBg && bg > 0, + glucoseDifference = bgDiff, + glucoseInsulin = insulinFromBG, + glucoseTrend = trend, + wasTrendUsed = useTrend, + trendInsulin = insulinFromTrend, + cob = cob, + wasCOBUsed = useCob, + cobInsulin = insulinFromCOB, + carbs = carbs.toDouble(), + wereCarbsUsed = cob > 0, + carbsInsulin = insulinFromCarbs, + otherCorrection = correction, + wasSuperbolusUsed = useSuperBolus, + superbolusInsulin = insulinFromSuperBolus, + wasTempTargetUsed = useTT, + totalInsulin = calculatedTotalInsulin, + percentageCorrection = percentageCorrection, + profileName = profileName, + note = notes + ) private fun confirmMessageAfterConstraints(advisor: Boolean): Spanned { val actions: LinkedList = LinkedList() if (insulinAfterConstraints > 0) { - val pct = if (percentageCorrection != 100.0) " (" + percentageCorrection.toInt() + "%)" else "" + val pct = if (percentageCorrection != 100) " ($percentageCorrection%)" else "" actions.add(resourceHelper.gs(R.string.bolus) + ": " + resourceHelper.gs(R.string.formatinsulinunits, insulinAfterConstraints).formatColor(resourceHelper, R.color.bolus) + pct) } if (carbs > 0 && !advisor) { @@ -301,7 +299,7 @@ class BolusWizard @Inject constructor( } if (insulinFromCOB > 0) { actions.add(resourceHelper.gs(R.string.cobvsiob) + ": " + resourceHelper.gs(R.string.formatsignedinsulinunits, insulinFromBolusIOB + insulinFromBasalIOB + insulinFromCOB + insulinFromBG).formatColor(resourceHelper, R.color.cobAlert)) - val absorptionRate = iobCobCalculatorPlugin.slowAbsorptionPercentage(60) + val absorptionRate = iobCobCalculator.ads.slowAbsorptionPercentage(60) if (absorptionRate > .25) actions.add(resourceHelper.gs(R.string.slowabsorptiondetected, resourceHelper.gc(R.color.cobAlert), (absorptionRate * 100).toInt())) } @@ -339,17 +337,19 @@ class BolusWizard @Inject constructor( val confirmMessage = confirmMessageAfterConstraints(advisor = true) OKDialog.showConfirmation(ctx, resourceHelper.gs(R.string.boluswizard), confirmMessage, { DetailedBolusInfo().apply { - eventType = TherapyEvent.Type.CORRECTION_BOLUS.text + eventType = DetailedBolusInfo.EventType.CORRECTION_BOLUS insulin = insulinAfterConstraints carbs = 0.0 context = ctx - glucose = bg - glucoseType = "Manual" + mgdlGlucose = Profile.toMgdl(bg, profile.units) + glucoseType = DetailedBolusInfo.MeterType.MANUAL carbTime = 0 - boluscalc = nsJSON() - source = Source.USER + bolusCalculatorResult = createBolusCalculatorResult() notes = this@BolusWizard.notes - uel.log(Action.BOLUS_ADVISOR, notes, ValueWithUnit(eventType, Units.TherapyEvent), ValueWithUnit(insulinAfterConstraints, Units.U)) + uel.log(Action.BOLUS_ADVISOR, if (quickWizard) Sources.QuickWizard else Sources.WizardDialog, + notes, + ValueWithUnit.TherapyEventType(eventType.toDBbEventType()), + ValueWithUnit.Insulin(insulinAfterConstraints)) if (insulin > 0) { commandQueue.bolus(this, object : Callback() { override fun run() { @@ -372,14 +372,14 @@ class BolusWizard @Inject constructor( OKDialog.showConfirmation(ctx, resourceHelper.gs(R.string.boluswizard), confirmMessage, { if (insulinAfterConstraints > 0 || carbs > 0) { if (useSuperBolus) { - uel.log(Action.SUPERBOLUS_TBR) + uel.log(Action.SUPERBOLUS_TBR, Sources.WizardDialog) if (loopPlugin.isEnabled(PluginType.LOOP)) { loopPlugin.superBolusTo(System.currentTimeMillis() + 2 * 60L * 60 * 1000) rxBus.send(EventRefreshOverview("WizardDialog")) } if (pump.pumpDescription.tempBasalStyle == PumpDescription.ABSOLUTE) { - commandQueue.tempBasalAbsolute(0.0, 120, true, profile, object : Callback() { + commandQueue.tempBasalAbsolute(0.0, 120, true, profile, PumpSync.TemporaryBasalType.NORMAL, object : Callback() { override fun run() { if (!result.success) { ErrorHelperActivity.runAlarm(ctx, result.comment, resourceHelper.gs(R.string.tempbasaldeliveryerror), R.raw.boluserror) @@ -387,8 +387,7 @@ class BolusWizard @Inject constructor( } }) } else { - - commandQueue.tempBasalPercent(0, 120, true, profile, object : Callback() { + commandQueue.tempBasalPercent(0, 120, true, profile, PumpSync.TemporaryBasalType.NORMAL, object : Callback() { override fun run() { if (!result.success) { val i = Intent(ctx, ErrorHelperActivity::class.java) @@ -403,18 +402,27 @@ class BolusWizard @Inject constructor( } } DetailedBolusInfo().apply { - eventType = TherapyEvent.Type.BOLUS_WIZARD.text + eventType = DetailedBolusInfo.EventType.BOLUS_WIZARD insulin = insulinAfterConstraints carbs = this@BolusWizard.carbs.toDouble() context = ctx - glucose = bg - glucoseType = "Manual" + mgdlGlucose = Profile.toMgdl(bg, profile.units) + glucoseType = DetailedBolusInfo.MeterType.MANUAL carbTime = this@BolusWizard.carbTime - boluscalc = nsJSON() - source = Source.USER + bolusCalculatorResult = createBolusCalculatorResult() notes = this@BolusWizard.notes - uel.log(Action.BOLUS, notes, ValueWithUnit(eventType,Units.TherapyEvent), ValueWithUnit(insulinAfterConstraints, Units.U), ValueWithUnit(this@BolusWizard.carbs, Units.G, this@BolusWizard.carbs != 0), ValueWithUnit(carbTime, Units.M, carbTime != 0)) - if (insulin > 0 || pump.pumpDescription.storesCarbInfo) { + if (insulin > 0 || carbs > 0) { + val action = when { + insulinAfterConstraints.equals(0.0) -> Action.CARBS + carbs.equals(0.0) -> Action.BOLUS + else -> Action.TREATMENT + } + uel.log(action, if (quickWizard) Sources.QuickWizard else Sources.WizardDialog, + notes, + ValueWithUnit.TherapyEventType(eventType.toDBbEventType()), + ValueWithUnit.Insulin(insulinAfterConstraints).takeIf { insulinAfterConstraints != 0.0 }, + ValueWithUnit.Gram(this@BolusWizard.carbs).takeIf { this@BolusWizard.carbs != 0 }, + ValueWithUnit.Minute(carbTime).takeIf { carbTime != 0 }) commandQueue.bolus(this, object : Callback() { override fun run() { if (!result.success) { @@ -422,12 +430,16 @@ class BolusWizard @Inject constructor( } } }) - } else { - activePlugin.activeTreatments.addToHistoryTreatment(this, false) } + disposable += repository.runTransactionForResult(InsertOrUpdateBolusCalculatorResultTransaction(bolusCalculatorResult!!)) + .subscribe( + { result -> result.inserted.forEach { inserted -> aapsLogger.debug(LTag.DATABASE, "Inserted bolusCalculatorResult $inserted") } }, + { aapsLogger.error(LTag.DATABASE, "Error while saving bolusCalculatorResult", it) } + ) + } if (useAlarm && carbs > 0 && carbTime > 0) { - carbTimer.scheduleReminder(dateUtil._now() + T.mins(carbTime.toLong()).msecs()) + carbTimer.scheduleReminder(dateUtil.now() + T.mins(carbTime.toLong()).msecs()) } } }) diff --git a/app/src/main/java/info/nightscout/androidaps/utils/wizard/QuickWizardEntry.kt b/app/src/main/java/info/nightscout/androidaps/utils/wizard/QuickWizardEntry.kt index 471bd0898a..5d3496e7e6 100644 --- a/app/src/main/java/info/nightscout/androidaps/utils/wizard/QuickWizardEntry.kt +++ b/app/src/main/java/info/nightscout/androidaps/utils/wizard/QuickWizardEntry.kt @@ -6,21 +6,18 @@ import info.nightscout.androidaps.data.Profile import info.nightscout.androidaps.database.AppRepository import info.nightscout.androidaps.database.ValueWrapper import info.nightscout.androidaps.database.entities.GlucoseValue +import info.nightscout.androidaps.interfaces.IobCobCalculator import info.nightscout.androidaps.interfaces.ProfileFunction import info.nightscout.androidaps.logging.AAPSLogger import info.nightscout.androidaps.plugins.aps.loop.LoopPlugin -import info.nightscout.androidaps.plugins.iob.iobCobCalculator.GlucoseStatus import info.nightscout.androidaps.plugins.iob.iobCobCalculator.GlucoseStatusProvider -import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorPlugin -import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin import info.nightscout.androidaps.utils.DateUtil import info.nightscout.androidaps.utils.JsonHelper.safeGetInt import info.nightscout.androidaps.utils.JsonHelper.safeGetString -import info.nightscout.androidaps.utils.extensions.valueToUnits +import info.nightscout.androidaps.extensions.valueToUnits import info.nightscout.androidaps.utils.sharedPreferences.SP import org.json.JSONException import org.json.JSONObject -import java.util.* import javax.inject.Inject class QuickWizardEntry @Inject constructor(private val injector: HasAndroidInjector) { @@ -28,9 +25,8 @@ class QuickWizardEntry @Inject constructor(private val injector: HasAndroidInjec @Inject lateinit var aapsLogger: AAPSLogger @Inject lateinit var sp: SP @Inject lateinit var profileFunction: ProfileFunction - @Inject lateinit var treatmentsPlugin: TreatmentsPlugin @Inject lateinit var loopPlugin: LoopPlugin - @Inject lateinit var iobCobCalculatorPlugin: IobCobCalculatorPlugin + @Inject lateinit var iobCobCalculator: IobCobCalculator @Inject lateinit var repository: AppRepository @Inject lateinit var dateUtil: DateUtil @Inject lateinit var glucoseStatusProvider: GlucoseStatusProvider @@ -80,7 +76,7 @@ class QuickWizardEntry @Inject constructor(private val injector: HasAndroidInjec fun isActive(): Boolean = Profile.secondsFromMidnight() >= validFrom() && Profile.secondsFromMidnight() <= validTo() fun doCalc(profile: Profile, profileName: String, lastBG: GlucoseValue, _synchronized: Boolean): BolusWizard { - val dbRecord = repository.getTemporaryTargetActiveAt(dateUtil._now()).blockingGet() + val dbRecord = repository.getTemporaryTargetActiveAt(dateUtil.now()).blockingGet() val tempTarget = if (dbRecord is ValueWrapper.Existing) dbRecord.value else null //BG var bg = 0.0 @@ -90,7 +86,7 @@ class QuickWizardEntry @Inject constructor(private val injector: HasAndroidInjec // COB var cob = 0.0 if (useCOB() == YES) { - val cobInfo = iobCobCalculatorPlugin.getCobInfo(_synchronized, "QuickWizard COB") + val cobInfo = iobCobCalculator.getCobInfo(_synchronized, "QuickWizard COB") if (cobInfo.displayCob != null) cob = cobInfo.displayCob!! } // Bolus IOB @@ -99,8 +95,7 @@ class QuickWizardEntry @Inject constructor(private val injector: HasAndroidInjec bolusIOB = true } // Basal IOB - treatmentsPlugin.updateTotalIOBTempBasals() - val basalIob = treatmentsPlugin.lastCalculationTempBasals.round() + val basalIob = iobCobCalculator.calculateIobFromTempBasalsIncludingConvertedExtended().round() var basalIOB = false if (useBasalIOB() == YES) { basalIOB = true @@ -125,17 +120,17 @@ class QuickWizardEntry @Inject constructor(private val injector: HasAndroidInjec } else if (useTrend() == NEGATIVE_ONLY && glucoseStatus != null && glucoseStatus.shortAvgDelta < 0) { trend = true } - val percentage = sp.getDouble(R.string.key_boluswizard_percentage, 100.0) - return BolusWizard(injector).doCalc(profile, profileName, tempTarget, carbs(), cob, bg, 0.0, percentage, true, useCOB() == YES, bolusIOB, basalIOB, superBolus, useTempTarget() == YES, trend, false, "QuickWizard") + val percentage = sp.getInt(R.string.key_boluswizard_percentage, 100) + return BolusWizard(injector).doCalc(profile, profileName, tempTarget, carbs(), cob, bg, 0.0, percentage, true, useCOB() == YES, bolusIOB, basalIOB, superBolus, useTempTarget() == YES, trend, false, buttonText(), quickWizard = true) //tbc, ok if only quickwizard, but if other sources elsewhere use Sources.QuickWiard } fun buttonText(): String = safeGetString(storage, "buttonText", "") fun carbs(): Int = safeGetInt(storage, "carbs") - fun validFromDate(): Date = DateUtil.toDate(validFrom()) + fun validFromDate(): Long = dateUtil.secondsOfTheDayToMilliseconds(validFrom()) - fun validToDate(): Date = DateUtil.toDate(validTo()) + fun validToDate(): Long = dateUtil.secondsOfTheDayToMilliseconds(validTo()) fun validFrom(): Int = safeGetInt(storage, "validFrom") diff --git a/app/src/main/res/layout/dialog_temptarget.xml b/app/src/main/res/layout/dialog_temptarget.xml index 7a53ea8496..61f92c402f 100644 --- a/app/src/main/res/layout/dialog_temptarget.xml +++ b/app/src/main/res/layout/dialog_temptarget.xml @@ -141,8 +141,6 @@ - - - - + android:autoLink="web" + tools:ignore="RtlHardcoded" /> @@ -42,18 +39,19 @@ android:gravity="center_horizontal"> + android:text="@string/nsclientinternal_autoscroll" + tools:ignore="RtlHardcoded" /> @@ -68,21 +66,23 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginRight="5dp" - android:text="@string/status" /> + android:text="@string/status" + tools:ignore="RtlHardcoded" /> + android:textAlignment="viewEnd" + tools:ignore="RtlHardcoded" /> @@ -96,7 +96,7 @@ android:layout_marginTop="10dp"> + + - - - - + diff --git a/app/src/main/res/layout/treatments_bolus_fragment.xml b/app/src/main/res/layout/treatments_bolus_carbs_fragment.xml similarity index 56% rename from app/src/main/res/layout/treatments_bolus_fragment.xml rename to app/src/main/res/layout/treatments_bolus_carbs_fragment.xml index e1690c3bcf..83b2d9284c 100644 --- a/app/src/main/res/layout/treatments_bolus_fragment.xml +++ b/app/src/main/res/layout/treatments_bolus_carbs_fragment.xml @@ -1,52 +1,10 @@ - - - - - - - - - - - - + tools:context=".plugins.treatments.fragments.TreatmentsBolusCarbsFragment"> + + + + @@ -31,49 +32,165 @@ android:id="@+id/date" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:paddingStart="5dp" - tools:ignore="RtlSymmetry" /> + android:layout_marginStart="5dp" + android:text="1.1.2000" + tools:ignore="HardcodedText,RtlSymmetry" /> + android:text="" /> + - + android:layout_gravity="center_vertical" + android:layout_marginStart="15dp" + android:gravity="center" + android:text="{fa-clock-o}" + tools:ignore="HardcodedText,RtlSymmetry" /> + + + android:layout_marginStart="10dp" + android:text="1.00 U" + android:textStyle="bold" + tools:ignore="HardcodedText" /> + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - + + - - - - - - - - - - - - + + diff --git a/app/src/main/res/layout/treatments_careportal_fragment.xml b/app/src/main/res/layout/treatments_careportal_fragment.xml index 973d528718..438aa7c1de 100644 --- a/app/src/main/res/layout/treatments_careportal_fragment.xml +++ b/app/src/main/res/layout/treatments_careportal_fragment.xml @@ -44,7 +44,7 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_vertical" - android:contentDescription="@string/show_calculation" + android:contentDescription="@string/show_removed" app:srcCompat="@drawable/ic_visibility" /> diff --git a/app/src/main/res/layout/treatments_extendedbolus_fragment.xml b/app/src/main/res/layout/treatments_extendedbolus_fragment.xml index 012880afe9..3f08ead681 100644 --- a/app/src/main/res/layout/treatments_extendedbolus_fragment.xml +++ b/app/src/main/res/layout/treatments_extendedbolus_fragment.xml @@ -1,10 +1,34 @@ + + + + + + + + - - - - - - - - - - - - - - - - @@ -156,6 +92,25 @@ android:layout_height="wrap_content" android:layout_gravity="top" android:paddingLeft="10dp" + android:paddingEnd="5dp" + android:text="@string/tempbasals_netratio_label_string" + android:textAppearance="?android:attr/textAppearanceSmall" + tools:ignore="RtlSymmetry" /> + + + + @@ -171,15 +126,35 @@ tools:ignore="HardcodedText" /> + + + + + + + android:orientation="horizontal"> - - + android:layout_gravity="center_vertical" + android:contentDescription="@string/show_removed" + app:srcCompat="@drawable/ic_visibility" /> + diff --git a/app/src/main/res/layout/treatments_tempbasals_item.xml b/app/src/main/res/layout/treatments_tempbasals_item.xml index 3816019fb9..cd9d6fcc4f 100644 --- a/app/src/main/res/layout/treatments_tempbasals_item.xml +++ b/app/src/main/res/layout/treatments_tempbasals_item.xml @@ -38,16 +38,7 @@ tools:ignore="HardcodedText" /> - - + + - - - - - - - - - - - - - @@ -160,11 +109,17 @@ android:id="@+id/ns" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:layout_marginEnd="10dp" + android:layout_marginStart="5dp" android:text="NS" android:textColor="@color/colorSetTempButton" tools:ignore="HardcodedText" /> + + + + + + + + diff --git a/app/src/main/res/layout/treatments_temptarget_fragment.xml b/app/src/main/res/layout/treatments_temptarget_fragment.xml index 24e20fe06f..b264f63d79 100644 --- a/app/src/main/res/layout/treatments_temptarget_fragment.xml +++ b/app/src/main/res/layout/treatments_temptarget_fragment.xml @@ -35,10 +35,9 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_vertical" - android:contentDescription="@string/show_calculation" + android:contentDescription="@string/show_removed" app:srcCompat="@drawable/ic_visibility" /> - - + android:orientation="horizontal"> + + + + + + + + + - + android:orientation="horizontal" > - - - + app:layout_constraintStart_toEndOf="@id/date" + app:layout_constraintEnd_toStartOf="@+id/iconSource" + app:layout_constraintTop_toTopOf="parent" + android:textAppearance="?android:attr/textAppearanceSmall" /> + + - @@ -54,8 +63,12 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:paddingStart="20dp" - android:visibility="gone" + android:paddingEnd="10dp" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@id/values" android:textAppearance="?android:attr/textAppearanceSmall" + android:visibility="gone" + android:text="Notes" tools:ignore="HardcodedText,RtlSymmetry" /> - - + diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 52a1be72c3..a523ed73cb 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -33,6 +33,19 @@ protection absorption_category_settings insulin_oref_peak_settings + ns_temporary_target_last_sync + ns_glucose_value_last_sync + ns_food_last_sync + ns_therapy_event_last_sync + smscommunicator_remotebolusmindistance + bolussnooze_dia_divisor + autosens_adjust_targets + ns_bolus_calculator_result_last_synced_id + ns_carbs_last_synced_id + ns_bolus_last_synced_id + ns_device_status_last_synced_id + ns_temporary_basal_last_synced_id + ns_extended_bolus_last_synced_id Treatments safety Max allowed bolus [U] @@ -131,7 +144,6 @@ Which constraints are applied? Constraints - Loop Loop Use this to activate AndroidAPS\' loop integration. APS @@ -226,7 +238,6 @@ SMS Remote Service stopped. To reactivate it, use AAPS on master smartphone. To send calibration %1$.2f reply with code %2$s Bolus failed - smscommunicator_remotebolusmindistance Minimum number of minutes that must elapse between one remote bolus and the next How many minutes must elapse, at least, between one bolus and the next For your safety, to edit this preference you need to add at least 2 phone numbers. @@ -339,10 +350,8 @@ Default value: 4 This is the other half of the key OpenAPS safety caps, and the other half of “3x max daily; 4x current” of the safety caps. This means your basal, regardless of max basal set on your pump, cannot be any higher than this number times the current level of your basal. This is to prevent people from getting into dangerous territory by setting excessively high max basals before understanding how the algorithm works. Again, the default is 4x; most people will never need to adjust this and are instead more likely to need to adjust other settings if they feel like they are “running into” this safety cap. Default value: 1.2\nThis is a multiplier cap for autosens (and soon autotune) to set a 20%% max limit on how high the autosens ratio can be, which in turn determines how high autosens can adjust basals, how low it can adjust ISF, and how low it can set the BG target. Default value: 0.7\nThe other side of the autosens safety limits, putting a cap on how low autosens can adjust basals, and how high it can adjust ISF and BG targets. - autosens_adjust_targets Autosens adjust targets, too Default value: true\nThis is used to allow autosens to adjust BG targets, in addition to ISF and basals. - bolussnooze_dia_divisor Default value: 2\nBolus snooze is enacted after you do a meal bolus, so the loop won’t counteract with low temps when you’ve just eaten. The example here and default is 2; so a 3 hour DIA means that bolus snooze will be gradually phased out over 1.5 hours (3DIA/2). min_5m_carbimpact Default value: 3.0 (AMA) or 8.0 (SMB). This is a setting for default carb absorption impact per 5 minutes. The default is an expected 3mg/dl/5min. This affects how fast COB are decayed, and how much carb absorption is assumed in calculating future predicted BG, when BG is falling more than expected, or not rising as much as expected. @@ -511,7 +520,6 @@ Amount of hours in the past for sensitivity detection (carbs absorption time is excluded) openapsama_autosens_period nsclient_localbroadcasts - Pump OpenAPS Uploader Sensitivity detection @@ -978,6 +986,7 @@ BG Tools Show calcuation + Show removed Clear queue? All data in queue will be lost! xdripstatus_detailediob xdripstatus_showbgi @@ -1125,7 +1134,7 @@ Maximal profile basal value Current basal value Profile carbs ratio value - - + Full sync + Prime diff --git a/app/src/test/java/info/nightscout/androidaps/TestBase.kt b/app/src/test/java/info/nightscout/androidaps/TestBase.kt index ff88739ba2..0a544ea43d 100644 --- a/app/src/test/java/info/nightscout/androidaps/TestBase.kt +++ b/app/src/test/java/info/nightscout/androidaps/TestBase.kt @@ -1,10 +1,13 @@ package info.nightscout.androidaps +import android.content.Context import info.nightscout.androidaps.logging.AAPSLoggerTest +import info.nightscout.androidaps.utils.DateUtil import info.nightscout.androidaps.utils.rx.AapsSchedulers import info.nightscout.androidaps.utils.rx.TestAapsSchedulers import org.junit.Before import org.junit.Rule +import org.mockito.Mock import org.mockito.Mockito import org.mockito.junit.MockitoJUnit import org.mockito.junit.MockitoRule diff --git a/app/src/test/java/info/nightscout/androidaps/TestBaseWithProfile.kt b/app/src/test/java/info/nightscout/androidaps/TestBaseWithProfile.kt index e3e5c7391b..84321ee27e 100644 --- a/app/src/test/java/info/nightscout/androidaps/TestBaseWithProfile.kt +++ b/app/src/test/java/info/nightscout/androidaps/TestBaseWithProfile.kt @@ -1,18 +1,13 @@ package info.nightscout.androidaps +import android.content.Context import dagger.android.AndroidInjector import dagger.android.HasAndroidInjector import info.nightscout.androidaps.data.Profile import info.nightscout.androidaps.db.ProfileSwitch -import info.nightscout.androidaps.db.Treatment -import info.nightscout.androidaps.interfaces.ActivePluginProvider -import info.nightscout.androidaps.interfaces.ConfigInterface -import info.nightscout.androidaps.interfaces.ProfileFunction -import info.nightscout.androidaps.interfaces.ProfileStore -import info.nightscout.androidaps.interfaces.TreatmentsInterface +import info.nightscout.androidaps.interfaces.* import info.nightscout.androidaps.plugins.bus.RxBusWrapper import info.nightscout.androidaps.utils.DateUtil -import info.nightscout.androidaps.utils.DefaultValueHelper import info.nightscout.androidaps.utils.FabricPrivacy import info.nightscout.androidaps.utils.resources.ResourceHelper import org.json.JSONObject @@ -24,15 +19,16 @@ import org.powermock.core.classloader.annotations.PrepareForTest @PrepareForTest(FabricPrivacy::class) open class TestBaseWithProfile : TestBase() { - @Mock lateinit var activePluginProvider: ActivePluginProvider + @Mock lateinit var activePluginProvider: ActivePlugin @Mock lateinit var resourceHelper: ResourceHelper @Mock lateinit var treatmentsInterface: TreatmentsInterface + @Mock lateinit var iobCobCalculator: IobCobCalculator @Mock lateinit var fabricPrivacy: FabricPrivacy @Mock lateinit var profileFunction: ProfileFunction - @Mock lateinit var defaultValueHelper: DefaultValueHelper - @Mock lateinit var dateUtil: DateUtil - @Mock lateinit var configInterface: ConfigInterface + @Mock lateinit var config: Config + @Mock lateinit var context: Context + lateinit var dateUtil: DateUtil val rxBus = RxBusWrapper(aapsSchedulers) val profileInjector = HasAndroidInjector { @@ -43,7 +39,8 @@ open class TestBaseWithProfile : TestBase() { it.resourceHelper = resourceHelper it.rxBus = rxBus it.fabricPrivacy = fabricPrivacy - it.configInterface = configInterface + it.config = config + it.dateUtil = dateUtil } if (it is ProfileSwitch) { it.treatmentsPlugin = treatmentsInterface @@ -52,12 +49,6 @@ open class TestBaseWithProfile : TestBase() { it.resourceHelper = resourceHelper it.dateUtil = dateUtil } - if (it is Treatment) { - it.activePlugin = activePluginProvider - it.profileFunction = profileFunction - it.defaultValueHelper = defaultValueHelper - it.resourceHelper = resourceHelper - } } } @@ -68,6 +59,7 @@ open class TestBaseWithProfile : TestBase() { @Before fun prepareMock() { validProfileJSON = "{\"dia\":\"3\",\"carbratio\":[{\"time\":\"00:00\",\"value\":\"30\"}],\"carbs_hr\":\"20\",\"delay\":\"20\",\"sens\":[{\"time\":\"00:00\",\"value\":\"100\"},{\"time\":\"2:00\",\"value\":\"110\"}],\"timezone\":\"UTC\",\"basal\":[{\"time\":\"00:00\",\"value\":\"1\"}],\"target_low\":[{\"time\":\"00:00\",\"value\":\"4\"}],\"target_high\":[{\"time\":\"00:00\",\"value\":\"5\"}],\"startDate\":\"1970-01-01T00:00:00.000Z\",\"units\":\"mmol\"}" + dateUtil = DateUtil(context) validProfile = Profile(profileInjector, JSONObject(validProfileJSON), Constants.MGDL) } diff --git a/app/src/test/java/info/nightscout/androidaps/TestPumpPlugin.kt b/app/src/test/java/info/nightscout/androidaps/TestPumpPlugin.kt index 97727ab5af..0cb1ec2e78 100644 --- a/app/src/test/java/info/nightscout/androidaps/TestPumpPlugin.kt +++ b/app/src/test/java/info/nightscout/androidaps/TestPumpPlugin.kt @@ -5,14 +5,15 @@ import info.nightscout.androidaps.data.DetailedBolusInfo import info.nightscout.androidaps.data.Profile import info.nightscout.androidaps.data.PumpEnactResult import info.nightscout.androidaps.interfaces.PumpDescription -import info.nightscout.androidaps.interfaces.PumpInterface +import info.nightscout.androidaps.interfaces.Pump +import info.nightscout.androidaps.interfaces.PumpSync import info.nightscout.androidaps.plugins.common.ManufacturerType import info.nightscout.androidaps.plugins.pump.common.defs.PumpType import info.nightscout.androidaps.utils.TimeChangeType import org.json.JSONObject @Suppress("MemberVisibilityCanBePrivate") -class TestPumpPlugin(val injector: HasAndroidInjector) : PumpInterface { +class TestPumpPlugin(val injector: HasAndroidInjector) : Pump { var connected = false var isProfileSet = true @@ -50,14 +51,14 @@ class TestPumpPlugin(val injector: HasAndroidInjector) : PumpInterface { override val batteryLevel: Int = 0 override fun deliverTreatment(detailedBolusInfo: DetailedBolusInfo): PumpEnactResult = PumpEnactResult(injector).success(true) override fun stopBolusDelivering() {} - override fun setTempBasalAbsolute(absoluteRate: Double, durationInMinutes: Int, profile: Profile, enforceNew: Boolean): PumpEnactResult = PumpEnactResult(injector).success(true) - override fun setTempBasalPercent(percent: Int, durationInMinutes: Int, profile: Profile, enforceNew: Boolean): PumpEnactResult = PumpEnactResult(injector).success(true) + override fun setTempBasalAbsolute(absoluteRate: Double, durationInMinutes: Int, profile: Profile, enforceNew: Boolean, tbrType: PumpSync.TemporaryBasalType): PumpEnactResult = PumpEnactResult(injector).success(true) + override fun setTempBasalPercent(percent: Int, durationInMinutes: Int, profile: Profile, enforceNew: Boolean, tbrType: PumpSync.TemporaryBasalType): PumpEnactResult = PumpEnactResult(injector).success(true) override fun setExtendedBolus(insulin: Double, durationInMinutes: Int): PumpEnactResult = PumpEnactResult(injector).success(true) override fun cancelTempBasal(enforceNew: Boolean): PumpEnactResult = PumpEnactResult(injector).success(true) override fun cancelExtendedBolus(): PumpEnactResult = PumpEnactResult(injector).success(true) override fun getJSONStatus(profile: Profile, profileName: String, version: String): JSONObject = JSONObject() override fun manufacturer(): ManufacturerType = ManufacturerType.AndroidAPS - override fun model(): PumpType = PumpType.GenericAAPS + override fun model(): PumpType = PumpType.GENERIC_AAPS override fun serialNumber(): String = "1" override fun shortStatus(veryShort: Boolean): String = "" override val isFakingTempsByExtendedBoluses: Boolean = false diff --git a/app/src/test/java/info/nightscout/androidaps/data/QuickWizardTest.kt b/app/src/test/java/info/nightscout/androidaps/data/QuickWizardTest.kt index 6deef1f826..9cf9031a61 100644 --- a/app/src/test/java/info/nightscout/androidaps/data/QuickWizardTest.kt +++ b/app/src/test/java/info/nightscout/androidaps/data/QuickWizardTest.kt @@ -30,13 +30,12 @@ class QuickWizardTest : TestBase() { @Mock lateinit var profileFunction: ProfileFunction @Mock lateinit var treatmentsPlugin: TreatmentsPlugin @Mock lateinit var loopPlugin: LoopPlugin - @Mock lateinit var iobCobCalculatorPlugin: IobCobCalculatorPlugin private val data1 = "{\"buttonText\":\"Meal\",\"carbs\":36,\"validFrom\":0,\"validTo\":18000," + "\"useBG\":0,\"useCOB\":0,\"useBolusIOB\":0,\"useBasalIOB\":0,\"useTrend\":0,\"useSuperBolus\":0,\"useTemptarget\":0}" private val data2 = "{\"buttonText\":\"Lunch\",\"carbs\":18,\"validFrom\":36000,\"validTo\":39600," + "\"useBG\":0,\"useCOB\":0,\"useBolusIOB\":1,\"useBasalIOB\":2,\"useTrend\":0,\"useSuperBolus\":0,\"useTemptarget\":0}" - var array: JSONArray = JSONArray("[$data1,$data2]") + private var array: JSONArray = JSONArray("[$data1,$data2]") val injector = HasAndroidInjector { AndroidInjector { @@ -44,9 +43,7 @@ class QuickWizardTest : TestBase() { it.aapsLogger = aapsLogger it.sp = sp it.profileFunction = profileFunction - it.treatmentsPlugin = treatmentsPlugin it.loopPlugin = loopPlugin - it.iobCobCalculatorPlugin = iobCobCalculatorPlugin } } } diff --git a/core/src/test/java/info/nightscout/androidaps/data/defaultProfile/DefaultProfileTest.kt b/app/src/test/java/info/nightscout/androidaps/data/defaultProfile/DefaultProfileTest.kt similarity index 61% rename from core/src/test/java/info/nightscout/androidaps/data/defaultProfile/DefaultProfileTest.kt rename to app/src/test/java/info/nightscout/androidaps/data/defaultProfile/DefaultProfileTest.kt index e97e63bafa..76cf88f4ff 100644 --- a/core/src/test/java/info/nightscout/androidaps/data/defaultProfile/DefaultProfileTest.kt +++ b/app/src/test/java/info/nightscout/androidaps/data/defaultProfile/DefaultProfileTest.kt @@ -1,29 +1,25 @@ package info.nightscout.androidaps.data.defaultProfile -import dagger.android.AndroidInjector -import dagger.android.HasAndroidInjector -import info.nightscout.androidaps.TestBase import info.nightscout.androidaps.Constants +import info.nightscout.androidaps.TestBaseWithProfile import org.junit.Assert.assertEquals import org.junit.Test -class DefaultProfileTest : TestBase() { - - val injector = HasAndroidInjector { AndroidInjector { } } +class DefaultProfileTest : TestBaseWithProfile() { @Test fun profile() { - var p = DefaultProfile(injector).profile(5.0, 5.1 / 0.3, 0.0, Constants.MMOL) + var p = DefaultProfile(profileInjector).profile(5.0, 5.1 / 0.3, 0.0, Constants.MMOL) assertEquals(0.150, p!!.getBasalTimeFromMidnight(0), 0.001) assertEquals(15.0, p.getIcTimeFromMidnight(0), 0.001) assertEquals(11.8, p.getIsfTimeFromMidnight(0), 0.001) - p = DefaultProfile(injector).profile(7.0, 10.0 / 0.4, 0.0, Constants.MMOL) + p = DefaultProfile(profileInjector).profile(7.0, 10.0 / 0.4, 0.0, Constants.MMOL) assertEquals(0.350, p!!.getBasalTimeFromMidnight(0), 0.001) assertEquals(15.0, p.getIcTimeFromMidnight(0), 0.001) assertEquals(6.8, p.getIsfTimeFromMidnight(0), 0.001) - p = DefaultProfile(injector).profile(12.0, 25.0 / 0.5, 0.0, Constants.MMOL) + p = DefaultProfile(profileInjector).profile(12.0, 25.0 / 0.5, 0.0, Constants.MMOL) assertEquals(0.80, p!!.getBasalTimeFromMidnight(0), 0.001) assertEquals(10.0, p.getIcTimeFromMidnight(0), 0.001) assertEquals(2.2, p.getIsfTimeFromMidnight(0), 0.001) diff --git a/app/src/test/java/info/nightscout/androidaps/interfaces/ConstraintsCheckerTest.kt b/app/src/test/java/info/nightscout/androidaps/interfaces/ConstraintsCheckerTest.kt index 192b107bef..5aa5cbdc82 100644 --- a/app/src/test/java/info/nightscout/androidaps/interfaces/ConstraintsCheckerTest.kt +++ b/app/src/test/java/info/nightscout/androidaps/interfaces/ConstraintsCheckerTest.kt @@ -3,8 +3,6 @@ package info.nightscout.androidaps.interfaces import android.content.Context import dagger.android.AndroidInjector import dagger.android.HasAndroidInjector -import info.nightscout.androidaps.Config -import info.nightscout.androidaps.MainApp import info.nightscout.androidaps.R import info.nightscout.androidaps.TestBaseWithProfile import info.nightscout.androidaps.dana.DanaPump @@ -15,7 +13,6 @@ import info.nightscout.androidaps.database.AppRepository import info.nightscout.androidaps.logging.UserEntryLogger import info.nightscout.androidaps.plugins.aps.openAPSAMA.OpenAPSAMAPlugin import info.nightscout.androidaps.plugins.aps.openAPSSMB.OpenAPSSMBPlugin -import info.nightscout.androidaps.plugins.configBuilder.ConfigBuilderPlugin import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker import info.nightscout.androidaps.plugins.constraints.objectives.ObjectivesPlugin import info.nightscout.androidaps.plugins.constraints.objectives.objectives.Objective @@ -23,9 +20,9 @@ import info.nightscout.androidaps.plugins.constraints.safety.SafetyPlugin import info.nightscout.androidaps.plugins.general.maintenance.LoggerUtils import info.nightscout.androidaps.plugins.general.nsclient.NSUpload import info.nightscout.androidaps.plugins.iob.iobCobCalculator.GlucoseStatusProvider -import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorPlugin import info.nightscout.androidaps.plugins.pump.combo.ComboPlugin import info.nightscout.androidaps.plugins.pump.common.bolusInfo.DetailedBolusInfoStorage +import info.nightscout.androidaps.plugins.pump.common.bolusInfo.TemporaryBasalStorage import info.nightscout.androidaps.plugins.pump.insight.LocalInsightPlugin import info.nightscout.androidaps.plugins.pump.virtual.VirtualPumpPlugin import info.nightscout.androidaps.plugins.sensitivity.SensitivityOref1Plugin @@ -35,6 +32,7 @@ import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin import info.nightscout.androidaps.utils.HardLimits import info.nightscout.androidaps.utils.Profiler import info.nightscout.androidaps.utils.buildHelper.BuildHelper +import info.nightscout.androidaps.utils.buildHelper.ConfigImpl import info.nightscout.androidaps.utils.sharedPreferences.SP import org.junit.Assert import org.junit.Before @@ -51,19 +49,18 @@ import java.util.* */ @RunWith(PowerMockRunner::class) @PrepareForTest( - MainApp::class, ConfigBuilderPlugin::class, ConstraintChecker::class, SP::class, Context::class, + ConstraintChecker::class, SP::class, Context::class, OpenAPSAMAPlugin::class, OpenAPSSMBPlugin::class, TreatmentsPlugin::class, TreatmentService::class, - VirtualPumpPlugin::class, DetailedBolusInfoStorage::class, GlimpPlugin::class, Profiler::class, - UserEntryLogger::class, IobCobCalculatorPlugin::class, LoggerUtils::class, AppRepository::class) + VirtualPumpPlugin::class, DetailedBolusInfoStorage::class, TemporaryBasalStorage::class, GlimpPlugin::class, Profiler::class, + UserEntryLogger::class, LoggerUtils::class, AppRepository::class) class ConstraintsCheckerTest : TestBaseWithProfile() { - @Mock lateinit var activePlugin: ActivePluginProvider + @Mock lateinit var activePlugin: ActivePlugin @Mock lateinit var virtualPumpPlugin: VirtualPumpPlugin @Mock lateinit var sp: SP @Mock lateinit var commandQueue: CommandQueueProvider @Mock lateinit var detailedBolusInfoStorage: DetailedBolusInfoStorage - @Mock lateinit var context: Context - @Mock lateinit var iobCobCalculatorPlugin: IobCobCalculatorPlugin + @Mock lateinit var temporaryBasalStorage: TemporaryBasalStorage @Mock lateinit var glimpPlugin: GlimpPlugin @Mock lateinit var sensitivityOref1Plugin: SensitivityOref1Plugin @Mock lateinit var profiler: Profiler @@ -73,6 +70,7 @@ class ConstraintsCheckerTest : TestBaseWithProfile() { @Mock lateinit var loggerUtils: LoggerUtils @Mock lateinit var databaseHelper: DatabaseHelperInterface @Mock lateinit var repository: AppRepository + @Mock lateinit var pumpSync: PumpSync private lateinit var danaPump: DanaPump @@ -91,6 +89,7 @@ class ConstraintsCheckerTest : TestBaseWithProfile() { AndroidInjector { if (it is Objective) { it.sp = sp + it.dateUtil = dateUtil } if (it is PumpEnactResult) { it.resourceHelper = resourceHelper @@ -136,19 +135,19 @@ class ConstraintsCheckerTest : TestBaseWithProfile() { `when`(activePlugin.activePump).thenReturn(virtualPumpPlugin) constraintChecker = ConstraintChecker(activePlugin) - val glucoseStatusProvider = GlucoseStatusProvider(aapsLogger = aapsLogger, iobCobCalculatorPlugin = iobCobCalculatorPlugin) + val glucoseStatusProvider = GlucoseStatusProvider(aapsLogger = aapsLogger, iobCobCalculator = iobCobCalculator, dateUtil = dateUtil) - danaPump = DanaPump(aapsLogger, sp, injector) - hardLimits = HardLimits(aapsLogger, rxBus, sp, resourceHelper, context, nsUpload) - objectivesPlugin = ObjectivesPlugin(injector, aapsLogger, resourceHelper, activePlugin, sp, Config(), uel) - comboPlugin = ComboPlugin(injector, aapsLogger, rxBus, resourceHelper, profileFunction, treatmentsInterface, sp, commandQueue, context, databaseHelper) - danaRPlugin = DanaRPlugin(injector, aapsLogger, aapsSchedulers, rxBus, context, resourceHelper, constraintChecker, activePlugin, sp, commandQueue, danaPump, dateUtil, fabricPrivacy) - danaRSPlugin = DanaRSPlugin(injector, aapsLogger, aapsSchedulers, rxBus, context, resourceHelper, constraintChecker, profileFunction, activePluginProvider, sp, commandQueue, danaPump, detailedBolusInfoStorage, fabricPrivacy, dateUtil) - insightPlugin = LocalInsightPlugin(injector, aapsLogger, rxBus, resourceHelper, treatmentsInterface, sp, commandQueue, profileFunction, nsUpload, context, uploadQueue, Config(), dateUtil, databaseHelper, repository) - openAPSSMBPlugin = OpenAPSSMBPlugin(injector, aapsLogger, rxBus, constraintChecker, resourceHelper, profileFunction, context, activePlugin, treatmentsInterface, iobCobCalculatorPlugin, hardLimits, profiler, sp, dateUtil, repository, glucoseStatusProvider) - openAPSAMAPlugin = OpenAPSAMAPlugin(injector, aapsLogger, rxBus, constraintChecker, resourceHelper, profileFunction, context, activePlugin, treatmentsInterface, iobCobCalculatorPlugin, hardLimits, profiler, fabricPrivacy, dateUtil, repository, glucoseStatusProvider) - safetyPlugin = SafetyPlugin(injector, aapsLogger, resourceHelper, sp, rxBus, constraintChecker, openAPSAMAPlugin, openAPSSMBPlugin, sensitivityOref1Plugin, activePlugin, hardLimits, BuildHelper(Config(), loggerUtils), treatmentsInterface, Config()) + danaPump = DanaPump(aapsLogger, sp, dateUtil, injector) + hardLimits = HardLimits(aapsLogger, rxBus, sp, resourceHelper, context, repository) + objectivesPlugin = ObjectivesPlugin(injector, aapsLogger, resourceHelper, activePlugin, sp, ConfigImpl(), dateUtil, uel) + comboPlugin = ComboPlugin(injector, aapsLogger, rxBus, resourceHelper, profileFunction, sp, commandQueue, context, databaseHelper, pumpSync, dateUtil) + danaRPlugin = DanaRPlugin(injector, aapsLogger, aapsSchedulers, rxBus, context, resourceHelper, constraintChecker, activePlugin, sp, commandQueue, danaPump, dateUtil, fabricPrivacy, pumpSync) + danaRSPlugin = DanaRSPlugin(injector, aapsLogger, aapsSchedulers, rxBus, context, resourceHelper, constraintChecker, profileFunction, sp, commandQueue, danaPump, pumpSync, detailedBolusInfoStorage, temporaryBasalStorage, fabricPrivacy, dateUtil) + insightPlugin = LocalInsightPlugin(injector, aapsLogger, rxBus, resourceHelper, treatmentsInterface, sp, commandQueue, profileFunction, nsUpload, context, uploadQueue, ConfigImpl(), dateUtil, databaseHelper, pumpSync) + openAPSSMBPlugin = OpenAPSSMBPlugin(injector, aapsLogger, rxBus, constraintChecker, resourceHelper, profileFunction, context, activePlugin, iobCobCalculator, hardLimits, profiler, sp, dateUtil, repository, glucoseStatusProvider) + openAPSAMAPlugin = OpenAPSAMAPlugin(injector, aapsLogger, rxBus, constraintChecker, resourceHelper, profileFunction, context, activePlugin, iobCobCalculator, hardLimits, profiler, fabricPrivacy, dateUtil, repository, glucoseStatusProvider) + safetyPlugin = SafetyPlugin(injector, aapsLogger, resourceHelper, sp, rxBus, constraintChecker, openAPSAMAPlugin, openAPSSMBPlugin, sensitivityOref1Plugin, activePlugin, hardLimits, BuildHelper(ConfigImpl(), loggerUtils), iobCobCalculator, ConfigImpl(), dateUtil) val constraintsPluginsList = ArrayList() constraintsPluginsList.add(safetyPlugin) constraintsPluginsList.add(objectivesPlugin) @@ -157,7 +156,7 @@ class ConstraintsCheckerTest : TestBaseWithProfile() { constraintsPluginsList.add(danaRSPlugin) constraintsPluginsList.add(insightPlugin) constraintsPluginsList.add(openAPSSMBPlugin) - `when`(activePlugin.getSpecificPluginsListByInterface(ConstraintsInterface::class.java)).thenReturn(constraintsPluginsList) + `when`(activePlugin.getSpecificPluginsListByInterface(Constraints::class.java)).thenReturn(constraintsPluginsList) objectivesPlugin.onStart() } diff --git a/app/src/test/java/info/nightscout/androidaps/plugins/aps/loop/LoopPluginTest.kt b/app/src/test/java/info/nightscout/androidaps/plugins/aps/loop/LoopPluginTest.kt index 32c37d1603..f6ec5e4687 100644 --- a/app/src/test/java/info/nightscout/androidaps/plugins/aps/loop/LoopPluginTest.kt +++ b/app/src/test/java/info/nightscout/androidaps/plugins/aps/loop/LoopPluginTest.kt @@ -4,19 +4,15 @@ import android.app.NotificationManager import android.content.Context import dagger.android.AndroidInjector import dagger.android.HasAndroidInjector -import info.nightscout.androidaps.Config +import info.nightscout.androidaps.utils.buildHelper.ConfigImpl import info.nightscout.androidaps.R import info.nightscout.androidaps.TestBase import info.nightscout.androidaps.database.AppRepository -import info.nightscout.androidaps.interfaces.ActivePluginProvider -import info.nightscout.androidaps.interfaces.CommandQueueProvider -import info.nightscout.androidaps.interfaces.PluginType -import info.nightscout.androidaps.interfaces.ProfileFunction -import info.nightscout.androidaps.interfaces.PumpDescription +import info.nightscout.androidaps.interfaces.* +import info.nightscout.androidaps.logging.UserEntryLogger import info.nightscout.androidaps.plugins.bus.RxBusWrapper import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker -import info.nightscout.androidaps.plugins.general.nsclient.NSUpload -import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorPlugin +import info.nightscout.androidaps.plugins.configBuilder.RunningConfiguration import info.nightscout.androidaps.plugins.pump.virtual.VirtualPumpPlugin import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin import info.nightscout.androidaps.receivers.ReceiverStatusStore @@ -27,9 +23,14 @@ import info.nightscout.androidaps.utils.sharedPreferences.SP import org.junit.Assert import org.junit.Before import org.junit.Test +import org.junit.runner.RunWith import org.mockito.Mock import org.mockito.Mockito.`when` +import org.powermock.core.classloader.annotations.PrepareForTest +import org.powermock.modules.junit4.PowerMockRunner +@RunWith(PowerMockRunner::class) +@PrepareForTest(ConstraintChecker::class, ReceiverStatusStore::class, RunningConfiguration::class, UserEntryLogger::class, DateUtil::class) class LoopPluginTest : TestBase() { @Mock lateinit var sp: SP @@ -39,23 +40,24 @@ class LoopPluginTest : TestBase() { @Mock lateinit var profileFunction: ProfileFunction @Mock lateinit var context: Context @Mock lateinit var commandQueue: CommandQueueProvider - @Mock lateinit var activePlugin: ActivePluginProvider + @Mock lateinit var activePlugin: ActivePlugin @Mock lateinit var treatmentsPlugin: TreatmentsPlugin @Mock lateinit var virtualPumpPlugin: VirtualPumpPlugin - @Mock lateinit var iobCobCalculatorPlugin: IobCobCalculatorPlugin + @Mock lateinit var iobCobCalculator: IobCobCalculator @Mock lateinit var fabricPrivacy: FabricPrivacy @Mock lateinit var receiverStatusStore: ReceiverStatusStore - @Mock lateinit var nsUpload: NSUpload @Mock lateinit var notificationManager: NotificationManager @Mock lateinit var repository: AppRepository + @Mock lateinit var uel:UserEntryLogger @Mock lateinit var dateUtil: DateUtil + @Mock lateinit var runningConfiguration: RunningConfiguration private lateinit var loopPlugin: LoopPlugin val injector = HasAndroidInjector { AndroidInjector { } } @Before fun prepareMock() { - loopPlugin = LoopPlugin(injector, aapsLogger, aapsSchedulers, rxBus, sp, Config(), constraintChecker, resourceHelper, profileFunction, context, commandQueue, activePlugin, treatmentsPlugin, virtualPumpPlugin, iobCobCalculatorPlugin, receiverStatusStore, fabricPrivacy, nsUpload, dateUtil, repository) + loopPlugin = LoopPlugin(injector, aapsLogger, aapsSchedulers, rxBus, sp, ConfigImpl(), constraintChecker, resourceHelper, profileFunction, context, commandQueue, activePlugin, virtualPumpPlugin, iobCobCalculator, receiverStatusStore, fabricPrivacy, dateUtil, uel, repository, runningConfiguration) `when`(activePlugin.activePump).thenReturn(virtualPumpPlugin) `when`(context.getSystemService(Context.NOTIFICATION_SERVICE)).thenReturn(notificationManager) } diff --git a/app/src/test/java/info/nightscout/androidaps/plugins/configBuilder/ConfigBuilderPluginTest.kt b/app/src/test/java/info/nightscout/androidaps/plugins/configBuilder/ConfigBuilderPluginTest.kt index 7a85c0284e..fa4d5196a2 100644 --- a/app/src/test/java/info/nightscout/androidaps/plugins/configBuilder/ConfigBuilderPluginTest.kt +++ b/app/src/test/java/info/nightscout/androidaps/plugins/configBuilder/ConfigBuilderPluginTest.kt @@ -1,15 +1,12 @@ package info.nightscout.androidaps.plugins.configBuilder -import dagger.Lazy import dagger.android.AndroidInjector import dagger.android.HasAndroidInjector import info.nightscout.androidaps.TestBase -import info.nightscout.androidaps.interfaces.ActivePluginProvider -import info.nightscout.androidaps.interfaces.CommandQueueProvider +import info.nightscout.androidaps.interfaces.ActivePlugin +import info.nightscout.androidaps.interfaces.PumpSync import info.nightscout.androidaps.logging.UserEntryLogger import info.nightscout.androidaps.plugins.bus.RxBusWrapper -import info.nightscout.androidaps.plugins.pump.virtual.VirtualPumpPlugin -import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin import info.nightscout.androidaps.utils.resources.ResourceHelper import info.nightscout.androidaps.utils.sharedPreferences.SP import org.junit.Before @@ -23,22 +20,15 @@ import org.powermock.modules.junit4.PowerMockRunner @PrepareForTest(UserEntryLogger::class) class ConfigBuilderPluginTest : TestBase() { - @Mock lateinit var virtualPumpPlugin: Lazy - @Mock lateinit var treatmentsPlugin: Lazy - @Mock lateinit var sp: SP @Mock lateinit var resourceHelper: ResourceHelper - @Mock lateinit var commandQueue: CommandQueueProvider - @Mock lateinit var activePlugin: ActivePluginProvider + @Mock lateinit var activePlugin: ActivePlugin @Mock lateinit var uel: UserEntryLogger + @Mock lateinit var pumpSync: PumpSync private lateinit var configBuilderPlugin: ConfigBuilderPlugin - val injector = HasAndroidInjector { - AndroidInjector { - - } - } + val injector = HasAndroidInjector { AndroidInjector { } } @Test fun dummy() { @@ -47,6 +37,6 @@ class ConfigBuilderPluginTest : TestBase() { @Before fun prepareMock() { - configBuilderPlugin = ConfigBuilderPlugin(injector, aapsLogger, resourceHelper, sp, RxBusWrapper(aapsSchedulers), activePlugin, uel) + configBuilderPlugin = ConfigBuilderPlugin(injector, aapsLogger, resourceHelper, sp, RxBusWrapper(aapsSchedulers), activePlugin, uel, pumpSync) } } \ No newline at end of file diff --git a/app/src/test/java/info/nightscout/androidaps/plugins/constraints/dstHelper/DstHelperPluginTest.kt b/app/src/test/java/info/nightscout/androidaps/plugins/constraints/dstHelper/DstHelperPluginTest.kt index 16acf0592e..da4192d33d 100644 --- a/app/src/test/java/info/nightscout/androidaps/plugins/constraints/dstHelper/DstHelperPluginTest.kt +++ b/app/src/test/java/info/nightscout/androidaps/plugins/constraints/dstHelper/DstHelperPluginTest.kt @@ -3,7 +3,7 @@ package info.nightscout.androidaps.plugins.constraints.dstHelper import dagger.android.AndroidInjector import dagger.android.HasAndroidInjector import info.nightscout.androidaps.TestBase -import info.nightscout.androidaps.interfaces.ActivePluginProvider +import info.nightscout.androidaps.interfaces.ActivePlugin import info.nightscout.androidaps.plugins.aps.loop.LoopPlugin import info.nightscout.androidaps.plugins.bus.RxBusWrapper import info.nightscout.androidaps.utils.resources.ResourceHelper @@ -23,7 +23,7 @@ class DstHelperPluginTest : TestBase() { @Mock lateinit var resourceHelper: ResourceHelper @Mock lateinit var sp: SP - @Mock lateinit var activePlugin: ActivePluginProvider + @Mock lateinit var activePlugin: ActivePlugin @Mock lateinit var loopPlugin: LoopPlugin private lateinit var plugin: DstHelperPlugin diff --git a/app/src/test/java/info/nightscout/androidaps/plugins/constraints/objectives/ObjectivesPluginTest.kt b/app/src/test/java/info/nightscout/androidaps/plugins/constraints/objectives/ObjectivesPluginTest.kt index 8c4f0bac87..270753e9a4 100644 --- a/app/src/test/java/info/nightscout/androidaps/plugins/constraints/objectives/ObjectivesPluginTest.kt +++ b/app/src/test/java/info/nightscout/androidaps/plugins/constraints/objectives/ObjectivesPluginTest.kt @@ -2,10 +2,10 @@ package info.nightscout.androidaps.plugins.constraints.objectives import dagger.android.AndroidInjector import dagger.android.HasAndroidInjector -import info.nightscout.androidaps.Config +import info.nightscout.androidaps.utils.buildHelper.ConfigImpl import info.nightscout.androidaps.R import info.nightscout.androidaps.TestBase -import info.nightscout.androidaps.interfaces.ActivePluginProvider +import info.nightscout.androidaps.interfaces.ActivePlugin import info.nightscout.androidaps.interfaces.Constraint import info.nightscout.androidaps.logging.UserEntryLogger import info.nightscout.androidaps.plugins.constraints.objectives.objectives.Objective @@ -21,13 +21,14 @@ import org.mockito.Mockito.`when` import org.powermock.core.classloader.annotations.PrepareForTest import org.powermock.modules.junit4.PowerMockRunner -@PrepareForTest(UserEntryLogger::class) @RunWith(PowerMockRunner::class) +@PrepareForTest(UserEntryLogger::class, DateUtil::class) class ObjectivesPluginTest : TestBase() { @Mock lateinit var resourceHelper: ResourceHelper - @Mock lateinit var activePlugin: ActivePluginProvider + @Mock lateinit var activePlugin: ActivePlugin @Mock lateinit var sp: SP + @Mock lateinit var dateUtil: DateUtil @Mock lateinit var uel: UserEntryLogger private lateinit var objectivesPlugin: ObjectivesPlugin @@ -37,12 +38,13 @@ class ObjectivesPluginTest : TestBase() { if (it is Objective) { it.sp = sp it.resourceHelper = resourceHelper + it.dateUtil = dateUtil } } } @Before fun prepareMock() { - objectivesPlugin = ObjectivesPlugin(injector, aapsLogger, resourceHelper, activePlugin, sp, Config(), uel) + objectivesPlugin = ObjectivesPlugin(injector, aapsLogger, resourceHelper, activePlugin, sp, ConfigImpl(), dateUtil, uel) objectivesPlugin.onStart() `when`(resourceHelper.gs(R.string.objectivenotstarted)).thenReturn("Objective %1\$d not started") } @@ -53,7 +55,7 @@ class ObjectivesPluginTest : TestBase() { c = objectivesPlugin.isLoopInvocationAllowed(c) Assert.assertEquals("Objectives: Objective 1 not started", c.getReasons(aapsLogger)) Assert.assertEquals(false, c.value()) - objectivesPlugin.objectives[ObjectivesPlugin.FIRST_OBJECTIVE].startedOn = DateUtil.now() + objectivesPlugin.objectives[ObjectivesPlugin.FIRST_OBJECTIVE].startedOn = dateUtil.now() } @Test fun notStartedObjective6ShouldLimitClosedLoop() { diff --git a/app/src/test/java/info/nightscout/androidaps/plugins/constraints/safety/SafetyPluginTest.kt b/app/src/test/java/info/nightscout/androidaps/plugins/constraints/safety/SafetyPluginTest.kt index 9f5bb89f01..209e7d2da6 100644 --- a/app/src/test/java/info/nightscout/androidaps/plugins/constraints/safety/SafetyPluginTest.kt +++ b/app/src/test/java/info/nightscout/androidaps/plugins/constraints/safety/SafetyPluginTest.kt @@ -1,19 +1,18 @@ package info.nightscout.androidaps.plugins.constraints.safety -import android.content.Context import dagger.android.AndroidInjector import dagger.android.HasAndroidInjector -import info.nightscout.androidaps.Config +import info.nightscout.androidaps.utils.buildHelper.ConfigImpl import info.nightscout.androidaps.Constants import info.nightscout.androidaps.R import info.nightscout.androidaps.TestBaseWithProfile -import info.nightscout.androidaps.interfaces.ActivePluginProvider +import info.nightscout.androidaps.database.AppRepository +import info.nightscout.androidaps.interfaces.ActivePlugin import info.nightscout.androidaps.interfaces.Constraint import info.nightscout.androidaps.interfaces.PumpDescription import info.nightscout.androidaps.plugins.aps.openAPSAMA.OpenAPSAMAPlugin import info.nightscout.androidaps.plugins.aps.openAPSSMB.OpenAPSSMBPlugin import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker -import info.nightscout.androidaps.plugins.general.nsclient.NSUpload import info.nightscout.androidaps.plugins.pump.virtual.VirtualPumpPlugin import info.nightscout.androidaps.plugins.sensitivity.SensitivityOref1Plugin import info.nightscout.androidaps.plugins.source.GlimpPlugin @@ -38,12 +37,11 @@ class SafetyPluginTest : TestBaseWithProfile() { @Mock lateinit var openAPSAMAPlugin: OpenAPSAMAPlugin @Mock lateinit var openAPSSMBPlugin: OpenAPSSMBPlugin @Mock lateinit var sensitivityOref1Plugin: SensitivityOref1Plugin - @Mock lateinit var activePlugin: ActivePluginProvider + @Mock lateinit var activePlugin: ActivePlugin @Mock lateinit var buildHelper: BuildHelper @Mock lateinit var virtualPumpPlugin: VirtualPumpPlugin @Mock lateinit var glimpPlugin: GlimpPlugin - @Mock lateinit var context: Context - @Mock lateinit var nsUpload: NSUpload + @Mock lateinit var repository: AppRepository private lateinit var hardLimits: HardLimits private lateinit var safetyPlugin: SafetyPlugin @@ -75,8 +73,8 @@ class SafetyPluginTest : TestBaseWithProfile() { `when`(activePlugin.activePump).thenReturn(virtualPumpPlugin) `when`(virtualPumpPlugin.pumpDescription).thenReturn(pumpDescription) - hardLimits = HardLimits(aapsLogger, rxBus, sp, resourceHelper, context, nsUpload) - safetyPlugin = SafetyPlugin(injector, aapsLogger, resourceHelper, sp, rxBus, constraintChecker, openAPSAMAPlugin, openAPSSMBPlugin, sensitivityOref1Plugin, activePlugin, hardLimits, buildHelper, treatmentsInterface, Config()) + hardLimits = HardLimits(aapsLogger, rxBus, sp, resourceHelper, context, repository) + safetyPlugin = SafetyPlugin(injector, aapsLogger, resourceHelper, sp, rxBus, constraintChecker, openAPSAMAPlugin, openAPSSMBPlugin, sensitivityOref1Plugin, activePlugin, hardLimits, buildHelper, iobCobCalculator, ConfigImpl(), dateUtil) } @Test fun pumpDescriptionShouldLimitLoopInvocation() { diff --git a/app/src/test/java/info/nightscout/androidaps/plugins/constraints/versionChecker/VersionCheckerUtilsKtTest.kt b/app/src/test/java/info/nightscout/androidaps/plugins/constraints/versionChecker/VersionCheckerUtilsKtTest.kt index b9d2db18da..473c9656cb 100644 --- a/app/src/test/java/info/nightscout/androidaps/plugins/constraints/versionChecker/VersionCheckerUtilsKtTest.kt +++ b/app/src/test/java/info/nightscout/androidaps/plugins/constraints/versionChecker/VersionCheckerUtilsKtTest.kt @@ -1,7 +1,7 @@ package info.nightscout.androidaps.plugins.constraints.versionChecker import android.content.Context -import info.nightscout.androidaps.Config +import info.nightscout.androidaps.utils.buildHelper.ConfigImpl import info.nightscout.androidaps.TestBase import info.nightscout.androidaps.plugins.bus.RxBusWrapper import info.nightscout.androidaps.utils.resources.ResourceHelper @@ -19,7 +19,7 @@ class VersionCheckerUtilsKtTest : TestBase() { @Mock lateinit var sp: SP @Mock lateinit var resourceHelper: ResourceHelper @Mock lateinit var context: Context - val config = Config() + val config = ConfigImpl() private val rxBus = RxBusWrapper(aapsSchedulers) diff --git a/app/src/test/java/info/nightscout/androidaps/plugins/general/maintenance/MaintenancePluginTest.kt b/app/src/test/java/info/nightscout/androidaps/plugins/general/maintenance/MaintenancePluginTest.kt index 385f327adb..d0d965961b 100644 --- a/app/src/test/java/info/nightscout/androidaps/plugins/general/maintenance/MaintenancePluginTest.kt +++ b/app/src/test/java/info/nightscout/androidaps/plugins/general/maintenance/MaintenancePluginTest.kt @@ -2,7 +2,7 @@ package info.nightscout.androidaps.plugins.general.maintenance import android.content.Context import dagger.android.HasAndroidInjector -import info.nightscout.androidaps.Config +import info.nightscout.androidaps.utils.buildHelper.ConfigImpl import info.nightscout.androidaps.TestBase import info.nightscout.androidaps.plugins.general.nsclient.data.NSSettingsStatus import info.nightscout.androidaps.utils.buildHelper.BuildHelper @@ -34,7 +34,7 @@ class MaintenancePluginTest : TestBase() { @Before fun mock() { - sut = MaintenancePlugin(injector, context, resourceHelper, sp, nsSettingsStatus, aapsLogger, buildHelper, Config(), loggerUtils) + sut = MaintenancePlugin(injector, context, resourceHelper, sp, nsSettingsStatus, aapsLogger, buildHelper, ConfigImpl(), loggerUtils) `when`(loggerUtils.suffix).thenReturn(".log.zip") `when`(loggerUtils.logDirectory).thenReturn("src/test/res/logger") } diff --git a/app/src/test/java/info/nightscout/androidaps/plugins/general/nsclient/NsClientReceiverDelegateTest.kt b/app/src/test/java/info/nightscout/androidaps/plugins/general/nsclient/NsClientReceiverDelegateTest.kt index 671178dfd9..74751fe5f5 100644 --- a/app/src/test/java/info/nightscout/androidaps/plugins/general/nsclient/NsClientReceiverDelegateTest.kt +++ b/app/src/test/java/info/nightscout/androidaps/plugins/general/nsclient/NsClientReceiverDelegateTest.kt @@ -1,7 +1,6 @@ package info.nightscout.androidaps.plugins.general.nsclient import android.content.Context -import info.nightscout.androidaps.MainApp import info.nightscout.androidaps.R import info.nightscout.androidaps.TestBase import info.nightscout.androidaps.events.EventChargingState @@ -25,7 +24,7 @@ import org.powermock.core.classloader.annotations.PrepareForTest import org.powermock.modules.junit4.PowerMockRunner @RunWith(PowerMockRunner::class) -@PrepareForTest(MainApp::class, SP::class, Context::class) +@PrepareForTest(SP::class, Context::class) class NsClientReceiverDelegateTest : TestBase() { @Mock lateinit var context: Context diff --git a/app/src/test/java/info/nightscout/androidaps/plugins/general/smsCommunicator/AuthRequestTest.kt b/app/src/test/java/info/nightscout/androidaps/plugins/general/smsCommunicator/AuthRequestTest.kt index 882cdbecc2..dcc14fabfc 100644 --- a/app/src/test/java/info/nightscout/androidaps/plugins/general/smsCommunicator/AuthRequestTest.kt +++ b/app/src/test/java/info/nightscout/androidaps/plugins/general/smsCommunicator/AuthRequestTest.kt @@ -5,7 +5,6 @@ import dagger.android.HasAndroidInjector import info.nightscout.androidaps.Constants import info.nightscout.androidaps.R import info.nightscout.androidaps.TestBase -import info.nightscout.androidaps.logging.AAPSLogger import info.nightscout.androidaps.plugins.general.smsCommunicator.otp.OneTimePassword import info.nightscout.androidaps.plugins.general.smsCommunicator.otp.OneTimePasswordValidationResult import info.nightscout.androidaps.utils.DateUtil @@ -30,6 +29,7 @@ class AuthRequestTest : TestBase() { @Mock lateinit var smsCommunicatorPlugin: SmsCommunicatorPlugin @Mock lateinit var resourceHelper: ResourceHelper @Mock lateinit var otp: OneTimePassword + @Mock lateinit var dateUtil: DateUtil var injector: HasAndroidInjector = HasAndroidInjector { AndroidInjector { @@ -38,6 +38,7 @@ class AuthRequestTest : TestBase() { it.resourceHelper = resourceHelper it.smsCommunicatorPlugin = smsCommunicatorPlugin it.otp = otp + it.dateUtil = dateUtil } } } @@ -87,10 +88,10 @@ class AuthRequestTest : TestBase() { // test timed out message val now: Long = 10000 PowerMockito.mockStatic(DateUtil::class.java) - PowerMockito.`when`(DateUtil.now()).thenReturn(now) + PowerMockito.`when`(dateUtil.now()).thenReturn(now) authRequest = AuthRequest(injector, requester, "Request text", "ABC", action) actionCalled = false - PowerMockito.`when`(DateUtil.now()).thenReturn(now + T.mins(Constants.SMS_CONFIRM_TIMEOUT).msecs() + 1) + PowerMockito.`when`(dateUtil.now()).thenReturn(now + T.mins(Constants.SMS_CONFIRM_TIMEOUT).msecs() + 1) authRequest.action("ABC") Assert.assertFalse(actionCalled) } diff --git a/app/src/test/java/info/nightscout/androidaps/plugins/general/smsCommunicator/SmsCommunicatorPluginTest.kt b/app/src/test/java/info/nightscout/androidaps/plugins/general/smsCommunicator/SmsCommunicatorPluginTest.kt index ecc7b3374d..9dead08680 100644 --- a/app/src/test/java/info/nightscout/androidaps/plugins/general/smsCommunicator/SmsCommunicatorPluginTest.kt +++ b/app/src/test/java/info/nightscout/androidaps/plugins/general/smsCommunicator/SmsCommunicatorPluginTest.kt @@ -2,11 +2,10 @@ package info.nightscout.androidaps.plugins.general.smsCommunicator -import android.content.Context import android.telephony.SmsManager import dagger.android.AndroidInjector import dagger.android.HasAndroidInjector -import info.nightscout.androidaps.Config +import info.nightscout.androidaps.utils.buildHelper.ConfigImpl import info.nightscout.androidaps.Constants import info.nightscout.androidaps.R import info.nightscout.androidaps.TestBaseWithProfile @@ -15,7 +14,7 @@ import info.nightscout.androidaps.data.PumpEnactResult import info.nightscout.androidaps.database.AppRepository import info.nightscout.androidaps.database.entities.GlucoseValue import info.nightscout.androidaps.database.transactions.InsertTemporaryTargetAndCancelCurrentTransaction -import info.nightscout.androidaps.interfaces.ActivePluginProvider +import info.nightscout.androidaps.interfaces.ActivePlugin import info.nightscout.androidaps.interfaces.CommandQueueProvider import info.nightscout.androidaps.interfaces.Constraint import info.nightscout.androidaps.interfaces.PluginType @@ -23,12 +22,11 @@ import info.nightscout.androidaps.interfaces.PumpDescription import info.nightscout.androidaps.logging.UserEntryLogger import info.nightscout.androidaps.plugins.aps.loop.LoopPlugin import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker -import info.nightscout.androidaps.plugins.general.nsclient.NSUpload import info.nightscout.androidaps.plugins.general.smsCommunicator.otp.OneTimePassword import info.nightscout.androidaps.plugins.general.smsCommunicator.otp.OneTimePasswordValidationResult +import info.nightscout.androidaps.plugins.iob.iobCobCalculator.AutosensDataStore import info.nightscout.androidaps.plugins.iob.iobCobCalculator.CobInfo import info.nightscout.androidaps.plugins.iob.iobCobCalculator.GlucoseStatusProvider -import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorPlugin import info.nightscout.androidaps.plugins.profile.local.LocalProfilePlugin import info.nightscout.androidaps.plugins.pump.common.defs.PumpType import info.nightscout.androidaps.plugins.pump.virtual.VirtualPumpPlugin @@ -49,6 +47,7 @@ import org.mockito.ArgumentMatchers import org.mockito.Mock import org.mockito.Mockito import org.mockito.Mockito.`when` +import org.mockito.Mockito.anyLong import org.mockito.invocation.InvocationOnMock import org.mockito.stubbing.Answer import org.powermock.api.mockito.PowerMockito @@ -60,25 +59,24 @@ import java.util.* @PrepareForTest( ConstraintChecker::class, FabricPrivacy::class, VirtualPumpPlugin::class, XdripCalibrations::class, SmsManager::class, CommandQueue::class, LocalProfilePlugin::class, DateUtil::class, - IobCobCalculatorPlugin::class, OneTimePassword::class, UserEntryLogger::class, LoopPlugin::class, - AppRepository::class) + OneTimePassword::class, UserEntryLogger::class, LoopPlugin::class, + AppRepository::class, DateUtil::class, AutosensDataStore::class) class SmsCommunicatorPluginTest : TestBaseWithProfile() { - @Mock lateinit var context: Context @Mock lateinit var sp: SP @Mock lateinit var constraintChecker: ConstraintChecker - @Mock lateinit var activePlugin: ActivePluginProvider + @Mock lateinit var activePlugin: ActivePlugin @Mock lateinit var commandQueue: CommandQueueProvider @Mock lateinit var loopPlugin: LoopPlugin - @Mock lateinit var iobCobCalculatorPlugin: IobCobCalculatorPlugin @Mock lateinit var virtualPumpPlugin: VirtualPumpPlugin @Mock lateinit var localProfilePlugin: LocalProfilePlugin @Mock lateinit var treatmentService: TreatmentService @Mock lateinit var otp: OneTimePassword @Mock lateinit var xdripCalibrations: XdripCalibrations @Mock lateinit var uel: UserEntryLogger - @Mock lateinit var nsUpload: NSUpload @Mock lateinit var repository: AppRepository + @Mock lateinit var dateUtilMocked: DateUtil + @Mock lateinit var autosensDataStore: AutosensDataStore var injector: HasAndroidInjector = HasAndroidInjector { AndroidInjector { @@ -90,6 +88,7 @@ class SmsCommunicatorPluginTest : TestBaseWithProfile() { it.smsCommunicatorPlugin = smsCommunicatorPlugin it.resourceHelper = resourceHelper it.otp = otp + it.dateUtil = dateUtil } } } @@ -102,12 +101,10 @@ class SmsCommunicatorPluginTest : TestBaseWithProfile() { val bgList: MutableList = ArrayList() bgList.add(reading) - `when`(iobCobCalculatorPlugin.dataLock).thenReturn(Unit) - `when`(iobCobCalculatorPlugin.bgReadings).thenReturn(bgList) - `when`(iobCobCalculatorPlugin.getCobInfo(false, "SMS COB")).thenReturn(CobInfo(10.0, 2.0)) - `when`(iobCobCalculatorPlugin.lastBg()).thenReturn(reading) + `when`(iobCobCalculator.getCobInfo(false, "SMS COB")).thenReturn(CobInfo(10.0, 2.0)) + `when`(iobCobCalculator.ads).thenReturn(autosensDataStore) + `when`(autosensDataStore.lastBg()).thenReturn(reading) - PowerMockito.spy(DateUtil::class.java) PowerMockito.mockStatic(SmsManager::class.java) val smsManager = PowerMockito.mock(SmsManager::class.java) `when`(SmsManager.getDefault()).thenReturn(smsManager) @@ -117,9 +114,9 @@ class SmsCommunicatorPluginTest : TestBaseWithProfile() { repository.runTransactionForResult(anyObject()) ).thenReturn(Single.just(InsertTemporaryTargetAndCancelCurrentTransaction.TransactionResult().apply { })) - val glucoseStatusProvider = GlucoseStatusProvider(aapsLogger = aapsLogger, iobCobCalculatorPlugin = iobCobCalculatorPlugin) + val glucoseStatusProvider = GlucoseStatusProvider(aapsLogger = aapsLogger, iobCobCalculator = iobCobCalculator, dateUtil = dateUtilMocked) - smsCommunicatorPlugin = SmsCommunicatorPlugin(injector, aapsLogger, resourceHelper, aapsSchedulers, sp, constraintChecker, rxBus, profileFunction, fabricPrivacy, activePlugin, commandQueue, loopPlugin, iobCobCalculatorPlugin, xdripCalibrations, otp, Config(), DateUtil(context), uel, nsUpload, glucoseStatusProvider, repository) + smsCommunicatorPlugin = SmsCommunicatorPlugin(injector, aapsLogger, resourceHelper, aapsSchedulers, sp, constraintChecker, rxBus, profileFunction, fabricPrivacy, activePlugin, commandQueue, loopPlugin, iobCobCalculator, xdripCalibrations, otp, ConfigImpl(), dateUtilMocked, uel, glucoseStatusProvider, repository) smsCommunicatorPlugin.setPluginEnabled(PluginType.GENERAL, true) Mockito.doAnswer { invocation: InvocationOnMock -> val callback = invocation.getArgument(1) @@ -146,17 +143,17 @@ class SmsCommunicatorPluginTest : TestBaseWithProfile() { null }.`when`(commandQueue).bolus(anyObject(), ArgumentMatchers.any(Callback::class.java)) Mockito.doAnswer { invocation: InvocationOnMock -> - val callback = invocation.getArgument(4) + val callback = invocation.getArgument(5) callback.result = PumpEnactResult(injector).success(true).isPercent(true).percent(invocation.getArgument(0)).duration(invocation.getArgument(1)) callback.run() null - }.`when`(commandQueue).tempBasalPercent(ArgumentMatchers.anyInt(), ArgumentMatchers.anyInt(), ArgumentMatchers.anyBoolean(), anyObject(), ArgumentMatchers.any(Callback::class.java)) + }.`when`(commandQueue).tempBasalPercent(ArgumentMatchers.anyInt(), ArgumentMatchers.anyInt(), ArgumentMatchers.anyBoolean(), anyObject(), anyObject(), ArgumentMatchers.any(Callback::class.java)) Mockito.doAnswer { invocation: InvocationOnMock -> - val callback = invocation.getArgument(4) + val callback = invocation.getArgument(5) callback.result = PumpEnactResult(injector).success(true).isPercent(false).absolute(invocation.getArgument(0)).duration(invocation.getArgument(1)) callback.run() null - }.`when`(commandQueue).tempBasalAbsolute(ArgumentMatchers.anyDouble(), ArgumentMatchers.anyInt(), ArgumentMatchers.anyBoolean(), anyObject(), ArgumentMatchers.any(Callback::class.java)) + }.`when`(commandQueue).tempBasalAbsolute(ArgumentMatchers.anyDouble(), ArgumentMatchers.anyInt(), ArgumentMatchers.anyBoolean(), anyObject(), anyObject(), ArgumentMatchers.any(Callback::class.java)) Mockito.doAnswer { invocation: InvocationOnMock -> val callback = invocation.getArgument(2) callback.result = PumpEnactResult(injector).success(true).isPercent(false).absolute(invocation.getArgument(0)).duration(invocation.getArgument(1)) @@ -170,13 +167,13 @@ class SmsCommunicatorPluginTest : TestBaseWithProfile() { `when`(virtualPumpPlugin.shortStatus(ArgumentMatchers.anyBoolean())).thenReturn("Virtual Pump") `when`(virtualPumpPlugin.isSuspended()).thenReturn(false) `when`(virtualPumpPlugin.pumpDescription).thenReturn(PumpDescription()) - `when`(virtualPumpPlugin.model()).thenReturn(PumpType.GenericAAPS) + `when`(virtualPumpPlugin.model()).thenReturn(PumpType.GENERIC_AAPS) - `when`(treatmentsInterface.lastCalculationTreatments).thenReturn(IobTotal(0)) - `when`(treatmentsInterface.lastCalculationTempBasals).thenReturn(IobTotal(0)) + `when`(iobCobCalculator.calculateIobFromBolus()).thenReturn(IobTotal(0)) + `when`(iobCobCalculator.calculateIobFromTempBasalsIncludingConvertedExtended()).thenReturn(IobTotal(0)) `when`(treatmentsInterface.service).thenReturn(treatmentService) - `when`(activePlugin.activeProfileInterface).thenReturn(localProfilePlugin) + `when`(activePlugin.activeProfileSource).thenReturn(localProfilePlugin) `when`(profileFunction.getUnits()).thenReturn(Constants.MGDL) @@ -248,6 +245,12 @@ class SmsCommunicatorPluginTest : TestBaseWithProfile() { `when`(resourceHelper.gs(R.string.smscommunicator_pumpdisconnected)).thenReturn("Pump disconnected") `when`(resourceHelper.gs(R.string.smscommunicator_code_from_authenticator_for)).thenReturn("from Authenticator app for: %1\$s followed by PIN") `when`(resourceHelper.gs(R.string.patient_name_default)).thenReturn("User") + `when`(resourceHelper.gsNotLocalised(R.string.loopsuspended)).thenReturn("Loop suspended") + `when`(resourceHelper.gsNotLocalised(R.string.smscommunicator_stoppedsms)).thenReturn("SMS Remote Service stopped. To reactivate it, use AAPS on master smartphone.") + `when`(resourceHelper.gsNotLocalised(R.string.profileswitchcreated)).thenReturn("Profile switch created") + `when`(resourceHelper.gsNotLocalised(R.string.smscommunicator_tempbasalcanceled)).thenReturn("Temp basal canceled") + `when`(resourceHelper.gsNotLocalised(R.string.smscommunicator_calibrationsent)).thenReturn("Calibration sent. Receiving must be enabled in xDrip+.") + `when`(resourceHelper.gsNotLocalised(R.string.smscommunicator_tt_canceled)).thenReturn("Temp Target canceled successfully") } @@ -472,36 +475,6 @@ class SmsCommunicatorPluginTest : TestBaseWithProfile() { Assert.assertEquals("LOOP BLABLA", smsCommunicatorPlugin.messages[0].text) Assert.assertEquals("Wrong format", smsCommunicatorPlugin.messages[1].text) - //TREATMENTS REFRESH - PowerMockito.`when`(loopPlugin.isEnabled(PluginType.LOOP)).thenReturn(true) - PowerMockito.`when`(loopPlugin.isSuspended).thenReturn(false) - smsCommunicatorPlugin.messages = ArrayList() - sms = Sms("1234", "TREATMENTS REFRESH") - smsCommunicatorPlugin.processSms(sms) - Assert.assertFalse(sms.ignored) - Assert.assertEquals("TREATMENTS REFRESH", smsCommunicatorPlugin.messages[0].text) - Assert.assertTrue(smsCommunicatorPlugin.messages[1].text.contains("TREATMENTS REFRESH")) - - //TREATMENTS BLA BLA - PowerMockito.`when`(loopPlugin.isEnabled(PluginType.LOOP)).thenReturn(true) - PowerMockito.`when`(loopPlugin.isSuspended).thenReturn(false) - smsCommunicatorPlugin.messages = ArrayList() - sms = Sms("1234", "TREATMENTS BLA BLA") - smsCommunicatorPlugin.processSms(sms) - Assert.assertFalse(sms.ignored) - Assert.assertEquals("TREATMENTS BLA BLA", smsCommunicatorPlugin.messages[0].text) - Assert.assertEquals("Wrong format", smsCommunicatorPlugin.messages[1].text) - - //TREATMENTS BLABLA - PowerMockito.`when`(loopPlugin.isEnabled(PluginType.LOOP)).thenReturn(true) - PowerMockito.`when`(loopPlugin.isSuspended).thenReturn(false) - smsCommunicatorPlugin.messages = ArrayList() - sms = Sms("1234", "TREATMENTS BLABLA") - smsCommunicatorPlugin.processSms(sms) - Assert.assertFalse(sms.ignored) - Assert.assertEquals("TREATMENTS BLABLA", smsCommunicatorPlugin.messages[0].text) - Assert.assertEquals("Wrong format", smsCommunicatorPlugin.messages[1].text) - //NSCLIENT RESTART PowerMockito.`when`(loopPlugin.isEnabled(PluginType.LOOP)).thenReturn(true) PowerMockito.`when`(loopPlugin.isSuspended).thenReturn(false) @@ -801,7 +774,7 @@ class SmsCommunicatorPluginTest : TestBaseWithProfile() { smsCommunicatorPlugin.processSms(sms) Assert.assertEquals("BASAL 20% 20", smsCommunicatorPlugin.messages[0].text) Assert.assertEquals("TBR duration must be a multiple of 30 minutes and greater than 0.", smsCommunicatorPlugin.messages[1].text) - `when`(constraintChecker.applyBasalPercentConstraints(anyObject(), anyObject())).thenReturn(Constraint(20)) + `when`(constraintChecker.applyBasalPercentConstraints(anyObject(), anyObject())).thenReturn(Constraint(20)) //BASAL 20% 30 smsCommunicatorPlugin.messages = ArrayList() @@ -921,7 +894,7 @@ class SmsCommunicatorPluginTest : TestBaseWithProfile() { Assert.assertEquals("BOLUS", smsCommunicatorPlugin.messages[0].text) Assert.assertEquals("Wrong format", smsCommunicatorPlugin.messages[1].text) `when`(constraintChecker.applyBolusConstraints(anyObject())).thenReturn(Constraint(1.0)) - PowerMockito.`when`(DateUtil.now()).thenReturn(1000L) + PowerMockito.`when`(dateUtilMocked.now()).thenReturn(1000L) `when`(sp.getLong(R.string.key_smscommunicator_remotebolusmindistance, T.msecs(Constants.remoteBolusMinDistance).mins())).thenReturn(15L) //BOLUS 1 smsCommunicatorPlugin.messages = ArrayList() @@ -930,7 +903,7 @@ class SmsCommunicatorPluginTest : TestBaseWithProfile() { Assert.assertEquals("BOLUS 1", smsCommunicatorPlugin.messages[0].text) Assert.assertEquals("Remote bolus not available. Try again later.", smsCommunicatorPlugin.messages[1].text) `when`(constraintChecker.applyBolusConstraints(anyObject())).thenReturn(Constraint(0.0)) - PowerMockito.`when`(DateUtil.now()).thenReturn(Constants.remoteBolusMinDistance + 1002L) + PowerMockito.`when`(dateUtilMocked.now()).thenReturn(Constants.remoteBolusMinDistance + 1002L) //BOLUS 0 smsCommunicatorPlugin.messages = ArrayList() @@ -1026,7 +999,7 @@ class SmsCommunicatorPluginTest : TestBaseWithProfile() { } @Test fun processCarbsTest() { - PowerMockito.`when`(DateUtil.now()).thenReturn(1000000L) + PowerMockito.`when`(dateUtilMocked.now()).thenReturn(1000000L) `when`(sp.getBoolean(R.string.key_smscommunicator_remotecommandsallowed, false)).thenReturn(false) //CAL smsCommunicatorPlugin.messages = ArrayList() @@ -1042,7 +1015,7 @@ class SmsCommunicatorPluginTest : TestBaseWithProfile() { smsCommunicatorPlugin.processSms(sms) Assert.assertEquals("CARBS", smsCommunicatorPlugin.messages[0].text) Assert.assertEquals("Wrong format", smsCommunicatorPlugin.messages[1].text) - `when`(constraintChecker.applyCarbsConstraints(anyObject())).thenReturn(Constraint(0)) + `when`(constraintChecker.applyCarbsConstraints(anyObject())).thenReturn(Constraint(0)) //CARBS 0 smsCommunicatorPlugin.messages = ArrayList() @@ -1050,7 +1023,7 @@ class SmsCommunicatorPluginTest : TestBaseWithProfile() { smsCommunicatorPlugin.processSms(sms) Assert.assertEquals("CARBS 0", smsCommunicatorPlugin.messages[0].text) Assert.assertEquals("Wrong format", smsCommunicatorPlugin.messages[1].text) - `when`(constraintChecker.applyCarbsConstraints(anyObject())).thenReturn(Constraint(1)) + `when`(constraintChecker.applyCarbsConstraints(anyObject())).thenReturn(Constraint(1)) //CARBS 1 smsCommunicatorPlugin.messages = ArrayList() @@ -1078,6 +1051,7 @@ class SmsCommunicatorPluginTest : TestBaseWithProfile() { Assert.assertTrue(smsCommunicatorPlugin.messages[1].text.contains("Wrong format")) //CARBS 1 12:01 + `when`(dateUtilMocked.timeString(anyLong())).thenReturn("12:01PM") smsCommunicatorPlugin.messages = ArrayList() sms = Sms("1234", "CARBS 1 12:01") smsCommunicatorPlugin.processSms(sms) @@ -1089,6 +1063,7 @@ class SmsCommunicatorPluginTest : TestBaseWithProfile() { Assert.assertTrue(smsCommunicatorPlugin.messages[3].text.startsWith("Carbs 1g entered successfully")) //CARBS 1 3:01AM + `when`(dateUtilMocked.timeString(anyLong())).thenReturn("03:01AM") smsCommunicatorPlugin.messages = ArrayList() sms = Sms("1234", "CARBS 1 3:01AM") smsCommunicatorPlugin.processSms(sms) diff --git a/app/src/test/java/info/nightscout/androidaps/plugins/insulin/InsulinLyumjevPluginTest.kt b/app/src/test/java/info/nightscout/androidaps/plugins/insulin/InsulinLyumjevPluginTest.kt index 6bfea57ff9..3c2edb886f 100644 --- a/app/src/test/java/info/nightscout/androidaps/plugins/insulin/InsulinLyumjevPluginTest.kt +++ b/app/src/test/java/info/nightscout/androidaps/plugins/insulin/InsulinLyumjevPluginTest.kt @@ -3,7 +3,7 @@ package info.nightscout.androidaps.plugins.insulin import dagger.android.AndroidInjector import dagger.android.HasAndroidInjector import info.nightscout.androidaps.R -import info.nightscout.androidaps.interfaces.InsulinInterface +import info.nightscout.androidaps.interfaces.Insulin import info.nightscout.androidaps.logging.AAPSLogger import info.nightscout.androidaps.plugins.bus.RxBusWrapper import info.nightscout.androidaps.interfaces.ProfileFunction @@ -47,7 +47,7 @@ class InsulinLyumjevPluginTest { @Test fun getIdTest() { - assertEquals(InsulinInterface.InsulinType.OREF_LYUMJEV, sut.id) + assertEquals(Insulin.InsulinType.OREF_LYUMJEV, sut.id) } @Test diff --git a/app/src/test/java/info/nightscout/androidaps/plugins/insulin/InsulinOrefBasePluginTest.kt b/app/src/test/java/info/nightscout/androidaps/plugins/insulin/InsulinOrefBasePluginTest.kt index 6558ed80be..112585e8e0 100644 --- a/app/src/test/java/info/nightscout/androidaps/plugins/insulin/InsulinOrefBasePluginTest.kt +++ b/app/src/test/java/info/nightscout/androidaps/plugins/insulin/InsulinOrefBasePluginTest.kt @@ -4,13 +4,13 @@ import dagger.android.AndroidInjector import dagger.android.HasAndroidInjector import info.nightscout.androidaps.Constants import info.nightscout.androidaps.data.Iob -import info.nightscout.androidaps.interfaces.ActivePluginProvider +import info.nightscout.androidaps.database.entities.Bolus +import info.nightscout.androidaps.interfaces.ActivePlugin +import info.nightscout.androidaps.interfaces.Insulin +import info.nightscout.androidaps.interfaces.ProfileFunction import info.nightscout.androidaps.logging.AAPSLogger import info.nightscout.androidaps.plugins.bus.RxBusWrapper -import info.nightscout.androidaps.interfaces.ProfileFunction import info.nightscout.androidaps.plugins.insulin.InsulinOrefBasePlugin.Companion.MIN_DIA -import info.nightscout.androidaps.db.Treatment -import info.nightscout.androidaps.interfaces.InsulinInterface import info.nightscout.androidaps.utils.DefaultValueHelper import info.nightscout.androidaps.utils.resources.ResourceHelper import org.json.JSONObject @@ -49,7 +49,7 @@ class InsulinOrefBasePluginTest { get() = testPeak override fun commentStandardText(): String = "" - override val id get(): InsulinInterface.InsulinType = InsulinInterface.InsulinType.UNKNOWN + override val id get(): Insulin.InsulinType = Insulin.InsulinType.UNKNOWN override val friendlyName get(): String = "" override fun configuration(): JSONObject = JSONObject() override fun applyConfiguration(configuration: JSONObject) {} @@ -65,16 +65,10 @@ class InsulinOrefBasePluginTest { @Mock lateinit var profileFunction: ProfileFunction @Mock lateinit var rxBus: RxBusWrapper @Mock lateinit var aapsLogger: AAPSLogger - @Mock lateinit var activePlugin: ActivePluginProvider + @Mock lateinit var activePlugin: ActivePlugin private var injector: HasAndroidInjector = HasAndroidInjector { AndroidInjector { - if (it is Treatment) { - it.defaultValueHelper = defaultValueHelper - it.resourceHelper = resourceHelper - it.profileFunction = profileFunction - it.activePlugin = activePlugin - } } } @@ -100,31 +94,32 @@ class InsulinOrefBasePluginTest { @Test fun testIobCalcForTreatment() { - val treatment = Treatment(injector) //TODO: this should be a separate sut. I'd prefer a separate class. + val treatment = Bolus(timestamp = 0, amount = 10.0, type = Bolus.Type.NORMAL) val expected = Iob() - Assert.assertEquals(expected, sut.iobCalcForTreatment(treatment, 0, 0.0)) + Assert.assertEquals(expected.iobContrib, sut.iobCalcForTreatment(treatment, 0, 0.0).iobContrib, 0.001) + Assert.assertEquals(expected.activityContrib, sut.iobCalcForTreatment(treatment, 0, 0.0).activityContrib, 0.001) testPeak = 30 testUserDefinedDia = 4.0 val time = System.currentTimeMillis() // check directly after bolus - treatment.date = time - treatment.insulin = 10.0 + treatment.timestamp = time + treatment.amount = 10.0 Assert.assertEquals(10.0, sut.iobCalcForTreatment(treatment, time, Constants.defaultDIA).iobContrib, 0.1) // check after 1 hour - treatment.date = time - 1 * 60 * 60 * 1000 // 1 hour - treatment.insulin = 10.0 + treatment.timestamp = time - 1 * 60 * 60 * 1000 // 1 hour + treatment.amount = 10.0 Assert.assertEquals(3.92, sut.iobCalcForTreatment(treatment, time, Constants.defaultDIA).iobContrib, 0.1) // check after 2 hour - treatment.date = time - 2 * 60 * 60 * 1000 // 1 hour - treatment.insulin = 10.0 + treatment.timestamp = time - 2 * 60 * 60 * 1000 // 2 hours + treatment.amount = 10.0 Assert.assertEquals(0.77, sut.iobCalcForTreatment(treatment, time, Constants.defaultDIA).iobContrib, 0.1) // check after 3 hour - treatment.date = time - 3 * 60 * 60 * 1000 // 1 hour - treatment.insulin = 10.0 + treatment.timestamp = time - 3 * 60 * 60 * 1000 // 3 hours + treatment.amount = 10.0 Assert.assertEquals(0.10, sut.iobCalcForTreatment(treatment, time, Constants.defaultDIA).iobContrib, 0.1) // check after dia - treatment.date = time - 4 * 60 * 60 * 1000 - treatment.insulin = 10.0 + treatment.timestamp = time - 4 * 60 * 60 * 1000 // 4 hours + treatment.amount = 10.0 Assert.assertEquals(0.0, sut.iobCalcForTreatment(treatment, time, Constants.defaultDIA).iobContrib, 0.1) } } \ No newline at end of file diff --git a/app/src/test/java/info/nightscout/androidaps/plugins/insulin/InsulinOrefFreePeakPluginTest.kt b/app/src/test/java/info/nightscout/androidaps/plugins/insulin/InsulinOrefFreePeakPluginTest.kt index a172e98116..3f6e828b34 100644 --- a/app/src/test/java/info/nightscout/androidaps/plugins/insulin/InsulinOrefFreePeakPluginTest.kt +++ b/app/src/test/java/info/nightscout/androidaps/plugins/insulin/InsulinOrefFreePeakPluginTest.kt @@ -4,7 +4,7 @@ import dagger.android.AndroidInjector import dagger.android.HasAndroidInjector import info.nightscout.androidaps.TestBase import info.nightscout.androidaps.R -import info.nightscout.androidaps.interfaces.InsulinInterface +import info.nightscout.androidaps.interfaces.Insulin import info.nightscout.androidaps.plugins.bus.RxBusWrapper import info.nightscout.androidaps.interfaces.ProfileFunction import info.nightscout.androidaps.utils.resources.ResourceHelper @@ -54,7 +54,7 @@ class InsulinOrefFreePeakPluginTest : TestBase() { @Test fun getIdTest() { - assertEquals(InsulinInterface.InsulinType.OREF_FREE_PEAK, sut.id) + assertEquals(Insulin.InsulinType.OREF_FREE_PEAK, sut.id) } @Test diff --git a/app/src/test/java/info/nightscout/androidaps/plugins/insulin/InsulinOrefRapidActingPluginTest.kt b/app/src/test/java/info/nightscout/androidaps/plugins/insulin/InsulinOrefRapidActingPluginTest.kt index e4a1b7a650..aa4990808a 100644 --- a/app/src/test/java/info/nightscout/androidaps/plugins/insulin/InsulinOrefRapidActingPluginTest.kt +++ b/app/src/test/java/info/nightscout/androidaps/plugins/insulin/InsulinOrefRapidActingPluginTest.kt @@ -3,7 +3,7 @@ package info.nightscout.androidaps.plugins.insulin import dagger.android.AndroidInjector import dagger.android.HasAndroidInjector import info.nightscout.androidaps.R -import info.nightscout.androidaps.interfaces.InsulinInterface +import info.nightscout.androidaps.interfaces.Insulin import info.nightscout.androidaps.logging.AAPSLogger import info.nightscout.androidaps.plugins.bus.RxBusWrapper import info.nightscout.androidaps.interfaces.ProfileFunction @@ -47,7 +47,7 @@ class InsulinOrefRapidActingPluginTest { @Test fun getIdTest() { - assertEquals(InsulinInterface.InsulinType.OREF_RAPID_ACTING, sut.id) + assertEquals(Insulin.InsulinType.OREF_RAPID_ACTING, sut.id) } @Test diff --git a/app/src/test/java/info/nightscout/androidaps/plugins/insulin/InsulinOrefUltraRapidActingPluginTest.kt b/app/src/test/java/info/nightscout/androidaps/plugins/insulin/InsulinOrefUltraRapidActingPluginTest.kt index 2690a826aa..7739049063 100644 --- a/app/src/test/java/info/nightscout/androidaps/plugins/insulin/InsulinOrefUltraRapidActingPluginTest.kt +++ b/app/src/test/java/info/nightscout/androidaps/plugins/insulin/InsulinOrefUltraRapidActingPluginTest.kt @@ -3,7 +3,7 @@ package info.nightscout.androidaps.plugins.insulin import dagger.android.AndroidInjector import dagger.android.HasAndroidInjector import info.nightscout.androidaps.R -import info.nightscout.androidaps.interfaces.InsulinInterface +import info.nightscout.androidaps.interfaces.Insulin import info.nightscout.androidaps.logging.AAPSLogger import info.nightscout.androidaps.plugins.bus.RxBusWrapper import info.nightscout.androidaps.interfaces.ProfileFunction @@ -47,7 +47,7 @@ class InsulinOrefUltraRapidActingPluginTest { @Test fun getIdTest() { - assertEquals(InsulinInterface.InsulinType.OREF_ULTRA_RAPID_ACTING, sut.id) + assertEquals(Insulin.InsulinType.OREF_ULTRA_RAPID_ACTING, sut.id) } @Test diff --git a/app/src/test/java/info/nightscout/androidaps/plugins/pump/virtual/VirtualPumpPluginUTest.kt b/app/src/test/java/info/nightscout/androidaps/plugins/pump/virtual/VirtualPumpPluginUTest.kt index 1d3db18e1c..53b4bc6086 100644 --- a/app/src/test/java/info/nightscout/androidaps/plugins/pump/virtual/VirtualPumpPluginUTest.kt +++ b/app/src/test/java/info/nightscout/androidaps/plugins/pump/virtual/VirtualPumpPluginUTest.kt @@ -1,14 +1,15 @@ package info.nightscout.androidaps.plugins.pump.virtual import dagger.android.AndroidInjector -import info.nightscout.androidaps.Config +import info.nightscout.androidaps.utils.buildHelper.ConfigImpl import info.nightscout.androidaps.R import info.nightscout.androidaps.TestBase import info.nightscout.androidaps.interfaces.CommandQueueProvider +import info.nightscout.androidaps.interfaces.IobCobCalculator import info.nightscout.androidaps.interfaces.ProfileFunction +import info.nightscout.androidaps.interfaces.PumpSync import info.nightscout.androidaps.plugins.bus.RxBusWrapper import info.nightscout.androidaps.plugins.pump.common.defs.PumpType -import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin import info.nightscout.androidaps.utils.DateUtil import info.nightscout.androidaps.utils.FabricPrivacy import info.nightscout.androidaps.utils.resources.ResourceHelper @@ -23,7 +24,7 @@ import org.powermock.core.classloader.annotations.PrepareForTest import org.powermock.modules.junit4.PowerMockRunner @RunWith(PowerMockRunner::class) -@PrepareForTest(FabricPrivacy::class) +@PrepareForTest(FabricPrivacy::class, DateUtil::class) class VirtualPumpPluginUTest : TestBase() { private val rxBus = RxBusWrapper(aapsSchedulers) @@ -31,22 +32,23 @@ class VirtualPumpPluginUTest : TestBase() { @Mock lateinit var resourceHelper: ResourceHelper @Mock lateinit var sp: SP @Mock lateinit var profileFunction: ProfileFunction - @Mock lateinit var treatmentsPlugin: TreatmentsPlugin + @Mock lateinit var iobCobCalculator: IobCobCalculator @Mock lateinit var commandQueue: CommandQueueProvider @Mock lateinit var dateUtil: DateUtil + @Mock lateinit var pumpSync: PumpSync lateinit var virtualPumpPlugin: VirtualPumpPlugin @Before fun prepareMocks() { - virtualPumpPlugin = VirtualPumpPlugin({ AndroidInjector { } }, aapsLogger, rxBus, fabricPrivacy, resourceHelper, aapsSchedulers, sp, profileFunction, treatmentsPlugin, commandQueue, Config(), dateUtil) + virtualPumpPlugin = VirtualPumpPlugin({ AndroidInjector { } }, aapsLogger, rxBus, fabricPrivacy, resourceHelper, aapsSchedulers, sp, profileFunction, iobCobCalculator, commandQueue, pumpSync, ConfigImpl(), dateUtil) } @Test fun refreshConfiguration() { PowerMockito.`when`(sp.getString(R.string.key_virtualpump_type, "Generic AAPS")).thenReturn("Accu-Chek Combo") virtualPumpPlugin.refreshConfiguration() - Assert.assertEquals(PumpType.AccuChekCombo, virtualPumpPlugin.pumpType) + Assert.assertEquals(PumpType.ACCU_CHEK_COMBO, virtualPumpPlugin.pumpType) } @Test @@ -55,6 +57,6 @@ class VirtualPumpPluginUTest : TestBase() { virtualPumpPlugin.refreshConfiguration() PowerMockito.`when`(sp.getString(R.string.key_virtualpump_type, "Generic AAPS")).thenReturn("Accu-Chek Combo") virtualPumpPlugin.refreshConfiguration() - Assert.assertEquals(PumpType.AccuChekCombo, virtualPumpPlugin.pumpType) + Assert.assertEquals(PumpType.ACCU_CHEK_COMBO, virtualPumpPlugin.pumpType) } } \ No newline at end of file diff --git a/app/src/test/java/info/nightscout/androidaps/plugins/sensitivity/AbstractSensitivityPluginTest.kt b/app/src/test/java/info/nightscout/androidaps/plugins/sensitivity/AbstractSensitivityPluginTest.kt index f1f0f3f5a0..40b5520720 100644 --- a/app/src/test/java/info/nightscout/androidaps/plugins/sensitivity/AbstractSensitivityPluginTest.kt +++ b/app/src/test/java/info/nightscout/androidaps/plugins/sensitivity/AbstractSensitivityPluginTest.kt @@ -3,10 +3,10 @@ package info.nightscout.androidaps.plugins.sensitivity import dagger.android.AndroidInjector import dagger.android.HasAndroidInjector import info.nightscout.androidaps.TestBase -import info.nightscout.androidaps.interfaces.IobCobCalculatorInterface import info.nightscout.androidaps.interfaces.PluginDescription -import info.nightscout.androidaps.interfaces.SensitivityInterface +import info.nightscout.androidaps.interfaces.Sensitivity import info.nightscout.androidaps.logging.AAPSLogger +import info.nightscout.androidaps.plugins.iob.iobCobCalculator.AutosensDataStore import info.nightscout.androidaps.plugins.iob.iobCobCalculator.AutosensResult import info.nightscout.androidaps.utils.resources.ResourceHelper import info.nightscout.androidaps.utils.sharedPreferences.SP @@ -26,16 +26,16 @@ class AbstractSensitivityPluginTest : TestBase() { private inner class SensitivityTestClass(pluginDescription: PluginDescription, aapsLogger: AAPSLogger, resourceHelper: ResourceHelper, sp: SP) : AbstractSensitivityPlugin(pluginDescription, HasAndroidInjector { AndroidInjector { } }, aapsLogger, resourceHelper, sp) { - override fun detectSensitivity(plugin: IobCobCalculatorInterface, fromTime: Long, toTime: Long): AutosensResult { + override fun detectSensitivity(ads: AutosensDataStore, fromTime: Long, toTime: Long): AutosensResult { return AutosensResult() } - override val id: SensitivityInterface.SensitivityType - get() = SensitivityInterface.SensitivityType.UNKNOWN + override val id: Sensitivity.SensitivityType + get() = Sensitivity.SensitivityType.UNKNOWN override fun configuration(): JSONObject = JSONObject() - override fun applyConfiguration(configuration: JSONObject) { } + override fun applyConfiguration(configuration: JSONObject) {} } @Test diff --git a/app/src/test/java/info/nightscout/androidaps/plugins/source/GlimpPluginTest.kt b/app/src/test/java/info/nightscout/androidaps/plugins/source/GlimpPluginTest.kt index 2fcd7b9a96..882f754d6d 100644 --- a/app/src/test/java/info/nightscout/androidaps/plugins/source/GlimpPluginTest.kt +++ b/app/src/test/java/info/nightscout/androidaps/plugins/source/GlimpPluginTest.kt @@ -3,21 +3,23 @@ package info.nightscout.androidaps.plugins.source import dagger.android.AndroidInjector import dagger.android.HasAndroidInjector import info.nightscout.androidaps.TestBase -import info.nightscout.androidaps.logging.AAPSLogger import info.nightscout.androidaps.utils.resources.ResourceHelper +import info.nightscout.androidaps.utils.sharedPreferences.SP import org.junit.Assert import org.junit.Before import org.junit.Test import org.mockito.Mock class GlimpPluginTest : TestBase() { + private lateinit var glimpPlugin: GlimpPlugin @Mock lateinit var resourceHelper: ResourceHelper + @Mock lateinit var sp: SP @Before fun setup() { - glimpPlugin = GlimpPlugin(HasAndroidInjector { AndroidInjector { } }, resourceHelper, aapsLogger) + glimpPlugin = GlimpPlugin(HasAndroidInjector { AndroidInjector { } }, resourceHelper, aapsLogger, sp) } @Test fun advancedFilteringSupported() { diff --git a/app/src/test/java/info/nightscout/androidaps/plugins/source/MM640GPluginTest.kt b/app/src/test/java/info/nightscout/androidaps/plugins/source/MM640GPluginTest.kt index f80d5db9e0..e2471d6acf 100644 --- a/app/src/test/java/info/nightscout/androidaps/plugins/source/MM640GPluginTest.kt +++ b/app/src/test/java/info/nightscout/androidaps/plugins/source/MM640GPluginTest.kt @@ -3,8 +3,8 @@ package info.nightscout.androidaps.plugins.source import dagger.android.AndroidInjector import dagger.android.HasAndroidInjector import info.nightscout.androidaps.TestBase -import info.nightscout.androidaps.logging.AAPSLogger import info.nightscout.androidaps.utils.resources.ResourceHelper +import info.nightscout.androidaps.utils.sharedPreferences.SP import org.junit.Assert import org.junit.Before import org.junit.Test @@ -18,10 +18,11 @@ class MM640GPluginTest : TestBase() { private lateinit var mM640gPlugin: MM640gPlugin @Mock lateinit var resourceHelper: ResourceHelper + @Mock lateinit var sp: SP @Before fun setup() { - mM640gPlugin = MM640gPlugin(HasAndroidInjector { AndroidInjector { } }, resourceHelper, aapsLogger) + mM640gPlugin = MM640gPlugin(HasAndroidInjector { AndroidInjector { } }, resourceHelper, aapsLogger, sp) } @Test fun advancedFilteringSupported() { diff --git a/app/src/test/java/info/nightscout/androidaps/plugins/source/NSClientPluginTest.kt b/app/src/test/java/info/nightscout/androidaps/plugins/source/NSClientPluginTest.kt index 3b068ea810..ebd1e14b03 100644 --- a/app/src/test/java/info/nightscout/androidaps/plugins/source/NSClientPluginTest.kt +++ b/app/src/test/java/info/nightscout/androidaps/plugins/source/NSClientPluginTest.kt @@ -1,7 +1,7 @@ package info.nightscout.androidaps.plugins.source import dagger.android.AndroidInjector -import info.nightscout.androidaps.Config +import info.nightscout.androidaps.utils.buildHelper.ConfigImpl import info.nightscout.androidaps.TestBase import info.nightscout.androidaps.utils.resources.ResourceHelper import info.nightscout.androidaps.utils.sharedPreferences.SP @@ -22,7 +22,7 @@ class NSClientPluginTest : TestBase() { @Before fun setup() { - nsClientSourcePlugin = NSClientSourcePlugin({ AndroidInjector { } }, resourceHelper, aapsLogger, Config()) + nsClientSourcePlugin = NSClientSourcePlugin({ AndroidInjector { } }, resourceHelper, aapsLogger, ConfigImpl()) } @Test fun advancedFilteringSupported() { diff --git a/app/src/test/java/info/nightscout/androidaps/plugins/treatments/TreatmentsPluginTest.kt b/app/src/test/java/info/nightscout/androidaps/plugins/treatments/TreatmentsPluginTest.kt index 4b0a188556..4d803ca0e9 100644 --- a/app/src/test/java/info/nightscout/androidaps/plugins/treatments/TreatmentsPluginTest.kt +++ b/app/src/test/java/info/nightscout/androidaps/plugins/treatments/TreatmentsPluginTest.kt @@ -1,6 +1,5 @@ package info.nightscout.androidaps.plugins.treatments -import android.content.Context import dagger.android.AndroidInjector import dagger.android.HasAndroidInjector import info.nightscout.androidaps.TestBaseWithProfile @@ -9,18 +8,12 @@ import info.nightscout.androidaps.db.TemporaryBasal import info.nightscout.androidaps.interfaces.DatabaseHelperInterface import info.nightscout.androidaps.interfaces.UploadQueueInterface import info.nightscout.androidaps.plugins.general.nsclient.NSUpload -import info.nightscout.androidaps.plugins.insulin.InsulinOrefRapidActingPlugin import info.nightscout.androidaps.utils.DateUtil import info.nightscout.androidaps.utils.FabricPrivacy -import info.nightscout.androidaps.utils.T import info.nightscout.androidaps.utils.sharedPreferences.SP -import org.junit.Assert -import org.junit.Before import org.junit.Test import org.junit.runner.RunWith -import org.mockito.ArgumentMatchers import org.mockito.Mock -import org.mockito.Mockito.`when` import org.powermock.core.classloader.annotations.PrepareForTest import org.powermock.modules.junit4.PowerMockRunner @@ -29,7 +22,6 @@ import org.powermock.modules.junit4.PowerMockRunner @PrepareForTest(FabricPrivacy::class, DatabaseHelperInterface::class, AppRepository::class) class TreatmentsPluginTest : TestBaseWithProfile() { - @Mock lateinit var context: Context @Mock lateinit var sp: SP @Mock lateinit var treatmentService: TreatmentService @Mock lateinit var nsUpload: NSUpload @@ -49,6 +41,8 @@ class TreatmentsPluginTest : TestBaseWithProfile() { } } + @Test fun dumy() {} +/* private lateinit var insulinOrefRapidActingPlugin: InsulinOrefRapidActingPlugin private lateinit var sot: TreatmentsPlugin @@ -59,13 +53,13 @@ class TreatmentsPluginTest : TestBaseWithProfile() { `when`(profileFunction.getProfile(ArgumentMatchers.anyLong())).thenReturn(validProfile) `when`(activePluginProvider.activeInsulin).thenReturn(insulinOrefRapidActingPlugin) - sot = TreatmentsPlugin(profileInjector, aapsLogger, rxBus, aapsSchedulers, resourceHelper, context, sp, profileFunction, activePluginProvider, nsUpload, fabricPrivacy, dateUtil, uploadQueue, databaseHelper, repository) + sot = TreatmentsPlugin(profileInjector, aapsLogger, rxBus, aapsSchedulers, resourceHelper, context, sp, profileFunction, activePluginProvider, nsUpload, fabricPrivacy, dateUtil, databaseHelper, repository) sot.service = treatmentService } @Test fun `zero TBR should produce zero absolute insulin`() { - val now = DateUtil.now() + val now = dateUtil._now() val tbrs: MutableList = ArrayList() tbrs.add(TemporaryBasal(injector).date(now - T.hours(30).msecs()).duration(10000).percent(0)) @@ -77,7 +71,7 @@ class TreatmentsPluginTest : TestBaseWithProfile() { @Test fun `90pct TBR and should produce less absolute insulin`() { - val now = DateUtil.now() + val now = dateUtil._now() val tbrs: MutableList = ArrayList() `when`(databaseHelper.getTemporaryBasalsDataFromTime(ArgumentMatchers.anyLong(), ArgumentMatchers.anyBoolean())).thenReturn(tbrs) sot.initializeData(T.hours(30).msecs()) @@ -91,7 +85,7 @@ class TreatmentsPluginTest : TestBaseWithProfile() { @Test fun `110pct TBR and should produce 10pct more absolute insulin`() { - val now = DateUtil.now() + val now = dateUtil._now() val tbrs: MutableList = ArrayList() `when`(databaseHelper.getTemporaryBasalsDataFromTime(ArgumentMatchers.anyLong(), ArgumentMatchers.anyBoolean())).thenReturn(tbrs) sot.initializeData(T.hours(30).msecs()) @@ -102,4 +96,6 @@ class TreatmentsPluginTest : TestBaseWithProfile() { val iob110pct = sot.getAbsoluteIOBTempBasals(now) Assert.assertEquals(1.1, iob110pct.basaliob / iob100pct.basaliob, 0.0001) } + + */ } \ No newline at end of file diff --git a/app/src/test/java/info/nightscout/androidaps/queue/CommandQueueTest.kt b/app/src/test/java/info/nightscout/androidaps/queue/CommandQueueTest.kt index 2448ea7b8b..1d069dd8a8 100644 --- a/app/src/test/java/info/nightscout/androidaps/queue/CommandQueueTest.kt +++ b/app/src/test/java/info/nightscout/androidaps/queue/CommandQueueTest.kt @@ -5,14 +5,17 @@ import android.os.PowerManager import dagger.Lazy import dagger.android.AndroidInjector import dagger.android.HasAndroidInjector -import info.nightscout.androidaps.Config +import info.nightscout.androidaps.utils.buildHelper.ConfigImpl import info.nightscout.androidaps.TestBaseWithProfile import info.nightscout.androidaps.TestPumpPlugin import info.nightscout.androidaps.core.R import info.nightscout.androidaps.data.DetailedBolusInfo -import info.nightscout.androidaps.interfaces.ActivePluginProvider +import info.nightscout.androidaps.database.AppRepository +import info.nightscout.androidaps.database.entities.Bolus +import info.nightscout.androidaps.interfaces.ActivePlugin import info.nightscout.androidaps.interfaces.Constraint import info.nightscout.androidaps.interfaces.ProfileFunction +import info.nightscout.androidaps.interfaces.PumpSync import info.nightscout.androidaps.logging.AAPSLogger import info.nightscout.androidaps.plugins.bus.RxBusWrapper import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker @@ -40,16 +43,17 @@ import java.util.* @RunWith(PowerMockRunner::class) @PrepareForTest( ConstraintChecker::class, VirtualPumpPlugin::class, ToastUtils::class, Context::class, - TreatmentsPlugin::class, FabricPrivacy::class, LoggerUtils::class, PowerManager::class) + TreatmentsPlugin::class, FabricPrivacy::class, LoggerUtils::class, PowerManager::class, + AppRepository::class) class CommandQueueTest : TestBaseWithProfile() { @Mock lateinit var constraintChecker: ConstraintChecker - @Mock lateinit var lazyActivePlugin: Lazy - @Mock lateinit var activePlugin: ActivePluginProvider - @Mock lateinit var context: Context + @Mock lateinit var lazyActivePlugin: Lazy + @Mock lateinit var activePlugin: ActivePlugin @Mock lateinit var sp: SP @Mock lateinit var loggerUtils: LoggerUtils @Mock lateinit var powerManager: PowerManager + @Mock lateinit var repository: AppRepository class CommandQueueMocked( injector: HasAndroidInjector, @@ -59,12 +63,14 @@ class CommandQueueTest : TestBaseWithProfile() { resourceHelper: ResourceHelper, constraintChecker: ConstraintChecker, profileFunction: ProfileFunction, - activePlugin: Lazy, + activePlugin: Lazy, context: Context, sp: SP, buildHelper: BuildHelper, + dateUtil: DateUtil, + repository: AppRepository, fabricPrivacy: FabricPrivacy - ) : CommandQueue(injector, aapsLogger, rxBus, aapsSchedulers, resourceHelper, constraintChecker, profileFunction, activePlugin, context, sp, buildHelper, fabricPrivacy) { + ) : CommandQueue(injector, aapsLogger, rxBus, aapsSchedulers, resourceHelper, constraintChecker, profileFunction, activePlugin, context, sp, buildHelper, dateUtil, repository, fabricPrivacy) { override fun notifyAboutNewCommand() {} @@ -95,12 +101,12 @@ class CommandQueueTest : TestBaseWithProfile() { } } - lateinit var commandQueue: CommandQueue - lateinit var testPumpPlugin: TestPumpPlugin + private lateinit var commandQueue: CommandQueue + private lateinit var testPumpPlugin: TestPumpPlugin @Before fun prepare() { - commandQueue = CommandQueueMocked(injector, aapsLogger, rxBus, aapsSchedulers, resourceHelper, constraintChecker, profileFunction, lazyActivePlugin, context, sp, BuildHelper(Config(), loggerUtils), fabricPrivacy) + commandQueue = CommandQueueMocked(injector, aapsLogger, rxBus, aapsSchedulers, resourceHelper, constraintChecker, profileFunction, lazyActivePlugin, context, sp, BuildHelper(ConfigImpl(), loggerUtils), dateUtil, repository, fabricPrivacy) testPumpPlugin = TestPumpPlugin(injector) testPumpPlugin.pumpDescription.basalMinimumRate = 0.1 @@ -109,7 +115,13 @@ class CommandQueueTest : TestBaseWithProfile() { `when`(lazyActivePlugin.get()).thenReturn(activePlugin) `when`(activePlugin.activePump).thenReturn(testPumpPlugin) `when`(activePlugin.activeTreatments).thenReturn(treatmentsInterface) - `when`(treatmentsInterface.lastBolusTime).thenReturn(Calendar.getInstance().also { it.set(2000, 0, 1) }.timeInMillis) + `when`(repository.getLastBolusRecord()).thenReturn( + Bolus( + timestamp = Calendar.getInstance().also { it.set(2000, 0, 1) }.timeInMillis, + type = Bolus.Type.NORMAL, + amount = 0.0 + ) + ) `when`(profileFunction.getProfile()).thenReturn(validProfile) val bolusConstraint = Constraint(0.0) @@ -126,7 +138,7 @@ class CommandQueueTest : TestBaseWithProfile() { @Test fun commandIsPickedUp() { - val commandQueue = CommandQueue(injector, aapsLogger, rxBus, aapsSchedulers, resourceHelper, constraintChecker, profileFunction, lazyActivePlugin, context, sp, BuildHelper(Config(), loggerUtils), fabricPrivacy) + val commandQueue = CommandQueue(injector, aapsLogger, rxBus, aapsSchedulers, resourceHelper, constraintChecker, profileFunction, lazyActivePlugin, context, sp, BuildHelper(ConfigImpl(), loggerUtils), dateUtil, repository, fabricPrivacy) // start with empty queue Assert.assertEquals(0, commandQueue.size()) @@ -163,11 +175,11 @@ class CommandQueueTest : TestBaseWithProfile() { Assert.assertEquals(0, commandQueue.size()) // add tempbasal - commandQueue.tempBasalAbsolute(0.0, 30, true, validProfile, null) + commandQueue.tempBasalAbsolute(0.0, 30, true, validProfile, PumpSync.TemporaryBasalType.NORMAL, null) Assert.assertEquals(1, commandQueue.size()) // add tempbasal percent. it should replace previous TEMPBASAL - commandQueue.tempBasalPercent(0, 30, true, validProfile, null) + commandQueue.tempBasalPercent(0, 30, true, validProfile, PumpSync.TemporaryBasalType.NORMAL, null) Assert.assertEquals(1, commandQueue.size()) // cancel tempbasal it should replace previous TEMPBASAL @@ -199,7 +211,7 @@ class CommandQueueTest : TestBaseWithProfile() { commandQueue.loadEvents(null) Assert.assertEquals(4, commandQueue.size()) commandQueue.clear() - commandQueue.tempBasalAbsolute(0.0, 30, true, validProfile, null) + commandQueue.tempBasalAbsolute(0.0, 30, true, validProfile, PumpSync.TemporaryBasalType.NORMAL, null) commandQueue.pickup() Assert.assertEquals(0, commandQueue.size()) Assert.assertNotNull(commandQueue.performing) @@ -213,8 +225,8 @@ class CommandQueueTest : TestBaseWithProfile() { // given Assert.assertEquals(0, commandQueue.size()) val smb = DetailedBolusInfo() - smb.lastKnownBolusTime = DateUtil.now() - smb.isSMB = true + smb.lastKnownBolusTime = System.currentTimeMillis() + smb.bolusType = DetailedBolusInfo.BolusType.SMB commandQueue.bolus(smb, null) commandQueue.bolus(DetailedBolusInfo(), null) Assert.assertEquals(2, commandQueue.size()) @@ -234,7 +246,7 @@ class CommandQueueTest : TestBaseWithProfile() { // when commandQueue.bolus(DetailedBolusInfo(), null) val smb = DetailedBolusInfo() - smb.isSMB = true + smb.bolusType = DetailedBolusInfo.BolusType.SMB val queued: Boolean = commandQueue.bolus(smb, null) // then @@ -249,7 +261,7 @@ class CommandQueueTest : TestBaseWithProfile() { // when val bolus = DetailedBolusInfo() - bolus.isSMB = true + bolus.bolusType = DetailedBolusInfo.BolusType.SMB bolus.lastKnownBolusTime = 0 val queued: Boolean = commandQueue.bolus(bolus, null) diff --git a/app/src/test/java/info/nightscout/androidaps/queue/QueueThreadTest.kt b/app/src/test/java/info/nightscout/androidaps/queue/QueueThreadTest.kt index d44a52bdb4..04dd667ff9 100644 --- a/app/src/test/java/info/nightscout/androidaps/queue/QueueThreadTest.kt +++ b/app/src/test/java/info/nightscout/androidaps/queue/QueueThreadTest.kt @@ -5,12 +5,14 @@ import android.os.PowerManager import dagger.Lazy import dagger.android.AndroidInjector import dagger.android.HasAndroidInjector -import info.nightscout.androidaps.Config +import info.nightscout.androidaps.utils.buildHelper.ConfigImpl import info.nightscout.androidaps.TestBaseWithProfile import info.nightscout.androidaps.TestPumpPlugin -import info.nightscout.androidaps.interfaces.ActivePluginProvider +import info.nightscout.androidaps.database.AppRepository +import info.nightscout.androidaps.interfaces.ActivePlugin import info.nightscout.androidaps.interfaces.Constraint import info.nightscout.androidaps.interfaces.PumpDescription +import info.nightscout.androidaps.interfaces.PumpSync import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker import info.nightscout.androidaps.plugins.general.maintenance.LoggerUtils import info.nightscout.androidaps.plugins.pump.virtual.VirtualPumpPlugin @@ -29,7 +31,6 @@ import org.mockito.Mock import org.mockito.Mockito import org.powermock.core.classloader.annotations.PrepareForTest import org.powermock.modules.junit4.PowerMockRunner -import java.util.* @RunWith(PowerMockRunner::class) @PrepareForTest( @@ -38,12 +39,12 @@ import java.util.* class QueueThreadTest : TestBaseWithProfile() { @Mock lateinit var constraintChecker: ConstraintChecker - @Mock lateinit var lazyActivePlugin: Lazy - @Mock lateinit var activePlugin: ActivePluginProvider - @Mock lateinit var context: Context + @Mock lateinit var lazyActivePlugin: Lazy + @Mock lateinit var activePlugin: ActivePlugin @Mock lateinit var sp: SP @Mock lateinit var loggerUtils: LoggerUtils @Mock lateinit var powerManager: PowerManager + @Mock lateinit var repository: AppRepository val injector = HasAndroidInjector { AndroidInjector { @@ -58,13 +59,13 @@ class QueueThreadTest : TestBaseWithProfile() { } private lateinit var pumpPlugin: TestPumpPlugin - lateinit var commandQueue: CommandQueue - lateinit var sut: QueueThread + private lateinit var commandQueue: CommandQueue + private lateinit var sut: QueueThread @Before fun prepare() { pumpPlugin = TestPumpPlugin(injector) - commandQueue = CommandQueue(injector, aapsLogger, rxBus, aapsSchedulers, resourceHelper, constraintChecker, profileFunction, lazyActivePlugin, context, sp, BuildHelper(Config(), loggerUtils), fabricPrivacy) + commandQueue = CommandQueue(injector, aapsLogger, rxBus, aapsSchedulers, resourceHelper, constraintChecker, profileFunction, lazyActivePlugin, context, sp, BuildHelper(ConfigImpl(), loggerUtils), dateUtil, repository, fabricPrivacy) val pumpDescription = PumpDescription() pumpDescription.basalMinimumRate = 0.1 @@ -73,7 +74,7 @@ class QueueThreadTest : TestBaseWithProfile() { Mockito.`when`(lazyActivePlugin.get()).thenReturn(activePlugin) Mockito.`when`(activePlugin.activePump).thenReturn(pumpPlugin) Mockito.`when`(activePlugin.activeTreatments).thenReturn(treatmentsInterface) - Mockito.`when`(treatmentsInterface.lastBolusTime).thenReturn(Calendar.getInstance().also { it.set(2000, 0, 1) }.timeInMillis) +// Mockito.`when`(treatmentsInterface.lastBolusTime).thenReturn(Calendar.getInstance().also { it.set(2000, 0, 1) }.timeInMillis) Mockito.`when`(profileFunction.getProfile()).thenReturn(validProfile) val bolusConstraint = Constraint(0.0) @@ -91,7 +92,7 @@ class QueueThreadTest : TestBaseWithProfile() { @Test fun commandIsPickedUp() { - commandQueue.tempBasalAbsolute(2.0, 60, true, validProfile, null) + commandQueue.tempBasalAbsolute(2.0, 60, true, validProfile, PumpSync.TemporaryBasalType.NORMAL, null) sut.run() Assert.assertEquals(0, commandQueue.size()) } diff --git a/app/src/test/java/info/nightscout/androidaps/utils/PercentageSplitterTest.java b/app/src/test/java/info/nightscout/androidaps/utils/PercentageSplitterTest.java deleted file mode 100644 index 37f94c1f2d..0000000000 --- a/app/src/test/java/info/nightscout/androidaps/utils/PercentageSplitterTest.java +++ /dev/null @@ -1,30 +0,0 @@ -package info.nightscout.androidaps.utils; - -import org.junit.Test; - -import static org.junit.Assert.assertEquals; - -/** - * Created by mike on 22.12.2017. - */ - -public class PercentageSplitterTest { - public PercentageSplitterTest() { - super(); - } - - @Test - public void pureNameTestPercentageOnly() { - assertEquals("Fiasp", PercentageSplitter.pureName("Fiasp(101%)")); - } - - @Test - public void pureNameTestPercentageAndPositiveTimeShift() { - assertEquals("Fiasp", PercentageSplitter.pureName("Fiasp (101%,2h)")); - } - - @Test - public void pureNameTestPercentageAndNegtiveTimeShift() { - assertEquals("Fiasp", PercentageSplitter.pureName("Fiasp (50%,-2h)")); - } -} diff --git a/app/src/test/java/info/nightscout/androidaps/utils/PercentageSplitterTest.kt b/app/src/test/java/info/nightscout/androidaps/utils/PercentageSplitterTest.kt new file mode 100644 index 0000000000..89f0e9b903 --- /dev/null +++ b/app/src/test/java/info/nightscout/androidaps/utils/PercentageSplitterTest.kt @@ -0,0 +1,23 @@ +package info.nightscout.androidaps.utils + +import info.nightscout.androidaps.utils.PercentageSplitter.pureName +import org.junit.Assert +import org.junit.Test + +/** + * Created by mike on 22.12.2017. + */ +class PercentageSplitterTest { + + @Test fun pureNameTestPercentageOnly() { + Assert.assertEquals("Fiasp", pureName("Fiasp(101%)")) + } + + @Test fun pureNameTestPercentageAndPositiveTimeShift() { + Assert.assertEquals("Fiasp", pureName("Fiasp (101%,2h)")) + } + + @Test fun pureNameTestPercentageAndNegtiveTimeShift() { + Assert.assertEquals("Fiasp", pureName("Fiasp (50%,-2h)")) + } +} \ No newline at end of file diff --git a/app/src/test/java/info/nightscout/androidaps/utils/SntpClientTest.kt b/app/src/test/java/info/nightscout/androidaps/utils/SntpClientTest.kt index 79a8541daf..5224a6129c 100644 --- a/app/src/test/java/info/nightscout/androidaps/utils/SntpClientTest.kt +++ b/app/src/test/java/info/nightscout/androidaps/utils/SntpClientTest.kt @@ -3,8 +3,14 @@ package info.nightscout.androidaps.utils import info.nightscout.androidaps.TestBase import org.junit.Assert import org.junit.Test +import org.junit.runner.RunWith import org.mockito.Mock +import org.powermock.core.classloader.annotations.PrepareForTest +import org.powermock.modules.junit4.PowerMockRunner + +@RunWith(PowerMockRunner::class) +@PrepareForTest(DateUtil::class) class SntpClientTest : TestBase() { @Mock lateinit var dateUtil: DateUtil @@ -22,7 +28,7 @@ class SntpClientTest : TestBase() { SntpClient(aapsLogger, dateUtil).doNtpTime(object : SntpClient.Callback() { override fun run() { Assert.assertTrue(success) - Assert.assertTrue(Math.abs(time - DateUtil.now()) < 60000) + Assert.assertTrue(Math.abs(time - System.currentTimeMillis()) < 60000) } }) } diff --git a/app/src/test/java/info/nightscout/androidaps/utils/wizard/BolusWizardTest.kt b/app/src/test/java/info/nightscout/androidaps/utils/wizard/BolusWizardTest.kt index 40238e7c68..b27156eaea 100644 --- a/app/src/test/java/info/nightscout/androidaps/utils/wizard/BolusWizardTest.kt +++ b/app/src/test/java/info/nightscout/androidaps/utils/wizard/BolusWizardTest.kt @@ -3,23 +3,19 @@ package info.nightscout.androidaps.utils.wizard import android.content.Context import dagger.android.AndroidInjector import dagger.android.HasAndroidInjector -import info.nightscout.androidaps.TestBase import info.nightscout.androidaps.Constants +import info.nightscout.androidaps.TestBase import info.nightscout.androidaps.data.IobTotal import info.nightscout.androidaps.data.Profile -import info.nightscout.androidaps.interfaces.ActivePluginProvider -import info.nightscout.androidaps.interfaces.CommandQueueProvider -import info.nightscout.androidaps.interfaces.Constraint -import info.nightscout.androidaps.interfaces.PumpDescription +import info.nightscout.androidaps.interfaces.* import info.nightscout.androidaps.plugins.aps.loop.LoopPlugin import info.nightscout.androidaps.plugins.bus.RxBusWrapper import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker -import info.nightscout.androidaps.interfaces.ProfileFunction -import info.nightscout.androidaps.plugins.iob.iobCobCalculator.GlucoseStatus +import info.nightscout.androidaps.plugins.iob.iobCobCalculator.AutosensDataStore import info.nightscout.androidaps.plugins.iob.iobCobCalculator.GlucoseStatusProvider -import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorPlugin import info.nightscout.androidaps.plugins.pump.virtual.VirtualPumpPlugin import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin +import info.nightscout.androidaps.utils.DateUtil import info.nightscout.androidaps.utils.resources.ResourceHelper import org.junit.Assert import org.junit.Test @@ -32,7 +28,7 @@ import org.powermock.core.classloader.annotations.PrepareForTest import org.powermock.modules.junit4.PowerMockRunner @RunWith(PowerMockRunner::class) -@PrepareForTest(ConstraintChecker::class, VirtualPumpPlugin::class, IobCobCalculatorPlugin::class) +@PrepareForTest(ConstraintChecker::class, VirtualPumpPlugin::class, DateUtil::class, AutosensDataStore::class) class BolusWizardTest : TestBase() { private val pumpBolusStep = 0.1 @@ -41,12 +37,14 @@ class BolusWizardTest : TestBase() { @Mock lateinit var profileFunction: ProfileFunction @Mock lateinit var constraintChecker: ConstraintChecker @Mock lateinit var context: Context - @Mock lateinit var activePlugin: ActivePluginProvider + @Mock lateinit var activePlugin: ActivePlugin @Mock lateinit var commandQueue: CommandQueueProvider @Mock lateinit var loopPlugin: LoopPlugin - @Mock lateinit var iobCobCalculatorPlugin: IobCobCalculatorPlugin + @Mock lateinit var iobCobCalculator: IobCobCalculator @Mock lateinit var treatmentsPlugin: TreatmentsPlugin @Mock lateinit var virtualPumpPlugin: VirtualPumpPlugin + @Mock lateinit var dateUtil: DateUtil + @Mock lateinit var autosensDataStore: AutosensDataStore val injector = HasAndroidInjector { AndroidInjector { @@ -59,8 +57,8 @@ class BolusWizardTest : TestBase() { it.activePlugin = activePlugin it.commandQueue = commandQueue it.loopPlugin = loopPlugin - it.iobCobCalculatorPlugin = iobCobCalculatorPlugin - it.glucoseStatusProvider = GlucoseStatusProvider(aapsLogger = aapsLogger, iobCobCalculatorPlugin = iobCobCalculatorPlugin) + it.iobCobCalculator = iobCobCalculator + it.glucoseStatusProvider = GlucoseStatusProvider(aapsLogger = aapsLogger, iobCobCalculator = iobCobCalculator, dateUtil = dateUtil) } } } @@ -74,14 +72,14 @@ class BolusWizardTest : TestBase() { `when`(profile.ic).thenReturn(insulinToCarbRatio) `when`(profileFunction.getUnits()).thenReturn(Constants.MGDL) - `when`(iobCobCalculatorPlugin.dataLock).thenReturn(Unit) `when`(activePlugin.activeTreatments).thenReturn(treatmentsPlugin) - `when`(treatmentsPlugin.lastCalculationTreatments).thenReturn(IobTotal(System.currentTimeMillis())) - `when`(treatmentsPlugin.lastCalculationTempBasals).thenReturn(IobTotal(System.currentTimeMillis())) + `when`(iobCobCalculator.calculateIobFromBolus()).thenReturn(IobTotal(System.currentTimeMillis())) + `when`(iobCobCalculator.calculateIobFromTempBasalsIncludingConvertedExtended()).thenReturn(IobTotal(System.currentTimeMillis())) `when`(activePlugin.activePump).thenReturn(virtualPumpPlugin) val pumpDescription = PumpDescription() pumpDescription.bolusStep = pumpBolusStep `when`(virtualPumpPlugin.pumpDescription).thenReturn(pumpDescription) + `when`(iobCobCalculator.ads).thenReturn(autosensDataStore) Mockito.doAnswer { invocation: InvocationOnMock -> invocation.getArgument>(0) @@ -93,9 +91,9 @@ class BolusWizardTest : TestBase() { /** Should calculate the same bolus when different blood glucose but both in target range */ fun shouldCalculateTheSameBolusWhenBGsInRange() { val profile = setupProfile(4.0, 8.0, 20.0, 12.0) - var bw = BolusWizard(injector).doCalc(profile, "", null, 20, 0.0, 4.2, 0.0, 100.0, useBg = true, useCob = true, includeBolusIOB = true, includeBasalIOB = true, useSuperBolus = false, useTT = false, useTrend = false, useAlarm = false) + var bw = BolusWizard(injector).doCalc(profile, "", null, 20, 0.0, 4.2, 0.0, 100, useBg = true, useCob = true, includeBolusIOB = true, includeBasalIOB = true, useSuperBolus = false, useTT = false, useTrend = false, useAlarm = false) val bolusForBg42 = bw.calculatedTotalInsulin - bw = BolusWizard(injector).doCalc(profile, "", null, 20, 0.0, 5.4, 0.0, 100.0, useBg = true, useCob = true, includeBolusIOB = true, includeBasalIOB = true, useSuperBolus = false, useTT = false, useTrend = false, useAlarm = false) + bw = BolusWizard(injector).doCalc(profile, "", null, 20, 0.0, 5.4, 0.0, 100, useBg = true, useCob = true, includeBolusIOB = true, includeBasalIOB = true, useSuperBolus = false, useTT = false, useTrend = false, useAlarm = false) val bolusForBg54 = bw.calculatedTotalInsulin Assert.assertEquals(bolusForBg42, bolusForBg54, 0.01) } @@ -103,9 +101,9 @@ class BolusWizardTest : TestBase() { @Test fun shouldCalculateHigherBolusWhenHighBG() { val profile = setupProfile(4.0, 8.0, 20.0, 12.0) - var bw = BolusWizard(injector).doCalc(profile, "", null, 20, 0.0, 9.8, 0.0, 100.0, useBg = true, useCob = true, includeBolusIOB = true, includeBasalIOB = true, useSuperBolus = false, useTT = false, useTrend = false, useAlarm = false) + var bw = BolusWizard(injector).doCalc(profile, "", null, 20, 0.0, 9.8, 0.0, 100, useBg = true, useCob = true, includeBolusIOB = true, includeBasalIOB = true, useSuperBolus = false, useTT = false, useTrend = false, useAlarm = false) val bolusForHighBg = bw.calculatedTotalInsulin - bw = BolusWizard(injector).doCalc(profile, "", null, 20, 0.0, 5.4, 0.0, 100.0, useBg = true, useCob = true, includeBolusIOB = true, includeBasalIOB = true, useSuperBolus = false, useTT = false, useTrend = false, useAlarm = false) + bw = BolusWizard(injector).doCalc(profile, "", null, 20, 0.0, 5.4, 0.0, 100, useBg = true, useCob = true, includeBolusIOB = true, includeBasalIOB = true, useSuperBolus = false, useTT = false, useTrend = false, useAlarm = false) val bolusForBgInRange = bw.calculatedTotalInsulin Assert.assertTrue(bolusForHighBg > bolusForBgInRange) } @@ -113,9 +111,9 @@ class BolusWizardTest : TestBase() { @Test fun shouldCalculateLowerBolusWhenLowBG() { val profile = setupProfile(4.0, 8.0, 20.0, 12.0) - var bw = BolusWizard(injector).doCalc(profile, "", null, 20, 0.0, 3.6, 0.0, 100.0, useBg = true, useCob = true, includeBolusIOB = true, includeBasalIOB = true, useSuperBolus = false, useTT = false, useTrend = false, useAlarm = false) + var bw = BolusWizard(injector).doCalc(profile, "", null, 20, 0.0, 3.6, 0.0, 100, useBg = true, useCob = true, includeBolusIOB = true, includeBasalIOB = true, useSuperBolus = false, useTT = false, useTrend = false, useAlarm = false) val bolusForLowBg = bw.calculatedTotalInsulin - bw = BolusWizard(injector).doCalc(profile, "", null, 20, 0.0, 5.4, 0.0, 100.0, useBg = true, useCob = true, includeBolusIOB = true, includeBasalIOB = true, useSuperBolus = false, useTT = false, useTrend = false, useAlarm = false) + bw = BolusWizard(injector).doCalc(profile, "", null, 20, 0.0, 5.4, 0.0, 100, useBg = true, useCob = true, includeBolusIOB = true, includeBasalIOB = true, useSuperBolus = false, useTT = false, useTrend = false, useAlarm = false) val bolusForBgInRange = bw.calculatedTotalInsulin Assert.assertTrue(bolusForLowBg < bolusForBgInRange) } diff --git a/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/AutomationEvent.kt b/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/AutomationEvent.kt index 4c4b43ba18..ca2ba012e0 100644 --- a/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/AutomationEvent.kt +++ b/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/AutomationEvent.kt @@ -17,6 +17,7 @@ import javax.inject.Inject class AutomationEvent(private val injector: HasAndroidInjector) { @Inject lateinit var aapsLogger: AAPSLogger + @Inject lateinit var dateUtil: DateUtil var title: String = "" var isEnabled = true @@ -83,6 +84,6 @@ class AutomationEvent(private val injector: HasAndroidInjector) { } fun shouldRun(): Boolean { - return lastRun <= DateUtil.now() - T.mins(5).msecs() + return lastRun <= dateUtil.now() - T.mins(5).msecs() } } \ No newline at end of file diff --git a/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/AutomationFragment.kt b/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/AutomationFragment.kt index b7ea2b3db0..6fba938876 100644 --- a/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/AutomationFragment.kt +++ b/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/AutomationFragment.kt @@ -20,7 +20,8 @@ import dagger.android.support.DaggerFragment import info.nightscout.androidaps.automation.R import info.nightscout.androidaps.automation.databinding.AutomationEventItemBinding import info.nightscout.androidaps.automation.databinding.AutomationFragmentBinding -import info.nightscout.androidaps.database.entities.UserEntry.* +import info.nightscout.androidaps.database.entities.UserEntry.Action +import info.nightscout.androidaps.database.entities.UserEntry.Sources import info.nightscout.androidaps.logging.UserEntryLogger import info.nightscout.androidaps.plugins.bus.RxBusWrapper import info.nightscout.androidaps.plugins.general.automation.dialogs.EditEventDialog @@ -35,7 +36,7 @@ import info.nightscout.androidaps.utils.FabricPrivacy import info.nightscout.androidaps.utils.HtmlHelper import info.nightscout.androidaps.utils.alertDialogs.OKDialog import io.reactivex.rxkotlin.plusAssign -import info.nightscout.androidaps.utils.extensions.toVisibility +import info.nightscout.androidaps.extensions.toVisibility import info.nightscout.androidaps.utils.resources.ResourceHelper import info.nightscout.androidaps.utils.rx.AapsSchedulers import io.reactivex.disposables.CompositeDisposable @@ -217,7 +218,7 @@ class AutomationFragment : DaggerFragment(), OnStartDragListener { holder.binding.iconTrash.setOnClickListener { OKDialog.showConfirmation(requireContext(), resourceHelper.gs(R.string.removerecord) + " " + automationPlugin.at(position).title, { - uel.log(Action.AUTOMATION_REMOVED, automationPlugin.at(position).title) + uel.log(Action.AUTOMATION_REMOVED, Sources.Automation, automationPlugin.at(position).title) automationPlugin.removeAt(position) notifyItemRemoved(position) }, { @@ -240,7 +241,7 @@ class AutomationFragment : DaggerFragment(), OnStartDragListener { activity?.let { activity -> OKDialog.showConfirmation(activity, resourceHelper.gs(R.string.removerecord) + " " + automationPlugin.at(position).title, Runnable { - uel.log(Action.AUTOMATION_REMOVED, automationPlugin.at(position).title) + uel.log(Action.AUTOMATION_REMOVED, Sources.Automation, automationPlugin.at(position).title) automationPlugin.removeAt(position) notifyItemRemoved(position) rxBus.send(EventAutomationDataChanged()) diff --git a/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/AutomationPlugin.kt b/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/AutomationPlugin.kt index 1b72161a43..6fdcd20ff7 100644 --- a/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/AutomationPlugin.kt +++ b/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/AutomationPlugin.kt @@ -7,7 +7,7 @@ import android.os.SystemClock import dagger.android.HasAndroidInjector import info.nightscout.androidaps.automation.R import info.nightscout.androidaps.events.* -import info.nightscout.androidaps.interfaces.ConfigInterface +import info.nightscout.androidaps.interfaces.Config import info.nightscout.androidaps.interfaces.LoopInterface import info.nightscout.androidaps.interfaces.PluginBase import info.nightscout.androidaps.interfaces.PluginDescription @@ -50,7 +50,7 @@ class AutomationPlugin @Inject constructor( private val constraintChecker: ConstraintChecker, aapsLogger: AAPSLogger, private val aapsSchedulers: AapsSchedulers, - private val config: ConfigInterface, + private val config: Config, private val locationServiceHelper: LocationServiceHelper, private val dateUtil: DateUtil ) : PluginBase(PluginDescription() @@ -203,11 +203,12 @@ class AutomationPlugin @Inject constructor( if (event.systemAction || userEventsEnabled) { val actions = event.actions for (action in actions) { + action.title = event.title if (action.isValid()) action.doAction(object : Callback() { override fun run() { val sb = StringBuilder() - sb.append(dateUtil.timeString(DateUtil.now())) + sb.append(dateUtil.timeString(dateUtil.now())) sb.append(" ") sb.append(if (result.success) "☺" else "▼") sb.append(" ") @@ -228,7 +229,7 @@ class AutomationPlugin @Inject constructor( } } SystemClock.sleep(1100) - event.lastRun = DateUtil.now() + event.lastRun = dateUtil.now() if (event.autoRemove) automationEvents.remove(event) } } diff --git a/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/actions/Action.kt b/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/actions/Action.kt index a7fe565e58..9d3b86e875 100644 --- a/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/actions/Action.kt +++ b/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/actions/Action.kt @@ -23,6 +23,8 @@ abstract class Action(val injector: HasAndroidInjector) { abstract fun isValid(): Boolean @DrawableRes abstract fun icon(): Int + var title = "" + init { injector.androidInjector().inject(this) } diff --git a/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/actions/ActionAlarm.kt b/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/actions/ActionAlarm.kt index 8e012f2771..1461e20838 100644 --- a/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/actions/ActionAlarm.kt +++ b/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/actions/ActionAlarm.kt @@ -24,6 +24,7 @@ class ActionAlarm(injector: HasAndroidInjector) : Action(injector) { @Inject lateinit var resourceHelper: ResourceHelper @Inject lateinit var rxBus: RxBusWrapper @Inject lateinit var context: Context + @Inject lateinit var dateUtil: DateUtil @Inject lateinit var timerUtil: TimerUtil var text = InputString() @@ -39,7 +40,7 @@ class ActionAlarm(injector: HasAndroidInjector) : Action(injector) { override fun isValid(): Boolean = true // empty alarm will show app name override fun doAction(callback: Callback) { - timerUtil.scheduleReminder(DateUtil.now() + T.secs(10L).msecs(), text.value.takeIf { it.isNotBlank() } + timerUtil.scheduleReminder(dateUtil.now() + T.secs(10L).msecs(), text.value.takeIf { it.isNotBlank() } ?: resourceHelper.gs(R.string.app_name)) callback.result(PumpEnactResult(injector).success(true).comment(R.string.ok))?.run() } diff --git a/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/actions/ActionLoopDisable.kt b/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/actions/ActionLoopDisable.kt index a629243628..848dc3c3b4 100644 --- a/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/actions/ActionLoopDisable.kt +++ b/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/actions/ActionLoopDisable.kt @@ -4,12 +4,15 @@ import androidx.annotation.DrawableRes import dagger.android.HasAndroidInjector import info.nightscout.androidaps.automation.R import info.nightscout.androidaps.data.PumpEnactResult +import info.nightscout.androidaps.database.entities.UserEntry +import info.nightscout.androidaps.database.entities.UserEntry.Sources import info.nightscout.androidaps.events.EventRefreshOverview import info.nightscout.androidaps.interfaces.CommandQueueProvider -import info.nightscout.androidaps.interfaces.ConfigBuilderInterface +import info.nightscout.androidaps.interfaces.ConfigBuilder import info.nightscout.androidaps.interfaces.LoopInterface import info.nightscout.androidaps.interfaces.PluginBase import info.nightscout.androidaps.interfaces.PluginType +import info.nightscout.androidaps.logging.UserEntryLogger import info.nightscout.androidaps.plugins.bus.RxBusWrapper import info.nightscout.androidaps.queue.Callback import info.nightscout.androidaps.utils.resources.ResourceHelper @@ -18,9 +21,10 @@ import javax.inject.Inject class ActionLoopDisable(injector: HasAndroidInjector) : Action(injector) { @Inject lateinit var loopPlugin: LoopInterface @Inject lateinit var resourceHelper: ResourceHelper - @Inject lateinit var configBuilderPlugin: ConfigBuilderInterface + @Inject lateinit var configBuilder: ConfigBuilder @Inject lateinit var commandQueue: CommandQueueProvider @Inject lateinit var rxBus: RxBusWrapper + @Inject lateinit var uel: UserEntryLogger override fun friendlyName(): Int = R.string.disableloop override fun shortDescription(): String = resourceHelper.gs(R.string.disableloop) @@ -29,7 +33,8 @@ class ActionLoopDisable(injector: HasAndroidInjector) : Action(injector) { override fun doAction(callback: Callback) { if ((loopPlugin as PluginBase).isEnabled()) { (loopPlugin as PluginBase).setPluginEnabled(PluginType.LOOP, false) - configBuilderPlugin.storeSettings("ActionLoopDisable") + configBuilder.storeSettings("ActionLoopDisable") + uel.log(UserEntry.Action.LOOP_DISABLED, Sources.Automation, title) commandQueue.cancelTempBasal(true, object : Callback() { override fun run() { rxBus.send(EventRefreshOverview("ActionLoopDisable")) diff --git a/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/actions/ActionLoopEnable.kt b/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/actions/ActionLoopEnable.kt index 43c7e897f7..d9c99ab41b 100644 --- a/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/actions/ActionLoopEnable.kt +++ b/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/actions/ActionLoopEnable.kt @@ -4,11 +4,14 @@ import androidx.annotation.DrawableRes import dagger.android.HasAndroidInjector import info.nightscout.androidaps.automation.R import info.nightscout.androidaps.data.PumpEnactResult +import info.nightscout.androidaps.database.entities.UserEntry +import info.nightscout.androidaps.database.entities.UserEntry.Sources import info.nightscout.androidaps.events.EventRefreshOverview -import info.nightscout.androidaps.interfaces.ConfigBuilderInterface +import info.nightscout.androidaps.interfaces.ConfigBuilder import info.nightscout.androidaps.interfaces.LoopInterface import info.nightscout.androidaps.interfaces.PluginBase import info.nightscout.androidaps.interfaces.PluginType +import info.nightscout.androidaps.logging.UserEntryLogger import info.nightscout.androidaps.plugins.bus.RxBusWrapper import info.nightscout.androidaps.queue.Callback import info.nightscout.androidaps.utils.resources.ResourceHelper @@ -18,8 +21,9 @@ class ActionLoopEnable(injector: HasAndroidInjector) : Action(injector) { @Inject lateinit var resourceHelper: ResourceHelper @Inject lateinit var loopPlugin: LoopInterface - @Inject lateinit var configBuilderPlugin: ConfigBuilderInterface + @Inject lateinit var configBuilder: ConfigBuilder @Inject lateinit var rxBus: RxBusWrapper + @Inject lateinit var uel: UserEntryLogger override fun friendlyName(): Int = R.string.enableloop override fun shortDescription(): String = resourceHelper.gs(R.string.enableloop) @@ -28,8 +32,9 @@ class ActionLoopEnable(injector: HasAndroidInjector) : Action(injector) { override fun doAction(callback: Callback) { if (!(loopPlugin as PluginBase).isEnabled()) { (loopPlugin as PluginBase).setPluginEnabled(PluginType.LOOP, true) - configBuilderPlugin.storeSettings("ActionLoopEnable") + configBuilder.storeSettings("ActionLoopEnable") rxBus.send(EventRefreshOverview("ActionLoopEnable")) + uel.log(UserEntry.Action.LOOP_ENABLED, Sources.Automation, title) callback.result(PumpEnactResult(injector).success(true).comment(R.string.ok))?.run() } else { callback.result(PumpEnactResult(injector).success(true).comment(R.string.alreadyenabled))?.run() diff --git a/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/actions/ActionLoopResume.kt b/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/actions/ActionLoopResume.kt index 4e910c594c..a113a84506 100644 --- a/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/actions/ActionLoopResume.kt +++ b/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/actions/ActionLoopResume.kt @@ -4,9 +4,12 @@ import androidx.annotation.DrawableRes import dagger.android.HasAndroidInjector import info.nightscout.androidaps.automation.R import info.nightscout.androidaps.data.PumpEnactResult +import info.nightscout.androidaps.database.entities.UserEntry +import info.nightscout.androidaps.database.entities.UserEntry.Sources import info.nightscout.androidaps.events.EventRefreshOverview -import info.nightscout.androidaps.interfaces.ConfigBuilderInterface +import info.nightscout.androidaps.interfaces.ConfigBuilder import info.nightscout.androidaps.interfaces.LoopInterface +import info.nightscout.androidaps.logging.UserEntryLogger import info.nightscout.androidaps.plugins.bus.RxBusWrapper import info.nightscout.androidaps.queue.Callback import info.nightscout.androidaps.utils.resources.ResourceHelper @@ -15,8 +18,9 @@ import javax.inject.Inject class ActionLoopResume(injector: HasAndroidInjector) : Action(injector) { @Inject lateinit var resourceHelper: ResourceHelper @Inject lateinit var loopPlugin: LoopInterface - @Inject lateinit var configBuilderPlugin: ConfigBuilderInterface + @Inject lateinit var configBuilder: ConfigBuilder @Inject lateinit var rxBus: RxBusWrapper + @Inject lateinit var uel: UserEntryLogger override fun friendlyName(): Int = R.string.resumeloop override fun shortDescription(): String = resourceHelper.gs(R.string.resumeloop) @@ -25,9 +29,10 @@ class ActionLoopResume(injector: HasAndroidInjector) : Action(injector) { override fun doAction(callback: Callback) { if (loopPlugin.isSuspended) { loopPlugin.suspendTo(0) - configBuilderPlugin.storeSettings("ActionLoopResume") + configBuilder.storeSettings("ActionLoopResume") loopPlugin.createOfflineEvent(0) rxBus.send(EventRefreshOverview("ActionLoopResume")) + uel.log(UserEntry.Action.RESUME, Sources.Automation, title) callback.result(PumpEnactResult(injector).success(true).comment(R.string.ok))?.run() } else { callback.result(PumpEnactResult(injector).success(true).comment(R.string.notsuspended))?.run() diff --git a/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/actions/ActionLoopSuspend.kt b/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/actions/ActionLoopSuspend.kt index 92bb748abd..797250b443 100644 --- a/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/actions/ActionLoopSuspend.kt +++ b/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/actions/ActionLoopSuspend.kt @@ -5,8 +5,12 @@ import androidx.annotation.DrawableRes import dagger.android.HasAndroidInjector import info.nightscout.androidaps.automation.R import info.nightscout.androidaps.data.PumpEnactResult +import info.nightscout.androidaps.database.entities.UserEntry +import info.nightscout.androidaps.database.entities.UserEntry.Sources +import info.nightscout.androidaps.database.entities.ValueWithUnit import info.nightscout.androidaps.events.EventRefreshOverview import info.nightscout.androidaps.interfaces.LoopInterface +import info.nightscout.androidaps.logging.UserEntryLogger import info.nightscout.androidaps.plugins.bus.RxBusWrapper import info.nightscout.androidaps.plugins.general.automation.elements.InputDuration import info.nightscout.androidaps.plugins.general.automation.elements.LabelWithElement @@ -21,6 +25,7 @@ class ActionLoopSuspend(injector: HasAndroidInjector) : Action(injector) { @Inject lateinit var resourceHelper: ResourceHelper @Inject lateinit var loopPlugin: LoopInterface @Inject lateinit var rxBus: RxBusWrapper + @Inject lateinit var uel: UserEntryLogger var minutes = InputDuration(30, InputDuration.TimeUnit.MINUTES) @@ -32,6 +37,8 @@ class ActionLoopSuspend(injector: HasAndroidInjector) : Action(injector) { if (!loopPlugin.isSuspended) { loopPlugin.suspendLoop(minutes.getMinutes()) rxBus.send(EventRefreshOverview("ActionLoopSuspend")) + uel.log(UserEntry.Action.SUSPEND, Sources.Automation, title + ": " + resourceHelper.gs(R.string.suspendloopforXmin, minutes.getMinutes()), + ValueWithUnit.Minute(minutes.getMinutes())) callback.result(PumpEnactResult(injector).success(true).comment(R.string.ok))?.run() } else { callback.result(PumpEnactResult(injector).success(true).comment(R.string.alreadysuspended))?.run() diff --git a/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/actions/ActionNotification.kt b/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/actions/ActionNotification.kt index 9913f55531..38550e5fa5 100644 --- a/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/actions/ActionNotification.kt +++ b/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/actions/ActionNotification.kt @@ -5,17 +5,20 @@ import androidx.annotation.DrawableRes import dagger.android.HasAndroidInjector import info.nightscout.androidaps.automation.R import info.nightscout.androidaps.data.PumpEnactResult +import info.nightscout.androidaps.database.AppRepository +import info.nightscout.androidaps.database.transactions.InsertTherapyEventAnnouncementTransaction import info.nightscout.androidaps.events.EventRefreshOverview import info.nightscout.androidaps.plugins.bus.RxBusWrapper import info.nightscout.androidaps.plugins.general.automation.elements.InputString import info.nightscout.androidaps.plugins.general.automation.elements.LabelWithElement import info.nightscout.androidaps.plugins.general.automation.elements.LayoutBuilder -import info.nightscout.androidaps.plugins.general.nsclient.NSUpload import info.nightscout.androidaps.plugins.general.overview.events.EventNewNotification import info.nightscout.androidaps.plugins.general.overview.notifications.NotificationUserMessage import info.nightscout.androidaps.queue.Callback import info.nightscout.androidaps.utils.JsonHelper import info.nightscout.androidaps.utils.resources.ResourceHelper +import io.reactivex.disposables.CompositeDisposable +import io.reactivex.rxkotlin.plusAssign import org.json.JSONObject import javax.inject.Inject @@ -23,7 +26,9 @@ class ActionNotification(injector: HasAndroidInjector) : Action(injector) { @Inject lateinit var resourceHelper: ResourceHelper @Inject lateinit var rxBus: RxBusWrapper - @Inject lateinit var nsUpload: NSUpload + @Inject lateinit var repository: AppRepository + + private val disposable = CompositeDisposable() var text = InputString() @@ -34,7 +39,7 @@ class ActionNotification(injector: HasAndroidInjector) : Action(injector) { override fun doAction(callback: Callback) { val notification = NotificationUserMessage(text.value) rxBus.send(EventNewNotification(notification)) - nsUpload.uploadError(text.value) + disposable += repository.runTransaction(InsertTherapyEventAnnouncementTransaction(text.value)).subscribe() rxBus.send(EventRefreshOverview("ActionNotification")) callback.result(PumpEnactResult(injector).success(true).comment(R.string.ok))?.run() } diff --git a/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/actions/ActionProfileSwitch.kt b/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/actions/ActionProfileSwitch.kt index de4f6e769f..db93aa0fb7 100644 --- a/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/actions/ActionProfileSwitch.kt +++ b/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/actions/ActionProfileSwitch.kt @@ -5,9 +5,13 @@ import androidx.annotation.DrawableRes import dagger.android.HasAndroidInjector import info.nightscout.androidaps.automation.R import info.nightscout.androidaps.data.PumpEnactResult -import info.nightscout.androidaps.interfaces.ActivePluginProvider +import info.nightscout.androidaps.database.entities.UserEntry +import info.nightscout.androidaps.database.entities.UserEntry.Sources +import info.nightscout.androidaps.database.entities.ValueWithUnit +import info.nightscout.androidaps.interfaces.ActivePlugin import info.nightscout.androidaps.logging.LTag import info.nightscout.androidaps.interfaces.ProfileFunction +import info.nightscout.androidaps.logging.UserEntryLogger import info.nightscout.androidaps.plugins.general.automation.elements.InputProfileName import info.nightscout.androidaps.plugins.general.automation.elements.LabelWithElement import info.nightscout.androidaps.plugins.general.automation.elements.LayoutBuilder @@ -20,8 +24,10 @@ import javax.inject.Inject class ActionProfileSwitch(injector: HasAndroidInjector) : Action(injector) { @Inject lateinit var resourceHelper: ResourceHelper - @Inject lateinit var activePlugin: ActivePluginProvider + @Inject lateinit var activePlugin: ActivePlugin @Inject lateinit var profileFunction: ProfileFunction + @Inject lateinit var dateUtil: DateUtil + @Inject lateinit var uel: UserEntryLogger var inputProfileName: InputProfileName = InputProfileName(resourceHelper, activePlugin, "") @@ -47,13 +53,16 @@ class ActionProfileSwitch(injector: HasAndroidInjector) : Action(injector) { callback.result(PumpEnactResult(injector).success(true).comment(R.string.alreadyset))?.run() return } - val profileStore = activePlugin.activeProfileInterface.profile ?: return + val profileStore = activePlugin.activeProfileSource.profile ?: return if (profileStore.getSpecificProfile(inputProfileName.value) == null) { aapsLogger.error(LTag.AUTOMATION, "Selected profile does not exist! - ${inputProfileName.value}") callback.result(PumpEnactResult(injector).success(false).comment(R.string.notexists))?.run() return } - activePlugin.activeTreatments.doProfileSwitch(profileStore, inputProfileName.value, 0, 100, 0, DateUtil.now()) + uel.log(UserEntry.Action.PROFILE_SWITCH, Sources.Automation, title, + ValueWithUnit.SimpleString(inputProfileName.value), + ValueWithUnit.Percent(100)) + activePlugin.activeTreatments.doProfileSwitch(profileStore, inputProfileName.value, 0, 100, 0, dateUtil.now()) callback.result(PumpEnactResult(injector).success(true).comment(R.string.ok))?.run() } @@ -79,5 +88,5 @@ class ActionProfileSwitch(injector: HasAndroidInjector) : Action(injector) { return this } - override fun isValid(): Boolean = activePlugin.activeProfileInterface.profile?.getSpecificProfile(inputProfileName.value) != null + override fun isValid(): Boolean = activePlugin.activeProfileSource.profile?.getSpecificProfile(inputProfileName.value) != null } \ No newline at end of file diff --git a/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/actions/ActionProfileSwitchPercent.kt b/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/actions/ActionProfileSwitchPercent.kt index 689fcd945f..de2cff70de 100644 --- a/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/actions/ActionProfileSwitchPercent.kt +++ b/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/actions/ActionProfileSwitchPercent.kt @@ -5,7 +5,11 @@ import androidx.annotation.DrawableRes import dagger.android.HasAndroidInjector import info.nightscout.androidaps.automation.R import info.nightscout.androidaps.data.PumpEnactResult -import info.nightscout.androidaps.interfaces.ActivePluginProvider +import info.nightscout.androidaps.database.entities.UserEntry +import info.nightscout.androidaps.database.entities.UserEntry.Sources +import info.nightscout.androidaps.database.entities.ValueWithUnit +import info.nightscout.androidaps.interfaces.ActivePlugin +import info.nightscout.androidaps.logging.UserEntryLogger import info.nightscout.androidaps.plugins.general.automation.elements.Comparator import info.nightscout.androidaps.plugins.general.automation.elements.InputDuration import info.nightscout.androidaps.plugins.general.automation.elements.InputPercent @@ -20,7 +24,8 @@ import javax.inject.Inject class ActionProfileSwitchPercent(injector: HasAndroidInjector) : Action(injector) { @Inject lateinit var resourceHelper: ResourceHelper - @Inject lateinit var activePlugin: ActivePluginProvider + @Inject lateinit var activePlugin: ActivePlugin + @Inject lateinit var uel: UserEntryLogger var pct = InputPercent() var duration = InputDuration(30, InputDuration.TimeUnit.MINUTES) @@ -37,6 +42,9 @@ class ActionProfileSwitchPercent(injector: HasAndroidInjector) : Action(injector } override fun doAction(callback: Callback) { + uel.log(UserEntry.Action.PROFILE_SWITCH, Sources.Automation, title + ": " + resourceHelper.gs(R.string.startprofile, pct.value.toInt(), duration.value), + ValueWithUnit.Percent(pct.value.toInt()), + ValueWithUnit.Minute(duration.value)) activePlugin.activeTreatments.doProfileSwitch(duration.value, pct.value.toInt(), 0) callback.result(PumpEnactResult(injector).success(true).comment(R.string.ok))?.run() } diff --git a/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/actions/ActionSendSMS.kt b/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/actions/ActionSendSMS.kt index 82bf9cc55b..446eeb4cee 100644 --- a/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/actions/ActionSendSMS.kt +++ b/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/actions/ActionSendSMS.kt @@ -4,7 +4,7 @@ import android.widget.LinearLayout import dagger.android.HasAndroidInjector import info.nightscout.androidaps.automation.R import info.nightscout.androidaps.data.PumpEnactResult -import info.nightscout.androidaps.interfaces.SmsCommunicatorInterface +import info.nightscout.androidaps.interfaces.SmsCommunicator import info.nightscout.androidaps.plugins.general.automation.elements.InputString import info.nightscout.androidaps.plugins.general.automation.elements.LabelWithElement import info.nightscout.androidaps.plugins.general.automation.elements.LayoutBuilder @@ -17,7 +17,7 @@ import javax.inject.Inject class ActionSendSMS(injector: HasAndroidInjector) : Action(injector) { @Inject lateinit var resourceHelper: ResourceHelper - @Inject lateinit var smsCommunicatorPlugin: SmsCommunicatorInterface + @Inject lateinit var smsCommunicatorPlugin: SmsCommunicator var text = InputString() diff --git a/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/actions/ActionStartTempTarget.kt b/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/actions/ActionStartTempTarget.kt index 7bebe4ac6c..92123b9a9d 100644 --- a/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/actions/ActionStartTempTarget.kt +++ b/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/actions/ActionStartTempTarget.kt @@ -9,22 +9,25 @@ import info.nightscout.androidaps.data.Profile import info.nightscout.androidaps.data.PumpEnactResult import info.nightscout.androidaps.database.AppRepository import info.nightscout.androidaps.database.entities.TemporaryTarget +import info.nightscout.androidaps.database.entities.UserEntry +import info.nightscout.androidaps.database.entities.UserEntry.Sources +import info.nightscout.androidaps.database.entities.ValueWithUnit import info.nightscout.androidaps.database.transactions.InsertTemporaryTargetAndCancelCurrentTransaction -import info.nightscout.androidaps.interfaces.ActivePluginProvider +import info.nightscout.androidaps.interfaces.ActivePlugin import info.nightscout.androidaps.interfaces.ProfileFunction import info.nightscout.androidaps.logging.LTag +import info.nightscout.androidaps.logging.UserEntryLogger import info.nightscout.androidaps.plugins.general.automation.elements.ComparatorExists import info.nightscout.androidaps.plugins.general.automation.elements.InputDuration import info.nightscout.androidaps.plugins.general.automation.elements.InputTempTarget import info.nightscout.androidaps.plugins.general.automation.elements.LabelWithElement import info.nightscout.androidaps.plugins.general.automation.elements.LayoutBuilder import info.nightscout.androidaps.plugins.general.automation.triggers.TriggerTempTarget -import info.nightscout.androidaps.plugins.general.nsclient.NSUpload import info.nightscout.androidaps.queue.Callback import info.nightscout.androidaps.utils.DateUtil import info.nightscout.androidaps.utils.JsonHelper import info.nightscout.androidaps.utils.JsonHelper.safeGetDouble -import info.nightscout.androidaps.utils.extensions.friendlyDescription +import info.nightscout.androidaps.extensions.friendlyDescription import info.nightscout.androidaps.utils.resources.ResourceHelper import io.reactivex.disposables.CompositeDisposable import io.reactivex.rxkotlin.plusAssign @@ -35,10 +38,11 @@ import javax.inject.Inject class ActionStartTempTarget(injector: HasAndroidInjector) : Action(injector) { @Inject lateinit var resourceHelper: ResourceHelper - @Inject lateinit var activePlugin: ActivePluginProvider + @Inject lateinit var activePlugin: ActivePlugin @Inject lateinit var repository: AppRepository - @Inject lateinit var nsUpload: NSUpload @Inject lateinit var profileFunction: ProfileFunction + @Inject lateinit var dateUtil: DateUtil + @Inject lateinit var uel: UserEntryLogger private val disposable = CompositeDisposable() @@ -56,11 +60,16 @@ class ActionStartTempTarget(injector: HasAndroidInjector) : Action(injector) { override fun doAction(callback: Callback) { disposable += repository.runTransactionForResult(InsertTemporaryTargetAndCancelCurrentTransaction(tt())) .subscribe({ result -> - result.inserted.forEach { nsUpload.uploadTempTarget(it) } - result.updated.forEach { nsUpload.updateTempTarget(it) } + result.inserted.forEach { aapsLogger.debug(LTag.DATABASE, "Inserted temp target $it") } + result.updated.forEach { aapsLogger.debug(LTag.DATABASE, "Updated temp target $it") } + uel.log(UserEntry.Action.TT, Sources.Automation, title, + ValueWithUnit.TherapyEventTTReason(TemporaryTarget.Reason.AUTOMATION), + ValueWithUnit.fromGlucoseUnit(tt().lowTarget, Constants.MGDL), + ValueWithUnit.fromGlucoseUnit(tt().highTarget, Constants.MGDL).takeIf { tt().lowTarget != tt().highTarget }, + ValueWithUnit.Minute(TimeUnit.MILLISECONDS.toMinutes(tt().duration).toInt())) callback.result(PumpEnactResult(injector).success(true).comment(R.string.ok))?.run() }, { - aapsLogger.error(LTag.BGSOURCE, "Error while saving temporary target", it) + aapsLogger.error(LTag.DATABASE, "Error while saving temporary target", it) callback.result(PumpEnactResult(injector).success(false).comment(R.string.error))?.run() }) } @@ -97,7 +106,7 @@ class ActionStartTempTarget(injector: HasAndroidInjector) : Action(injector) { } fun tt() = TemporaryTarget( - timestamp = DateUtil.now(), + timestamp = dateUtil.now(), duration = TimeUnit.MINUTES.toMillis(duration.getMinutes().toLong()), reason = TemporaryTarget.Reason.AUTOMATION, lowTarget = Profile.toMgdl(value.value, value.units), diff --git a/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/actions/ActionStopTempTarget.kt b/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/actions/ActionStopTempTarget.kt index e566c6f6cf..9d4443d466 100644 --- a/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/actions/ActionStopTempTarget.kt +++ b/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/actions/ActionStopTempTarget.kt @@ -4,10 +4,11 @@ import dagger.android.HasAndroidInjector import info.nightscout.androidaps.automation.R import info.nightscout.androidaps.data.PumpEnactResult import info.nightscout.androidaps.database.AppRepository +import info.nightscout.androidaps.database.entities.UserEntry +import info.nightscout.androidaps.database.entities.UserEntry.Sources import info.nightscout.androidaps.database.transactions.CancelCurrentTemporaryTargetIfAnyTransaction -import info.nightscout.androidaps.interfaces.ActivePluginProvider import info.nightscout.androidaps.logging.LTag -import info.nightscout.androidaps.plugins.general.nsclient.NSUpload +import info.nightscout.androidaps.logging.UserEntryLogger import info.nightscout.androidaps.queue.Callback import info.nightscout.androidaps.utils.DateUtil import info.nightscout.androidaps.utils.resources.ResourceHelper @@ -18,10 +19,9 @@ import javax.inject.Inject class ActionStopTempTarget(injector: HasAndroidInjector) : Action(injector) { @Inject lateinit var resourceHelper: ResourceHelper - @Inject lateinit var activePlugin: ActivePluginProvider @Inject lateinit var repository: AppRepository - @Inject lateinit var nsUpload: NSUpload @Inject lateinit var dateUtil: DateUtil + @Inject lateinit var uel: UserEntryLogger private val disposable = CompositeDisposable() @@ -30,11 +30,12 @@ class ActionStopTempTarget(injector: HasAndroidInjector) : Action(injector) { override fun icon(): Int = R.drawable.ic_stop_24dp override fun doAction(callback: Callback) { - disposable += repository.runTransactionForResult(CancelCurrentTemporaryTargetIfAnyTransaction(DateUtil.now())) + disposable += repository.runTransactionForResult(CancelCurrentTemporaryTargetIfAnyTransaction(dateUtil.now())) .subscribe({ result -> - result.updated.forEach { nsUpload.updateTempTarget(it) } + uel.log(UserEntry.Action.CANCEL_TT, Sources.Automation, title) + result.updated.forEach { aapsLogger.debug(LTag.DATABASE, "Updated temp target $it") } }, { - aapsLogger.error(LTag.BGSOURCE, "Error while saving temporary target", it) + aapsLogger.error(LTag.DATABASE, "Error while saving temporary target", it) }) callback.result(PumpEnactResult(injector).success(true).comment(R.string.ok))?.run() } diff --git a/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/dialogs/EditEventDialog.kt b/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/dialogs/EditEventDialog.kt index b408ff76fa..9c2e327cbc 100644 --- a/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/dialogs/EditEventDialog.kt +++ b/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/dialogs/EditEventDialog.kt @@ -26,7 +26,7 @@ import info.nightscout.androidaps.plugins.general.automation.triggers.TriggerCon import info.nightscout.androidaps.utils.FabricPrivacy import info.nightscout.androidaps.utils.ToastUtils import io.reactivex.rxkotlin.plusAssign -import info.nightscout.androidaps.utils.extensions.toVisibility +import info.nightscout.androidaps.extensions.toVisibility import info.nightscout.androidaps.utils.rx.AapsSchedulers import io.reactivex.disposables.CompositeDisposable import javax.inject.Inject diff --git a/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/elements/InputDateTime.kt b/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/elements/InputDateTime.kt index c78b8e5e3c..df0939bfa7 100644 --- a/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/elements/InputDateTime.kt +++ b/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/elements/InputDateTime.kt @@ -12,13 +12,13 @@ import info.nightscout.androidaps.utils.DateUtil import info.nightscout.androidaps.utils.resources.ResourceHelper import java.util.* -class InputDateTime(private val resourceHelper: ResourceHelper, private val dateUtil: DateUtil, var value: Long = DateUtil.now()) : Element() { +class InputDateTime(private val resourceHelper: ResourceHelper, private val dateUtil: DateUtil, var value: Long = dateUtil.now()) : Element() { override fun addToLayout(root: LinearLayout) { val label = TextView(root.context) val dateButton = TextView(root.context) val timeButton = TextView(root.context) - dateButton.text = DateUtil.dateString(value) + dateButton.text = dateUtil.dateString(value) timeButton.text = dateUtil.timeString(value) // create an OnDateSetListener @@ -29,7 +29,7 @@ class InputDateTime(private val resourceHelper: ResourceHelper, private val date cal.set(Calendar.MONTH, monthOfYear) cal.set(Calendar.DAY_OF_MONTH, dayOfMonth) value = cal.timeInMillis - dateButton.text = DateUtil.dateString(value) + dateButton.text = dateUtil.dateString(value) } dateButton.setOnClickListener { diff --git a/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/elements/InputProfileName.kt b/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/elements/InputProfileName.kt index 36e9e5e763..967f22e0bf 100644 --- a/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/elements/InputProfileName.kt +++ b/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/elements/InputProfileName.kt @@ -7,15 +7,15 @@ import android.widget.ArrayAdapter import android.widget.LinearLayout import android.widget.Spinner import info.nightscout.androidaps.automation.R -import info.nightscout.androidaps.interfaces.ActivePluginProvider +import info.nightscout.androidaps.interfaces.ActivePlugin import info.nightscout.androidaps.utils.resources.ResourceHelper -class InputProfileName(private val resourceHelper: ResourceHelper, private val activePlugin: ActivePluginProvider, val name: String = "") : Element() { +class InputProfileName(private val resourceHelper: ResourceHelper, private val activePlugin: ActivePlugin, val name: String = "") : Element() { var value: String = name override fun addToLayout(root: LinearLayout) { - val profileStore = activePlugin.activeProfileInterface.profile ?: return + val profileStore = activePlugin.activeProfileSource.profile ?: return val profileList = profileStore.getProfileList() val adapter = ArrayAdapter(root.context, R.layout.spinner_centered, profileList) adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item) diff --git a/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/elements/InputTime.kt b/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/elements/InputTime.kt index aee207cf5a..d73b5150b6 100644 --- a/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/elements/InputTime.kt +++ b/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/elements/InputTime.kt @@ -15,7 +15,7 @@ import java.util.* class InputTime(private val resourceHelper: ResourceHelper, private val dateUtil: DateUtil) : Element() { - var value: Int = getMinSinceMidnight(DateUtil.now()) + var value: Int = getMinSinceMidnight(dateUtil.now()) override fun addToLayout(root: LinearLayout) { val label = TextView(root.context) diff --git a/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/elements/InputTimeRange.kt b/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/elements/InputTimeRange.kt index 8e5ffd0a8e..6511eb8194 100644 --- a/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/elements/InputTimeRange.kt +++ b/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/elements/InputTimeRange.kt @@ -15,8 +15,8 @@ import java.util.* class InputTimeRange(private val resourceHelper: ResourceHelper, private val dateUtil: DateUtil) : Element() { - var start: Int = getMinSinceMidnight(DateUtil.now()) - var end: Int = getMinSinceMidnight(DateUtil.now()) + var start: Int = getMinSinceMidnight(dateUtil.now()) + var end: Int = getMinSinceMidnight(dateUtil.now()) override fun addToLayout(root: LinearLayout) { val label = TextView(root.context) diff --git a/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/elements/LabelWithElement.kt b/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/elements/LabelWithElement.kt index 4ea68104f3..adc29fdb1e 100644 --- a/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/elements/LabelWithElement.kt +++ b/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/elements/LabelWithElement.kt @@ -25,7 +25,6 @@ class LabelWithElement( textViewPre.text = textPre textViewPre.layoutParams = LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT) - //textViewPre.setWidth(MainApp.dpToPx(120)); textViewPre.setPadding(px, px, px, px) textViewPre.setTypeface(textViewPre.typeface, Typeface.BOLD) layout.addView(textViewPre) @@ -40,7 +39,6 @@ class LabelWithElement( textViewPost.text = textPost textViewPost.layoutParams = LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT) - //textViewPost.setWidth(MainApp.dpToPx(45)); textViewPost.setPadding(px, px, px, px) textViewPost.setTypeface(textViewPost.typeface, Typeface.BOLD) layout.addView(textViewPost) diff --git a/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/Trigger.kt b/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/Trigger.kt index b467a3b933..c67c10bb75 100644 --- a/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/Trigger.kt +++ b/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/Trigger.kt @@ -10,10 +10,10 @@ import androidx.appcompat.app.AppCompatActivity import com.google.common.base.Optional import dagger.android.HasAndroidInjector import info.nightscout.androidaps.automation.R -import info.nightscout.androidaps.interfaces.ActivePluginProvider -import info.nightscout.androidaps.interfaces.IobCobCalculatorInterface +import info.nightscout.androidaps.database.AppRepository +import info.nightscout.androidaps.interfaces.ActivePlugin +import info.nightscout.androidaps.interfaces.IobCobCalculator import info.nightscout.androidaps.interfaces.ProfileFunction -import info.nightscout.androidaps.interfaces.TreatmentsInterface import info.nightscout.androidaps.logging.AAPSLogger import info.nightscout.androidaps.plugins.bus.RxBusWrapper import info.nightscout.androidaps.plugins.general.automation.dialogs.ChooseTriggerDialog @@ -22,12 +22,11 @@ import info.nightscout.androidaps.plugins.general.automation.events.EventTrigger import info.nightscout.androidaps.plugins.general.automation.events.EventTriggerRemove import info.nightscout.androidaps.plugins.iob.iobCobCalculator.GlucoseStatusProvider import info.nightscout.androidaps.services.LastLocationDataContainer +import info.nightscout.androidaps.utils.DateUtil import info.nightscout.androidaps.utils.resources.ResourceHelper import info.nightscout.androidaps.utils.sharedPreferences.SP -import org.json.JSONException import org.json.JSONObject import javax.inject.Inject -import kotlin.reflect.full.primaryConstructor abstract class Trigger(val injector: HasAndroidInjector) { @@ -37,17 +36,18 @@ abstract class Trigger(val injector: HasAndroidInjector) { @Inject lateinit var profileFunction: ProfileFunction @Inject lateinit var sp: SP @Inject lateinit var locationDataContainer: LastLocationDataContainer - @Inject lateinit var treatmentsInterface: TreatmentsInterface - @Inject lateinit var activePlugin: ActivePluginProvider - @Inject lateinit var iobCobCalculatorPlugin: IobCobCalculatorInterface + @Inject lateinit var repository: AppRepository + @Inject lateinit var activePlugin: ActivePlugin + @Inject lateinit var iobCobCalculator: IobCobCalculator @Inject lateinit var glucoseStatusProvider: GlucoseStatusProvider + @Inject lateinit var dateUtil: DateUtil init { injector.androidInjector().inject(this) } abstract fun shouldRun(): Boolean - abstract fun toJSON(): String + abstract fun dataJSON(): JSONObject abstract fun fromJSON(data: String): Trigger abstract fun friendlyName(): Int @@ -74,23 +74,56 @@ abstract class Trigger(val injector: HasAndroidInjector) { root.addView(title) } + fun toJSON(): String = + JSONObject() + .put("type", this::class.java.simpleName) + .put("data", dataJSON()) + .toString() + fun instantiate(obj: JSONObject): Trigger? { - try { - val type = obj.getString("type") - val data = obj.getJSONObject("data") - val clazz = Class.forName(type).kotlin - return (clazz.primaryConstructor?.call(injector) as Trigger).fromJSON(data?.toString() - ?: "") - } catch (e: ClassNotFoundException) { - aapsLogger.error("Unhandled exception", e) - } catch (e: InstantiationException) { - aapsLogger.error("Unhandled exception", e) - } catch (e: IllegalAccessException) { - aapsLogger.error("Unhandled exception", e) - } catch (e: JSONException) { - aapsLogger.error("Unhandled exception", e) + val type = obj.getString("type") + val data = obj.getJSONObject("data") + //val clazz = Class.forName(type).kotlin + //return (clazz.primaryConstructor?.call(injector) as Trigger).fromJSON(data?.toString() ?: "") + return when (type) { + TriggerAutosensValue::class.java.name, // backward compatibility + TriggerAutosensValue::class.java.simpleName -> TriggerAutosensValue(injector).fromJSON(data?.toString() ?: "") + TriggerBg::class.java.name, + TriggerBg::class.java.simpleName -> TriggerBg(injector).fromJSON(data?.toString() ?: "") + TriggerBolusAgo::class.java.name, + TriggerBolusAgo::class.java.simpleName -> TriggerBolusAgo(injector).fromJSON(data?.toString() ?: "") + TriggerBTDevice::class.java.name, + TriggerBTDevice::class.java.simpleName -> TriggerBTDevice(injector).fromJSON(data?.toString() ?: "") + TriggerIob::class.java.name, + TriggerIob::class.java.simpleName -> TriggerIob(injector).fromJSON(data?.toString() ?: "") + TriggerCOB::class.java.name, + TriggerCOB::class.java.simpleName -> TriggerCOB(injector).fromJSON(data?.toString() ?: "") + TriggerConnector::class.java.name, + TriggerConnector::class.java.simpleName -> TriggerConnector(injector).fromJSON(data?.toString() ?: "") + TriggerDelta::class.java.name, + TriggerDelta::class.java.simpleName -> TriggerDelta(injector).fromJSON(data?.toString() ?: "") + TriggerDummy::class.java.name, + TriggerDummy::class.java.simpleName -> TriggerDummy(injector).fromJSON(data?.toString() ?: "") + TriggerIob::class.java.name, + TriggerIob::class.java.simpleName -> TriggerIob(injector).fromJSON(data?.toString() ?: "") + TriggerLocation::class.java.name, + TriggerLocation::class.java.simpleName -> TriggerLocation(injector).fromJSON(data?.toString() ?: "") + TriggerProfilePercent::class.java.name, + TriggerProfilePercent::class.java.simpleName -> TriggerProfilePercent(injector).fromJSON(data?.toString() ?: "") + TriggerPumpLastConnection::class.java.name, + TriggerPumpLastConnection::class.java.simpleName -> TriggerPumpLastConnection(injector).fromJSON(data?.toString() ?: "") + TriggerRecurringTime::class.java.name, + TriggerRecurringTime::class.java.simpleName -> TriggerRecurringTime(injector).fromJSON(data?.toString() ?: "") + TriggerTempTarget::class.java.name, + TriggerTempTarget::class.java.simpleName -> TriggerTempTarget(injector).fromJSON(data?.toString() ?: "") + TriggerTime::class.java.name, + TriggerTime::class.java.simpleName -> TriggerTime(injector).fromJSON(data?.toString() ?: "") + TriggerTimeRange::class.java.name, + TriggerTimeRange::class.java.simpleName -> TriggerTimeRange(injector).fromJSON(data?.toString() ?: "") + TriggerWifiSsid::class.java.name, + TriggerWifiSsid::class.java.simpleName -> TriggerWifiSsid(injector).fromJSON(data?.toString() ?: "") + else -> throw ClassNotFoundException(type) } - return null } fun createAddButton(context: Context, trigger: TriggerConnector): ImageButton { diff --git a/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerAutosensValue.kt b/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerAutosensValue.kt index d0d50fe418..45fc094d6a 100644 --- a/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerAutosensValue.kt +++ b/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerAutosensValue.kt @@ -30,7 +30,7 @@ class TriggerAutosensValue(injector: HasAndroidInjector) : Trigger(injector) { } override fun shouldRun(): Boolean { - val autosensData = iobCobCalculatorPlugin.getLastAutosensData("Automation trigger") + val autosensData = iobCobCalculator.ads.getLastAutosensData("Automation trigger", aapsLogger, dateUtil) ?: return if (comparator.value == Comparator.Compare.IS_NOT_AVAILABLE) { aapsLogger.debug(LTag.AUTOMATION, "Ready for execution: " + friendlyDescription()) true @@ -46,15 +46,10 @@ class TriggerAutosensValue(injector: HasAndroidInjector) : Trigger(injector) { return false } - override fun toJSON(): String { - val data = JSONObject() + override fun dataJSON(): JSONObject = + JSONObject() .put("value", autosens.value) .put("comparator", comparator.value.toString()) - return JSONObject() - .put("type", this::class.java.name) - .put("data", data) - .toString() - } override fun fromJSON(data: String): Trigger { val d = JSONObject(data) diff --git a/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerBTDevice.kt b/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerBTDevice.kt index 4b75a476e3..292a29cda6 100644 --- a/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerBTDevice.kt +++ b/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerBTDevice.kt @@ -39,15 +39,10 @@ class TriggerBTDevice(injector: HasAndroidInjector) : Trigger(injector) { return false } - @Synchronized override fun toJSON(): String { - val data = JSONObject() + override fun dataJSON(): JSONObject = + JSONObject() .put("comparator", comparator.value.toString()) .put("name", btDevice.value) - return JSONObject() - .put("type", this::class.java.name) - .put("data", data) - .toString() - } override fun fromJSON(data: String): Trigger { val d = JSONObject(data) diff --git a/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerBg.kt b/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerBg.kt index b4d9d6d10b..3c173f4e3d 100644 --- a/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerBg.kt +++ b/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerBg.kt @@ -63,16 +63,11 @@ class TriggerBg(injector: HasAndroidInjector) : Trigger(injector) { return false } - override fun toJSON(): String { - val data = JSONObject() + override fun dataJSON(): JSONObject = + JSONObject() .put("bg", bg.value) .put("comparator", comparator.value.toString()) .put("units", bg.units) - return JSONObject() - .put("type", this::class.java.name) - .put("data", data) - .toString() - } override fun fromJSON(data: String): Trigger { val d = JSONObject(data) diff --git a/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerBolusAgo.kt b/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerBolusAgo.kt index 723da22bd4..b7b47aa66f 100644 --- a/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerBolusAgo.kt +++ b/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerBolusAgo.kt @@ -4,19 +4,20 @@ import android.widget.LinearLayout import com.google.common.base.Optional import dagger.android.HasAndroidInjector import info.nightscout.androidaps.automation.R +import info.nightscout.androidaps.database.entities.Bolus import info.nightscout.androidaps.logging.LTag import info.nightscout.androidaps.plugins.general.automation.elements.Comparator import info.nightscout.androidaps.plugins.general.automation.elements.InputDuration import info.nightscout.androidaps.plugins.general.automation.elements.LabelWithElement import info.nightscout.androidaps.plugins.general.automation.elements.LayoutBuilder import info.nightscout.androidaps.plugins.general.automation.elements.StaticLabel -import info.nightscout.androidaps.utils.DateUtil import info.nightscout.androidaps.utils.JsonHelper import info.nightscout.androidaps.utils.JsonHelper.safeGetString import org.json.JSONObject class TriggerBolusAgo(injector: HasAndroidInjector) : Trigger(injector) { - var minutesAgo: InputDuration = InputDuration( 30, InputDuration.TimeUnit.MINUTES) + + var minutesAgo: InputDuration = InputDuration(30, InputDuration.TimeUnit.MINUTES) var comparator: Comparator = Comparator(resourceHelper) private constructor(injector: HasAndroidInjector, triggerBolusAgo: TriggerBolusAgo) : this(injector) { @@ -35,7 +36,7 @@ class TriggerBolusAgo(injector: HasAndroidInjector) : Trigger(injector) { } override fun shouldRun(): Boolean { - val lastBolusTime = treatmentsInterface.getLastBolusTime(true) + val lastBolusTime = repository.getLastBolusRecordOfType(Bolus.Type.NORMAL)?.timestamp ?: 0L if (lastBolusTime == 0L) return if (comparator.value == Comparator.Compare.IS_NOT_AVAILABLE) { aapsLogger.debug(LTag.AUTOMATION, "Ready for execution: " + friendlyDescription()) @@ -44,7 +45,7 @@ class TriggerBolusAgo(injector: HasAndroidInjector) : Trigger(injector) { aapsLogger.debug(LTag.AUTOMATION, "NOT ready for execution: " + friendlyDescription()) false } - val last = (DateUtil.now() - lastBolusTime).toDouble() / (60 * 1000) + val last = (dateUtil.now() - lastBolusTime).toDouble() / (60 * 1000) aapsLogger.debug(LTag.AUTOMATION, "LastBolus min ago: $minutesAgo") val doRun = comparator.value.check(last.toInt(), minutesAgo.getMinutes()) if (doRun) { @@ -55,15 +56,10 @@ class TriggerBolusAgo(injector: HasAndroidInjector) : Trigger(injector) { return false } - override fun toJSON(): String { - val data = JSONObject() + override fun dataJSON(): JSONObject = + JSONObject() .put("minutesAgo", minutesAgo.value) .put("comparator", comparator.value.toString()) - return JSONObject() - .put("type", this::class.java.name) - .put("data", data) - .toString() - } override fun fromJSON(data: String): Trigger { val d = JSONObject(data) diff --git a/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerCOB.kt b/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerCOB.kt index a87ea5691f..dda052bcaf 100644 --- a/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerCOB.kt +++ b/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerCOB.kt @@ -16,6 +16,7 @@ import org.json.JSONObject import java.text.DecimalFormat class TriggerCOB(injector: HasAndroidInjector) : Trigger(injector) { + private val minValue = 0 private val maxValue = sp.getInt(R.string.key_treatmentssafety_maxcarbs, 48) var cob: InputDouble = InputDouble(0.0, minValue.toDouble(), maxValue.toDouble(), 1.0, DecimalFormat("1")) @@ -26,18 +27,18 @@ class TriggerCOB(injector: HasAndroidInjector) : Trigger(injector) { comparator = Comparator(resourceHelper, triggerCOB.comparator.value) } - fun setValue(value:Double) : TriggerCOB { + fun setValue(value: Double): TriggerCOB { cob.value = value return this } - fun comparator(comparator: Comparator.Compare) : TriggerCOB { + fun comparator(comparator: Comparator.Compare): TriggerCOB { this.comparator.value = comparator return this } override fun shouldRun(): Boolean { - val cobInfo = iobCobCalculatorPlugin.getCobInfo(false, "AutomationTriggerCOB") + val cobInfo = iobCobCalculator.getCobInfo(false, "AutomationTriggerCOB") if (cobInfo.displayCob == null) { return if (comparator.value === Comparator.Compare.IS_NOT_AVAILABLE) { aapsLogger.debug(LTag.AUTOMATION, "Ready for execution: " + friendlyDescription()) @@ -55,15 +56,10 @@ class TriggerCOB(injector: HasAndroidInjector) : Trigger(injector) { return false } - @Synchronized override fun toJSON(): String { - val data = JSONObject() + override fun dataJSON(): JSONObject = + JSONObject() .put("carbs", cob.value) .put("comparator", comparator.value.toString()) - return JSONObject() - .put("type", this::class.java.name) - .put("data", data) - .toString() - } override fun fromJSON(data: String): Trigger { val d = JSONObject(data) diff --git a/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerConnector.kt b/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerConnector.kt index fa1487aabd..105f91fe3b 100644 --- a/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerConnector.kt +++ b/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerConnector.kt @@ -19,6 +19,7 @@ import org.json.JSONObject import java.util.* class TriggerConnector(injector: HasAndroidInjector) : Trigger(injector) { + var list: MutableList = ArrayList() private var connectorType: Type = Type.AND @@ -40,6 +41,7 @@ class TriggerConnector(injector: HasAndroidInjector) : Trigger(injector) { } companion object { + fun labels(resourceHelper: ResourceHelper): List { val list: MutableList = ArrayList() for (t in values()) { @@ -79,16 +81,12 @@ class TriggerConnector(injector: HasAndroidInjector) : Trigger(injector) { return result } - @Synchronized override fun toJSON(): String { + override fun dataJSON(): JSONObject { val array = JSONArray() for (t in list) array.put(t.toJSON()) - val data = JSONObject() + return JSONObject() .put("connectorType", connectorType.toString()) .put("triggerList", array) - return JSONObject() - .put("type", TriggerConnector::class.java.name) - .put("data", data) - .toString() } override fun fromJSON(data: String): Trigger { diff --git a/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerDelta.kt b/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerDelta.kt index 35d23fe43d..9a5e564054 100644 --- a/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerDelta.kt +++ b/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerDelta.kt @@ -13,7 +13,6 @@ import info.nightscout.androidaps.plugins.general.automation.elements.InputDelta import info.nightscout.androidaps.plugins.general.automation.elements.LabelWithElement import info.nightscout.androidaps.plugins.general.automation.elements.LayoutBuilder import info.nightscout.androidaps.plugins.general.automation.elements.StaticLabel -import info.nightscout.androidaps.plugins.iob.iobCobCalculator.GlucoseStatus import info.nightscout.androidaps.utils.JsonHelper import org.json.JSONObject import java.text.DecimalFormat @@ -25,6 +24,7 @@ class TriggerDelta(injector: HasAndroidInjector) : Trigger(injector) { var comparator: Comparator = Comparator(resourceHelper) companion object { + private const val MMOL_MAX = 4.0 private const val MGDL_MAX = 72.0 } @@ -85,17 +85,12 @@ class TriggerDelta(injector: HasAndroidInjector) : Trigger(injector) { return false } - override fun toJSON(): String { - val data = JSONObject() + override fun dataJSON(): JSONObject = + JSONObject() .put("value", delta.value) .put("units", units) .put("deltaType", delta.deltaType) .put("comparator", comparator.value.toString()) - return JSONObject() - .put("type", this::class.java.name) - .put("data", data) - .toString() - } override fun fromJSON(data: String): Trigger { val d = JSONObject(data) diff --git a/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerDummy.kt b/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerDummy.kt index 84a5177a3f..d3b580768a 100644 --- a/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerDummy.kt +++ b/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerDummy.kt @@ -2,6 +2,7 @@ package info.nightscout.androidaps.plugins.general.automation.triggers import com.google.common.base.Optional import dagger.android.HasAndroidInjector +import org.json.JSONObject // Used for instantiation of other triggers only class TriggerDummy(injector: HasAndroidInjector, val shouldRun: Boolean = false) : Trigger(injector) { @@ -10,7 +11,7 @@ class TriggerDummy(injector: HasAndroidInjector, val shouldRun: Boolean = false) return shouldRun } - override fun toJSON(): String { + override fun dataJSON(): JSONObject { throw NotImplementedError("An operation is not implemented") } diff --git a/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerIob.kt b/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerIob.kt index ca009ee794..8707c6c576 100644 --- a/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerIob.kt +++ b/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerIob.kt @@ -10,7 +10,6 @@ import info.nightscout.androidaps.plugins.general.automation.elements.InputInsul import info.nightscout.androidaps.plugins.general.automation.elements.LabelWithElement import info.nightscout.androidaps.plugins.general.automation.elements.LayoutBuilder import info.nightscout.androidaps.plugins.general.automation.elements.StaticLabel -import info.nightscout.androidaps.utils.DateUtil import info.nightscout.androidaps.utils.JsonHelper import org.json.JSONObject @@ -35,7 +34,7 @@ class TriggerIob(injector: HasAndroidInjector) : Trigger(injector) { override fun shouldRun(): Boolean { val profile = profileFunction.getProfile() ?: return false - val iob = iobCobCalculatorPlugin.calculateFromTreatmentsAndTempsSynchronized(DateUtil.now(), profile) + val iob = iobCobCalculator.calculateFromTreatmentsAndTemps(dateUtil.now(), profile) if (comparator.value.check(iob.iob, insulin.value)) { aapsLogger.debug(LTag.AUTOMATION, "Ready for execution: " + friendlyDescription()) return true @@ -44,15 +43,10 @@ class TriggerIob(injector: HasAndroidInjector) : Trigger(injector) { return false } - @Synchronized override fun toJSON(): String { - val data = JSONObject() + override fun dataJSON(): JSONObject = + JSONObject() .put("insulin", insulin.value) .put("comparator", comparator.value.toString()) - return JSONObject() - .put("type", this::class.java.name) - .put("data", data) - .toString() - } override fun fromJSON(data: String): Trigger { val d = JSONObject(data) diff --git a/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerLocation.kt b/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerLocation.kt index bc7614cd80..f9fbbfc27b 100644 --- a/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerLocation.kt +++ b/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerLocation.kt @@ -12,6 +12,7 @@ import org.json.JSONObject import java.text.DecimalFormat class TriggerLocation(injector: HasAndroidInjector) : Trigger(injector) { + var latitude = InputDouble(0.0, -90.0, +90.0, 0.000001, DecimalFormat("0.000000")) var longitude = InputDouble(0.0, -180.0, +180.0, 0.000001, DecimalFormat("0.000000")) var distance = InputDouble(200.0, 0.0, 100000.0, 10.0, DecimalFormat("0")) @@ -56,18 +57,13 @@ class TriggerLocation(injector: HasAndroidInjector) : Trigger(injector) { return false } - override fun toJSON(): String { - val data = JSONObject() + override fun dataJSON(): JSONObject = + JSONObject() .put("latitude", latitude.value) .put("longitude", longitude.value) .put("distance", distance.value) .put("name", name.value) .put("mode", modeSelected.value) - return JSONObject() - .put("type", this::class.java.name) - .put("data", data) - .toString() - } override fun fromJSON(data: String): Trigger { val d = JSONObject(data) diff --git a/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerProfilePercent.kt b/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerProfilePercent.kt index 1996ec623d..9724d52278 100644 --- a/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerProfilePercent.kt +++ b/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerProfilePercent.kt @@ -14,11 +14,12 @@ import info.nightscout.androidaps.utils.JsonHelper import org.json.JSONObject class TriggerProfilePercent(injector: HasAndroidInjector) : Trigger(injector) { + var pct = InputPercent() var comparator = Comparator(resourceHelper) constructor(injector: HasAndroidInjector, value: Double, compare: Comparator.Compare) : this(injector) { - pct = InputPercent( value) + pct = InputPercent(value) comparator = Comparator(resourceHelper, compare) } @@ -55,15 +56,10 @@ class TriggerProfilePercent(injector: HasAndroidInjector) : Trigger(injector) { return false } - @Synchronized override fun toJSON(): String { - val data = JSONObject() + override fun dataJSON(): JSONObject = + JSONObject() .put("percentage", pct.value) .put("comparator", comparator.value.toString()) - return JSONObject() - .put("type", this::class.java.name) - .put("data", data) - .toString() - } override fun fromJSON(data: String): Trigger { val d = JSONObject(data) diff --git a/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerPumpLastConnection.kt b/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerPumpLastConnection.kt index 3fecec8ff6..cfcdd788ba 100644 --- a/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerPumpLastConnection.kt +++ b/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerPumpLastConnection.kt @@ -10,12 +10,12 @@ import info.nightscout.androidaps.plugins.general.automation.elements.InputDurat import info.nightscout.androidaps.plugins.general.automation.elements.LabelWithElement import info.nightscout.androidaps.plugins.general.automation.elements.LayoutBuilder import info.nightscout.androidaps.plugins.general.automation.elements.StaticLabel -import info.nightscout.androidaps.utils.DateUtil import info.nightscout.androidaps.utils.JsonHelper.safeGetInt import info.nightscout.androidaps.utils.JsonHelper.safeGetString import org.json.JSONObject class TriggerPumpLastConnection(injector: HasAndroidInjector) : Trigger(injector) { + var minutesAgo = InputDuration() var comparator = Comparator(resourceHelper) @@ -46,7 +46,7 @@ class TriggerPumpLastConnection(injector: HasAndroidInjector) : Trigger(injector aapsLogger.debug(LTag.AUTOMATION, "Ready for execution: " + friendlyDescription()) return true } - val connectionAgo = (DateUtil.now() - lastConnection) / (60 * 1000) + val connectionAgo = (dateUtil.now() - lastConnection) / (60 * 1000) aapsLogger.debug(LTag.AUTOMATION, "Last connection min ago: $connectionAgo") if (comparator.value.check(connectionAgo.toInt(), minutesAgo.value)) { aapsLogger.debug(LTag.AUTOMATION, "Ready for execution: " + friendlyDescription()) @@ -56,15 +56,10 @@ class TriggerPumpLastConnection(injector: HasAndroidInjector) : Trigger(injector return false } - override fun toJSON(): String { - val data = JSONObject() + override fun dataJSON(): JSONObject = + JSONObject() .put("minutesAgo", minutesAgo.value) .put("comparator", comparator.value.toString()) - return JSONObject() - .put("type", this::class.java.name) - .put("data", data) - .toString() - } override fun fromJSON(data: String): Trigger { val d = JSONObject(data) diff --git a/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerRecurringTime.kt b/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerRecurringTime.kt index 4d15d779e5..383adcce50 100644 --- a/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerRecurringTime.kt +++ b/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerRecurringTime.kt @@ -10,15 +10,12 @@ import info.nightscout.androidaps.plugins.general.automation.elements.InputTime import info.nightscout.androidaps.plugins.general.automation.elements.InputWeekDay import info.nightscout.androidaps.plugins.general.automation.elements.LayoutBuilder import info.nightscout.androidaps.plugins.general.automation.elements.StaticLabel -import info.nightscout.androidaps.utils.DateUtil import info.nightscout.androidaps.utils.JsonHelper import info.nightscout.androidaps.utils.MidnightTime import org.json.JSONObject import java.util.* -import javax.inject.Inject class TriggerRecurringTime(injector: HasAndroidInjector) : Trigger(injector) { - @Inject lateinit var dateUtil: DateUtil val days = InputWeekDay() val time = InputTime(resourceHelper, dateUtil) @@ -34,8 +31,8 @@ class TriggerRecurringTime(injector: HasAndroidInjector) : Trigger(injector) { return this } - override fun shouldRun() : Boolean { - val currentMinSinceMidnight = getMinSinceMidnight(dateUtil._now()) + override fun shouldRun(): Boolean { + val currentMinSinceMidnight = getMinSinceMidnight(dateUtil.now()) val scheduledDayOfWeek = Calendar.getInstance()[Calendar.DAY_OF_WEEK] if (days.isSet(Objects.requireNonNull(InputWeekDay.DayOfWeek.fromCalendarInt(scheduledDayOfWeek)))) { if (currentMinSinceMidnight >= time.value && currentMinSinceMidnight - time.value < 5) { @@ -47,16 +44,13 @@ class TriggerRecurringTime(injector: HasAndroidInjector) : Trigger(injector) { return false } - override fun toJSON(): String { + override fun dataJSON(): JSONObject { val data = JSONObject() .put("time", time.value) for (i in days.weekdays.indices) { data.put(InputWeekDay.DayOfWeek.values()[i].name, days.weekdays[i]) } - return JSONObject() - .put("type", TriggerRecurringTime::class.java.name) - .put("data", data) - .toString() + return data } override fun fromJSON(data: String): Trigger { diff --git a/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerTempTarget.kt b/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerTempTarget.kt index 8302608a47..216e84871d 100644 --- a/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerTempTarget.kt +++ b/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerTempTarget.kt @@ -4,22 +4,16 @@ import android.widget.LinearLayout import com.google.common.base.Optional import dagger.android.HasAndroidInjector import info.nightscout.androidaps.automation.R -import info.nightscout.androidaps.database.AppRepository import info.nightscout.androidaps.database.ValueWrapper import info.nightscout.androidaps.logging.LTag import info.nightscout.androidaps.plugins.general.automation.elements.ComparatorExists import info.nightscout.androidaps.plugins.general.automation.elements.LayoutBuilder import info.nightscout.androidaps.plugins.general.automation.elements.StaticLabel -import info.nightscout.androidaps.utils.DateUtil import info.nightscout.androidaps.utils.JsonHelper import org.json.JSONObject -import javax.inject.Inject class TriggerTempTarget(injector: HasAndroidInjector) : Trigger(injector) { - @Inject lateinit var repository: AppRepository - @Inject lateinit var dateUtil: DateUtil - var comparator = ComparatorExists(resourceHelper) constructor(injector: HasAndroidInjector, compare: ComparatorExists.Compare) : this(injector) { @@ -36,7 +30,7 @@ class TriggerTempTarget(injector: HasAndroidInjector) : Trigger(injector) { } override fun shouldRun(): Boolean { - val tt = repository.getTemporaryTargetActiveAt(dateUtil._now()).blockingGet() + val tt = repository.getTemporaryTargetActiveAt(dateUtil.now()).blockingGet() if (tt is ValueWrapper.Absent && comparator.value == ComparatorExists.Compare.NOT_EXISTS) { aapsLogger.debug(LTag.AUTOMATION, "Ready for execution: " + friendlyDescription()) return true @@ -49,14 +43,9 @@ class TriggerTempTarget(injector: HasAndroidInjector) : Trigger(injector) { return false } - override fun toJSON(): String { - val data = JSONObject() + override fun dataJSON(): JSONObject = + JSONObject() .put("comparator", comparator.value.toString()) - return JSONObject() - .put("type", TriggerTempTarget::class.java.name) - .put("data", data) - .toString() - } override fun fromJSON(data: String): Trigger { val d = JSONObject(data) diff --git a/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerTime.kt b/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerTime.kt index 722d50abe2..f03c35c6fc 100644 --- a/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerTime.kt +++ b/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerTime.kt @@ -1,6 +1,5 @@ package info.nightscout.androidaps.plugins.general.automation.triggers -import android.content.Context import android.widget.LinearLayout import com.google.common.base.Optional import dagger.android.HasAndroidInjector @@ -9,14 +8,11 @@ import info.nightscout.androidaps.logging.LTag import info.nightscout.androidaps.plugins.general.automation.elements.InputDateTime import info.nightscout.androidaps.plugins.general.automation.elements.LayoutBuilder import info.nightscout.androidaps.plugins.general.automation.elements.StaticLabel -import info.nightscout.androidaps.utils.DateUtil import info.nightscout.androidaps.utils.JsonHelper import info.nightscout.androidaps.utils.T import org.json.JSONObject -import javax.inject.Inject class TriggerTime(injector: HasAndroidInjector) : Trigger(injector) { - @Inject lateinit var dateUtil: DateUtil var time = InputDateTime(resourceHelper, dateUtil) @@ -24,7 +20,8 @@ class TriggerTime(injector: HasAndroidInjector) : Trigger(injector) { this.time.value = runAt } - @Suppress("unused") constructor(injector: HasAndroidInjector, triggerTime: TriggerTime) : this(injector) { + @Suppress("unused") + constructor(injector: HasAndroidInjector, triggerTime: TriggerTime) : this(injector) { this.time.value = triggerTime.time.value } @@ -34,7 +31,7 @@ class TriggerTime(injector: HasAndroidInjector) : Trigger(injector) { } override fun shouldRun(): Boolean { - val now = DateUtil.now() + val now = dateUtil.now() if (now >= time.value && now - time.value < T.mins(5).msecs()) { aapsLogger.debug(LTag.AUTOMATION, "Ready for execution: " + friendlyDescription()) return true @@ -43,14 +40,9 @@ class TriggerTime(injector: HasAndroidInjector) : Trigger(injector) { return false } - override fun toJSON(): String { - val data = JSONObject() + override fun dataJSON(): JSONObject = + JSONObject() .put("runAt", time.value) - return JSONObject() - .put("type", this::class.java.name) - .put("data", data) - .toString() - } override fun fromJSON(data: String): Trigger { val o = JSONObject(data) diff --git a/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerTimeRange.kt b/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerTimeRange.kt index ff183bee41..494b3980cf 100644 --- a/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerTimeRange.kt +++ b/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerTimeRange.kt @@ -9,17 +9,13 @@ import info.nightscout.androidaps.logging.LTag import info.nightscout.androidaps.plugins.general.automation.elements.InputTimeRange import info.nightscout.androidaps.plugins.general.automation.elements.LayoutBuilder import info.nightscout.androidaps.plugins.general.automation.elements.StaticLabel -import info.nightscout.androidaps.utils.DateUtil import info.nightscout.androidaps.utils.JsonHelper.safeGetInt import info.nightscout.androidaps.utils.MidnightTime import org.json.JSONObject -import javax.inject.Inject // Trigger for time range ( from 10:00AM till 13:00PM ) class TriggerTimeRange(injector: HasAndroidInjector) : Trigger(injector) { - @Inject lateinit var dateUtil: DateUtil - // in minutes since midnight 60 means 1AM var range = InputTimeRange(resourceHelper, dateUtil) @@ -28,7 +24,8 @@ class TriggerTimeRange(injector: HasAndroidInjector) : Trigger(injector) { range.end = end } - @Suppress("unused") constructor(injector: HasAndroidInjector, triggerTimeRange: TriggerTimeRange) : this(injector) { + @Suppress("unused") + constructor(injector: HasAndroidInjector, triggerTimeRange: TriggerTimeRange) : this(injector) { range.start = triggerTimeRange.range.start range.end = triggerTimeRange.range.end } @@ -40,7 +37,7 @@ class TriggerTimeRange(injector: HasAndroidInjector) : Trigger(injector) { } override fun shouldRun(): Boolean { - val currentMinSinceMidnight = getMinSinceMidnight(DateUtil.now()) + val currentMinSinceMidnight = getMinSinceMidnight(dateUtil.now()) var doRun = false if (range.start < range.end && range.start < currentMinSinceMidnight && currentMinSinceMidnight < range.end) doRun = true else if (range.start > range.end && (range.start < currentMinSinceMidnight || currentMinSinceMidnight < range.end)) doRun = true @@ -52,15 +49,10 @@ class TriggerTimeRange(injector: HasAndroidInjector) : Trigger(injector) { return false } - override fun toJSON(): String { - val data = JSONObject() + override fun dataJSON(): JSONObject = + JSONObject() .put("start", range.start) .put("end", range.end) - return JSONObject() - .put("type", this::class.java.name) - .put("data", data) - .toString() - } override fun fromJSON(data: String): TriggerTimeRange { val o = JSONObject(data) diff --git a/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerWifiSsid.kt b/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerWifiSsid.kt index 316d1d1aab..8fa919e8c3 100644 --- a/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerWifiSsid.kt +++ b/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerWifiSsid.kt @@ -16,12 +16,14 @@ import org.json.JSONObject import javax.inject.Inject class TriggerWifiSsid(injector: HasAndroidInjector) : Trigger(injector) { + @Inject lateinit var receiverStatusStore: ReceiverStatusStore var ssid = InputString() var comparator = Comparator(resourceHelper) - @Suppress("unused") constructor(injector: HasAndroidInjector, ssid: String, compare: Comparator.Compare) : this(injector) { + @Suppress("unused") + constructor(injector: HasAndroidInjector, ssid: String, compare: Comparator.Compare) : this(injector) { this.ssid = InputString(ssid) comparator = Comparator(resourceHelper, compare) } @@ -55,15 +57,10 @@ class TriggerWifiSsid(injector: HasAndroidInjector) : Trigger(injector) { return false } - override fun toJSON(): String { - val data = JSONObject() + override fun dataJSON(): JSONObject = + JSONObject() .put("ssid", ssid.value) .put("comparator", comparator.value.toString()) - return JSONObject() - .put("type", this::class.java.name) - .put("data", data) - .toString() - } override fun fromJSON(data: String): Trigger { val d = JSONObject(data) diff --git a/automation/src/main/java/info/nightscout/androidaps/services/LocationService.kt b/automation/src/main/java/info/nightscout/androidaps/services/LocationService.kt index aeb3c9f416..9f5063be77 100644 --- a/automation/src/main/java/info/nightscout/androidaps/services/LocationService.kt +++ b/automation/src/main/java/info/nightscout/androidaps/services/LocationService.kt @@ -19,7 +19,7 @@ import dagger.android.DaggerService import info.nightscout.androidaps.automation.R import info.nightscout.androidaps.events.EventAppExit import info.nightscout.androidaps.events.EventLocationChange -import info.nightscout.androidaps.interfaces.NotificationHolderInterface +import info.nightscout.androidaps.interfaces.NotificationHolder import info.nightscout.androidaps.logging.AAPSLogger import info.nightscout.androidaps.logging.LTag import info.nightscout.androidaps.plugins.bus.RxBusWrapper @@ -37,7 +37,7 @@ class LocationService : DaggerService() { @Inject lateinit var sp: SP @Inject lateinit var aapsSchedulers: AapsSchedulers @Inject lateinit var fabricPrivacy: FabricPrivacy - @Inject lateinit var notificationHolder: NotificationHolderInterface + @Inject lateinit var notificationHolder: NotificationHolder @Inject lateinit var lastLocationDataContainer: LastLocationDataContainer private val disposable = CompositeDisposable() diff --git a/automation/src/main/java/info/nightscout/androidaps/services/LocationServiceHelper.kt b/automation/src/main/java/info/nightscout/androidaps/services/LocationServiceHelper.kt index 3767d0c2a2..8021406f76 100644 --- a/automation/src/main/java/info/nightscout/androidaps/services/LocationServiceHelper.kt +++ b/automation/src/main/java/info/nightscout/androidaps/services/LocationServiceHelper.kt @@ -5,7 +5,7 @@ import android.content.Context import android.content.Intent import android.content.ServiceConnection import android.os.IBinder -import info.nightscout.androidaps.interfaces.NotificationHolderInterface +import info.nightscout.androidaps.interfaces.NotificationHolder import javax.inject.Inject import javax.inject.Singleton @@ -20,7 +20,7 @@ import javax.inject.Singleton */ @Singleton class LocationServiceHelper @Inject constructor( - private val notificationHolder: NotificationHolderInterface + private val notificationHolder: NotificationHolder ) { fun startService(context: Context) { diff --git a/automation/src/main/res/values/strings.xml b/automation/src/main/res/values/strings.xml index b8ee4c099a..2e23b54761 100644 --- a/automation/src/main/res/values/strings.xml +++ b/automation/src/main/res/values/strings.xml @@ -25,7 +25,6 @@ Already set Profile percentage Start profile %1$d%% - Start profile %1$d%% for %2$d min Percent [%]: Send SMS: %1$s Send SMS to all numbers diff --git a/automation/src/test/java/info/nightscout/androidaps/plugins/general/automation/AutomationEventTest.kt b/automation/src/test/java/info/nightscout/androidaps/plugins/general/automation/AutomationEventTest.kt index cf9522fcb4..6c0087b86b 100644 --- a/automation/src/test/java/info/nightscout/androidaps/plugins/general/automation/AutomationEventTest.kt +++ b/automation/src/test/java/info/nightscout/androidaps/plugins/general/automation/AutomationEventTest.kt @@ -3,7 +3,7 @@ package info.nightscout.androidaps.plugins.general.automation import dagger.android.AndroidInjector import dagger.android.HasAndroidInjector import info.nightscout.androidaps.TestBase -import info.nightscout.androidaps.interfaces.ConfigBuilderInterface +import info.nightscout.androidaps.interfaces.ConfigBuilder import info.nightscout.androidaps.interfaces.LoopInterface import info.nightscout.androidaps.plugins.bus.RxBusWrapper import info.nightscout.androidaps.plugins.general.automation.actions.ActionLoopEnable @@ -22,7 +22,7 @@ class AutomationEventTest : TestBase() { @Mock lateinit var loopPlugin: LoopInterface @Mock lateinit var resourceHelper: ResourceHelper - @Mock lateinit var configBuilderPlugin: ConfigBuilderInterface + @Mock lateinit var configBuilder: ConfigBuilder var injector: HasAndroidInjector = HasAndroidInjector { AndroidInjector { @@ -32,7 +32,7 @@ class AutomationEventTest : TestBase() { if (it is ActionLoopEnable) { it.loopPlugin = loopPlugin it.resourceHelper = resourceHelper - it.configBuilderPlugin = configBuilderPlugin + it.configBuilder = configBuilder it.rxBus = RxBusWrapper(aapsSchedulers) } } @@ -48,7 +48,7 @@ class AutomationEventTest : TestBase() { event.addAction(ActionLoopEnable(injector)) // export to json - val eventJsonExpected = "{\"autoRemove\":false,\"readOnly\":false,\"trigger\":\"{\\\"data\\\":{\\\"connectorType\\\":\\\"AND\\\",\\\"triggerList\\\":[\\\"{\\\\\\\"data\\\\\\\":{\\\\\\\"connectorType\\\\\\\":\\\\\\\"AND\\\\\\\",\\\\\\\"triggerList\\\\\\\":[]},\\\\\\\"type\\\\\\\":\\\\\\\"info.nightscout.androidaps.plugins.general.automation.triggers.TriggerConnector\\\\\\\"}\\\"]},\\\"type\\\":\\\"info.nightscout.androidaps.plugins.general.automation.triggers.TriggerConnector\\\"}\",\"title\":\"Test\",\"systemAction\":false,\"actions\":[\"{\\\"type\\\":\\\"info.nightscout.androidaps.plugins.general.automation.actions.ActionLoopEnable\\\"}\"],\"enabled\":true}" + val eventJsonExpected = "{\"autoRemove\":false,\"readOnly\":false,\"trigger\":\"{\\\"data\\\":{\\\"connectorType\\\":\\\"AND\\\",\\\"triggerList\\\":[\\\"{\\\\\\\"data\\\\\\\":{\\\\\\\"connectorType\\\\\\\":\\\\\\\"AND\\\\\\\",\\\\\\\"triggerList\\\\\\\":[]},\\\\\\\"type\\\\\\\":\\\\\\\"TriggerConnector\\\\\\\"}\\\"]},\\\"type\\\":\\\"TriggerConnector\\\"}\",\"title\":\"Test\",\"systemAction\":false,\"actions\":[\"{\\\"type\\\":\\\"info.nightscout.androidaps.plugins.general.automation.actions.ActionLoopEnable\\\"}\"],\"enabled\":true}" Assert.assertEquals(eventJsonExpected, event.toJSON()) // clone diff --git a/automation/src/test/java/info/nightscout/androidaps/plugins/general/automation/TestBaseWithProfile.kt b/automation/src/test/java/info/nightscout/androidaps/plugins/general/automation/TestBaseWithProfile.kt index e3e5c7391b..3abdbbe4bf 100644 --- a/automation/src/test/java/info/nightscout/androidaps/plugins/general/automation/TestBaseWithProfile.kt +++ b/automation/src/test/java/info/nightscout/androidaps/plugins/general/automation/TestBaseWithProfile.kt @@ -3,10 +3,10 @@ package info.nightscout.androidaps import dagger.android.AndroidInjector import dagger.android.HasAndroidInjector import info.nightscout.androidaps.data.Profile +import info.nightscout.androidaps.database.AppRepository import info.nightscout.androidaps.db.ProfileSwitch -import info.nightscout.androidaps.db.Treatment -import info.nightscout.androidaps.interfaces.ActivePluginProvider -import info.nightscout.androidaps.interfaces.ConfigInterface +import info.nightscout.androidaps.interfaces.ActivePlugin +import info.nightscout.androidaps.interfaces.Config import info.nightscout.androidaps.interfaces.ProfileFunction import info.nightscout.androidaps.interfaces.ProfileStore import info.nightscout.androidaps.interfaces.TreatmentsInterface @@ -21,17 +21,18 @@ import org.mockito.Mock import org.powermock.core.classloader.annotations.PrepareForTest @Suppress("SpellCheckingInspection") -@PrepareForTest(FabricPrivacy::class) +@PrepareForTest(FabricPrivacy::class, AppRepository::class) open class TestBaseWithProfile : TestBase() { - @Mock lateinit var activePluginProvider: ActivePluginProvider + @Mock lateinit var activePluginProvider: ActivePlugin @Mock lateinit var resourceHelper: ResourceHelper @Mock lateinit var treatmentsInterface: TreatmentsInterface @Mock lateinit var fabricPrivacy: FabricPrivacy @Mock lateinit var profileFunction: ProfileFunction @Mock lateinit var defaultValueHelper: DefaultValueHelper @Mock lateinit var dateUtil: DateUtil - @Mock lateinit var configInterface: ConfigInterface + @Mock lateinit var config: Config + @Mock lateinit var repository: AppRepository val rxBus = RxBusWrapper(aapsSchedulers) @@ -43,7 +44,7 @@ open class TestBaseWithProfile : TestBase() { it.resourceHelper = resourceHelper it.rxBus = rxBus it.fabricPrivacy = fabricPrivacy - it.configInterface = configInterface + it.config = config } if (it is ProfileSwitch) { it.treatmentsPlugin = treatmentsInterface @@ -52,12 +53,6 @@ open class TestBaseWithProfile : TestBase() { it.resourceHelper = resourceHelper it.dateUtil = dateUtil } - if (it is Treatment) { - it.activePlugin = activePluginProvider - it.profileFunction = profileFunction - it.defaultValueHelper = defaultValueHelper - it.resourceHelper = resourceHelper - } } } diff --git a/automation/src/test/java/info/nightscout/androidaps/plugins/general/automation/TestPumpPlugin.kt b/automation/src/test/java/info/nightscout/androidaps/plugins/general/automation/TestPumpPlugin.kt index 478abe9484..5864054151 100644 --- a/automation/src/test/java/info/nightscout/androidaps/plugins/general/automation/TestPumpPlugin.kt +++ b/automation/src/test/java/info/nightscout/androidaps/plugins/general/automation/TestPumpPlugin.kt @@ -7,7 +7,8 @@ import info.nightscout.androidaps.data.PumpEnactResult import info.nightscout.androidaps.interfaces.PluginBase import info.nightscout.androidaps.interfaces.PluginDescription import info.nightscout.androidaps.interfaces.PumpDescription -import info.nightscout.androidaps.interfaces.PumpInterface +import info.nightscout.androidaps.interfaces.Pump +import info.nightscout.androidaps.interfaces.PumpSync import info.nightscout.androidaps.logging.AAPSLogger import info.nightscout.androidaps.plugins.common.ManufacturerType import info.nightscout.androidaps.plugins.pump.common.defs.PumpType @@ -22,7 +23,7 @@ class TestPumpPlugin(pluginDescription: PluginDescription, injector: HasAndroidInjector ) : PluginBase( pluginDescription, aapsLogger, resourceHelper, injector -), PumpInterface { +), Pump { var connected = false var isProfileSet = true @@ -61,14 +62,14 @@ class TestPumpPlugin(pluginDescription: PluginDescription, override val batteryLevel: Int = 0 override fun deliverTreatment(detailedBolusInfo: DetailedBolusInfo): PumpEnactResult = PumpEnactResult(injector).success(true) override fun stopBolusDelivering() {} - override fun setTempBasalAbsolute(absoluteRate: Double, durationInMinutes: Int, profile: Profile, enforceNew: Boolean): PumpEnactResult = PumpEnactResult(injector).success(true) - override fun setTempBasalPercent(percent: Int, durationInMinutes: Int, profile: Profile, enforceNew: Boolean): PumpEnactResult = PumpEnactResult(injector).success(true) + override fun setTempBasalAbsolute(absoluteRate: Double, durationInMinutes: Int, profile: Profile, enforceNew: Boolean, tbrType: PumpSync.TemporaryBasalType): PumpEnactResult = PumpEnactResult(injector).success(true) + override fun setTempBasalPercent(percent: Int, durationInMinutes: Int, profile: Profile, enforceNew: Boolean, tbrType: PumpSync.TemporaryBasalType): PumpEnactResult = PumpEnactResult(injector).success(true) override fun setExtendedBolus(insulin: Double, durationInMinutes: Int): PumpEnactResult = PumpEnactResult(injector).success(true) override fun cancelTempBasal(enforceNew: Boolean): PumpEnactResult = PumpEnactResult(injector).success(true) override fun cancelExtendedBolus(): PumpEnactResult = PumpEnactResult(injector).success(true) override fun getJSONStatus(profile: Profile, profileName: String, version: String): JSONObject = JSONObject() override fun manufacturer(): ManufacturerType = ManufacturerType.AndroidAPS - override fun model(): PumpType = PumpType.GenericAAPS + override fun model(): PumpType = PumpType.GENERIC_AAPS override fun serialNumber(): String = "1" override fun shortStatus(veryShort: Boolean): String = "" override val isFakingTempsByExtendedBoluses: Boolean = false diff --git a/automation/src/test/java/info/nightscout/androidaps/plugins/general/automation/actions/ActionAlarmTest.kt b/automation/src/test/java/info/nightscout/androidaps/plugins/general/automation/actions/ActionAlarmTest.kt index 1639de19bb..b3d62498e4 100644 --- a/automation/src/test/java/info/nightscout/androidaps/plugins/general/automation/actions/ActionAlarmTest.kt +++ b/automation/src/test/java/info/nightscout/androidaps/plugins/general/automation/actions/ActionAlarmTest.kt @@ -10,6 +10,7 @@ import info.nightscout.androidaps.plugins.bus.RxBusWrapper import info.nightscout.androidaps.plugins.general.automation.elements.InputString import info.nightscout.androidaps.plugins.general.nsclient.NSUpload import info.nightscout.androidaps.queue.Callback +import info.nightscout.androidaps.utils.DateUtil import info.nightscout.androidaps.utils.TimerUtil import info.nightscout.androidaps.utils.resources.ResourceHelper import org.junit.Assert @@ -30,6 +31,7 @@ class ActionAlarmTest : TestBase() { @Mock lateinit var rxBus: RxBusWrapper @Mock lateinit var context: Context @Mock lateinit var timerUtil: TimerUtil + @Mock lateinit var dateUtil: DateUtil private lateinit var sut: ActionAlarm var injector: HasAndroidInjector = HasAndroidInjector { @@ -39,6 +41,7 @@ class ActionAlarmTest : TestBase() { it.rxBus = rxBus it.context = context it.timerUtil = timerUtil + it.dateUtil = dateUtil } if (it is PumpEnactResult) { it.resourceHelper = resourceHelper diff --git a/automation/src/test/java/info/nightscout/androidaps/plugins/general/automation/actions/ActionLoopDisableTest.kt b/automation/src/test/java/info/nightscout/androidaps/plugins/general/automation/actions/ActionLoopDisableTest.kt index ececed86fd..0a0aa4db2b 100644 --- a/automation/src/test/java/info/nightscout/androidaps/plugins/general/automation/actions/ActionLoopDisableTest.kt +++ b/automation/src/test/java/info/nightscout/androidaps/plugins/general/automation/actions/ActionLoopDisableTest.kt @@ -51,7 +51,7 @@ class ActionLoopDisableTest : ActionsTestBase() { override fun run() {} }) Mockito.verify(loopPlugin, Mockito.times(1)).setPluginEnabled(PluginType.LOOP, false) - Mockito.verify(configBuilderPlugin, Mockito.times(1)).storeSettings("ActionLoopDisable") + Mockito.verify(configBuilder, Mockito.times(1)).storeSettings("ActionLoopDisable") Mockito.verify(commandQueue, Mockito.times(1)).cancelTempBasal(eq(true), anyObject()) `when`(loopPlugin.isEnabled()).thenReturn(false) @@ -61,7 +61,7 @@ class ActionLoopDisableTest : ActionsTestBase() { override fun run() {} }) Mockito.verify(loopPlugin, Mockito.times(1)).setPluginEnabled(PluginType.LOOP, false) - Mockito.verify(configBuilderPlugin, Mockito.times(1)).storeSettings("ActionLoopDisable") + Mockito.verify(configBuilder, Mockito.times(1)).storeSettings("ActionLoopDisable") Mockito.verify(commandQueue, Mockito.times(1)).cancelTempBasal(eq(true), anyObject()) } } \ No newline at end of file diff --git a/automation/src/test/java/info/nightscout/androidaps/plugins/general/automation/actions/ActionLoopEnableTest.kt b/automation/src/test/java/info/nightscout/androidaps/plugins/general/automation/actions/ActionLoopEnableTest.kt index 9851c7b25f..21cc20b448 100644 --- a/automation/src/test/java/info/nightscout/androidaps/plugins/general/automation/actions/ActionLoopEnableTest.kt +++ b/automation/src/test/java/info/nightscout/androidaps/plugins/general/automation/actions/ActionLoopEnableTest.kt @@ -45,7 +45,7 @@ class ActionLoopEnableTest : ActionsTestBase() { override fun run() {} }) Mockito.verify(loopPlugin, Mockito.times(1)).setPluginEnabled(PluginType.LOOP, true) - Mockito.verify(configBuilderPlugin, Mockito.times(1)).storeSettings("ActionLoopEnable") + Mockito.verify(configBuilder, Mockito.times(1)).storeSettings("ActionLoopEnable") `when`(loopPlugin.isEnabled()).thenReturn(true) @@ -54,6 +54,6 @@ class ActionLoopEnableTest : ActionsTestBase() { override fun run() {} }) Mockito.verify(loopPlugin, Mockito.times(1)).setPluginEnabled(PluginType.LOOP, true) - Mockito.verify(configBuilderPlugin, Mockito.times(1)).storeSettings("ActionLoopEnable") + Mockito.verify(configBuilder, Mockito.times(1)).storeSettings("ActionLoopEnable") } } \ No newline at end of file diff --git a/automation/src/test/java/info/nightscout/androidaps/plugins/general/automation/actions/ActionLoopResumeTest.kt b/automation/src/test/java/info/nightscout/androidaps/plugins/general/automation/actions/ActionLoopResumeTest.kt index f3f1a0f480..b24aef178c 100644 --- a/automation/src/test/java/info/nightscout/androidaps/plugins/general/automation/actions/ActionLoopResumeTest.kt +++ b/automation/src/test/java/info/nightscout/androidaps/plugins/general/automation/actions/ActionLoopResumeTest.kt @@ -42,7 +42,7 @@ class ActionLoopResumeTest : ActionsTestBase() { override fun run() {} }) Mockito.verify(loopPlugin, Mockito.times(1)).suspendTo(0) - Mockito.verify(configBuilderPlugin, Mockito.times(1)).storeSettings("ActionLoopResume") + Mockito.verify(configBuilder, Mockito.times(1)).storeSettings("ActionLoopResume") Mockito.verify(loopPlugin, Mockito.times(1)).createOfflineEvent(0) // another call should keep it resumed, , no new invocation @@ -51,7 +51,7 @@ class ActionLoopResumeTest : ActionsTestBase() { override fun run() {} }) Mockito.verify(loopPlugin, Mockito.times(1)).suspendTo(0) - Mockito.verify(configBuilderPlugin, Mockito.times(1)).storeSettings("ActionLoopResume") + Mockito.verify(configBuilder, Mockito.times(1)).storeSettings("ActionLoopResume") Mockito.verify(loopPlugin, Mockito.times(1)).createOfflineEvent(0) } } \ No newline at end of file diff --git a/automation/src/test/java/info/nightscout/androidaps/plugins/general/automation/actions/ActionNotificationTest.kt b/automation/src/test/java/info/nightscout/androidaps/plugins/general/automation/actions/ActionNotificationTest.kt index 68e446a922..0617b7c78e 100644 --- a/automation/src/test/java/info/nightscout/androidaps/plugins/general/automation/actions/ActionNotificationTest.kt +++ b/automation/src/test/java/info/nightscout/androidaps/plugins/general/automation/actions/ActionNotificationTest.kt @@ -5,6 +5,9 @@ import dagger.android.HasAndroidInjector import info.nightscout.androidaps.TestBase import info.nightscout.androidaps.automation.R import info.nightscout.androidaps.data.PumpEnactResult +import info.nightscout.androidaps.database.AppRepository +import info.nightscout.androidaps.database.transactions.InsertTherapyEventAnnouncementTransaction +import info.nightscout.androidaps.database.transactions.Transaction import info.nightscout.androidaps.plugins.bus.RxBusWrapper import info.nightscout.androidaps.plugins.general.automation.elements.InputString import info.nightscout.androidaps.plugins.general.nsclient.NSUpload @@ -18,6 +21,7 @@ import org.mockito.ArgumentMatchers import org.mockito.Mock import org.mockito.Mockito import org.mockito.Mockito.`when` +import org.mockito.Mockito.any import org.powermock.core.classloader.annotations.PrepareForTest import org.powermock.modules.junit4.PowerMockRunner @@ -27,7 +31,7 @@ class ActionNotificationTest : TestBase() { @Mock lateinit var resourceHelper: ResourceHelper @Mock lateinit var rxBus: RxBusWrapper - @Mock lateinit var nsUpload: NSUpload + @Mock lateinit var repository: AppRepository private lateinit var sut: ActionNotification var injector: HasAndroidInjector = HasAndroidInjector { @@ -35,7 +39,7 @@ class ActionNotificationTest : TestBase() { if (it is ActionNotification) { it.resourceHelper = resourceHelper it.rxBus = rxBus - it.nsUpload = nsUpload + it.repository = repository } if (it is PumpEnactResult) { it.resourceHelper = resourceHelper @@ -72,7 +76,7 @@ class ActionNotificationTest : TestBase() { } }) Mockito.verify(rxBus, Mockito.times(2)).send(anyObject()) - Mockito.verify(nsUpload, Mockito.times(1)).uploadError(anyObject()) + //Mockito.verify(repository, Mockito.times(1)).runTransaction(any(Transaction::class.java)) } @Test fun hasDialogTest() { diff --git a/automation/src/test/java/info/nightscout/androidaps/plugins/general/automation/actions/ActionsTestBase.kt b/automation/src/test/java/info/nightscout/androidaps/plugins/general/automation/actions/ActionsTestBase.kt index 6451441f0f..0db3108dee 100644 --- a/automation/src/test/java/info/nightscout/androidaps/plugins/general/automation/actions/ActionsTestBase.kt +++ b/automation/src/test/java/info/nightscout/androidaps/plugins/general/automation/actions/ActionsTestBase.kt @@ -6,11 +6,10 @@ import info.nightscout.androidaps.Constants import info.nightscout.androidaps.TestBaseWithProfile import info.nightscout.androidaps.TestPumpPlugin import info.nightscout.androidaps.data.PumpEnactResult -import info.nightscout.androidaps.database.AppRepository import info.nightscout.androidaps.interfaces.* import info.nightscout.androidaps.logging.AAPSLogger +import info.nightscout.androidaps.logging.UserEntryLogger import info.nightscout.androidaps.plugins.bus.RxBusWrapper -import info.nightscout.androidaps.plugins.general.automation.elements.InputTempTarget import info.nightscout.androidaps.plugins.general.automation.triggers.Trigger import info.nightscout.androidaps.utils.resources.ResourceHelper import info.nightscout.androidaps.utils.sharedPreferences.SP @@ -18,9 +17,8 @@ import org.junit.Before import org.mockito.Mock import org.mockito.Mockito.`when` import org.powermock.core.classloader.annotations.PrepareForTest -import javax.inject.Inject -@PrepareForTest(RxBusWrapper::class, ActionsTestBase.TestLoopPlugin::class, AppRepository::class) +@PrepareForTest(RxBusWrapper::class, ActionsTestBase.TestLoopPlugin::class, UserEntryLogger::class) open class ActionsTestBase : TestBaseWithProfile() { open class TestLoopPlugin( @@ -32,7 +30,7 @@ open class ActionsTestBase : TestBaseWithProfile() { pluginDescription, aapsLogger, resourceHelper, injector ), LoopInterface { - var suspended = false + private var suspended = false override var lastRun: LoopInterface.LastRun? = LoopInterface.LastRun() override val isSuspended: Boolean = suspended override fun suspendTo(endTime: Long) {} @@ -42,12 +40,12 @@ open class ActionsTestBase : TestBaseWithProfile() { @Mock lateinit var sp: SP @Mock lateinit var commandQueue: CommandQueueProvider - @Mock lateinit var configBuilderPlugin: ConfigBuilderInterface - @Mock lateinit var activePlugin: ActivePluginProvider - @Mock lateinit var profilePlugin: ProfileInterface - @Mock lateinit var smsCommunicatorPlugin: SmsCommunicatorInterface + @Mock lateinit var configBuilder: ConfigBuilder + @Mock lateinit var activePlugin: ActivePlugin + @Mock lateinit var profilePlugin: ProfileSource + @Mock lateinit var smsCommunicatorPlugin: SmsCommunicator @Mock lateinit var loopPlugin: TestLoopPlugin - @Mock lateinit var repository: AppRepository + @Mock lateinit var uel: UserEntryLogger private val pluginDescription = PluginDescription() lateinit var testPumpPlugin: TestPumpPlugin @@ -57,8 +55,9 @@ open class ActionsTestBase : TestBaseWithProfile() { if (it is ActionStopTempTarget) { it.aapsLogger = aapsLogger it.resourceHelper = resourceHelper - it.activePlugin = activePlugin + it.dateUtil = dateUtil it.repository = repository + it.uel = uel } if (it is ActionStartTempTarget) { it.aapsLogger = aapsLogger @@ -66,6 +65,8 @@ open class ActionsTestBase : TestBaseWithProfile() { it.activePlugin = activePlugin it.repository = repository it.profileFunction = profileFunction + it.uel = uel + it.dateUtil = dateUtil } if (it is ActionSendSMS) { it.aapsLogger = aapsLogger @@ -77,10 +78,13 @@ open class ActionsTestBase : TestBaseWithProfile() { it.resourceHelper = resourceHelper it.activePlugin = activePlugin it.profileFunction = profileFunction + it.uel = uel + it.dateUtil = dateUtil } if (it is ActionProfileSwitchPercent) { it.resourceHelper = resourceHelper it.activePlugin = activePlugin + it.uel = uel } if (it is ActionNotification) { it.resourceHelper = resourceHelper @@ -90,30 +94,34 @@ open class ActionsTestBase : TestBaseWithProfile() { it.loopPlugin = loopPlugin it.resourceHelper = resourceHelper it.rxBus = rxBus + it.uel = uel } if (it is ActionLoopResume) { it.loopPlugin = loopPlugin it.resourceHelper = resourceHelper - it.configBuilderPlugin = configBuilderPlugin + it.configBuilder = configBuilder it.rxBus = rxBus + it.uel = uel } if (it is ActionLoopEnable) { it.loopPlugin = loopPlugin it.resourceHelper = resourceHelper - it.configBuilderPlugin = configBuilderPlugin + it.configBuilder = configBuilder it.rxBus = rxBus + it.uel = uel } if (it is ActionLoopDisable) { it.loopPlugin = loopPlugin it.resourceHelper = resourceHelper - it.configBuilderPlugin = configBuilderPlugin + it.configBuilder = configBuilder it.commandQueue = commandQueue it.rxBus = rxBus + it.uel = uel } if (it is PumpEnactResult) { it.resourceHelper = resourceHelper } - if(it is Trigger) { + if (it is Trigger) { it.resourceHelper = resourceHelper it.profileFunction = profileFunction } @@ -125,7 +133,7 @@ open class ActionsTestBase : TestBaseWithProfile() { testPumpPlugin = TestPumpPlugin(pluginDescription, aapsLogger, resourceHelper, injector) `when`(activePlugin.activePump).thenReturn(testPumpPlugin) `when`(profileFunction.getUnits()).thenReturn(Constants.MGDL) - `when`(activePlugin.activeProfileInterface).thenReturn(profilePlugin) + `when`(activePlugin.activeProfileSource).thenReturn(profilePlugin) `when`(profilePlugin.profile).thenReturn(getValidProfileStore()) } } \ No newline at end of file diff --git a/automation/src/test/java/info/nightscout/androidaps/plugins/general/automation/triggers/DummyTrigger.kt b/automation/src/test/java/info/nightscout/androidaps/plugins/general/automation/triggers/DummyTrigger.kt index fbf9213625..7242079411 100644 --- a/automation/src/test/java/info/nightscout/androidaps/plugins/general/automation/triggers/DummyTrigger.kt +++ b/automation/src/test/java/info/nightscout/androidaps/plugins/general/automation/triggers/DummyTrigger.kt @@ -3,34 +3,15 @@ package info.nightscout.androidaps.plugins.general.automation.triggers import com.google.common.base.Optional import dagger.android.AndroidInjector import dagger.android.HasAndroidInjector +import org.json.JSONObject class DummyTrigger(var result: Boolean) : Trigger(HasAndroidInjector { AndroidInjector { } }) { - override fun shouldRun(): Boolean { - return result - } - - override fun toJSON(): String { - return "" - } - - override fun fromJSON(data: String): Trigger { - return DummyTrigger(result) - } - - override fun friendlyName(): Int { - return 0 - } - - override fun friendlyDescription(): String { - return " " - } - - override fun icon(): Optional { - return Optional.absent() - } - - override fun duplicate(): Trigger { - return DummyTrigger(result) - } + override fun shouldRun(): Boolean = result + override fun dataJSON(): JSONObject = JSONObject() + override fun fromJSON(data: String): Trigger = DummyTrigger(result) + override fun friendlyName(): Int = 0 + override fun friendlyDescription(): String = " " + override fun icon(): Optional = Optional.absent() + override fun duplicate(): Trigger = DummyTrigger(result) } \ No newline at end of file diff --git a/automation/src/test/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerAutosensValueTest.kt b/automation/src/test/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerAutosensValueTest.kt index 27b040ad3b..39ddf09fde 100644 --- a/automation/src/test/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerAutosensValueTest.kt +++ b/automation/src/test/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerAutosensValueTest.kt @@ -25,7 +25,7 @@ class TriggerAutosensValueTest : TriggerTestBase() { @Test fun shouldRunTest() { `when`(sp.getDouble(Mockito.eq(R.string.key_openapsama_autosens_max), ArgumentMatchers.anyDouble())).thenReturn(1.2) `when`(sp.getDouble(Mockito.eq(R.string.key_openapsama_autosens_min), ArgumentMatchers.anyDouble())).thenReturn(0.7) - `when`(iobCobCalculatorPlugin.getLastAutosensData("Automation trigger")).thenReturn(generateAutosensData()) + `when`(autosensDataStore.getLastAutosensData(anyObject(), anyObject(), anyObject())).thenReturn(generateAutosensData()) var t = TriggerAutosensValue(injector) t.autosens.value = 110.0 t.comparator.value = Comparator.Compare.IS_EQUAL @@ -65,14 +65,14 @@ class TriggerAutosensValueTest : TriggerTestBase() { t.autosens.value = 390.0 t.comparator.value = Comparator.Compare.IS_EQUAL_OR_LESSER Assert.assertTrue(t.shouldRun()) - PowerMockito.`when`(iobCobCalculatorPlugin.getLastAutosensData("Automation trigger")).thenReturn(AutosensData(injector)) + PowerMockito.`when`(autosensDataStore.getLastAutosensData(anyObject(), anyObject(), anyObject())).thenReturn(AutosensData(injector)) t = TriggerAutosensValue(injector) t.autosens.value = 80.0 t.comparator.value = Comparator.Compare.IS_EQUAL_OR_LESSER Assert.assertFalse(t.shouldRun()) // Test autosensData == null and Comparator == IS_NOT_AVAILABLE - PowerMockito.`when`(iobCobCalculatorPlugin.getLastAutosensData("Automation trigger")).thenReturn(null) + PowerMockito.`when`(autosensDataStore.getLastAutosensData(anyObject(), anyObject(), anyObject())).thenReturn(null) t = TriggerAutosensValue(injector) t.comparator.value = Comparator.Compare.IS_NOT_AVAILABLE Assert.assertTrue(t.shouldRun()) @@ -88,7 +88,7 @@ class TriggerAutosensValueTest : TriggerTestBase() { Assert.assertEquals(Comparator.Compare.IS_EQUAL_OR_LESSER, t.comparator.value) } - private var asJson = "{\"data\":{\"comparator\":\"IS_EQUAL\",\"value\":410},\"type\":\"info.nightscout.androidaps.plugins.general.automation.triggers.TriggerAutosensValue\"}" + private var asJson = "{\"data\":{\"comparator\":\"IS_EQUAL\",\"value\":410},\"type\":\"TriggerAutosensValue\"}" @Test fun toJSONTest() { @@ -109,13 +109,12 @@ class TriggerAutosensValueTest : TriggerTestBase() { } @Test fun iconTest() { - Assert.assertEquals(Optional.of(R.drawable.`ic_as`), TriggerAutosensValue(injector).icon()) + Assert.assertEquals(Optional.of(R.drawable.ic_as), TriggerAutosensValue(injector).icon()) } @Before fun mock() { - PowerMockito.mockStatic(DateUtil::class.java) - PowerMockito.`when`(DateUtil.now()).thenReturn(now) + PowerMockito.`when`(dateUtil.now()).thenReturn(now) } private fun generateAutosensData(): AutosensData { diff --git a/automation/src/test/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerBTDeviceTest.kt b/automation/src/test/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerBTDeviceTest.kt index 8cd9a57ab8..47b98b582d 100644 --- a/automation/src/test/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerBTDeviceTest.kt +++ b/automation/src/test/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerBTDeviceTest.kt @@ -15,7 +15,7 @@ class TriggerBTDeviceTest : TriggerTestBase() { var now = 1514766900000L private var someName = "Headset" - private var btJson = "{\"data\":{\"comparator\":\"ON_CONNECT\",\"name\":\"Headset\"},\"type\":\"info.nightscout.androidaps.plugins.general.automation.triggers.TriggerBTDevice\"}" + private var btJson = "{\"data\":{\"comparator\":\"ON_CONNECT\",\"name\":\"Headset\"},\"type\":\"TriggerBTDevice\"}" @Test fun shouldRun() { @Suppress("UNUSED_VARIABLE") diff --git a/automation/src/test/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerBgTest.kt b/automation/src/test/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerBgTest.kt index 41cdcc851a..873364b678 100644 --- a/automation/src/test/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerBgTest.kt +++ b/automation/src/test/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerBgTest.kt @@ -13,7 +13,6 @@ import org.junit.Before import org.junit.Test import org.junit.runner.RunWith import org.mockito.Mockito.`when` -import org.powermock.api.mockito.PowerMockito import org.powermock.core.classloader.annotations.PrepareForTest import org.powermock.modules.junit4.PowerMockRunner import java.util.* @@ -27,14 +26,12 @@ class TriggerBgTest : TriggerTestBase() { @Before fun prepare() { `when`(profileFunction.getUnits()).thenReturn(Constants.MGDL) - `when`(iobCobCalculatorPlugin.dataLock).thenReturn(Unit) - PowerMockito.mockStatic(DateUtil::class.java) - `when`(DateUtil.now()).thenReturn(now) + `when`(dateUtil.now()).thenReturn(now) } @Test fun shouldRunTest() { - `when`(iobCobCalculatorPlugin.bgReadings).thenReturn(generateOneCurrentRecordBgData()) + `when`(autosensDataStore.getBgReadingsDataTableCopy()).thenReturn(generateOneCurrentRecordBgData()) var t: TriggerBg = TriggerBg(injector).setUnits(Constants.MMOL).setValue(4.1).comparator(Comparator.Compare.IS_EQUAL) Assert.assertFalse(t.shouldRun()) t = TriggerBg(injector).setUnits(Constants.MGDL).setValue(214.0).comparator(Comparator.Compare.IS_EQUAL) @@ -53,7 +50,7 @@ class TriggerBgTest : TriggerTestBase() { Assert.assertTrue(t.shouldRun()) t = TriggerBg(injector).setUnits(Constants.MGDL).setValue(213.0).comparator(Comparator.Compare.IS_EQUAL_OR_LESSER) Assert.assertFalse(t.shouldRun()) - `when`(iobCobCalculatorPlugin.bgReadings).thenReturn(ArrayList()) + `when`(autosensDataStore.getBgReadingsDataTableCopy()).thenReturn(ArrayList()) t = TriggerBg(injector).setUnits(Constants.MGDL).setValue(213.0).comparator(Comparator.Compare.IS_EQUAL_OR_LESSER) Assert.assertFalse(t.shouldRun()) t = TriggerBg(injector).comparator(Comparator.Compare.IS_NOT_AVAILABLE) @@ -69,7 +66,7 @@ class TriggerBgTest : TriggerTestBase() { Assert.assertEquals(Comparator.Compare.IS_EQUAL_OR_LESSER, t.comparator.value) } - private var bgJson = "{\"data\":{\"comparator\":\"IS_EQUAL\",\"bg\":4.1,\"units\":\"mmol\"},\"type\":\"info.nightscout.androidaps.plugins.general.automation.triggers.TriggerBg\"}" + private var bgJson = "{\"data\":{\"comparator\":\"IS_EQUAL\",\"bg\":4.1,\"units\":\"mmol\"},\"type\":\"TriggerBg\"}" @Test fun toJSONTest() { diff --git a/automation/src/test/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerBolusAgoTest.kt b/automation/src/test/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerBolusAgoTest.kt index 1394801ce1..29beab1464 100644 --- a/automation/src/test/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerBolusAgoTest.kt +++ b/automation/src/test/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerBolusAgoTest.kt @@ -2,6 +2,7 @@ package info.nightscout.androidaps.plugins.general.automation.triggers import com.google.common.base.Optional import info.nightscout.androidaps.automation.R +import info.nightscout.androidaps.database.entities.Bolus import info.nightscout.androidaps.plugins.general.automation.elements.Comparator import info.nightscout.androidaps.utils.DateUtil import org.json.JSONException @@ -23,14 +24,19 @@ class TriggerBolusAgoTest : TriggerTestBase() { @Before fun mock() { - PowerMockito.mockStatic(DateUtil::class.java) - PowerMockito.`when`(DateUtil.now()).thenReturn(now) + PowerMockito.`when`(dateUtil.now()).thenReturn(now) } @Test fun shouldRunTest() { - `when`(treatmentsInterface.getLastBolusTime(true)).thenReturn(now) // Set last bolus time to now - `when`(DateUtil.now()).thenReturn(now + 10 * 60 * 1000) // set current time to now + 10 min + `when`(repository.getLastBolusRecordOfType(Bolus.Type.NORMAL)).thenReturn( + Bolus( + timestamp = now, + amount = 0.0, + type = Bolus.Type.NORMAL + ) + ) // Set last bolus time to now + `when`(dateUtil.now()).thenReturn(now + 10 * 60 * 1000) // set current time to now + 10 min var t = TriggerBolusAgo(injector).setValue(110).comparator(Comparator.Compare.IS_EQUAL) Assert.assertEquals(110, t.minutesAgo.value) Assert.assertEquals(Comparator.Compare.IS_EQUAL, t.comparator.value) @@ -52,7 +58,13 @@ class TriggerBolusAgoTest : TriggerTestBase() { Assert.assertTrue(t.shouldRun()) t = TriggerBolusAgo(injector).setValue(390).comparator(Comparator.Compare.IS_EQUAL_OR_LESSER) Assert.assertTrue(t.shouldRun()) - PowerMockito.`when`(treatmentsInterface.getLastBolusTime(true)).thenReturn(0L) // Set last bolus time to 0 + `when`(repository.getLastBolusRecordOfType(Bolus.Type.NORMAL)).thenReturn( + Bolus( + timestamp = 0L, + amount = 0.0, + type = Bolus.Type.NORMAL + ) + ) // Set last bolus time to 0 t = TriggerBolusAgo(injector).comparator(Comparator.Compare.IS_NOT_AVAILABLE) Assert.assertTrue(t.shouldRun()) } @@ -64,7 +76,7 @@ class TriggerBolusAgoTest : TriggerTestBase() { Assert.assertEquals(Comparator.Compare.IS_EQUAL_OR_LESSER, t.comparator.value) } - private var lbJson = "{\"data\":{\"comparator\":\"IS_EQUAL\",\"minutesAgo\":410},\"type\":\"info.nightscout.androidaps.plugins.general.automation.triggers.TriggerBolusAgo\"}" + private var lbJson = "{\"data\":{\"comparator\":\"IS_EQUAL\",\"minutesAgo\":410},\"type\":\"TriggerBolusAgo\"}" @Test fun toJSONTest() { val t: TriggerBolusAgo = TriggerBolusAgo(injector).setValue(410).comparator(Comparator.Compare.IS_EQUAL) Assert.assertEquals(lbJson, t.toJSON()) diff --git a/automation/src/test/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerCOBTest.kt b/automation/src/test/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerCOBTest.kt index ae14c4db6d..d67fb0a109 100644 --- a/automation/src/test/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerCOBTest.kt +++ b/automation/src/test/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerCOBTest.kt @@ -22,14 +22,13 @@ class TriggerCOBTest : TriggerTestBase() { var now = 1514766900000L @Before fun mock() { - PowerMockito.mockStatic(DateUtil::class.java) - PowerMockito.`when`(DateUtil.now()).thenReturn(now) + PowerMockito.`when`(dateUtil.now()).thenReturn(now) PowerMockito.`when`(sp.getInt(ArgumentMatchers.anyInt(), ArgumentMatchers.anyInt())).thenReturn(48) } @Test fun shouldRunTest() { // COB value is 6 - PowerMockito.`when`(iobCobCalculatorPlugin.getCobInfo(false, "AutomationTriggerCOB")).thenReturn(CobInfo(6.0, 2.0)) + PowerMockito.`when`(iobCobCalculator.getCobInfo(false, "AutomationTriggerCOB")).thenReturn(CobInfo(6.0, 2.0)) var t: TriggerCOB = TriggerCOB(injector).setValue(1.0).comparator(Comparator.Compare.IS_EQUAL) Assert.assertFalse(t.shouldRun()) t = TriggerCOB(injector).setValue(6.0).comparator(Comparator.Compare.IS_EQUAL) @@ -54,7 +53,7 @@ class TriggerCOBTest : TriggerTestBase() { Assert.assertEquals(Comparator.Compare.IS_EQUAL_OR_LESSER, t.comparator.value) } - private var bgJson = "{\"data\":{\"comparator\":\"IS_EQUAL\",\"carbs\":4},\"type\":\"info.nightscout.androidaps.plugins.general.automation.triggers.TriggerCOB\"}" + private var bgJson = "{\"data\":{\"comparator\":\"IS_EQUAL\",\"carbs\":4},\"type\":\"TriggerCOB\"}" @Test fun toJSONTest() { val t: TriggerCOB = TriggerCOB(injector).setValue(4.0).comparator(Comparator.Compare.IS_EQUAL) Assert.assertEquals(bgJson, t.toJSON()) diff --git a/automation/src/test/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerConnectorTest.kt b/automation/src/test/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerConnectorTest.kt index 386e77b89f..74754f924e 100644 --- a/automation/src/test/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerConnectorTest.kt +++ b/automation/src/test/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerConnectorTest.kt @@ -77,7 +77,7 @@ class TriggerConnectorTest : TriggerTestBase() { } companion object { - const val empty = "{\"data\":{\"connectorType\":\"AND\",\"triggerList\":[]},\"type\":\"info.nightscout.androidaps.plugins.general.automation.triggers.TriggerConnector\"}" - const val oneItem = "{\"data\":{\"connectorType\":\"AND\",\"triggerList\":[\"{\\\"data\\\":{\\\"connectorType\\\":\\\"AND\\\",\\\"triggerList\\\":[]},\\\"type\\\":\\\"info.nightscout.androidaps.plugins.general.automation.triggers.TriggerConnector\\\"}\"]},\"type\":\"info.nightscout.androidaps.plugins.general.automation.triggers.TriggerConnector\"}" + const val empty = "{\"data\":{\"connectorType\":\"AND\",\"triggerList\":[]},\"type\":\"TriggerConnector\"}" + const val oneItem = "{\"data\":{\"connectorType\":\"AND\",\"triggerList\":[\"{\\\"data\\\":{\\\"connectorType\\\":\\\"AND\\\",\\\"triggerList\\\":[]},\\\"type\\\":\\\"TriggerConnector\\\"}\"]},\"type\":\"TriggerConnector\"}" } } \ No newline at end of file diff --git a/automation/src/test/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerDeltaTest.kt b/automation/src/test/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerDeltaTest.kt index 9636d999bd..2cb030d190 100644 --- a/automation/src/test/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerDeltaTest.kt +++ b/automation/src/test/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerDeltaTest.kt @@ -20,21 +20,19 @@ import org.powermock.modules.junit4.PowerMockRunner import java.util.* @RunWith(PowerMockRunner::class) -@PrepareForTest(DateUtil::class, ProfileFunction::class) +@PrepareForTest(DateUtil::class, ProfileFunction::class) class TriggerDeltaTest : TriggerTestBase() { var now = 1514766900000L @Before fun mock() { - PowerMockito.mockStatic(DateUtil::class.java) - PowerMockito.`when`(DateUtil.now()).thenReturn(now) - `when`(iobCobCalculatorPlugin.dataLock).thenReturn(Unit) + PowerMockito.`when`(dateUtil.now()).thenReturn(now) `when`(profileFunction.getUnits()).thenReturn(Constants.MGDL) } @Test fun shouldRunTest() { - `when`(iobCobCalculatorPlugin.bgReadings).thenReturn(generateValidBgData()) + `when`(autosensDataStore.getBgReadingsDataTableCopy()).thenReturn(generateValidBgData()) var t = TriggerDelta(injector).units(Constants.MGDL).setValue(73.0, DeltaType.LONG_AVERAGE).comparator(Comparator.Compare.IS_EQUAL) Assert.assertFalse(t.shouldRun()) Assert.assertEquals(DeltaType.LONG_AVERAGE, t.delta.deltaType) @@ -56,7 +54,7 @@ class TriggerDeltaTest : TriggerTestBase() { Assert.assertFalse(t.shouldRun()) t = TriggerDelta(injector).units(Constants.MGDL).setValue(-0.2, DeltaType.LONG_AVERAGE).comparator(Comparator.Compare.IS_EQUAL_OR_LESSER) Assert.assertTrue(t.shouldRun()) - `when`(iobCobCalculatorPlugin.bgReadings).thenReturn(ArrayList()) + `when`(autosensDataStore.getBgReadingsDataTableCopy()).thenReturn(ArrayList()) t = TriggerDelta(injector).units(Constants.MGDL).setValue(213.0, DeltaType.DELTA).comparator(Comparator.Compare.IS_EQUAL_OR_LESSER) Assert.assertFalse(t.shouldRun()) t = TriggerDelta(injector).comparator(Comparator.Compare.IS_NOT_AVAILABLE) @@ -72,7 +70,7 @@ class TriggerDeltaTest : TriggerTestBase() { Assert.assertEquals(Comparator.Compare.IS_EQUAL_OR_LESSER, t.comparator.value) } - private var deltaJson = "{\"data\":{\"comparator\":\"IS_EQUAL\",\"deltaType\":\"DELTA\",\"units\":\"mg/dl\",\"value\":4.1},\"type\":\"info.nightscout.androidaps.plugins.general.automation.triggers.TriggerDelta\"}" + private var deltaJson = "{\"data\":{\"comparator\":\"IS_EQUAL\",\"deltaType\":\"DELTA\",\"units\":\"mg/dl\",\"value\":4.1},\"type\":\"TriggerDelta\"}" @Test fun toJSONTest() { diff --git a/automation/src/test/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerIobTest.kt b/automation/src/test/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerIobTest.kt index 8a2961bc17..af3a608550 100644 --- a/automation/src/test/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerIobTest.kt +++ b/automation/src/test/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerIobTest.kt @@ -3,7 +3,6 @@ package info.nightscout.androidaps.plugins.general.automation.triggers import com.google.common.base.Optional import info.nightscout.androidaps.automation.R import info.nightscout.androidaps.data.IobTotal -import info.nightscout.androidaps.data.Profile import info.nightscout.androidaps.plugins.general.automation.elements.Comparator import info.nightscout.androidaps.utils.DateUtil import org.json.JSONObject @@ -13,7 +12,6 @@ import org.junit.Test import org.junit.runner.RunWith import org.mockito.ArgumentMatchers import org.mockito.Mockito.`when` -import org.powermock.api.mockito.PowerMockito import org.powermock.core.classloader.annotations.PrepareForTest import org.powermock.modules.junit4.PowerMockRunner @@ -24,13 +22,12 @@ class TriggerIobTest : TriggerTestBase() { var now = 1514766900000L @Before fun mock() { - PowerMockito.mockStatic(DateUtil::class.java) - `when`(DateUtil.now()).thenReturn(now) + `when`(dateUtil.now()).thenReturn(now) `when`(profileFunction.getProfile()).thenReturn(validProfile) } @Test fun shouldRunTest() { - `when`(iobCobCalculatorPlugin.calculateFromTreatmentsAndTempsSynchronized(ArgumentMatchers.anyLong(), ArgumentMatchers.any(Profile::class.java))).thenReturn(generateIobRecordData()) + `when`(iobCobCalculator.calculateFromTreatmentsAndTemps(ArgumentMatchers.anyLong(), anyObject())).thenReturn(generateIobRecordData()) var t: TriggerIob = TriggerIob(injector).setValue(1.1).comparator(Comparator.Compare.IS_EQUAL) Assert.assertFalse(t.shouldRun()) t = TriggerIob(injector).setValue(1.0).comparator(Comparator.Compare.IS_EQUAL) @@ -57,7 +54,7 @@ class TriggerIobTest : TriggerTestBase() { Assert.assertEquals(Comparator.Compare.IS_EQUAL_OR_LESSER, t.comparator.value) } - private var bgJson = "{\"data\":{\"comparator\":\"IS_EQUAL\",\"insulin\":4.1},\"type\":\"info.nightscout.androidaps.plugins.general.automation.triggers.TriggerIob\"}" + private var bgJson = "{\"data\":{\"comparator\":\"IS_EQUAL\",\"insulin\":4.1},\"type\":\"TriggerIob\"}" @Test fun toJSONTest() { val t: TriggerIob = TriggerIob(injector).setValue(4.1).comparator(Comparator.Compare.IS_EQUAL) Assert.assertEquals(bgJson, t.toJSON()) diff --git a/automation/src/test/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerLocationTest.kt b/automation/src/test/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerLocationTest.kt index 3fa5319d88..c533c8f257 100644 --- a/automation/src/test/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerLocationTest.kt +++ b/automation/src/test/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerLocationTest.kt @@ -24,9 +24,8 @@ class TriggerLocationTest : TriggerTestBase() { var now = 1514766900000L @Before fun mock() { - PowerMockito.mockStatic(DateUtil::class.java) PowerMockito.mockStatic(LocationService::class.java) - `when`(DateUtil.now()).thenReturn(now) + `when`(dateUtil.now()).thenReturn(now) PowerMockito.spy(LocationService::class.java) `when`(locationDataContainer.lastLocation).thenReturn(mockedLocation()) } @@ -73,7 +72,7 @@ class TriggerLocationTest : TriggerTestBase() { // Currently unavailable due to problems with Location mocking } - private var locationJson = "{\"data\":{\"mode\":\"OUTSIDE\",\"distance\":2,\"latitude\":213,\"name\":\"\",\"longitude\":212},\"type\":\"info.nightscout.androidaps.plugins.general.automation.triggers.TriggerLocation\"}" + private var locationJson = "{\"data\":{\"mode\":\"OUTSIDE\",\"distance\":2,\"latitude\":213,\"name\":\"\",\"longitude\":212},\"type\":\"TriggerLocation\"}" @Test fun toJSONTest() { val t = TriggerLocation(injector) t.latitude.setValue(213.0) diff --git a/automation/src/test/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerProfilePercentTest.kt b/automation/src/test/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerProfilePercentTest.kt index 896e036c3a..27c910ca78 100644 --- a/automation/src/test/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerProfilePercentTest.kt +++ b/automation/src/test/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerProfilePercentTest.kt @@ -23,8 +23,7 @@ class TriggerProfilePercentTest : TriggerTestBase() { @Before fun mock() { `when`(profileFunction.getProfile()).thenReturn(validProfile) - PowerMockito.mockStatic(DateUtil::class.java) - PowerMockito.`when`(DateUtil.now()).thenReturn(now) + PowerMockito.`when`(dateUtil.now()).thenReturn(now) } @Test fun shouldRunTest() { @@ -55,7 +54,7 @@ class TriggerProfilePercentTest : TriggerTestBase() { Assert.assertEquals(Comparator.Compare.IS_EQUAL_OR_LESSER, t.comparator.value) } - private val bgJson = "{\"data\":{\"comparator\":\"IS_EQUAL\",\"percentage\":110},\"type\":\"info.nightscout.androidaps.plugins.general.automation.triggers.TriggerProfilePercent\"}" + private val bgJson = "{\"data\":{\"comparator\":\"IS_EQUAL\",\"percentage\":110},\"type\":\"TriggerProfilePercent\"}" @Test fun toJSONTest() { val t: TriggerProfilePercent = TriggerProfilePercent(injector).setValue(110.0).comparator(Comparator.Compare.IS_EQUAL) Assert.assertEquals(bgJson, t.toJSON()) diff --git a/automation/src/test/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerPumpLastConnectionTest.kt b/automation/src/test/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerPumpLastConnectionTest.kt index 3c3d5f131b..bddce94217 100644 --- a/automation/src/test/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerPumpLastConnectionTest.kt +++ b/automation/src/test/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerPumpLastConnectionTest.kt @@ -21,8 +21,7 @@ class TriggerPumpLastConnectionTest : TriggerTestBase() { @Before fun mock() { - PowerMockito.mockStatic(DateUtil::class.java) - PowerMockito.`when`(DateUtil.now()).thenReturn(now) + PowerMockito.`when`(dateUtil.now()).thenReturn(now) } @Test @@ -30,7 +29,7 @@ class TriggerPumpLastConnectionTest : TriggerTestBase() { // System.currentTimeMillis() is always 0 // and so is every last connection time Assert.assertEquals(0L, testPumpPlugin.lastDataTime()) - PowerMockito.`when`(DateUtil.now()).thenReturn(now + 10 * 60 * 1000) // set current time to now + 10 min + PowerMockito.`when`(dateUtil.now()).thenReturn(now + 10 * 60 * 1000) // set current time to now + 10 min var t = TriggerPumpLastConnection(injector).setValue(110).comparator(Comparator.Compare.IS_EQUAL) Assert.assertEquals(110, t.minutesAgo.value) Assert.assertEquals(Comparator.Compare.IS_EQUAL, t.comparator.value) @@ -53,7 +52,7 @@ class TriggerPumpLastConnectionTest : TriggerTestBase() { Assert.assertEquals(Comparator.Compare.IS_EQUAL_OR_LESSER, t.comparator.value) } - private var lbJson = "{\"data\":{\"comparator\":\"IS_EQUAL\",\"minutesAgo\":410},\"type\":\"info.nightscout.androidaps.plugins.general.automation.triggers.TriggerPumpLastConnection\"}" + private var lbJson = "{\"data\":{\"comparator\":\"IS_EQUAL\",\"minutesAgo\":410},\"type\":\"TriggerPumpLastConnection\"}" @Test fun toJSONTest() { val t: TriggerPumpLastConnection = TriggerPumpLastConnection(injector).setValue(410).comparator(Comparator.Compare.IS_EQUAL) Assert.assertEquals(lbJson, t.toJSON()) diff --git a/automation/src/test/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerRecurringTimeTest.kt b/automation/src/test/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerRecurringTimeTest.kt index d23b8e8428..e764e22747 100644 --- a/automation/src/test/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerRecurringTimeTest.kt +++ b/automation/src/test/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerRecurringTimeTest.kt @@ -20,7 +20,7 @@ class TriggerRecurringTimeTest : TriggerTestBase() { @Before fun mock() { now = MidnightTime.calc() + T.mins(95).msecs() // 95 min from midnight - PowerMockito.`when`(dateUtil._now()).thenReturn(now) + PowerMockito.`when`(dateUtil.now()).thenReturn(now) } @Test fun shouldRunTest() { @@ -35,7 +35,7 @@ class TriggerRecurringTimeTest : TriggerTestBase() { Assert.assertTrue(t.shouldRun()) } - private var timeJson = "{\"data\":{\"WEDNESDAY\":false,\"MONDAY\":false,\"THURSDAY\":false,\"SUNDAY\":false,\"TUESDAY\":false,\"FRIDAY\":false,\"SATURDAY\":false,\"time\":4444},\"type\":\"info.nightscout.androidaps.plugins.general.automation.triggers.TriggerRecurringTime\"}" + private var timeJson = "{\"data\":{\"WEDNESDAY\":false,\"MONDAY\":false,\"THURSDAY\":false,\"SUNDAY\":false,\"TUESDAY\":false,\"FRIDAY\":false,\"SATURDAY\":false,\"time\":4444},\"type\":\"TriggerRecurringTime\"}" @Test fun toJSONTest() { diff --git a/automation/src/test/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerTempTargetTest.kt b/automation/src/test/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerTempTargetTest.kt index 5eac61c320..64ba71fd14 100644 --- a/automation/src/test/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerTempTargetTest.kt +++ b/automation/src/test/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerTempTargetTest.kt @@ -20,8 +20,7 @@ class TriggerTempTargetTest : TriggerTestBase() { var now = 1514766900000L @Before fun mock() { - PowerMockito.mockStatic(DateUtil::class.java) - PowerMockito.`when`(DateUtil.now()).thenReturn(now) + PowerMockito.`when`(dateUtil.now()).thenReturn(now) } /* @Test fun shouldRunTest() { @@ -43,7 +42,7 @@ class TriggerTempTargetTest : TriggerTestBase() { Assert.assertEquals(ComparatorExists.Compare.NOT_EXISTS, t1.comparator.value) } - private var ttJson = "{\"data\":{\"comparator\":\"EXISTS\"},\"type\":\"info.nightscout.androidaps.plugins.general.automation.triggers.TriggerTempTarget\"}" + private var ttJson = "{\"data\":{\"comparator\":\"EXISTS\"},\"type\":\"TriggerTempTarget\"}" @Test fun toJSONTest() { val t: TriggerTempTarget = TriggerTempTarget(injector).comparator(ComparatorExists.Compare.EXISTS) Assert.assertEquals(ttJson, t.toJSON()) diff --git a/automation/src/test/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerTestBase.kt b/automation/src/test/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerTestBase.kt index fe3538d319..21c8090bd9 100644 --- a/automation/src/test/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerTestBase.kt +++ b/automation/src/test/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerTestBase.kt @@ -5,16 +5,12 @@ import dagger.android.AndroidInjector import dagger.android.HasAndroidInjector import info.nightscout.androidaps.TestBaseWithProfile import info.nightscout.androidaps.TestPumpPlugin -import info.nightscout.androidaps.database.AppRepository -import info.nightscout.androidaps.interfaces.ActivePluginProvider -import info.nightscout.androidaps.interfaces.IobCobCalculatorInterface +import info.nightscout.androidaps.interfaces.ActivePlugin +import info.nightscout.androidaps.interfaces.IobCobCalculator import info.nightscout.androidaps.interfaces.PluginDescription import info.nightscout.androidaps.plugins.bus.RxBusWrapper import info.nightscout.androidaps.plugins.general.automation.AutomationPlugin -import info.nightscout.androidaps.plugins.general.automation.elements.InputBg -import info.nightscout.androidaps.plugins.general.automation.elements.InputTempTarget -import info.nightscout.androidaps.plugins.general.automation.elements.StaticLabel -import info.nightscout.androidaps.plugins.iob.iobCobCalculator.GlucoseStatus +import info.nightscout.androidaps.plugins.iob.iobCobCalculator.AutosensDataStore import info.nightscout.androidaps.plugins.iob.iobCobCalculator.GlucoseStatusProvider import info.nightscout.androidaps.receivers.ReceiverStatusStore import info.nightscout.androidaps.services.LastLocationDataContainer @@ -24,26 +20,27 @@ import org.mockito.Mock import org.mockito.Mockito.`when` import org.powermock.core.classloader.annotations.PrepareForTest -@PrepareForTest(LastLocationDataContainer::class, AutomationPlugin::class, AppRepository::class) +@PrepareForTest(LastLocationDataContainer::class, AutomationPlugin::class, AutosensDataStore::class) open class TriggerTestBase : TestBaseWithProfile() { @Mock lateinit var sp: SP @Mock lateinit var locationDataContainer: LastLocationDataContainer - @Mock lateinit var activePlugin: ActivePluginProvider - @Mock lateinit var iobCobCalculatorPlugin: IobCobCalculatorInterface + @Mock lateinit var activePlugin: ActivePlugin + @Mock lateinit var iobCobCalculator: IobCobCalculator + @Mock lateinit var autosensDataStore: AutosensDataStore @Mock lateinit var context: Context @Mock lateinit var automationPlugin: AutomationPlugin - @Mock lateinit var repository: AppRepository lateinit var receiverStatusStore: ReceiverStatusStore private val pluginDescription = PluginDescription() - lateinit var testPumpPlugin : TestPumpPlugin + lateinit var testPumpPlugin: TestPumpPlugin @Before fun prepareMock1() { receiverStatusStore = ReceiverStatusStore(context, rxBus) testPumpPlugin = TestPumpPlugin(pluginDescription, aapsLogger, resourceHelper, injector) `when`(activePlugin.activePump).thenReturn(testPumpPlugin) + `when`(iobCobCalculator.ads).thenReturn(autosensDataStore) } var injector: HasAndroidInjector = HasAndroidInjector { @@ -55,10 +52,11 @@ open class TriggerTestBase : TestBaseWithProfile() { it.profileFunction = profileFunction it.sp = sp it.locationDataContainer = locationDataContainer - it.treatmentsInterface = treatmentsInterface + it.repository = repository it.activePlugin = activePlugin - it.iobCobCalculatorPlugin = iobCobCalculatorPlugin - it.glucoseStatusProvider = GlucoseStatusProvider(aapsLogger, iobCobCalculatorPlugin) + it.iobCobCalculator = iobCobCalculator + it.glucoseStatusProvider = GlucoseStatusProvider(aapsLogger, iobCobCalculator, dateUtil) + it.dateUtil = dateUtil } if (it is TriggerBg) { it.profileFunction = profileFunction diff --git a/automation/src/test/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerTimeRangeTest.kt b/automation/src/test/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerTimeRangeTest.kt index af5a9ea355..3e01059aa6 100644 --- a/automation/src/test/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerTimeRangeTest.kt +++ b/automation/src/test/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerTimeRangeTest.kt @@ -18,13 +18,12 @@ import org.powermock.modules.junit4.PowerMockRunner class TriggerTimeRangeTest : TriggerTestBase() { var now = 754 // in minutes from midnight - private var timeJson = "{\"data\":{\"start\":753,\"end\":784},\"type\":\"info.nightscout.androidaps.plugins.general.automation.triggers.TriggerTimeRange\"}" + private var timeJson = "{\"data\":{\"start\":753,\"end\":784},\"type\":\"TriggerTimeRange\"}" @Before fun mock() { - PowerMockito.mockStatic(DateUtil::class.java) val nowMills = MidnightTime.calcPlusMinutes(now) - PowerMockito.`when`(DateUtil.now()).thenReturn(nowMills) + PowerMockito.`when`(dateUtil.now()).thenReturn(nowMills) } @Test diff --git a/automation/src/test/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerTimeTest.kt b/automation/src/test/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerTimeTest.kt index db6a2dd645..8c38c37761 100644 --- a/automation/src/test/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerTimeTest.kt +++ b/automation/src/test/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerTimeTest.kt @@ -21,8 +21,7 @@ class TriggerTimeTest : TriggerTestBase() { var now = 1514766900000L @Before fun mock() { - PowerMockito.mockStatic(DateUtil::class.java) - PowerMockito.`when`(DateUtil.now()).thenReturn(now) + PowerMockito.`when`(dateUtil.now()).thenReturn(now) } @Test fun shouldRunTest() { @@ -36,7 +35,7 @@ class TriggerTimeTest : TriggerTestBase() { Assert.assertFalse(t.shouldRun()) } - private var timeJson = "{\"data\":{\"runAt\":1514766840000},\"type\":\"info.nightscout.androidaps.plugins.general.automation.triggers.TriggerTime\"}" + private var timeJson = "{\"data\":{\"runAt\":1514766840000},\"type\":\"TriggerTime\"}" @Test fun toJSONTest() { val t: TriggerTime = TriggerTime(injector).runAt(now - T.mins(1).msecs()) Assert.assertEquals(timeJson, t.toJSON()) diff --git a/automation/src/test/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerWifiSsidTest.kt b/automation/src/test/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerWifiSsidTest.kt index 9cd013008a..4b38476f98 100644 --- a/automation/src/test/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerWifiSsidTest.kt +++ b/automation/src/test/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerWifiSsidTest.kt @@ -24,8 +24,7 @@ class TriggerWifiSsidTest : TriggerTestBase() { @Before fun mock() { PowerMockito.mockStatic(NetworkChangeReceiver::class.java) - PowerMockito.mockStatic(DateUtil::class.java) - PowerMockito.`when`(DateUtil.now()).thenReturn(now) + PowerMockito.`when`(dateUtil.now()).thenReturn(now) } @Test fun shouldRunTest() { @@ -56,7 +55,7 @@ class TriggerWifiSsidTest : TriggerTestBase() { Assert.assertEquals(Comparator.Compare.IS_EQUAL_OR_LESSER, t.comparator.value) } - var json = "{\"data\":{\"comparator\":\"IS_EQUAL\",\"ssid\":\"aSSID\"},\"type\":\"info.nightscout.androidaps.plugins.general.automation.triggers.TriggerWifiSsid\"}" + var json = "{\"data\":{\"comparator\":\"IS_EQUAL\",\"ssid\":\"aSSID\"},\"type\":\"TriggerWifiSsid\"}" @Test fun toJSONTest() { val t: TriggerWifiSsid = TriggerWifiSsid(injector).setValue("aSSID").comparator(Comparator.Compare.IS_EQUAL) Assert.assertEquals(json, t.toJSON()) diff --git a/combo/build.gradle b/combo/build.gradle index 55565f892b..8020051b31 100644 --- a/combo/build.gradle +++ b/combo/build.gradle @@ -17,5 +17,4 @@ android { dependencies { implementation project(':core') - implementation project(':database') } \ No newline at end of file diff --git a/combo/src/main/java/info/nightscout/androidaps/plugins/pump/combo/ComboFragment.java b/combo/src/main/java/info/nightscout/androidaps/plugins/pump/combo/ComboFragment.java index d2358de9d7..159e637eaa 100644 --- a/combo/src/main/java/info/nightscout/androidaps/plugins/pump/combo/ComboFragment.java +++ b/combo/src/main/java/info/nightscout/androidaps/plugins/pump/combo/ComboFragment.java @@ -37,6 +37,7 @@ public class ComboFragment extends DaggerFragment { @Inject ResourceHelper resourceHelper; @Inject RxBusWrapper rxBus; @Inject SP sp; + @Inject DateUtil dateUtil; @Inject FabricPrivacy fabricPrivacy; @Inject AapsSchedulers aapsSchedulers; @@ -192,7 +193,7 @@ public class ComboFragment extends DaggerFragment { } // last connection - String minAgo = DateUtil.minAgo(resourceHelper, comboPlugin.getPump().lastSuccessfulCmdTime); + String minAgo = dateUtil.minAgo(resourceHelper, comboPlugin.getPump().lastSuccessfulCmdTime); long min = (System.currentTimeMillis() - comboPlugin.getPump().lastSuccessfulCmdTime) / 1000 / 60; if (comboPlugin.getPump().lastSuccessfulCmdTime + 60 * 1000 > System.currentTimeMillis()) { lastConnectionView.setText(R.string.combo_pump_connected_now); @@ -215,9 +216,9 @@ public class ComboFragment extends DaggerFragment { if ((agoMsc < 60 * 1000)) { ago = resourceHelper.gs(R.string.combo_pump_connected_now); } else if (bolusMinAgo < 60) { - ago = DateUtil.minAgo(resourceHelper, bolus.timestamp); + ago = dateUtil.minAgo(resourceHelper, bolus.timestamp); } else { - ago = DateUtil.hourAgo(bolus.timestamp, resourceHelper); + ago = dateUtil.hourAgo(bolus.timestamp, resourceHelper); } lastBolusView.setText(resourceHelper.gs(R.string.combo_last_bolus, bolus.amount, unit, ago)); } else { diff --git a/combo/src/main/java/info/nightscout/androidaps/plugins/pump/combo/ComboPlugin.java b/combo/src/main/java/info/nightscout/androidaps/plugins/pump/combo/ComboPlugin.java index 8c9f0864ac..1f17b035cc 100644 --- a/combo/src/main/java/info/nightscout/androidaps/plugins/pump/combo/ComboPlugin.java +++ b/combo/src/main/java/info/nightscout/androidaps/plugins/pump/combo/ComboPlugin.java @@ -6,6 +6,7 @@ import android.os.SystemClock; import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import info.nightscout.androidaps.extensions.PumpStateExtensionKt; import org.joda.time.DateTime; import org.json.JSONObject; @@ -25,24 +26,20 @@ import info.nightscout.androidaps.combo.R; import info.nightscout.androidaps.data.DetailedBolusInfo; import info.nightscout.androidaps.data.Profile; import info.nightscout.androidaps.data.PumpEnactResult; -import info.nightscout.androidaps.database.entities.TherapyEvent; -import info.nightscout.androidaps.db.Source; import info.nightscout.androidaps.db.TDD; -import info.nightscout.androidaps.db.TemporaryBasal; -import info.nightscout.androidaps.db.Treatment; import info.nightscout.androidaps.events.EventInitializationChanged; import info.nightscout.androidaps.events.EventRefreshOverview; import info.nightscout.androidaps.interfaces.CommandQueueProvider; import info.nightscout.androidaps.interfaces.Constraint; -import info.nightscout.androidaps.interfaces.ConstraintsInterface; +import info.nightscout.androidaps.interfaces.Constraints; import info.nightscout.androidaps.interfaces.DatabaseHelperInterface; import info.nightscout.androidaps.interfaces.PluginDescription; import info.nightscout.androidaps.interfaces.PluginType; import info.nightscout.androidaps.interfaces.ProfileFunction; import info.nightscout.androidaps.interfaces.PumpDescription; -import info.nightscout.androidaps.interfaces.PumpInterface; +import info.nightscout.androidaps.interfaces.Pump; import info.nightscout.androidaps.interfaces.PumpPluginBase; -import info.nightscout.androidaps.interfaces.TreatmentsInterface; +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; @@ -67,6 +64,7 @@ import info.nightscout.androidaps.plugins.pump.combo.ruffyscripter.history.Tdd; import info.nightscout.androidaps.plugins.pump.common.defs.PumpType; import info.nightscout.androidaps.utils.DateUtil; import info.nightscout.androidaps.utils.InstanceId; +import info.nightscout.androidaps.utils.T; import info.nightscout.androidaps.utils.resources.ResourceHelper; import info.nightscout.androidaps.utils.sharedPreferences.SP; @@ -74,17 +72,18 @@ import info.nightscout.androidaps.utils.sharedPreferences.SP; * Created by mike on 05.08.2016. */ @Singleton -public class ComboPlugin extends PumpPluginBase implements PumpInterface, ConstraintsInterface { +public class ComboPlugin extends PumpPluginBase implements Pump, Constraints { static final String COMBO_TBRS_SET = "combo_tbrs_set"; static final String COMBO_BOLUSES_DELIVERED = "combo_boluses_delivered"; private final ProfileFunction profileFunction; - private final TreatmentsInterface treatmentsPlugin; - private final info.nightscout.androidaps.utils.sharedPreferences.SP sp; + private final SP sp; private RxBusWrapper rxBus; private final CommandQueueProvider commandQueue; private final Context context; private final DatabaseHelperInterface databaseHelper; + private final PumpSync pumpSync; + private final DateUtil dateUtil; private final static PumpDescription pumpDescription = new PumpDescription(); @@ -98,7 +97,7 @@ public class ComboPlugin extends PumpPluginBase implements PumpInterface, Constr */ private volatile boolean scripterIsBolusing; /** - * This is set to true to request a bolus cancellation. {@link #deliverBolus(DetailedBolusInfo)} + * This is set to true to request a bolus cancellation. {@link #deliverTreatment(DetailedBolusInfo)} (DetailedBolusInfo)} * will reset this flag. */ private volatile boolean cancelBolus; @@ -106,8 +105,8 @@ public class ComboPlugin extends PumpPluginBase implements PumpInterface, Constr /** * This is set (in {@link #checkHistory()} whenever a connection to the pump is made and * indicates if new history records on the pump have been found. This effectively blocks - * high temps ({@link #setTempBasalPercent(Integer, Integer)} and boluses - * ({@link #deliverBolus(DetailedBolusInfo)} till the queue is empty and the connection + * high temps ({@link #setTempBasalPercent(Integer, Integer, PumpSync.TemporaryBasalType)} and boluses + * ({@link #deliverTreatment(DetailedBolusInfo)} till the queue is empty and the connection * is shut down. * {@link #initializePump()} resets this since on startup the history is allowed to have * changed (and the user can't possible have already calculated anything with out of date IOB). @@ -122,7 +121,7 @@ public class ComboPlugin extends PumpPluginBase implements PumpInterface, Constr /** * Cache of the last <=2 boluses on the pump. Used to detect changes in pump history, * requiring reading more pump history. This is read/set in {@link #checkHistory()} when changed - * pump history was detected and was read, as well as in {@link #deliverBolus(DetailedBolusInfo)} + * pump history was detected and was read, as well as in {@link #deliverTreatment(DetailedBolusInfo)} * after bolus delivery. Newest record is the first one. */ private volatile List recentBoluses = new ArrayList<>(0); @@ -136,11 +135,12 @@ public class ComboPlugin extends PumpPluginBase implements PumpInterface, Constr RxBusWrapper rxBus, ResourceHelper resourceHelper, ProfileFunction profileFunction, - TreatmentsInterface treatmentsPlugin, SP sp, CommandQueueProvider commandQueue, Context context, - DatabaseHelperInterface databaseHelper + DatabaseHelperInterface databaseHelper, + PumpSync pumpSync, + DateUtil dateUtil ) { super(new PluginDescription() .mainType(PluginType.PUMP) @@ -153,13 +153,14 @@ public class ComboPlugin extends PumpPluginBase implements PumpInterface, Constr ); this.rxBus = rxBus; this.profileFunction = profileFunction; - this.treatmentsPlugin = treatmentsPlugin; this.sp = sp; this.commandQueue = commandQueue; this.context = context; this.databaseHelper = databaseHelper; + this.pumpSync = pumpSync; + this.dateUtil = dateUtil; - pumpDescription.setPumpDescription(PumpType.AccuChekCombo); + pumpDescription.setPumpDescription(PumpType.ACCU_CHEK_COMBO); } @Override protected void onStart() { @@ -474,37 +475,9 @@ public class ComboPlugin extends PumpPluginBase implements PumpInterface, Constr */ @NonNull @Override public PumpEnactResult deliverTreatment(DetailedBolusInfo detailedBolusInfo) { - try { - if (detailedBolusInfo.insulin == 0 && detailedBolusInfo.carbs == 0) { - // neither carbs nor bolus requested - getAapsLogger().error("deliverTreatment: Invalid input"); - return new PumpEnactResult(getInjector()).success(false).enacted(false) - .bolusDelivered(0d).carbsDelivered(0d) - .comment(R.string.invalidinput); - } else if (detailedBolusInfo.insulin > 0) { - // bolus needed, ask pump to deliver it - return deliverBolus(detailedBolusInfo); - } else { - // no bolus required, carb only treatment - treatmentsPlugin.addToHistoryTreatment(detailedBolusInfo, false); - - EventOverviewBolusProgress bolusingEvent = EventOverviewBolusProgress.INSTANCE; - bolusingEvent.setT(new Treatment()); - bolusingEvent.getT().isSMB = detailedBolusInfo.isSMB; - bolusingEvent.setPercent(100); - rxBus.send(bolusingEvent); - - return new PumpEnactResult(getInjector()).success(true).enacted(true) - .bolusDelivered(0d).carbsDelivered(detailedBolusInfo.carbs) - .comment(R.string.virtualpump_resultok); - } - } finally { - rxBus.send(new EventComboPumpUpdateGUI()); + if (detailedBolusInfo.insulin == 0 || detailedBolusInfo.carbs > 0) { + throw new IllegalArgumentException(detailedBolusInfo.toString()); } - } - - @NonNull - private PumpEnactResult deliverBolus(final DetailedBolusInfo detailedBolusInfo) { try { pump.activity = getResourceHelper().gs(R.string.combo_pump_action_bolusing, detailedBolusInfo.insulin); rxBus.send(new EventComboPumpUpdateGUI()); @@ -567,8 +540,7 @@ public class ComboPlugin extends PumpPluginBase implements PumpInterface, Constr return new PumpEnactResult(getInjector()).success(true).enacted(false); } - Treatment treatment = new Treatment(); - treatment.isSMB = detailedBolusInfo.isSMB; + EventOverviewBolusProgress.Treatment treatment = new EventOverviewBolusProgress.Treatment(0.0, 0, detailedBolusInfo.getBolusType() == DetailedBolusInfo.BolusType.SMB); EventOverviewBolusProgress.INSTANCE.setT(treatment); // start bolus delivery @@ -665,29 +637,18 @@ public class ComboPlugin extends PumpPluginBase implements PumpInterface, Constr * Creates a treatment record based on the request in DetailBolusInfo and the delivered bolus. */ private boolean addBolusToTreatments(DetailedBolusInfo detailedBolusInfo, Bolus lastPumpBolus) { - DetailedBolusInfo bolusInfo = detailedBolusInfo.copy(); - bolusInfo.date = calculateFakeBolusDate(lastPumpBolus); - bolusInfo.pumpId = bolusInfo.date; - bolusInfo.source = Source.PUMP; - bolusInfo.insulin = lastPumpBolus.amount; try { - if (bolusInfo.carbs > 0 && bolusInfo.carbTime != 0) { - // split out a separate carbs record without a pumpId - DetailedBolusInfo carbInfo = new DetailedBolusInfo(); - carbInfo.date = bolusInfo.date + bolusInfo.carbTime * 60L * 1000L; - carbInfo.carbs = bolusInfo.carbs; - carbInfo.source = Source.USER; - treatmentsPlugin.addToHistoryTreatment(carbInfo, true); - - // remove carbs from bolusInfo to not trigger any unwanted code paths in - // TreatmentsPlugin.addToHistoryTreatment() method - bolusInfo.carbTime = 0; - bolusInfo.carbs = 0; - } - treatmentsPlugin.addToHistoryTreatment(bolusInfo, true); + pumpSync.syncBolusWithPumpId( + lastPumpBolus.timestamp, + lastPumpBolus.amount, + detailedBolusInfo.getBolusType(), + generatePumpBolusId(lastPumpBolus), + PumpType.ACCU_CHEK_COMBO, + serialNumber() + ); } catch (Exception e) { getAapsLogger().error("Adding treatment record failed", e); - if (bolusInfo.isSMB) { + if (detailedBolusInfo.getBolusType() == DetailedBolusInfo.BolusType.SMB) { Notification notification = new Notification(Notification.COMBO_PUMP_ALARM, getResourceHelper().gs(R.string.combo_error_updating_treatment_record), Notification.URGENT); rxBus.send(new EventNewNotification(notification)); } @@ -714,7 +675,7 @@ public class ComboPlugin extends PumpPluginBase implements PumpInterface, Constr * the new value (and thus still has the old duration of e.g. 1 min) expires?) */ @NonNull @Override - public PumpEnactResult setTempBasalAbsolute(double absoluteRate, int durationInMinutes, @NonNull Profile profile, boolean force) { + public PumpEnactResult setTempBasalAbsolute(double absoluteRate, int durationInMinutes, @NonNull Profile profile, boolean force, @NonNull PumpSync.TemporaryBasalType tbrType) { getAapsLogger().debug(LTag.PUMP, "setTempBasalAbsolute called with a rate of " + absoluteRate + " for " + durationInMinutes + " min."); int unroundedPercentage = Double.valueOf(absoluteRate / getBaseBasalRate() * 100).intValue(); int roundedPercentage = (int) (Math.round(absoluteRate / getBaseBasalRate() * 10) * 10); @@ -722,7 +683,7 @@ public class ComboPlugin extends PumpPluginBase implements PumpInterface, Constr getAapsLogger().debug(LTag.PUMP, "Rounded requested rate " + unroundedPercentage + "% -> " + roundedPercentage + "%"); } - return setTempBasalPercent(roundedPercentage, durationInMinutes); + return setTempBasalPercent(roundedPercentage, durationInMinutes, tbrType); } /** @@ -732,11 +693,11 @@ public class ComboPlugin extends PumpPluginBase implements PumpInterface, Constr * is or isn't running at the moment */ @NonNull @Override - public PumpEnactResult setTempBasalPercent(int percent, int durationInMinutes, @NonNull Profile profile, boolean forceNew) { - return setTempBasalPercent(percent, durationInMinutes); + public PumpEnactResult setTempBasalPercent(int percent, int durationInMinutes, @NonNull Profile profile, boolean forceNew, @NonNull PumpSync.TemporaryBasalType tbrType) { + return setTempBasalPercent(percent, durationInMinutes, tbrType); } - private PumpEnactResult setTempBasalPercent(Integer percent, final Integer durationInMinutes) { + private PumpEnactResult setTempBasalPercent(Integer percent, final Integer durationInMinutes, @NonNull PumpSync.TemporaryBasalType tbrType) { getAapsLogger().debug(LTag.PUMP, "setTempBasalPercent called with " + percent + "% for " + durationInMinutes + "min"); if (pumpHistoryChanged && percent > 110) { @@ -772,12 +733,21 @@ public class ComboPlugin extends PumpPluginBase implements PumpInterface, Constr PumpState state = commandResult.state; if (state.tbrActive && state.tbrPercent == adjustedPercent && (state.tbrRemainingDuration == durationInMinutes || state.tbrRemainingDuration == durationInMinutes - 1)) { - TemporaryBasal tempStart = new TemporaryBasal(getInjector()) - .date(state.timestamp) - .duration(state.tbrRemainingDuration) - .percent(state.tbrPercent) - .source(Source.USER); - treatmentsPlugin.addToHistoryTempBasal(tempStart); + pumpSync.syncTemporaryBasalWithPumpId( + state.timestamp, + state.tbrPercent, + T.mins(state.tbrRemainingDuration).msecs(), + false, + tbrType, + // There are no IDs for TBRs on the pump and none is calculated (in contrast to boluses). + // The current time is used here as an ID, which has no meaning and does not allow identifying + // the record on the pump (which isn't needed), but only needs to be unique. + // Generally, TBR records are created when a TBR is set by AAPS or when a change on the pump has + // been detected, rather than checking the pumps history of TBRs. + state.timestamp, + PumpType.ACCU_CHEK_COMBO, + serialNumber() + ); rxBus.send(new EventComboPumpUpdateGUI()); } @@ -803,7 +773,7 @@ public class ComboPlugin extends PumpPluginBase implements PumpInterface, Constr @NonNull @Override public PumpEnactResult cancelTempBasal(boolean enforceNew) { getAapsLogger().debug(LTag.PUMP, "cancelTempBasal called"); - final TemporaryBasal activeTemp = treatmentsPlugin.getTempBasalFromHistory(System.currentTimeMillis()); + final PumpSync.PumpState.TemporaryBasal activeTemp = pumpSync.expectedPumpState().getTemporaryBasal(); if (enforceNew) { CommandResult stateResult = runCommand(getResourceHelper().gs(R.string.combo_pump_action_refreshing), 2, ruffyScripter::readPumpState); if (!stateResult.success) { @@ -818,32 +788,35 @@ public class ComboPlugin extends PumpPluginBase implements PumpInterface, Constr return new PumpEnactResult(getInjector()).success(false).enacted(false); } if (!cancelResult.state.tbrActive) { - TemporaryBasal tempBasal = new TemporaryBasal(getInjector()) - .date(cancelResult.state.timestamp) - .duration(0) - .source(Source.USER); - treatmentsPlugin.addToHistoryTempBasal(tempBasal); + pumpSync.syncStopTemporaryBasalWithPumpId( + cancelResult.state.timestamp, + // Combo doesn't have nor uses IDs for TBRs, see note in #setTempBasalPercent + cancelResult.state.timestamp, + PumpType.ACCU_CHEK_COMBO, + serialNumber() + ); return new PumpEnactResult(getInjector()).isTempCancel(true).success(true).enacted(true); } else { return new PumpEnactResult(getInjector()).success(false).enacted(false); } } else if (activeTemp == null) { return new PumpEnactResult(getInjector()).success(true).enacted(false); - } else if ((activeTemp.percentRate >= 90 && activeTemp.percentRate <= 110) && activeTemp.getPlannedRemainingMinutes() <= 15) { + } else if ((activeTemp.getRate() >= 90 && activeTemp.getRate() <= 110) + && PumpStateExtensionKt.getPlannedRemainingMinutes(activeTemp) <= 15) { // Let fake neutral temp keep run (see below) // Note that since this runs on the queue a connection is opened regardless, but this // case doesn't occur all that often, so it's not worth optimizing (1.3k SetTBR vs 4 cancelTBR). - getAapsLogger().debug(LTag.PUMP, "cancelTempBasal: skipping changing tbr since it already is at " + activeTemp.percentRate + "% and running for another " + activeTemp.getPlannedRemainingMinutes() + " mins."); + getAapsLogger().debug(LTag.PUMP, "cancelTempBasal: skipping changing tbr since it already is at " + activeTemp.getRate() + "% and running for another " + PumpStateExtensionKt.getPlannedRemainingMinutes(activeTemp) + " mins."); return new PumpEnactResult(getInjector()).success(true).enacted(true) .comment("cancelTempBasal skipping changing tbr since it already is at " - + activeTemp.percentRate + "% and running for another " - + activeTemp.getPlannedRemainingMinutes() + " mins."); + + activeTemp.getRate() + "% and running for another " + + PumpStateExtensionKt.getPlannedRemainingMinutes(activeTemp) + " mins."); } else { // Set a fake neutral temp to avoid TBR cancel alert. Decide 90% vs 110% based on // on whether the TBR we're cancelling is above or below 100%. - final int percentage = (activeTemp.percentRate > 100) ? 110 : 90; + final int percentage = (activeTemp.getRate() > 100) ? 110 : 90; getAapsLogger().debug(LTag.PUMP, "cancelTempBasal: changing TBR to " + percentage + "% for 15 mins."); - return setTempBasalPercent(percentage, 15); + return setTempBasalPercent(percentage, 15, PumpSync.TemporaryBasalType.NORMAL); } } @@ -949,7 +922,7 @@ public class ComboPlugin extends PumpPluginBase implements PumpInterface, Constr // so update the var with it, so the check routines below can work on it preCheckResult = alertConfirmationResult; } else if (activeAlert.errorCode != null) { - Notification notification = new Notification(Notification.COMBO_PUMP_ALARM, DateUtil.now(), getResourceHelper().gs(R.string.combo_is_in_error_state, activeAlert.errorCode, activeAlert.message), Notification.URGENT, 0); + Notification notification = new Notification(Notification.COMBO_PUMP_ALARM, dateUtil.now(), getResourceHelper().gs(R.string.combo_is_in_error_state, activeAlert.errorCode, activeAlert.message), Notification.URGENT, 0); rxBus.send(new EventNewNotification(notification)); return preCheckResult.success(false); } @@ -963,15 +936,20 @@ public class ComboPlugin extends PumpPluginBase implements PumpInterface, Constr return checkHistory(); } else { long now = System.currentTimeMillis(); - TemporaryBasal aapsTbr = treatmentsPlugin.getTempBasalFromHistory(now); - if (aapsTbr == null || aapsTbr.percentRate != 0) { + PumpSync.PumpState.TemporaryBasal aapsTbr = pumpSync.expectedPumpState().getTemporaryBasal(); + if (aapsTbr == null || aapsTbr.getRate() != 0) { getAapsLogger().debug(LTag.PUMP, "Creating 15m zero temp since pump is suspended"); - TemporaryBasal newTempBasal = new TemporaryBasal(getInjector()) - .date(now) - .percent(0) - .duration(15) - .source(Source.USER); - treatmentsPlugin.addToHistoryTempBasal(newTempBasal); + pumpSync.syncTemporaryBasalWithPumpId( + now, + 0.0, + T.mins(15).msecs(), + false, + PumpSync.TemporaryBasalType.PUMP_SUSPEND, + // Combo doesn't have nor uses IDs for TBRs, see note in #setTempBasalPercent + now, + PumpType.ACCU_CHEK_COMBO, + serialNumber() + ); } } @@ -1043,7 +1021,7 @@ public class ComboPlugin extends PumpPluginBase implements PumpInterface, Constr throw new IllegalArgumentException(activeAlert.toString()); } Notification notification = new Notification(); - notification.setDate(DateUtil.now()); + notification.setDate(dateUtil.now()); notification.setId(Notification.COMBO_PUMP_ALARM); notification.setLevel(Notification.NORMAL); if (activeAlert.warningCode == PumpWarningCodes.CARTRIDGE_LOW) { @@ -1089,38 +1067,55 @@ public class ComboPlugin extends PumpPluginBase implements PumpInterface, Constr private void checkAndResolveTbrMismatch(PumpState state) { // compare with: info.nightscout.androidaps.plugins.PumpDanaR.comm.MsgStatusTempBasal.updateTempBasalInDB() long now = System.currentTimeMillis(); - TemporaryBasal aapsTbr = treatmentsPlugin.getTempBasalFromHistory(now); + // Combo doesn't have nor uses IDs for TBRs, see note in #setTempBasalPercent + long tbrId = now; + //TemporaryBasal aapsTbr = treatmentsPlugin.getTempBasalFromHistoryIncludingConvertedExtended(now); + PumpSync.PumpState.TemporaryBasal aapsTbr = pumpSync.expectedPumpState().getTemporaryBasal(); if (aapsTbr == null && state.tbrActive && state.tbrRemainingDuration > 2) { getAapsLogger().debug(LTag.PUMP, "Creating temp basal from pump TBR"); - TemporaryBasal newTempBasal = new TemporaryBasal(getInjector()) - .date(now) - .percent(state.tbrPercent) - .duration(state.tbrRemainingDuration) - .source(Source.USER); - treatmentsPlugin.addToHistoryTempBasal(newTempBasal); - } else if (aapsTbr != null && aapsTbr.getPlannedRemainingMinutes() > 2 && !state.tbrActive) { + pumpSync.syncTemporaryBasalWithPumpId( + now, + state.tbrPercent, + T.mins(state.tbrRemainingDuration).msecs(), + false, + PumpSync.TemporaryBasalType.NORMAL, + tbrId, + PumpType.ACCU_CHEK_COMBO, + serialNumber() + ); + } else if (aapsTbr != null && PumpStateExtensionKt.getPlannedRemainingMinutes(aapsTbr) > 2 && !state.tbrActive) { getAapsLogger().debug(LTag.PUMP, "Ending AAPS-TBR since pump has no TBR active"); - TemporaryBasal tempStop = new TemporaryBasal(getInjector()) - .date(now) - .duration(0) - .source(Source.USER); - treatmentsPlugin.addToHistoryTempBasal(tempStop); + pumpSync.syncStopTemporaryBasalWithPumpId( + now, + tbrId, + PumpType.ACCU_CHEK_COMBO, + serialNumber() + ); } else if (aapsTbr != null && state.tbrActive - && (aapsTbr.percentRate != state.tbrPercent || - Math.abs(aapsTbr.getPlannedRemainingMinutes() - state.tbrRemainingDuration) > 2)) { + && (aapsTbr.getRate() != state.tbrPercent || + Math.abs(PumpStateExtensionKt.getPlannedRemainingMinutes(aapsTbr) - state.tbrRemainingDuration) > 2)) { getAapsLogger().debug(LTag.PUMP, "AAPSs and pump-TBR differ; ending AAPS-TBR and creating new TBR based on pump TBR"); - TemporaryBasal tempStop = new TemporaryBasal(getInjector()) - .date(now - 1000) - .duration(0) - .source(Source.USER); - treatmentsPlugin.addToHistoryTempBasal(tempStop); - TemporaryBasal newTempBasal = new TemporaryBasal(getInjector()) - .date(now) - .percent(state.tbrPercent) - .duration(state.tbrRemainingDuration) - .source(Source.USER); - treatmentsPlugin.addToHistoryTempBasal(newTempBasal); + // crate TBR end record a second ago + pumpSync.syncStopTemporaryBasalWithPumpId( + now - 1000, + // fake a unique ID that doesn't clash with the record below + tbrId - 1000, + PumpType.ACCU_CHEK_COMBO, + serialNumber() + ); + + // Create TBR start record, starting now + pumpSync.syncTemporaryBasalWithPumpId( + now, + state.tbrPercent, + T.mins(state.tbrRemainingDuration).msecs(), + false, + PumpSync.TemporaryBasalType.NORMAL, + tbrId, + PumpType.ACCU_CHEK_COMBO, + serialNumber() + ); } } @@ -1153,13 +1148,14 @@ public class ComboPlugin extends PumpPluginBase implements PumpInterface, Constr private boolean updateDbFromPumpHistory(@NonNull PumpHistory history) { boolean updated = false; for (Bolus pumpBolus : history.bolusHistory) { - DetailedBolusInfo dbi = new DetailedBolusInfo(); - dbi.date = calculateFakeBolusDate(pumpBolus); - dbi.pumpId = dbi.date; - dbi.source = Source.PUMP; - dbi.insulin = pumpBolus.amount; - dbi.eventType = TherapyEvent.Type.CORRECTION_BOLUS.getText(); - if (treatmentsPlugin.addToHistoryTreatment(dbi, true)) { + if (pumpSync.syncBolusWithPumpId( + pumpBolus.timestamp, + pumpBolus.amount, + DetailedBolusInfo.BolusType.NORMAL, + generatePumpBolusId(pumpBolus), + PumpType.ACCU_CHEK_COMBO, + serialNumber() + )) { updated = true; } } @@ -1173,7 +1169,7 @@ public class ComboPlugin extends PumpPluginBase implements PumpInterface, Constr * Should be good enough, even with command mode, it's a challenge to create that situation * and most time clashes will be around SMBs which are covered. */ - long calculateFakeBolusDate(Bolus pumpBolus) { + long generatePumpBolusId(Bolus pumpBolus) { double bolus = pumpBolus.amount - 0.1; int secondsFromBolus = (int) (bolus * 10 * 1000); return pumpBolus.timestamp + Math.min(secondsFromBolus, 59 * 1000); @@ -1258,7 +1254,7 @@ public class ComboPlugin extends PumpPluginBase implements PumpInterface, Constr try { JSONObject pumpJson = new JSONObject(); - pumpJson.put("clock", DateUtil.toISOString(pump.lastSuccessfulCmdTime)); + pumpJson.put("clock", dateUtil.toISOString(pump.lastSuccessfulCmdTime)); int level; if (pump.reservoirLevel != -1) level = pump.reservoirLevel; @@ -1308,7 +1304,7 @@ public class ComboPlugin extends PumpPluginBase implements PumpInterface, Constr @NonNull @Override public PumpType model() { - return PumpType.AccuChekCombo; + return PumpType.ACCU_CHEK_COMBO; } @NonNull @Override diff --git a/combo/src/test/java/info/nightscout/androidaps/plugins/pump/combo/ComboPluginTest.kt b/combo/src/test/java/info/nightscout/androidaps/plugins/pump/combo/ComboPluginTest.kt index 108973affd..875f07a657 100644 --- a/combo/src/test/java/info/nightscout/androidaps/plugins/pump/combo/ComboPluginTest.kt +++ b/combo/src/test/java/info/nightscout/androidaps/plugins/pump/combo/ComboPluginTest.kt @@ -9,6 +9,7 @@ import info.nightscout.androidaps.data.PumpEnactResult import info.nightscout.androidaps.interfaces.* import info.nightscout.androidaps.plugins.bus.RxBusWrapper import info.nightscout.androidaps.plugins.pump.combo.ruffyscripter.history.Bolus +import info.nightscout.androidaps.utils.DateUtil import info.nightscout.androidaps.utils.resources.ResourceHelper import info.nightscout.androidaps.utils.sharedPreferences.SP import org.junit.Assert @@ -26,12 +27,13 @@ class ComboPluginTest : TestBase() { @Mock lateinit var resourceHelper: ResourceHelper @Mock lateinit var profileFunction: ProfileFunction - @Mock lateinit var activePlugin: ActivePluginProvider + @Mock lateinit var activePlugin: ActivePlugin @Mock lateinit var commandQueue: CommandQueueProvider - @Mock lateinit var treatmentsPlugin: TreatmentsInterface + @Mock lateinit var pumpSync: PumpSync @Mock lateinit var sp: SP @Mock lateinit var context: Context @Mock lateinit var databaseHelper: DatabaseHelperInterface + @Mock lateinit var dateUtil: DateUtil val injector = HasAndroidInjector { AndroidInjector { @@ -47,7 +49,7 @@ class ComboPluginTest : TestBase() { fun prepareMocks() { `when`(resourceHelper.gs(R.string.novalidbasalrate)).thenReturn("No valid basal rate read from pump") `when`(resourceHelper.gs(R.string.combo_pump_unsupported_operation)).thenReturn("Requested operation not supported by pump") - comboPlugin = ComboPlugin(injector, aapsLogger, RxBusWrapper(aapsSchedulers), resourceHelper, profileFunction, treatmentsPlugin, sp, commandQueue, context, databaseHelper) + comboPlugin = ComboPlugin(injector, aapsLogger, RxBusWrapper(aapsSchedulers), resourceHelper, profileFunction, sp, commandQueue, context, databaseHelper, pumpSync, dateUtil) } @Test @@ -62,22 +64,22 @@ class ComboPluginTest : TestBase() { } @Test - fun calculateFakePumpTimestamp() { + fun `generate bolus ID from timestamp and amount`() { val now = System.currentTimeMillis() val pumpTimestamp = now - now % 1000 // same timestamp, different bolus leads to different fake timestamp Assert.assertNotEquals( - comboPlugin.calculateFakeBolusDate(Bolus(pumpTimestamp, 0.1, true)), - comboPlugin.calculateFakeBolusDate(Bolus(pumpTimestamp, 0.3, true)) + comboPlugin.generatePumpBolusId(Bolus(pumpTimestamp, 0.1, true)), + comboPlugin.generatePumpBolusId(Bolus(pumpTimestamp, 0.3, true)) ) // different timestamp, same bolus leads to different fake timestamp Assert.assertNotEquals( - comboPlugin.calculateFakeBolusDate(Bolus(pumpTimestamp, 0.3, true)), - comboPlugin.calculateFakeBolusDate(Bolus(pumpTimestamp + 60 * 1000, 0.3, true)) + comboPlugin.generatePumpBolusId(Bolus(pumpTimestamp, 0.3, true)), + comboPlugin.generatePumpBolusId(Bolus(pumpTimestamp + 60 * 1000, 0.3, true)) ) // generated timestamp has second-precision val bolus = Bolus(pumpTimestamp, 0.2, true) - val calculatedTimestamp = comboPlugin.calculateFakeBolusDate(bolus) + val calculatedTimestamp = comboPlugin.generatePumpBolusId(bolus) Assert.assertEquals(calculatedTimestamp, calculatedTimestamp - calculatedTimestamp % 1000) } } \ No newline at end of file diff --git a/core/src/main/java/info/nightscout/androidaps/Constants.java b/core/src/main/java/info/nightscout/androidaps/Constants.java index 94f76cc2d7..f8748d2639 100644 --- a/core/src/main/java/info/nightscout/androidaps/Constants.java +++ b/core/src/main/java/info/nightscout/androidaps/Constants.java @@ -1,14 +1,14 @@ package info.nightscout.androidaps; +import info.nightscout.androidaps.database.entities.ValueWithUnit; import info.nightscout.androidaps.utils.T; -import info.nightscout.androidaps.database.entities.UserEntry.*; /** * Created by mike on 07.06.2016. */ public class Constants { - public static final String MGDL = Units.Mg_Dl.getText(); // This is Nightscout's representation - public static final String MMOL = Units.Mmol_L.getText(); + public static final String MGDL = ValueWithUnit.MGDL; // This is Nightscout's representation + public static final String MMOL = ValueWithUnit.MMOL; public static final double MMOLL_TO_MGDL = 18; // 18.0182; public static final double MGDL_TO_MMOLL = 1 / MMOLL_TO_MGDL; @@ -72,7 +72,7 @@ public class Constants { public static final int MIN_WATCHDOG_INTERVAL_IN_SECONDS = 12 * 60; //SMS Communicator - public static final long SMS_CONFIRM_TIMEOUT = T.mins(5).msecs(); + public static final long SMS_CONFIRM_TIMEOUT = T.mins(5L).msecs(); //Storage [MB] public static final long MINIMUM_FREE_SPACE = 200; diff --git a/core/src/main/java/info/nightscout/androidaps/activities/DaggerAppCompatActivityWithResult.kt b/core/src/main/java/info/nightscout/androidaps/activities/DaggerAppCompatActivityWithResult.kt index f28a06d286..986ef95719 100644 --- a/core/src/main/java/info/nightscout/androidaps/activities/DaggerAppCompatActivityWithResult.kt +++ b/core/src/main/java/info/nightscout/androidaps/activities/DaggerAppCompatActivityWithResult.kt @@ -6,7 +6,7 @@ import androidx.activity.result.contract.ActivityResultContracts import androidx.core.app.ActivityCompat import dagger.android.support.DaggerAppCompatActivity import info.nightscout.androidaps.core.R -import info.nightscout.androidaps.interfaces.ImportExportPrefsInterface +import info.nightscout.androidaps.interfaces.ImportExportPrefs import info.nightscout.androidaps.plugins.general.maintenance.PrefsFileContract import info.nightscout.androidaps.utils.alertDialogs.OKDialog import info.nightscout.androidaps.utils.permissions.OptimizationPermissionContract @@ -16,7 +16,7 @@ import javax.inject.Inject open class DaggerAppCompatActivityWithResult : DaggerAppCompatActivity() { @Inject lateinit var resourceHelper: ResourceHelperImplementation - @Inject lateinit var importExportPrefs: ImportExportPrefsInterface + @Inject lateinit var importExportPrefs: ImportExportPrefs val callForPrefFile = registerForActivityResult(PrefsFileContract()) { it?.let { diff --git a/core/src/main/java/info/nightscout/androidaps/activities/ErrorHelperActivity.kt b/core/src/main/java/info/nightscout/androidaps/activities/ErrorHelperActivity.kt index 0b970ccbe0..0fc25ff143 100644 --- a/core/src/main/java/info/nightscout/androidaps/activities/ErrorHelperActivity.kt +++ b/core/src/main/java/info/nightscout/androidaps/activities/ErrorHelperActivity.kt @@ -5,14 +5,20 @@ import android.content.Intent import android.os.Bundle import androidx.annotation.RawRes import info.nightscout.androidaps.core.R +import info.nightscout.androidaps.database.AppRepository +import info.nightscout.androidaps.database.transactions.InsertTherapyEventAnnouncementTransaction import info.nightscout.androidaps.dialogs.ErrorDialog -import info.nightscout.androidaps.plugins.general.nsclient.NSUpload import info.nightscout.androidaps.utils.sharedPreferences.SP +import io.reactivex.disposables.CompositeDisposable +import io.reactivex.rxkotlin.plusAssign import javax.inject.Inject class ErrorHelperActivity : DialogAppCompatActivity() { - @Inject lateinit var sp : SP - @Inject lateinit var nsUpload: NSUpload + + @Inject lateinit var sp: SP + @Inject lateinit var repository: AppRepository + + private val disposable = CompositeDisposable() @Override override fun onCreate(savedInstanceState: Bundle?) { @@ -24,17 +30,17 @@ class ErrorHelperActivity : DialogAppCompatActivity() { errorDialog.title = intent.getStringExtra(TITLE) errorDialog.show(supportFragmentManager, "Error") - if (sp.getBoolean(R.string.key_ns_create_announcements_from_errors, true)) { - nsUpload.uploadError(intent.getStringExtra(STATUS)) - } + if (sp.getBoolean(R.string.key_ns_create_announcements_from_errors, true)) + disposable += repository.runTransaction(InsertTherapyEventAnnouncementTransaction(intent.getStringExtra(STATUS))).subscribe() } companion object { + const val SOUND_ID = "soundId" const val STATUS = "status" const val TITLE = "title" - fun runAlarm(ctx: Context, status: String, title : String, @RawRes soundId: Int = 0) { + fun runAlarm(ctx: Context, status: String, title: String, @RawRes soundId: Int = 0) { val i = Intent(ctx, ErrorHelperActivity::class.java) i.putExtra(SOUND_ID, soundId) i.putExtra(STATUS, status) diff --git a/core/src/main/java/info/nightscout/androidaps/activities/TDDStatsActivity.kt b/core/src/main/java/info/nightscout/androidaps/activities/TDDStatsActivity.kt index ba650bace7..353f808935 100644 --- a/core/src/main/java/info/nightscout/androidaps/activities/TDDStatsActivity.kt +++ b/core/src/main/java/info/nightscout/androidaps/activities/TDDStatsActivity.kt @@ -20,7 +20,7 @@ import info.nightscout.androidaps.core.databinding.ActivityTddStatsBinding import info.nightscout.androidaps.db.TDD import info.nightscout.androidaps.events.EventDanaRSyncStatus import info.nightscout.androidaps.events.EventPumpStatusChanged -import info.nightscout.androidaps.interfaces.ActivePluginProvider +import info.nightscout.androidaps.interfaces.ActivePlugin import info.nightscout.androidaps.interfaces.CommandQueueProvider import info.nightscout.androidaps.interfaces.DatabaseHelperInterface import info.nightscout.androidaps.interfaces.ProfileFunction @@ -47,7 +47,7 @@ class TDDStatsActivity : NoSplashAppCompatActivity() { @Inject lateinit var rxBus: RxBusWrapper @Inject lateinit var sp: SP @Inject lateinit var profileFunction: ProfileFunction - @Inject lateinit var activePlugin: ActivePluginProvider + @Inject lateinit var activePlugin: ActivePlugin @Inject lateinit var commandQueue: CommandQueueProvider @Inject lateinit var databaseHelper: DatabaseHelperInterface @Inject lateinit var fabricPrivacy: FabricPrivacy @@ -422,7 +422,7 @@ class TDDStatsActivity : NoSplashAppCompatActivity() { private fun isOldData(historyList: List): Boolean { val type = activePlugin.activePump.pumpDescription.pumpType - val startsYesterday = type == PumpType.DanaR || type == PumpType.DanaRS || type == PumpType.DanaRv2 || type == PumpType.DanaRKorean || type == PumpType.AccuChekInsight + val startsYesterday = type == PumpType.DANA_R || type == PumpType.DANA_RS || type == PumpType.DANA_RV2 || type == PumpType.DANA_R_KOREAN || type == PumpType.ACCU_CHEK_INSIGHT val df: DateFormat = SimpleDateFormat("dd.MM.", Locale.getDefault()) return historyList.size < 3 || df.format(Date(historyList[0].date)) != df.format(Date(System.currentTimeMillis() - if (startsYesterday) 1000 * 60 * 60 * 24 else 0)) } diff --git a/core/src/main/java/info/nightscout/androidaps/core/di/CoreDataClassesModule.kt b/core/src/main/java/info/nightscout/androidaps/core/di/CoreDataClassesModule.kt index d041655d07..c5b2f91fc7 100644 --- a/core/src/main/java/info/nightscout/androidaps/core/di/CoreDataClassesModule.kt +++ b/core/src/main/java/info/nightscout/androidaps/core/di/CoreDataClassesModule.kt @@ -2,10 +2,8 @@ package info.nightscout.androidaps.core.di import dagger.Module import dagger.android.ContributesAndroidInjector -import info.nightscout.androidaps.data.GlucoseValueDataPoint import info.nightscout.androidaps.data.Profile import info.nightscout.androidaps.data.PumpEnactResult -import info.nightscout.androidaps.data.TherapyEventDataPoint import info.nightscout.androidaps.db.ExtendedBolus import info.nightscout.androidaps.db.ProfileSwitch import info.nightscout.androidaps.db.TemporaryBasal @@ -31,6 +29,4 @@ abstract class CoreDataClassesModule { @ContributesAndroidInjector abstract fun profileSwitchInjector(): ProfileSwitch @ContributesAndroidInjector abstract fun temporaryBasalInjector(): TemporaryBasal @ContributesAndroidInjector abstract fun extendedBolusInjector(): ExtendedBolus - @ContributesAndroidInjector abstract fun glucoseValueDataPointInjector(): GlucoseValueDataPoint - @ContributesAndroidInjector abstract fun therapyEventDataPointInjector(): TherapyEventDataPoint } diff --git a/core/src/main/java/info/nightscout/androidaps/core/di/CoreModule.kt b/core/src/main/java/info/nightscout/androidaps/core/di/CoreModule.kt index 013e0459c2..8f018cdc71 100644 --- a/core/src/main/java/info/nightscout/androidaps/core/di/CoreModule.kt +++ b/core/src/main/java/info/nightscout/androidaps/core/di/CoreModule.kt @@ -5,12 +5,13 @@ import android.preference.PreferenceManager import dagger.Module import dagger.Provides import dagger.android.HasAndroidInjector -import info.nightscout.androidaps.interfaces.ActivePluginProvider +import info.nightscout.androidaps.interfaces.ActivePlugin import info.nightscout.androidaps.interfaces.ProfileFunction import info.nightscout.androidaps.logging.AAPSLogger import info.nightscout.androidaps.logging.AAPSLoggerProduction import info.nightscout.androidaps.logging.L import info.nightscout.androidaps.plugins.configBuilder.ProfileFunctionImplementation +import info.nightscout.androidaps.utils.DateUtil import info.nightscout.androidaps.utils.FabricPrivacy import info.nightscout.androidaps.utils.resources.ResourceHelper import info.nightscout.androidaps.utils.resources.ResourceHelperImplementation @@ -27,8 +28,8 @@ open class CoreModule { @Provides @Singleton - fun provideProfileFunction(injector: HasAndroidInjector, aapsLogger: AAPSLogger, sp: SP, resourceHelper: ResourceHelper, activePlugin: ActivePluginProvider, fabricPrivacy: FabricPrivacy): ProfileFunction { - return ProfileFunctionImplementation(injector, aapsLogger, sp, resourceHelper, activePlugin, fabricPrivacy) + fun provideProfileFunction(injector: HasAndroidInjector, aapsLogger: AAPSLogger, sp: SP, resourceHelper: ResourceHelper, activePlugin: ActivePlugin, fabricPrivacy: FabricPrivacy, dateUtil: DateUtil): ProfileFunction { + return ProfileFunctionImplementation(injector, aapsLogger, sp, resourceHelper, activePlugin, fabricPrivacy, dateUtil) } @Provides diff --git a/core/src/main/java/info/nightscout/androidaps/data/DetailedBolusInfo.java b/core/src/main/java/info/nightscout/androidaps/data/DetailedBolusInfo.java deleted file mode 100644 index b544f9b284..0000000000 --- a/core/src/main/java/info/nightscout/androidaps/data/DetailedBolusInfo.java +++ /dev/null @@ -1,65 +0,0 @@ -package info.nightscout.androidaps.data; - -import android.content.Context; - -import org.json.JSONObject; - -import java.util.Date; - -import info.nightscout.androidaps.database.entities.TherapyEvent; -import info.nightscout.androidaps.db.Source; - -/** - * Created by mike on 29.05.2017. - */ - -public class DetailedBolusInfo { - public long date = System.currentTimeMillis(); - public long lastKnownBolusTime; - public String eventType = TherapyEvent.Type.MEAL_BOLUS.getText(); - public double insulin = 0; - public double carbs = 0; - public int source = Source.NONE; - public boolean isValid = true; - public double glucose = 0; // Bg value in current units - public String glucoseType = ""; // NS values: Manual, Finger, Sensor - public int carbTime = 0; // time shift of carbs in minutes - public JSONObject boluscalc = null; // additional bolus wizard info - public Context context = null; // context for progress dialog - public long pumpId = 0; // id of record if comming from pump history (not a newly created treatment) - public boolean isSMB = false; // is a Super-MicroBolus - public long deliverAt = 0; // SMB should be delivered within 1 min from this time - public String notes = null; - - public DetailedBolusInfo copy() { - DetailedBolusInfo n = new DetailedBolusInfo(); - n.date = date; - n.eventType = eventType; - n.insulin = insulin; - n.carbs = carbs; - n.source = source; - n.isValid = isValid; - n.glucose = glucose; - n.glucoseType = glucoseType; - n.carbTime = carbTime; - n.boluscalc = boluscalc; - n.context = context; - n.pumpId = pumpId; - n.isSMB = isSMB; - n.deliverAt = deliverAt; - n.notes = notes; - return n; - } - - @Override - public String toString() { - return new Date(date).toLocaleString() + - " date: " + date + - " insulin: " + insulin + - " carbs: " + carbs + - " isValid: " + isValid + - " carbTime: " + carbTime + - " isSMB: " + isSMB + - " deliverAt: " + new Date(deliverAt).toLocaleString(); - } -} diff --git a/core/src/main/java/info/nightscout/androidaps/data/DetailedBolusInfo.kt b/core/src/main/java/info/nightscout/androidaps/data/DetailedBolusInfo.kt new file mode 100644 index 0000000000..c9d31cd18a --- /dev/null +++ b/core/src/main/java/info/nightscout/androidaps/data/DetailedBolusInfo.kt @@ -0,0 +1,169 @@ +package info.nightscout.androidaps.data + +import android.content.Context +import com.google.gson.Gson +import info.nightscout.androidaps.database.entities.Bolus +import info.nightscout.androidaps.database.entities.BolusCalculatorResult +import info.nightscout.androidaps.database.entities.Carbs +import info.nightscout.androidaps.database.entities.TemporaryBasal +import info.nightscout.androidaps.database.entities.TherapyEvent +import info.nightscout.androidaps.database.transactions.InsertOrUpdateBolusTransaction +import info.nightscout.androidaps.database.transactions.InsertOrUpdateCarbsTransaction +import info.nightscout.androidaps.plugins.pump.common.defs.PumpType +import info.nightscout.androidaps.utils.T + +class DetailedBolusInfo { + + // Requesting parameters for driver + @JvmField var insulin = 0.0 + @JvmField var carbs = 0.0 + + // Additional requesting parameters + @JvmField var timestamp = System.currentTimeMillis() + @JvmField var carbTime = 0 // time shift of carbs in minutes + @JvmField var lastKnownBolusTime: Long = 0 // for SMB check + @JvmField var deliverAtTheLatest: Long = 0 // SMB should be delivered within 1 min from this time + @Transient var context: Context? = null // context for progress dialog + + // Prefilled info for storing to db + var bolusCalculatorResult: BolusCalculatorResult? = null + var eventType = EventType.MEAL_BOLUS + var notes: String? = null + var mgdlGlucose: Double? = null // Bg value in mgdl + var glucoseType: MeterType? = null // NS values: Manual, Finger, Sensor + var bolusType = BolusType.NORMAL + var carbsDuration = 0L // in milliseconds + + // Collected info from driver + var pumpType: PumpType? = null // if == USER + var pumpSerial: String? = null + var bolusPumpId: Long? = null + var bolusTimestamp: Long? = null + var carbsPumpId: Long? = null + var carbsTimestamp: Long? = null + + enum class MeterType(val text: String) { + FINGER("Finger"), + SENSOR("Sensor"), + MANUAL("Manual"); + + fun toDbMeterType(): TherapyEvent.MeterType = + when (this) { + FINGER -> TherapyEvent.MeterType.FINGER + SENSOR -> TherapyEvent.MeterType.SENSOR + MANUAL -> TherapyEvent.MeterType.MANUAL + } + } + + enum class BolusType { + NORMAL, + SMB, + PRIMING; + + fun toDBbBolusType(): Bolus.Type = + when (this) { + NORMAL -> Bolus.Type.NORMAL + SMB -> Bolus.Type.SMB + PRIMING -> Bolus.Type.PRIMING + } + } + + enum class EventType { + MEAL_BOLUS, + BOLUS_WIZARD, + CORRECTION_BOLUS, + CARBS_CORRECTION, + CANNULA_CHANGE, + INSULIN_CHANGE, + PUMP_BATTERY_CHANGE, + NOTE; + + fun toDBbEventType(): TherapyEvent.Type = + when (this) { + MEAL_BOLUS -> TherapyEvent.Type.MEAL_BOLUS + BOLUS_WIZARD -> TherapyEvent.Type.BOLUS_WIZARD + CORRECTION_BOLUS -> TherapyEvent.Type.CORRECTION_BOLUS + CARBS_CORRECTION -> TherapyEvent.Type.CARBS_CORRECTION + CANNULA_CHANGE -> TherapyEvent.Type.CANNULA_CHANGE + INSULIN_CHANGE -> TherapyEvent.Type.INSULIN_CHANGE + PUMP_BATTERY_CHANGE -> TherapyEvent.Type.PUMP_BATTERY_CHANGE + NOTE -> TherapyEvent.Type.NOTE + } + } + + fun createTherapyEvent(): TherapyEvent = + TherapyEvent( + timestamp = timestamp, + type = eventType.toDBbEventType(), + glucoseUnit = TherapyEvent.GlucoseUnit.MGDL, + note = notes, + glucose = mgdlGlucose, + glucoseType = glucoseType?.toDbMeterType() + ) + + fun createBolus(): Bolus? = + if (insulin != 0.0) + Bolus( + timestamp = bolusTimestamp ?: timestamp, + amount = insulin, + type = bolusType.toDBbBolusType() + ) + else null + + fun createCarbs(): Carbs? = + if (carbs != 0.0) + Carbs( + timestamp = carbsTimestamp ?: timestamp + T.mins(carbTime.toLong()).msecs(), + amount = carbs, + duration = carbsDuration + ) + else null + + fun insertCarbsTransaction(): InsertOrUpdateCarbsTransaction { + if (carbs == 0.0) throw IllegalStateException("carbs == 0.0") + return InsertOrUpdateCarbsTransaction(createCarbs()!!) + } + + fun insertBolusTransaction(): InsertOrUpdateBolusTransaction { + if (insulin == 0.0) throw IllegalStateException("insulin == 0.0") + return InsertOrUpdateBolusTransaction(createBolus()!!) + } + + fun toJsonString(): String = + Gson().toJson(this) + + fun copy(): DetailedBolusInfo { + val n = DetailedBolusInfo() + n.insulin = insulin + n.carbs = carbs + + n.timestamp = timestamp + n.carbTime = carbTime + n.lastKnownBolusTime = lastKnownBolusTime + n.deliverAtTheLatest = deliverAtTheLatest + n.context = context + + n.bolusCalculatorResult = bolusCalculatorResult + n.eventType = eventType + n.notes = notes + n.mgdlGlucose = mgdlGlucose + n.glucoseType = glucoseType + n.bolusType = bolusType + n.carbsDuration = carbsDuration + + n.pumpType = pumpType + n.pumpSerial = pumpSerial + n.bolusPumpId = bolusPumpId + n.carbsPumpId = carbsPumpId + n.carbsTimestamp = carbsTimestamp + return n + } + + override fun toString(): String = toJsonString() + + companion object { + + fun fromJsonString(json: String): DetailedBolusInfo = + Gson().fromJson(json, DetailedBolusInfo::class.java) + } +} \ No newline at end of file diff --git a/core/src/main/java/info/nightscout/androidaps/data/InMemoryGlucoseValue.kt b/core/src/main/java/info/nightscout/androidaps/data/InMemoryGlucoseValue.kt new file mode 100644 index 0000000000..5c80f6767c --- /dev/null +++ b/core/src/main/java/info/nightscout/androidaps/data/InMemoryGlucoseValue.kt @@ -0,0 +1,9 @@ +package info.nightscout.androidaps.data + +import info.nightscout.androidaps.database.entities.GlucoseValue + +class InMemoryGlucoseValue @JvmOverloads constructor(var timestamp: Long = 0L, var value: Double = 0.0, var interpolated: Boolean = false) { + + constructor(gv: GlucoseValue) : this(gv.timestamp, gv.value) + // var generated : value doesn't correspond to real value with timestamp close to real BG +} \ No newline at end of file diff --git a/core/src/main/java/info/nightscout/androidaps/data/IobTotal.kt b/core/src/main/java/info/nightscout/androidaps/data/IobTotal.kt index b295f66416..93ee6f5f64 100644 --- a/core/src/main/java/info/nightscout/androidaps/data/IobTotal.kt +++ b/core/src/main/java/info/nightscout/androidaps/data/IobTotal.kt @@ -64,19 +64,19 @@ class IobTotal(var time: Long) : DataPointWithLabelInterface { return this } - fun json(): JSONObject { + fun json(dateUtil: DateUtil): JSONObject { val json = JSONObject() try { json.put("iob", iob) json.put("basaliob", basaliob) json.put("activity", activity) - json.put("time", DateUtil.toISOString(Date())) + json.put("time", dateUtil.toISOString(time)) } catch (ignored: JSONException) { } return json } - fun determineBasalJson(): JSONObject { + fun determineBasalJson(dateUtil: DateUtil): JSONObject { val json = JSONObject() try { json.put("iob", iob) @@ -84,7 +84,7 @@ class IobTotal(var time: Long) : DataPointWithLabelInterface { json.put("bolussnooze", bolussnooze) json.put("activity", activity) json.put("lastBolusTime", lastBolusTime) - json.put("time", DateUtil.toISOString(Date(time))) + json.put("time", dateUtil.toISOString(time)) /* This is requested by SMB determine_basal but by based on Scott's info @@ -98,7 +98,7 @@ class IobTotal(var time: Long) : DataPointWithLabelInterface { json.put("lastTemp", lastTemp); */ if (iobWithZeroTemp != null) { - val iwzt = iobWithZeroTemp!!.determineBasalJson() + val iwzt = iobWithZeroTemp!!.determineBasalJson(dateUtil) json.put("iobWithZeroTemp", iwzt) } } catch (ignored: JSONException) { diff --git a/core/src/main/java/info/nightscout/androidaps/data/MealData.kt b/core/src/main/java/info/nightscout/androidaps/data/MealData.kt index 3084c636c6..98f8adca7c 100644 --- a/core/src/main/java/info/nightscout/androidaps/data/MealData.kt +++ b/core/src/main/java/info/nightscout/androidaps/data/MealData.kt @@ -2,7 +2,6 @@ package info.nightscout.androidaps.data class MealData { - var boluses = 0.0 var carbs = 0.0 var mealCOB = 0.0 var slopeFromMaxDeviation = 0.0 diff --git a/core/src/main/java/info/nightscout/androidaps/data/Profile.java b/core/src/main/java/info/nightscout/androidaps/data/Profile.java index 0ce7f5d2d6..3292c6fe96 100644 --- a/core/src/main/java/info/nightscout/androidaps/data/Profile.java +++ b/core/src/main/java/info/nightscout/androidaps/data/Profile.java @@ -16,11 +16,11 @@ import javax.inject.Inject; import dagger.android.HasAndroidInjector; import info.nightscout.androidaps.Constants; import info.nightscout.androidaps.core.R; -import info.nightscout.androidaps.interfaces.ActivePluginProvider; -import info.nightscout.androidaps.interfaces.ConfigInterface; +import info.nightscout.androidaps.interfaces.ActivePlugin; +import info.nightscout.androidaps.interfaces.Config; import info.nightscout.androidaps.interfaces.ProfileFunction; import info.nightscout.androidaps.interfaces.PumpDescription; -import info.nightscout.androidaps.interfaces.PumpInterface; +import info.nightscout.androidaps.interfaces.Pump; import info.nightscout.androidaps.logging.AAPSLogger; import info.nightscout.androidaps.plugins.bus.RxBusWrapper; import info.nightscout.androidaps.plugins.general.overview.events.EventNewNotification; @@ -33,17 +33,18 @@ import info.nightscout.androidaps.utils.resources.ResourceHelper; public class Profile { @Inject public AAPSLogger aapsLogger; - @Inject public ActivePluginProvider activePlugin; + @Inject public ActivePlugin activePlugin; @Inject public ResourceHelper resourceHelper; @Inject public RxBusWrapper rxBus; @Inject public FabricPrivacy fabricPrivacy; - @Inject public ConfigInterface configInterface; + @Inject public Config config; + @Inject public DateUtil dateUtil; private final HasAndroidInjector injector; private JSONObject json; private String units; - private double dia; + private double dia; // TODO change to insulinInterface link private TimeZone timeZone; private JSONArray isf; private LongSparseArray isf_v; // oldest at index 0 @@ -188,7 +189,7 @@ public class Profile { long tas; try { String time = o.getString("time"); - tas = getShitfTimeSecs(DateUtil.toSeconds(time)); + tas = getShitfTimeSecs(dateUtil.toSeconds(time)); } catch (JSONException e) { //log.debug(">>>>>>>>>>>> Used recalculated timeAsSecons: " + time + " " + tas); tas = getShitfTimeSecs((int) o.getLong("timeAsSeconds")); @@ -244,12 +245,12 @@ public class Profile { if (isValid) { // Check for hours alignment - PumpInterface pump = activePlugin.getActivePump(); + Pump pump = activePlugin.getActivePump(); if (!pump.getPumpDescription().is30minBasalRatesCapable()) { for (int index = 0; index < basal_v.size(); index++) { long secondsFromMidnight = basal_v.keyAt(index); if (notify && secondsFromMidnight % 3600 != 0) { - if (configInterface.getAPS()) { + if (config.getAPS()) { Notification notification = new Notification(Notification.BASAL_PROFILE_NOT_ALIGNED_TO_HOURS, resourceHelper.gs(R.string.basalprofilenotaligned, from), Notification.NORMAL); rxBus.send(new EventNewNotification(notification)); } @@ -628,7 +629,7 @@ public class Profile { } public static int secondsFromMidnight() { - // long passed = DateUtil.now() - MidnightTime.calc(); + // long passed = dateUtil._now() - MidnightTime.calc(); long passed = new DateTime().getMillisOfDay(); return (int) (passed / 1000); } diff --git a/core/src/main/java/info/nightscout/androidaps/data/PumpEnactResult.kt b/core/src/main/java/info/nightscout/androidaps/data/PumpEnactResult.kt index f1e05341be..66c4b51b16 100644 --- a/core/src/main/java/info/nightscout/androidaps/data/PumpEnactResult.kt +++ b/core/src/main/java/info/nightscout/androidaps/data/PumpEnactResult.kt @@ -31,11 +31,8 @@ class PumpEnactResult(injector: HasAndroidInjector) { var bolusDelivered = 0.0 // real value of delivered insulin var carbsDelivered = 0.0 // real value of delivered carbs var queued = false - fun success(success: Boolean): PumpEnactResult { - this.success = success - return this - } + fun success(success: Boolean): PumpEnactResult = this.also { this.success = success } fun enacted(enacted: Boolean): PumpEnactResult = this.also { it.enacted = enacted } fun comment(comment: String): PumpEnactResult = this.also { it.comment = comment } fun comment(comment: Int): PumpEnactResult = this.also { it.comment = resourceHelper.gs(comment) } diff --git a/core/src/main/java/info/nightscout/androidaps/db/ExtendedBolus.java b/core/src/main/java/info/nightscout/androidaps/db/ExtendedBolus.java index 37a160a50d..f00a49dbe6 100644 --- a/core/src/main/java/info/nightscout/androidaps/db/ExtendedBolus.java +++ b/core/src/main/java/info/nightscout/androidaps/db/ExtendedBolus.java @@ -17,15 +17,11 @@ import javax.inject.Inject; import dagger.android.HasAndroidInjector; import info.nightscout.androidaps.Constants; -import info.nightscout.androidaps.data.Iob; -import info.nightscout.androidaps.data.IobTotal; -import info.nightscout.androidaps.data.Profile; -import info.nightscout.androidaps.interfaces.ActivePluginProvider; -import info.nightscout.androidaps.interfaces.InsulinInterface; +import info.nightscout.androidaps.interfaces.ActivePlugin; +import info.nightscout.androidaps.interfaces.Insulin; import info.nightscout.androidaps.interfaces.Interval; import info.nightscout.androidaps.plugins.general.overview.graphExtensions.DataPointWithLabelInterface; import info.nightscout.androidaps.plugins.general.overview.graphExtensions.PointsWithLabelGraphSeries; -import info.nightscout.androidaps.plugins.iob.iobCobCalculator.AutosensResult; import info.nightscout.androidaps.utils.DateUtil; import info.nightscout.androidaps.utils.DecimalFormatter; import info.nightscout.androidaps.utils.JsonHelper; @@ -35,10 +31,11 @@ import info.nightscout.androidaps.utils.Round; * Created by mike on 21.05.2017. */ +@Deprecated @DatabaseTable(tableName = "ExtendedBoluses") public class ExtendedBolus implements Interval, DataPointWithLabelInterface { - @Inject ActivePluginProvider activePlugin; + @Inject ActivePlugin activePlugin; @Inject DateUtil dateUtil; private HasAndroidInjector injector; @@ -63,7 +60,7 @@ public class ExtendedBolus implements Interval, DataPointWithLabelInterface { public int durationInMinutes = 0; // duration == 0 means end of extended bolus @DatabaseField - public int insulinInterfaceID = InsulinInterface.InsulinType.OREF_RAPID_ACTING.getValue(); + public int insulinInterfaceID = Insulin.InsulinType.OREF_RAPID_ACTING.getValue(); @DatabaseField public double dia = Constants.defaultDIA; @@ -230,90 +227,6 @@ public class ExtendedBolus implements Interval, DataPointWithLabelInterface { return absoluteRate() * getRealDuration() / 60d; } - public IobTotal iobCalc(long time, Profile profile) { - IobTotal result = new IobTotal(time); - InsulinInterface insulinInterface = activePlugin.getActiveInsulin(); - - double realDuration = getDurationToTime(time); - - if (realDuration > 0) { - double dia = profile.getDia(); - double dia_ago = time - dia * 60 * 60 * 1000; - int aboutFiveMinIntervals = (int) Math.ceil(realDuration / 5d); - double spacing = realDuration / aboutFiveMinIntervals; - - for (long j = 0L; j < aboutFiveMinIntervals; j++) { - // find middle of the interval - long calcdate = (long) (date + j * spacing * 60 * 1000 + 0.5d * spacing * 60 * 1000); - - if (calcdate > dia_ago && calcdate <= time) { - double tempBolusSize = absoluteRate() * spacing / 60d; - - Treatment tempBolusPart = new Treatment(); - tempBolusPart.insulin = tempBolusSize; - tempBolusPart.date = calcdate; - - Iob aIOB = insulinInterface.iobCalcForTreatment(tempBolusPart, time, dia); - result.iob += aIOB.getIobContrib(); - result.activity += aIOB.getActivityContrib(); - result.extendedBolusInsulin += tempBolusPart.insulin; - } - } - } - return result; - } - - public IobTotal iobCalc(long time, Profile profile, AutosensResult lastAutosensResult, boolean exercise_mode, int half_basal_exercise_target, boolean isTempTarget) { - IobTotal result = new IobTotal(time); - InsulinInterface insulinInterface = activePlugin.getActiveInsulin(); - - double realDuration = getDurationToTime(time); - double netBasalAmount = 0d; - - double sensitivityRatio = lastAutosensResult.ratio; - double normalTarget = 100; - - if (exercise_mode && isTempTarget && profile.getTargetMgdl() >= normalTarget + 5) { - // w/ target 100, temp target 110 = .89, 120 = 0.8, 140 = 0.67, 160 = .57, and 200 = .44 - // e.g.: Sensitivity ratio set to 0.8 based on temp target of 120; Adjusting basal from 1.65 to 1.35; ISF from 58.9 to 73.6 - double c = half_basal_exercise_target - normalTarget; - sensitivityRatio = c / (c + profile.getTargetMgdl() - normalTarget); - } - - if (realDuration > 0) { - double netBasalRate; - double dia = profile.getDia(); - double dia_ago = time - dia * 60 * 60 * 1000; - int aboutFiveMinIntervals = (int) Math.ceil(realDuration / 5d); - double spacing = realDuration / aboutFiveMinIntervals; - - for (long j = 0L; j < aboutFiveMinIntervals; j++) { - // find middle of the interval - long calcdate = (long) (date + j * spacing * 60 * 1000 + 0.5d * spacing * 60 * 1000); - - double basalRate = profile.getBasal(calcdate); - double basalRateCorrection = basalRate * (sensitivityRatio - 1); - - - netBasalRate = absoluteRate() - basalRateCorrection; - - if (calcdate > dia_ago && calcdate <= time) { - double tempBolusSize = netBasalRate * spacing / 60d; - - Treatment tempBolusPart = new Treatment(); - tempBolusPart.insulin = tempBolusSize; - tempBolusPart.date = calcdate; - - Iob aIOB = insulinInterface.iobCalcForTreatment(tempBolusPart, time, dia); - result.iob += aIOB.getIobContrib(); - result.activity += aIOB.getActivityContrib(); - result.extendedBolusInsulin += tempBolusPart.insulin; - } - } - } - return result; - } - public int getRealDuration() { return getDurationToTime(System.currentTimeMillis()); } @@ -335,10 +248,6 @@ public class ExtendedBolus implements Interval, DataPointWithLabelInterface { " " + getRealDuration() + "/" + durationInMinutes + "min"; } - public String toStringShort() { - return "E " + DecimalFormatter.INSTANCE.to2Decimal(absoluteRate()) + "U/h "; - } - public String toStringMedium() { return DecimalFormatter.INSTANCE.to2Decimal(absoluteRate()) + "U/h " + getRealDuration() + "/" + durationInMinutes + "'"; diff --git a/core/src/main/java/info/nightscout/androidaps/db/ProfileSwitch.java b/core/src/main/java/info/nightscout/androidaps/db/ProfileSwitch.java index 6e011e869d..7f4477e13d 100644 --- a/core/src/main/java/info/nightscout/androidaps/db/ProfileSwitch.java +++ b/core/src/main/java/info/nightscout/androidaps/db/ProfileSwitch.java @@ -235,7 +235,7 @@ public class ProfileSwitch implements Interval, DataPointWithLabelInterface { @Override public boolean isValid() { boolean isValid = getProfileObject() != null && getProfileObject().isValid(dateUtil.dateAndTimeString(date)); - ProfileSwitch active = treatmentsPlugin.getProfileSwitchFromHistory(DateUtil.now()); + ProfileSwitch active = treatmentsPlugin.getProfileSwitchFromHistory(dateUtil.now()); long activeProfileSwitchDate = active != null ? active.date : -1L; if (!isValid && date == activeProfileSwitchDate) createNotificationInvalidProfile(dateUtil.dateAndTimeString(date)); diff --git a/core/src/main/java/info/nightscout/androidaps/db/TemporaryBasal.java b/core/src/main/java/info/nightscout/androidaps/db/TemporaryBasal.java index f38b66f1b8..762c7b7971 100644 --- a/core/src/main/java/info/nightscout/androidaps/db/TemporaryBasal.java +++ b/core/src/main/java/info/nightscout/androidaps/db/TemporaryBasal.java @@ -8,16 +8,11 @@ import java.util.Objects; import javax.inject.Inject; import dagger.android.HasAndroidInjector; -import info.nightscout.androidaps.core.R; -import info.nightscout.androidaps.data.Iob; -import info.nightscout.androidaps.data.IobTotal; import info.nightscout.androidaps.data.Profile; -import info.nightscout.androidaps.interfaces.ActivePluginProvider; -import info.nightscout.androidaps.interfaces.InsulinInterface; +import info.nightscout.androidaps.interfaces.ActivePlugin; import info.nightscout.androidaps.interfaces.Interval; import info.nightscout.androidaps.interfaces.ProfileFunction; import info.nightscout.androidaps.logging.AAPSLogger; -import info.nightscout.androidaps.plugins.iob.iobCobCalculator.AutosensResult; import info.nightscout.androidaps.utils.DateUtil; import info.nightscout.androidaps.utils.DecimalFormatter; import info.nightscout.androidaps.utils.sharedPreferences.SP; @@ -26,12 +21,13 @@ import info.nightscout.androidaps.utils.sharedPreferences.SP; * Created by mike on 21.05.2017. */ +@Deprecated @DatabaseTable(tableName = "TemporaryBasals") public class TemporaryBasal implements Interval, DbObjectBase { @Inject public AAPSLogger aapsLogger; @Inject public ProfileFunction profileFunction; - @Inject public ActivePluginProvider activePlugin; + @Inject public ActivePlugin activePlugin; @Inject public SP sp; @Inject public DateUtil dateUtil; @@ -244,128 +240,6 @@ public class TemporaryBasal implements Interval, DbObjectBase { // -------- Interval interface end --------- - public IobTotal iobCalc(long time, Profile profile) { - - if (isFakeExtended) { - aapsLogger.error("iobCalc should only be called on Extended boluses separately"); - return new IobTotal(time); - } - - IobTotal result = new IobTotal(time); - InsulinInterface insulinInterface = activePlugin.getActiveInsulin(); - - int realDuration = getDurationToTime(time); - double netBasalAmount = 0d; - - if (realDuration > 0) { - double netBasalRate; - double dia = profile.getDia(); - double dia_ago = time - dia * 60 * 60 * 1000; - int aboutFiveMinIntervals = (int) Math.ceil(realDuration / 5d); - double tempBolusSpacing = (double) (realDuration / aboutFiveMinIntervals); - - for (long j = 0L; j < aboutFiveMinIntervals; j++) { - // find middle of the interval - long calcdate = (long) (date + j * tempBolusSpacing * 60 * 1000 + 0.5d * tempBolusSpacing * 60 * 1000); - - double basalRate = profile.getBasal(calcdate); - - if (isAbsolute) { - netBasalRate = absoluteRate - basalRate; - } else { - netBasalRate = (percentRate - 100) / 100d * basalRate; - } - - if (calcdate > dia_ago && calcdate <= time) { - double tempBolusSize = netBasalRate * tempBolusSpacing / 60d; - netBasalAmount += tempBolusSize; - - Treatment tempBolusPart = new Treatment(); - tempBolusPart.insulin = tempBolusSize; - tempBolusPart.date = calcdate; - - Iob aIOB = insulinInterface.iobCalcForTreatment(tempBolusPart, time, dia); - result.basaliob += aIOB.getIobContrib(); - result.activity += aIOB.getActivityContrib(); - result.netbasalinsulin += tempBolusPart.insulin; - if (tempBolusPart.insulin > 0) { - result.hightempinsulin += tempBolusPart.insulin; - } - } - result.netRatio = netBasalRate; // ratio at the end of interval - } - } - result.netInsulin = netBasalAmount; - return result; - } - - public IobTotal iobCalc(long time, Profile profile, AutosensResult lastAutosensResult, boolean exercise_mode, int half_basal_exercise_target, boolean isTempTarget) { - - if (isFakeExtended) { - aapsLogger.error("iobCalc should only be called on Extended boluses separately"); - return new IobTotal(time); - } - - IobTotal result = new IobTotal(time); - InsulinInterface insulinInterface = activePlugin.getActiveInsulin(); - - double realDuration = getDurationToTime(time); - double netBasalAmount = 0d; - - double sensitivityRatio = lastAutosensResult.ratio; - double normalTarget = 100; - - if (exercise_mode && isTempTarget && profile.getTargetMgdl() >= normalTarget + 5) { - // w/ target 100, temp target 110 = .89, 120 = 0.8, 140 = 0.67, 160 = .57, and 200 = .44 - // e.g.: Sensitivity ratio set to 0.8 based on temp target of 120; Adjusting basal from 1.65 to 1.35; ISF from 58.9 to 73.6 - double c = half_basal_exercise_target - normalTarget; - sensitivityRatio = c / (c + profile.getTargetMgdl() - normalTarget); - } - - if (realDuration > 0) { - double netBasalRate; - double dia = profile.getDia(); - double dia_ago = time - dia * 60 * 60 * 1000; - int aboutFiveMinIntervals = (int) Math.ceil(realDuration / 5d); - double tempBolusSpacing = realDuration / aboutFiveMinIntervals; - - for (long j = 0L; j < aboutFiveMinIntervals; j++) { - // find middle of the interval - long calcdate = (long) (date + j * tempBolusSpacing * 60 * 1000 + 0.5d * tempBolusSpacing * 60 * 1000); - - double basalRate = profile.getBasal(calcdate); - basalRate *= sensitivityRatio; - - if (isAbsolute) { - netBasalRate = absoluteRate - basalRate; - } else { - double abs = percentRate / 100d * profile.getBasal(calcdate); - netBasalRate = abs - basalRate; - } - - if (calcdate > dia_ago && calcdate <= time) { - double tempBolusSize = netBasalRate * tempBolusSpacing / 60d; - netBasalAmount += tempBolusSize; - - Treatment tempBolusPart = new Treatment(); - tempBolusPart.insulin = tempBolusSize; - tempBolusPart.date = calcdate; - - Iob aIOB = insulinInterface.iobCalcForTreatment(tempBolusPart, time, dia); - result.basaliob += aIOB.getIobContrib(); - result.activity += aIOB.getActivityContrib(); - result.netbasalinsulin += tempBolusPart.insulin; - if (tempBolusPart.insulin > 0) { - result.hightempinsulin += tempBolusPart.insulin; - } - } - result.netRatio = netBasalRate; // ratio at the end of interval - } - } - result.netInsulin = netBasalAmount; - return result; - } - public int getRealDuration() { return getDurationToTime(System.currentTimeMillis()); } @@ -431,7 +305,7 @@ public class TemporaryBasal implements Interval, DbObjectBase { return "null"; Double currentBasalRate = profile.getBasal(); double rate = currentBasalRate + netExtendedRate; - return getCalcuatedPercentageIfNeeded() + DecimalFormatter.INSTANCE.to2Decimal(rate) + "U/h (" + DecimalFormatter.INSTANCE.to2Decimal(netExtendedRate) + "E) @" + + return DecimalFormatter.INSTANCE.to2Decimal(rate) + "U/h (" + DecimalFormatter.INSTANCE.to2Decimal(netExtendedRate) + "E) @" + dateUtil.timeString(date) + " " + getRealDuration() + "/" + durationInMinutes + "'"; } else if (isAbsolute) { @@ -459,47 +333,12 @@ public class TemporaryBasal implements Interval, DbObjectBase { rate = absoluteRate; } - if (sp.getBoolean(R.string.key_danar_visualizeextendedaspercentage, false) && sp.getBoolean(R.string.key_danar_useextended, false)) { - Profile profile = profileFunction.getProfile(); - if (profile != null) { - double basal = profile.getBasal(); - if (basal != 0) { - return Math.round(rate * 100d / basal) + "%"; - } - } - } return DecimalFormatter.INSTANCE.to2Decimal(rate) + "U/h"; } else { // percent return percentRate + "%"; } } - private String getCalcuatedPercentageIfNeeded() { - Profile profile = profileFunction.getProfile(); - - if (profile == null) - return "null"; - - if (isAbsolute || isFakeExtended) { - - double rate; - if (isFakeExtended) { - double currentBasalRate = profile.getBasal(); - rate = currentBasalRate + netExtendedRate; - } else { - rate = absoluteRate; - } - - if (sp.getBoolean(R.string.key_danar_visualizeextendedaspercentage, false) && sp.getBoolean(R.string.key_danar_useextended, false)) { - double basal = profile.getBasal(); - if (basal != 0) { - return Math.round(rate * 100d / basal) + "% "; - } - } - } - return ""; - } - public String toStringVeryShort() { Profile profile = profileFunction.getProfile(); diff --git a/core/src/main/java/info/nightscout/androidaps/db/Treatment.java b/core/src/main/java/info/nightscout/androidaps/db/Treatment.java index 6cc8c48556..0285844cce 100644 --- a/core/src/main/java/info/nightscout/androidaps/db/Treatment.java +++ b/core/src/main/java/info/nightscout/androidaps/db/Treatment.java @@ -18,10 +18,10 @@ import javax.inject.Inject; import dagger.android.HasAndroidInjector; import info.nightscout.androidaps.Constants; import info.nightscout.androidaps.core.R; -import info.nightscout.androidaps.data.Iob; import info.nightscout.androidaps.data.Profile; -import info.nightscout.androidaps.interfaces.ActivePluginProvider; -import info.nightscout.androidaps.interfaces.InsulinInterface; +import info.nightscout.androidaps.database.entities.Bolus; +import info.nightscout.androidaps.interfaces.ActivePlugin; +import info.nightscout.androidaps.interfaces.Insulin; import info.nightscout.androidaps.interfaces.ProfileFunction; import info.nightscout.androidaps.plugins.general.overview.graphExtensions.DataPointWithLabelInterface; import info.nightscout.androidaps.plugins.general.overview.graphExtensions.PointsWithLabelGraphSeries; @@ -31,12 +31,13 @@ import info.nightscout.androidaps.utils.DefaultValueHelper; import info.nightscout.androidaps.utils.JsonHelper; import info.nightscout.androidaps.utils.resources.ResourceHelper; +@Deprecated @DatabaseTable(tableName = Treatment.TABLE_TREATMENTS) public class Treatment implements DataPointWithLabelInterface, DbObjectBase { @Inject public DefaultValueHelper defaultValueHelper; @Inject public ResourceHelper resourceHelper; @Inject public ProfileFunction profileFunction; - @Inject public ActivePluginProvider activePlugin; + @Inject public ActivePlugin activePlugin; @Inject public DateUtil dateUtil; public static final String TABLE_TREATMENTS = "Treatments"; @@ -65,7 +66,7 @@ public class Treatment implements DataPointWithLabelInterface, DbObjectBase { public boolean isSMB = false; @DatabaseField - public int insulinInterfaceID = InsulinInterface.InsulinType.OREF_RAPID_ACTING.getValue(); // currently unused, will be used in the future + public int insulinInterfaceID = Insulin.InsulinType.OREF_RAPID_ACTING.getValue(); // currently unused, will be used in the future @DatabaseField public double dia = Constants.defaultDIA; // currently unused, will be used in the future @DatabaseField @@ -79,31 +80,15 @@ public class Treatment implements DataPointWithLabelInterface, DbObjectBase { injector.androidInjector().inject(this); } - public static Treatment createFromJson(JSONObject json) throws JSONException { - Treatment treatment = new Treatment(); - treatment.source = Source.NIGHTSCOUT; - treatment.date = DateUtil.roundDateToSec(JsonHelper.safeGetLong(json, "mills")); - if (treatment.date == 0L) - return null; - treatment.carbs = JsonHelper.safeGetDouble(json, "carbs"); - treatment.insulin = JsonHelper.safeGetDouble(json, "insulin"); - treatment.pumpId = JsonHelper.safeGetLong(json, "pumpId"); - treatment._id = json.getString("_id"); - treatment.isSMB = JsonHelper.safeGetBoolean(json, "isSMB"); - if (json.has("eventType")) { - treatment.mealBolus = !json.get("eventType").equals("Correction Bolus"); - double carbs = treatment.carbs; - if (json.has("boluscalc")) { - JSONObject boluscalc = json.getJSONObject("boluscalc"); - treatment.boluscalc = boluscalc.toString(); - if (boluscalc.has("carbs")) { - carbs = Math.max(boluscalc.getDouble("carbs"), carbs); - } - } - if (carbs <= 0) - treatment.mealBolus = false; - } - return treatment; + public Treatment(HasAndroidInjector injector, Bolus bolus) { + this(injector); + date = bolus.getTimestamp(); + isValid = bolus.isValid(); + pumpId = (bolus.getInterfaceIDs().getPumpId() != null) ? bolus.getInterfaceIDs().getPumpId() : 0; + source = (bolus.getInterfaceIDs().getPumpId() != null) ? Source.PUMP : Source.USER; + _id = bolus.getInterfaceIDs().getNightscoutId(); + insulin = bolus.getAmount(); + isSMB = bolus.getType() == Bolus.Type.SMB; } @NonNull public String toString() { @@ -243,7 +228,8 @@ public class Treatment implements DataPointWithLabelInterface, DbObjectBase { @Override public String getLabel() { String label = ""; - if (insulin > 0) label += DecimalFormatter.INSTANCE.toPumpSupportedBolus(insulin, activePlugin.getActivePump(), resourceHelper); + if (insulin > 0) + label += DecimalFormatter.INSTANCE.toPumpSupportedBolus(insulin, activePlugin.getActivePump(), resourceHelper); if (carbs > 0) label += "~" + resourceHelper.gs(R.string.format_carbs, (int) carbs); return label; @@ -284,14 +270,6 @@ public class Treatment implements DataPointWithLabelInterface, DbObjectBase { // ----------------- DataPointInterface end -------------------- - public Iob iobCalc(long time, double dia) { - if (!isValid) - return new Iob(); - - InsulinInterface insulinInterface = activePlugin.getActiveInsulin(); - return insulinInterface.iobCalcForTreatment(this, time, dia); - } - @Override public long getDate() { return this.date; diff --git a/core/src/main/java/info/nightscout/androidaps/dialogs/DialogFragmentWithDate.kt b/core/src/main/java/info/nightscout/androidaps/dialogs/DialogFragmentWithDate.kt index 5e35ef2682..0ad6a55114 100644 --- a/core/src/main/java/info/nightscout/androidaps/dialogs/DialogFragmentWithDate.kt +++ b/core/src/main/java/info/nightscout/androidaps/dialogs/DialogFragmentWithDate.kt @@ -16,7 +16,7 @@ import info.nightscout.androidaps.core.R import info.nightscout.androidaps.logging.AAPSLogger import info.nightscout.androidaps.logging.LTag import info.nightscout.androidaps.utils.DateUtil -import info.nightscout.androidaps.utils.extensions.toVisibility +import info.nightscout.androidaps.extensions.toVisibility import info.nightscout.androidaps.utils.sharedPreferences.SP import java.util.* import javax.inject.Inject @@ -63,7 +63,7 @@ abstract class DialogFragmentWithDate : DaggerDialogFragment() { eventTime = savedInstanceState?.getLong("eventTime") ?: dateUtil.nowWithoutMilliseconds() eventTimeChanged = savedInstanceState?.getBoolean("eventTimeChanged") ?: false - eventDateView?.text = DateUtil.dateString(eventTime) + eventDateView?.text = dateUtil.dateString(eventTime) eventTimeView?.text = dateUtil.timeString(eventTime) // create an OnDateSetListener @@ -75,7 +75,7 @@ abstract class DialogFragmentWithDate : DaggerDialogFragment() { cal.set(Calendar.DAY_OF_MONTH, dayOfMonth) eventTime = cal.timeInMillis eventTimeChanged = true - eventDateView?.text = DateUtil.dateString(eventTime) + eventDateView?.text = dateUtil.dateString(eventTime) } eventDateView?.setOnClickListener { diff --git a/core/src/main/java/info/nightscout/androidaps/dialogs/ErrorDialog.kt b/core/src/main/java/info/nightscout/androidaps/dialogs/ErrorDialog.kt index 9e5a88f08a..609b70a01e 100644 --- a/core/src/main/java/info/nightscout/androidaps/dialogs/ErrorDialog.kt +++ b/core/src/main/java/info/nightscout/androidaps/dialogs/ErrorDialog.kt @@ -11,11 +11,13 @@ import dagger.android.support.DaggerDialogFragment import info.nightscout.androidaps.activities.ErrorHelperActivity import info.nightscout.androidaps.core.R import info.nightscout.androidaps.core.databinding.DialogErrorBinding -import info.nightscout.androidaps.database.entities.UserEntry.* +import info.nightscout.androidaps.database.entities.UserEntry.Action +import info.nightscout.androidaps.database.entities.UserEntry.Sources import info.nightscout.androidaps.logging.AAPSLogger import info.nightscout.androidaps.logging.UserEntryLogger import info.nightscout.androidaps.services.AlarmSoundServiceHelper import info.nightscout.androidaps.utils.T +import org.mozilla.javascript.tools.jsc.Main import javax.inject.Inject class ErrorDialog : DaggerDialogFragment() { @@ -59,15 +61,15 @@ class ErrorDialog : DaggerDialogFragment() { binding.title.text = title binding.ok.setOnClickListener { - uel.log(Action.ERROR_DIALOG_OK) + uel.log(Action.ERROR_DIALOG_OK, Sources.Unknown) dismiss() } binding.mute.setOnClickListener { - uel.log(Action.ERROR_DIALOG_MUTE) + uel.log(Action.ERROR_DIALOG_MUTE, Sources.Unknown) stopAlarm() } binding.mute5min.setOnClickListener { - uel.log(Action.ERROR_DIALOG_MUTE_5MIN) + uel.log(Action.ERROR_DIALOG_MUTE_5MIN, Sources.Unknown) stopAlarm() loopHandler.postDelayed(this::startAlarm, T.mins(5).msecs()) } diff --git a/core/src/main/java/info/nightscout/androidaps/dialogs/ProfileViewerDialog.kt b/core/src/main/java/info/nightscout/androidaps/dialogs/ProfileViewerDialog.kt index f905d7b40d..94dd93ef51 100644 --- a/core/src/main/java/info/nightscout/androidaps/dialogs/ProfileViewerDialog.kt +++ b/core/src/main/java/info/nightscout/androidaps/dialogs/ProfileViewerDialog.kt @@ -13,7 +13,7 @@ import info.nightscout.androidaps.Constants import info.nightscout.androidaps.core.R import info.nightscout.androidaps.core.databinding.DialogProfileviewerBinding import info.nightscout.androidaps.data.Profile -import info.nightscout.androidaps.interfaces.ActivePluginProvider +import info.nightscout.androidaps.interfaces.ActivePlugin import info.nightscout.androidaps.interfaces.DatabaseHelperInterface import info.nightscout.androidaps.interfaces.ProfileFunction import info.nightscout.androidaps.utils.DateUtil @@ -27,7 +27,7 @@ class ProfileViewerDialog : DaggerDialogFragment() { @Inject lateinit var injector: HasAndroidInjector @Inject lateinit var resourceHelper: ResourceHelper - @Inject lateinit var activePlugin: ActivePluginProvider + @Inject lateinit var activePlugin: ActivePlugin @Inject lateinit var dateUtil: DateUtil @Inject lateinit var profileFunction: ProfileFunction @Inject lateinit var databaseHelper: DatabaseHelperInterface diff --git a/core/src/main/java/info/nightscout/androidaps/events/EventAutosensCalculationFinished.kt b/core/src/main/java/info/nightscout/androidaps/events/EventAutosensCalculationFinished.kt index 3c6073d9f0..32eff6350f 100644 --- a/core/src/main/java/info/nightscout/androidaps/events/EventAutosensCalculationFinished.kt +++ b/core/src/main/java/info/nightscout/androidaps/events/EventAutosensCalculationFinished.kt @@ -3,4 +3,4 @@ package info.nightscout.androidaps.events import info.nightscout.androidaps.events.Event import info.nightscout.androidaps.events.EventLoop -class EventAutosensCalculationFinished(var cause: Event) : EventLoop() +class EventAutosensCalculationFinished(val cause: Event?) : EventLoop() diff --git a/core/src/main/java/info/nightscout/androidaps/extensions/BolusCalculatorResultExtension.kt b/core/src/main/java/info/nightscout/androidaps/extensions/BolusCalculatorResultExtension.kt new file mode 100644 index 0000000000..786f9c7d13 --- /dev/null +++ b/core/src/main/java/info/nightscout/androidaps/extensions/BolusCalculatorResultExtension.kt @@ -0,0 +1,21 @@ +package info.nightscout.androidaps.extensions + +import com.google.gson.Gson +import info.nightscout.androidaps.Constants +import info.nightscout.androidaps.database.entities.BolusCalculatorResult +import info.nightscout.androidaps.database.entities.TherapyEvent +import info.nightscout.androidaps.utils.DateUtil +import org.json.JSONObject + +fun BolusCalculatorResult.toJson(dateUtil: DateUtil): JSONObject = + JSONObject() + .put("eventType", TherapyEvent.Type.BOLUS_WIZARD.text) + .put("created_at", dateUtil.toISOString(timestamp)) + .put("bolusCalculatorResult", Gson().toJson(this)) + .put("date", timestamp) + .put("glucose", glucoseValue) + .put("units", Constants.MGDL) + .put("notes", note) + .also { + if (interfaceIDs.nightscoutId != null) it.put("_id", interfaceIDs.nightscoutId) + } diff --git a/core/src/main/java/info/nightscout/androidaps/extensions/BolusExtension.kt b/core/src/main/java/info/nightscout/androidaps/extensions/BolusExtension.kt new file mode 100644 index 0000000000..bef74006e9 --- /dev/null +++ b/core/src/main/java/info/nightscout/androidaps/extensions/BolusExtension.kt @@ -0,0 +1,71 @@ +package info.nightscout.androidaps.extensions + +import info.nightscout.androidaps.data.Iob +import info.nightscout.androidaps.database.embedments.InterfaceIDs +import info.nightscout.androidaps.database.entities.Bolus +import info.nightscout.androidaps.database.entities.TherapyEvent +import info.nightscout.androidaps.interfaces.ActivePlugin +import info.nightscout.androidaps.interfaces.Insulin +import info.nightscout.androidaps.utils.DateUtil +import info.nightscout.androidaps.utils.JsonHelper +import org.json.JSONObject + +fun Bolus.iobCalc(activePlugin: ActivePlugin, time: Long, dia: Double): Iob { + if (!isValid || type == Bolus.Type.PRIMING ) return Iob() + val insulinInterface: Insulin = activePlugin.activeInsulin + return insulinInterface.iobCalcForTreatment(this, time, dia) +} + +fun Bolus.toJson(dateUtil: DateUtil): JSONObject = + JSONObject() + .put("eventType", if (type == Bolus.Type.SMB) TherapyEvent.Type.CORRECTION_BOLUS.text else TherapyEvent.Type.MEAL_BOLUS.text) + .put("insulin", amount) + .put("created_at", dateUtil.toISOString(timestamp)) + .put("date", timestamp) + .put("type", type.name) + .put("isValid", isValid) + .put("isSMB", type == Bolus.Type.SMB).also { + if (interfaceIDs.pumpId != null) it.put("pumpId", interfaceIDs.pumpId) + if (interfaceIDs.pumpType != null) it.put("pumpType", interfaceIDs.pumpType!!.name) + if (interfaceIDs.pumpSerial != null) it.put("pumpSerial", interfaceIDs.pumpSerial) + if (interfaceIDs.nightscoutId != null) it.put("_id", interfaceIDs.nightscoutId) + } + +/* + create fake object with nsID and isValid == false + */ +fun bolusFromNsIdForInvalidating(nsId: String): Bolus = + bolusFromJson( + JSONObject() + .put("mills", 1) + .put("insulin", -1.0) + .put("_id", nsId) + .put("isValid", false) + )!! + +fun bolusFromJson(jsonObject: JSONObject): Bolus? { + val timestamp = JsonHelper.safeGetLongAllowNull(jsonObject, "mills", null) ?: return null + val amount = JsonHelper.safeGetDoubleAllowNull(jsonObject, "insulin") ?: return null + val type = Bolus.Type.fromString(JsonHelper.safeGetString(jsonObject, "type")) + val isValid = JsonHelper.safeGetBoolean(jsonObject, "isValid", true) + val id = JsonHelper.safeGetStringAllowNull(jsonObject, "_id", null) ?: return null + val pumpId = JsonHelper.safeGetLongAllowNull(jsonObject, "pumpId", null) + val pumpType = InterfaceIDs.PumpType.fromString(JsonHelper.safeGetStringAllowNull(jsonObject, "pumpType", null)) + val pumpSerial = JsonHelper.safeGetStringAllowNull(jsonObject, "pumpSerial", null) + + if (timestamp == 0L) return null + if (amount == 0.0) return null + + return Bolus( + timestamp = timestamp, + amount = amount, + type = type, + isValid = isValid + ).also { + it.interfaceIDs.nightscoutId = id + it.interfaceIDs.pumpId = pumpId + it.interfaceIDs.pumpType = pumpType + it.interfaceIDs.pumpSerial = pumpSerial + } +} + diff --git a/core/src/main/java/info/nightscout/androidaps/extensions/CarbsExtension.kt b/core/src/main/java/info/nightscout/androidaps/extensions/CarbsExtension.kt new file mode 100644 index 0000000000..54d200e9f6 --- /dev/null +++ b/core/src/main/java/info/nightscout/androidaps/extensions/CarbsExtension.kt @@ -0,0 +1,60 @@ +package info.nightscout.androidaps.extensions + +import info.nightscout.androidaps.database.embedments.InterfaceIDs +import info.nightscout.androidaps.database.entities.Carbs +import info.nightscout.androidaps.database.entities.TherapyEvent +import info.nightscout.androidaps.utils.DateUtil +import info.nightscout.androidaps.utils.JsonHelper +import org.json.JSONObject + +fun Carbs.toJson(dateUtil: DateUtil): JSONObject = + JSONObject() + .put("eventType", if (amount < 12) TherapyEvent.Type.CARBS_CORRECTION.text else TherapyEvent.Type.MEAL_BOLUS.text) + .put("carbs", amount) + .put("created_at", dateUtil.toISOString(timestamp)) + .put("date", timestamp).also { + if (duration != 0L) it.put("duration", duration) + if (interfaceIDs.pumpId != null) it.put("pumpId", interfaceIDs.pumpId) + if (interfaceIDs.pumpType != null) it.put("pumpType", interfaceIDs.pumpType!!.name) + if (interfaceIDs.pumpSerial != null) it.put("pumpSerial", interfaceIDs.pumpSerial) + if (interfaceIDs.nightscoutId != null) it.put("_id", interfaceIDs.nightscoutId) + } + +/* + create fake object with nsID and isValid == false + */ +fun carbsFromNsIdForInvalidating(nsId: String): Carbs = + carbsFromJson( + JSONObject() + .put("mills", 1) + .put("carbs", -1.0) + .put("_id", nsId) + .put("isValid", false) + )!! + +fun carbsFromJson(jsonObject: JSONObject): Carbs? { + val timestamp = JsonHelper.safeGetLongAllowNull(jsonObject, "mills", null) ?: return null + val duration = JsonHelper.safeGetLong(jsonObject, "duration") + val amount = JsonHelper.safeGetDoubleAllowNull(jsonObject, "carbs") ?: return null + val isValid = JsonHelper.safeGetBoolean(jsonObject, "isValid", true) + val id = JsonHelper.safeGetStringAllowNull(jsonObject, "_id", null) ?: return null + val pumpId = JsonHelper.safeGetLongAllowNull(jsonObject, "pumpId", null) + val pumpType = InterfaceIDs.PumpType.fromString(JsonHelper.safeGetStringAllowNull(jsonObject, "pumpType", null)) + val pumpSerial = JsonHelper.safeGetStringAllowNull(jsonObject, "pumpSerial", null) + + if (timestamp == 0L) return null + if (amount == 0.0) return null + + return Carbs( + timestamp = timestamp, + duration = duration, + amount = amount, + isValid = isValid + ).also { + it.interfaceIDs.nightscoutId = id + it.interfaceIDs.pumpId = pumpId + it.interfaceIDs.pumpType = pumpType + it.interfaceIDs.pumpSerial = pumpSerial + } +} + diff --git a/core/src/main/java/info/nightscout/androidaps/utils/extensions/Concurrency.kt b/core/src/main/java/info/nightscout/androidaps/extensions/Concurrency.kt similarity index 93% rename from core/src/main/java/info/nightscout/androidaps/utils/extensions/Concurrency.kt rename to core/src/main/java/info/nightscout/androidaps/extensions/Concurrency.kt index b958a0ea24..e0ecdf7f37 100644 --- a/core/src/main/java/info/nightscout/androidaps/utils/extensions/Concurrency.kt +++ b/core/src/main/java/info/nightscout/androidaps/extensions/Concurrency.kt @@ -1,4 +1,4 @@ -package info.nightscout.androidaps.utils.extensions +package info.nightscout.androidaps.extensions @Suppress("PLATFORM_CLASS_MAPPED_TO_KOTLIN", "NOTHING_TO_INLINE") diff --git a/core/src/main/java/info/nightscout/androidaps/plugins/aps/loop/DeviceStatus.java b/core/src/main/java/info/nightscout/androidaps/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/extensions/DeviceStatusExtension.kt index f883c49da7..1d5d6dea9c 100644 --- a/core/src/main/java/info/nightscout/androidaps/plugins/aps/loop/DeviceStatus.java +++ b/core/src/main/java/info/nightscout/androidaps/extensions/DeviceStatusExtension.kt @@ -1,12 +1,88 @@ -package info.nightscout.androidaps.plugins.aps.loop; +package info.nightscout.androidaps.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.Pump +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(dateUtil: DateUtil): 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, + pump: Pump, + receiverStatusStore: ReceiverStatusStore, + runningConfiguration: RunningConfiguration, + version: String +): DeviceStatus? { + val profile = profileFunction.getProfile() ?: return null + val profileName = profileFunction.getProfileName() + + 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(dateUtil)?.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(dateUtil) + 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 = pump.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/core/src/main/java/info/nightscout/androidaps/extensions/ExtendedBolusExtension.kt b/core/src/main/java/info/nightscout/androidaps/extensions/ExtendedBolusExtension.kt new file mode 100644 index 0000000000..ab34f7fcc5 --- /dev/null +++ b/core/src/main/java/info/nightscout/androidaps/extensions/ExtendedBolusExtension.kt @@ -0,0 +1,195 @@ +package info.nightscout.androidaps.extensions + +import info.nightscout.androidaps.data.IobTotal +import info.nightscout.androidaps.data.Profile +import info.nightscout.androidaps.database.embedments.InterfaceIDs +import info.nightscout.androidaps.database.entities.Bolus +import info.nightscout.androidaps.database.entities.ExtendedBolus +import info.nightscout.androidaps.database.entities.TemporaryBasal +import info.nightscout.androidaps.database.entities.TherapyEvent +import info.nightscout.androidaps.database.interfaces.end +import info.nightscout.androidaps.interfaces.Insulin +import info.nightscout.androidaps.plugins.iob.iobCobCalculator.AutosensResult +import info.nightscout.androidaps.utils.DateUtil +import info.nightscout.androidaps.utils.DecimalFormatter.to2Decimal +import info.nightscout.androidaps.utils.JsonHelper +import info.nightscout.androidaps.utils.T +import org.json.JSONObject +import kotlin.math.ceil +import kotlin.math.max +import kotlin.math.min +import kotlin.math.round +import kotlin.math.roundToInt + +fun ExtendedBolus.isInProgress(dateUtil: DateUtil): Boolean = + dateUtil.now() in timestamp..timestamp + duration + +val ExtendedBolus.plannedRemainingMinutes: Int + get() = max(round((end - System.currentTimeMillis()) / 1000.0 / 60).toInt(), 0) + +fun ExtendedBolus.toStringFull(dateUtil: DateUtil): String = + "E " + to2Decimal(rate) + "U/h @" + dateUtil.timeString(timestamp) + + " " + getPassedDurationToTimeInMinutes(dateUtil.now()) + "/" + T.msecs(duration).mins() + "min" + +fun ExtendedBolus.toStringMedium(dateUtil: DateUtil): String = + to2Decimal(rate) + "U/h " + getPassedDurationToTimeInMinutes(dateUtil.now()) + "/" + T.msecs(duration).mins() + "'" + +fun ExtendedBolus.toStringTotal(): String = "${to2Decimal(amount)}U ( ${to2Decimal(rate)} U/h )" + +fun ExtendedBolus.getPassedDurationToTimeInMinutes(time: Long): Int = + ((min(time, end) - timestamp) / 60.0 / 1000).roundToInt() + +fun ExtendedBolus.toTemporaryBasal(profile: Profile): TemporaryBasal = + TemporaryBasal( + timestamp = timestamp, + duration = duration, + rate = profile.getBasal(timestamp) + rate, + isAbsolute = true, + isValid = isValid, + interfaceIDs_backing = interfaceIDs_backing, + type = TemporaryBasal.Type.FAKE_EXTENDED + ) + +fun ExtendedBolus.toJson(profile: Profile, dateUtil: DateUtil): JSONObject = + if (isEmulatingTempBasal) + toTemporaryBasal(profile) + .toJson(profile, dateUtil) + .put("extendedEmulated", toRealJson(dateUtil)) + else toRealJson(dateUtil) + +fun ExtendedBolus.toRealJson(dateUtil: DateUtil): JSONObject = + JSONObject() + .put("created_at", dateUtil.toISOString(timestamp)) + .put("enteredBy", "openaps://" + "AndroidAPS") + .put("eventType", TherapyEvent.Type.COMBO_BOLUS.text) + .put("duration", T.msecs(duration).mins()) + .put("splitNow", 0) + .put("splitExt", 100) + .put("enteredinsulin", amount) + .put("relative", rate) + .put("isValid", isValid) + .put("isEmulatingTempBasal", isEmulatingTempBasal) + .also { + if (interfaceIDs.pumpId != null) it.put("pumpId", interfaceIDs.pumpId) + if (interfaceIDs.endId != null) it.put("endId", interfaceIDs.endId) + if (interfaceIDs.pumpType != null) it.put("pumpType", interfaceIDs.pumpType!!.name) + if (interfaceIDs.pumpSerial != null) it.put("pumpSerial", interfaceIDs.pumpSerial) + if (interfaceIDs.nightscoutId != null) it.put("_id", interfaceIDs.nightscoutId) + } + +/* + create fake object with nsID and isValid == false + */ +fun extendedBolusFromNsIdForInvalidating(nsId: String): ExtendedBolus = + extendedBolusFromJson( + JSONObject() + .put("mills", 1) + .put("amount", -1.0) + .put("duration", -1.0) + .put("splitNow", 0) + .put("splitExt", 100) + .put("_id", nsId) + .put("isValid", false) + )!! + +fun extendedBolusFromJson(jsonObject: JSONObject): ExtendedBolus? { + val timestamp = JsonHelper.safeGetLongAllowNull(jsonObject, "mills", null) ?: return null + if (JsonHelper.safeGetIntAllowNull(jsonObject, "splitNow") != 0) return null + if (JsonHelper.safeGetIntAllowNull(jsonObject, "splitExt") != 100) return null + val amount = JsonHelper.safeGetDoubleAllowNull(jsonObject, "enteredinsulin") ?: return null + val duration = JsonHelper.safeGetLongAllowNull(jsonObject, "duration") ?: return null + val isValid = JsonHelper.safeGetBoolean(jsonObject, "isValid", true) + val isEmulatingTempBasal = JsonHelper.safeGetBoolean(jsonObject, "isEmulatingTempBasal", false) + val id = JsonHelper.safeGetStringAllowNull(jsonObject, "_id", null) ?: return null + val pumpId = JsonHelper.safeGetLongAllowNull(jsonObject, "pumpId", null) + val endPumpId = JsonHelper.safeGetLongAllowNull(jsonObject, "endId", null) + val pumpType = InterfaceIDs.PumpType.fromString(JsonHelper.safeGetStringAllowNull(jsonObject, "pumpType", null)) + val pumpSerial = JsonHelper.safeGetStringAllowNull(jsonObject, "pumpSerial", null) + + if (timestamp == 0L) return null + if (duration == 0L) return null + if (amount == 0.0) return null + + return ExtendedBolus( + timestamp = timestamp, + amount = amount, + duration = T.mins(duration).msecs(), + isEmulatingTempBasal = isEmulatingTempBasal, + isValid = isValid + ).also { + it.interfaceIDs.nightscoutId = id + it.interfaceIDs.pumpId = pumpId + it.interfaceIDs.endId = endPumpId + it.interfaceIDs.pumpType = pumpType + it.interfaceIDs.pumpSerial = pumpSerial + } +} + +fun ExtendedBolus.iobCalc(time: Long, profile: Profile, insulinInterface: Insulin): IobTotal { + val result = IobTotal(time) + val realDuration = getPassedDurationToTimeInMinutes(time) + if (realDuration > 0) { + val dia = profile.dia + val diaAgo = time - dia * 60 * 60 * 1000 + val aboutFiveMinIntervals = ceil(realDuration / 5.0).toInt() + val spacing = realDuration / aboutFiveMinIntervals + for (j in 0L until aboutFiveMinIntervals) { + // find middle of the interval + val calcDate = (timestamp + j * spacing * 60 * 1000 + 0.5 * spacing * 60 * 1000).toLong() + if (calcDate > diaAgo && calcDate <= time) { + val tempBolusSize: Double = rate * spacing / 60.0 + val tempBolusPart = Bolus( + timestamp = calcDate, + amount = tempBolusSize, + type = Bolus.Type.NORMAL + ) + val aIOB = insulinInterface.iobCalcForTreatment(tempBolusPart, time, dia) + result.iob += aIOB.iobContrib + result.activity += aIOB.activityContrib + result.extendedBolusInsulin += tempBolusPart.amount + } + } + } + return result +} + +fun ExtendedBolus.iobCalc(time: Long, profile: Profile, lastAutosensResult: AutosensResult, exercise_mode: Boolean, half_basal_exercise_target: Int, isTempTarget: Boolean, insulinInterface: Insulin): IobTotal { + val result = IobTotal(time) + val realDuration = getPassedDurationToTimeInMinutes(time) + var sensitivityRatio = lastAutosensResult.ratio + val normalTarget = 100.0 + if (exercise_mode && isTempTarget && profile.targetMgdl >= normalTarget + 5) { + // w/ target 100, temp target 110 = .89, 120 = 0.8, 140 = 0.67, 160 = .57, and 200 = .44 + // e.g.: Sensitivity ratio set to 0.8 based on temp target of 120; Adjusting basal from 1.65 to 1.35; ISF from 58.9 to 73.6 + val c = half_basal_exercise_target - normalTarget + sensitivityRatio = c / (c + profile.targetMgdl - normalTarget) + } + if (realDuration > 0) { + var netBasalRate: Double + val dia = profile.dia + val diaAgo = time - dia * 60 * 60 * 1000 + val aboutFiveMinIntervals = ceil(realDuration / 5.0).toInt() + val spacing = realDuration / aboutFiveMinIntervals + for (j in 0L until aboutFiveMinIntervals) { + // find middle of the interval + val calcDate = (timestamp + j * spacing * 60 * 1000 + 0.5 * spacing * 60 * 1000).toLong() + val basalRate = profile.getBasal(calcDate) + val basalRateCorrection = basalRate * (sensitivityRatio - 1) + netBasalRate = rate - basalRateCorrection + if (calcDate > diaAgo && calcDate <= time) { + val tempBolusSize = netBasalRate * spacing / 60.0 + val tempBolusPart = Bolus( + timestamp = calcDate, + amount = tempBolusSize, + type = Bolus.Type.NORMAL + ) + val aIOB = insulinInterface.iobCalcForTreatment(tempBolusPart, time, dia) + result.iob += aIOB.iobContrib + result.activity += aIOB.activityContrib + result.extendedBolusInsulin += tempBolusPart.amount + } + } + } + return result +} + diff --git a/core/src/main/java/info/nightscout/androidaps/utils/extensions/FoodExtension.kt b/core/src/main/java/info/nightscout/androidaps/extensions/FoodExtension.kt similarity index 70% rename from core/src/main/java/info/nightscout/androidaps/utils/extensions/FoodExtension.kt rename to core/src/main/java/info/nightscout/androidaps/extensions/FoodExtension.kt index e2624775a7..dfda0de134 100644 --- a/core/src/main/java/info/nightscout/androidaps/utils/extensions/FoodExtension.kt +++ b/core/src/main/java/info/nightscout/androidaps/extensions/FoodExtension.kt @@ -1,7 +1,6 @@ -package info.nightscout.androidaps.utils.extensions +package info.nightscout.androidaps.extensions import info.nightscout.androidaps.database.entities.Food -import info.nightscout.androidaps.plugins.general.nsclient.NSUpload import info.nightscout.androidaps.utils.JsonHelper import org.json.JSONObject @@ -18,7 +17,7 @@ fun foodFromJson(jsonObject: JSONObject): Food? { val protein = JsonHelper.safeGetIntAllowNull(jsonObject, "protein") val fat = JsonHelper.safeGetIntAllowNull(jsonObject, "fat") val id = JsonHelper.safeGetStringAllowNull(jsonObject, "_id", null) ?: return null - val isValid = JsonHelper.safeGetBoolean(jsonObject, NSUpload.ISVALID, true) + val isValid = JsonHelper.safeGetBoolean(jsonObject, "isValid", true) val food = Food( name = name, @@ -38,3 +37,22 @@ fun foodFromJson(jsonObject: JSONObject): Food? { } return null } + +fun Food.toJson(): JSONObject = + JSONObject() + .put("type", "food") + .put("name", name) + .put("category", category) + .put("subcategory", subCategory) + .put("unit", unit) + .put("portion", portion) + .put("carbs", carbs) + .put("gi", gi) + .put("energy", energy) + .put("protein", protein) + .put("fat", fat) + .put("isValid", isValid).also { + if (interfaceIDs.nightscoutId != null) it + .put("_id", interfaceIDs.nightscoutId) + } + diff --git a/core/src/main/java/info/nightscout/androidaps/extensions/GlucoseValueExtension.kt b/core/src/main/java/info/nightscout/androidaps/extensions/GlucoseValueExtension.kt new file mode 100644 index 0000000000..1396c99c4a --- /dev/null +++ b/core/src/main/java/info/nightscout/androidaps/extensions/GlucoseValueExtension.kt @@ -0,0 +1,26 @@ +package info.nightscout.androidaps.extensions + +import info.nightscout.androidaps.Constants +import info.nightscout.androidaps.database.entities.GlucoseValue +import info.nightscout.androidaps.utils.DateUtil +import info.nightscout.androidaps.utils.DecimalFormatter +import org.json.JSONObject + +fun GlucoseValue.valueToUnits(units: String): Double = + if (units == Constants.MGDL) value + else value * Constants.MGDL_TO_MMOLL + +fun GlucoseValue.valueToUnitsString(units: String): String = + if (units == Constants.MGDL) DecimalFormatter.to0Decimal(value) + else DecimalFormatter.to1Decimal(value * Constants.MGDL_TO_MMOLL) + +fun GlucoseValue.toJson(dateUtil: DateUtil): JSONObject = + JSONObject() + .put("device", sourceSensor.text) + .put("date", timestamp) + .put("dateString", dateUtil.toISOString(timestamp)) + .put("sgv", value) + .put("direction", trendArrow.text) + .put("type", "sgv").also { + if (interfaceIDs.nightscoutId != null) it.put("_id", interfaceIDs.nightscoutId) + } diff --git a/core/src/main/java/info/nightscout/androidaps/utils/extensions/HexByteArrayConversion.kt b/core/src/main/java/info/nightscout/androidaps/extensions/HexByteArrayConversion.kt similarity index 94% rename from core/src/main/java/info/nightscout/androidaps/utils/extensions/HexByteArrayConversion.kt rename to core/src/main/java/info/nightscout/androidaps/extensions/HexByteArrayConversion.kt index 2d685210e7..8de21e6552 100644 --- a/core/src/main/java/info/nightscout/androidaps/utils/extensions/HexByteArrayConversion.kt +++ b/core/src/main/java/info/nightscout/androidaps/extensions/HexByteArrayConversion.kt @@ -1,4 +1,4 @@ -package info.nightscout.androidaps.utils.extensions +package info.nightscout.androidaps.extensions import java.util.* diff --git a/core/src/main/java/info/nightscout/androidaps/utils/extensions/HtmlString.kt b/core/src/main/java/info/nightscout/androidaps/extensions/HtmlString.kt similarity index 86% rename from core/src/main/java/info/nightscout/androidaps/utils/extensions/HtmlString.kt rename to core/src/main/java/info/nightscout/androidaps/extensions/HtmlString.kt index 6dbb621c6a..e72d37e334 100644 --- a/core/src/main/java/info/nightscout/androidaps/utils/extensions/HtmlString.kt +++ b/core/src/main/java/info/nightscout/androidaps/extensions/HtmlString.kt @@ -1,4 +1,4 @@ -package info.nightscout.androidaps.utils.extensions +package info.nightscout.androidaps.extensions import androidx.annotation.ColorRes import info.nightscout.androidaps.utils.resources.ResourceHelper diff --git a/core/src/main/java/info/nightscout/androidaps/utils/extensions/JSONObjectExt.kt b/core/src/main/java/info/nightscout/androidaps/extensions/JSONObjectExt.kt similarity index 97% rename from core/src/main/java/info/nightscout/androidaps/utils/extensions/JSONObjectExt.kt rename to core/src/main/java/info/nightscout/androidaps/extensions/JSONObjectExt.kt index 6ddb1920ed..3a42eabe4b 100644 --- a/core/src/main/java/info/nightscout/androidaps/utils/extensions/JSONObjectExt.kt +++ b/core/src/main/java/info/nightscout/androidaps/extensions/JSONObjectExt.kt @@ -1,4 +1,4 @@ -package info.nightscout.androidaps.utils.extensions +package info.nightscout.androidaps.extensions import androidx.annotation.StringRes import info.nightscout.androidaps.utils.resources.ResourceHelper diff --git a/core/src/main/java/info/nightscout/androidaps/extensions/PumpStateExtension.kt b/core/src/main/java/info/nightscout/androidaps/extensions/PumpStateExtension.kt new file mode 100644 index 0000000000..beb349d3d6 --- /dev/null +++ b/core/src/main/java/info/nightscout/androidaps/extensions/PumpStateExtension.kt @@ -0,0 +1,62 @@ +package info.nightscout.androidaps.extensions + +import info.nightscout.androidaps.data.Profile +import info.nightscout.androidaps.interfaces.PumpSync +import info.nightscout.androidaps.utils.DateUtil +import info.nightscout.androidaps.utils.DecimalFormatter +import info.nightscout.androidaps.utils.DecimalFormatter.to2Decimal +import info.nightscout.androidaps.utils.T +import kotlin.math.ceil +import kotlin.math.max +import kotlin.math.min +import kotlin.math.roundToInt + +val PumpSync.PumpState.TemporaryBasal.end: Long + get() = timestamp + duration + +val PumpSync.PumpState.TemporaryBasal.plannedRemainingMinutes: Long + get() = max(T.msecs(end - System.currentTimeMillis()).mins(), 0L) + +val PumpSync.PumpState.TemporaryBasal.plannedRemainingMinutesRoundedUp: Int + get() = max(ceil((end - System.currentTimeMillis()) / 1000.0 / 60).toInt(), 0) + +val PumpSync.PumpState.TemporaryBasal.durationInMinutes: Int + get() = T.msecs(duration).mins().toInt() + +fun PumpSync.PumpState.TemporaryBasal.getPassedDurationToTimeInMinutes(time: Long): Int = + ((min(time, end) - timestamp) / 60.0 / 1000).roundToInt() + +fun PumpSync.PumpState.TemporaryBasal.convertedToAbsolute(time: Long, profile: Profile): Double = + if (isAbsolute) rate + else profile.getBasal(time) * rate / 100 + +fun PumpSync.PumpState.TemporaryBasal.toStringFull(dateUtil: DateUtil): String { + return when { + isAbsolute -> { + DecimalFormatter.to2Decimal(rate) + "U/h @" + + dateUtil.timeString(timestamp) + + " " + getPassedDurationToTimeInMinutes(dateUtil.now()) + "/" + durationInMinutes + "'" + } + + else -> { // percent + rate.toString() + "% @" + + dateUtil.timeString(timestamp) + + " " + getPassedDurationToTimeInMinutes(dateUtil.now()) + "/" + durationInMinutes + "'" + } + } +} + +val PumpSync.PumpState.ExtendedBolus.end: Long + get() = timestamp + duration + +val PumpSync.PumpState.ExtendedBolus.plannedRemainingMinutes: Long + get() = max(T.msecs(end - System.currentTimeMillis()).mins(), 0L) + +fun PumpSync.PumpState.ExtendedBolus.getPassedDurationToTimeInMinutes(time: Long): Int = + ((min(time, end) - timestamp) / 60.0 / 1000).roundToInt() + +fun PumpSync.PumpState.ExtendedBolus.toStringFull(dateUtil: DateUtil): String = + "E " + to2Decimal(rate) + "U/h @" + + dateUtil.timeString(timestamp) + + " " + getPassedDurationToTimeInMinutes(dateUtil.now()) + "/" + T.msecs(duration).mins() + "min" + diff --git a/core/src/main/java/info/nightscout/androidaps/extensions/TemporaryBasalExtension.kt b/core/src/main/java/info/nightscout/androidaps/extensions/TemporaryBasalExtension.kt new file mode 100644 index 0000000000..6ab4c012e3 --- /dev/null +++ b/core/src/main/java/info/nightscout/androidaps/extensions/TemporaryBasalExtension.kt @@ -0,0 +1,225 @@ +package info.nightscout.androidaps.extensions + +import info.nightscout.androidaps.data.IobTotal +import info.nightscout.androidaps.data.Profile +import info.nightscout.androidaps.database.embedments.InterfaceIDs +import info.nightscout.androidaps.database.entities.Bolus +import info.nightscout.androidaps.database.entities.TemporaryBasal +import info.nightscout.androidaps.database.entities.TemporaryBasal.Type.Companion.fromString +import info.nightscout.androidaps.database.entities.TherapyEvent +import info.nightscout.androidaps.database.interfaces.end +import info.nightscout.androidaps.interfaces.Insulin +import info.nightscout.androidaps.plugins.iob.iobCobCalculator.AutosensResult +import info.nightscout.androidaps.utils.DateUtil +import info.nightscout.androidaps.utils.DecimalFormatter.to0Decimal +import info.nightscout.androidaps.utils.DecimalFormatter.to2Decimal +import info.nightscout.androidaps.utils.JsonHelper +import info.nightscout.androidaps.utils.T +import org.json.JSONObject +import kotlin.math.ceil +import kotlin.math.max +import kotlin.math.min +import kotlin.math.round +import kotlin.math.roundToInt + +fun TemporaryBasal.getPassedDurationToTimeInMinutes(time: Long): Int = + ((min(time, end) - timestamp) / 60.0 / 1000).roundToInt() + +val TemporaryBasal.plannedRemainingMinutes: Int + get() = max(round((end - System.currentTimeMillis()) / 1000.0 / 60).toInt(), 0) + +fun TemporaryBasal.convertedToAbsolute(time: Long, profile: Profile): Double = + if (isAbsolute) rate + else profile.getBasal(time) * rate / 100 + +fun TemporaryBasal.convertedToPercent(time: Long, profile: Profile): Int = + if (!isAbsolute) rate.toInt() + else (rate / profile.getBasal(time) * 100).toInt() + +fun TemporaryBasal.netExtendedRate(profile: Profile) = rate - profile.getBasal(timestamp) +val TemporaryBasal.durationInMinutes + get() = T.msecs(duration).mins() + +fun TemporaryBasal.toStringFull(profile: Profile, dateUtil: DateUtil): String { + return when { + type == TemporaryBasal.Type.FAKE_EXTENDED -> { + to2Decimal(rate) + "U/h (" + to2Decimal(netExtendedRate(profile)) + "E) @" + + dateUtil.timeString(timestamp) + + " " + getPassedDurationToTimeInMinutes(dateUtil.now()) + "/" + durationInMinutes + "'" + } + + isAbsolute -> { + to2Decimal(rate) + "U/h @" + + dateUtil.timeString(timestamp) + + " " + getPassedDurationToTimeInMinutes(dateUtil.now()) + "/" + durationInMinutes + "'" + } + + else -> { // percent + rate.toString() + "% @" + + dateUtil.timeString(timestamp) + + " " + getPassedDurationToTimeInMinutes(dateUtil.now()) + "/" + durationInMinutes + "'" + } + } +} + +fun TemporaryBasal.toJson(profile: Profile, dateUtil: DateUtil): JSONObject = + JSONObject() + .put("created_at", dateUtil.toISOString(timestamp)) + .put("enteredBy", "openaps://" + "AndroidAPS") + .put("eventType", TherapyEvent.Type.TEMPORARY_BASAL.text) + .put("duration", T.msecs(duration).mins()) + .put("rate", rate) + .put("type", type.name) + .also { + if (isAbsolute) it.put("absolute", rate) + else it.put("percent", convertedToPercent(timestamp, profile) - 100) + if (interfaceIDs.pumpId != null) it.put("pumpId", interfaceIDs.pumpId) + if (interfaceIDs.endId != null) it.put("endId", interfaceIDs.endId) + if (interfaceIDs.pumpType != null) it.put("pumpType", interfaceIDs.pumpType!!.name) + if (interfaceIDs.pumpSerial != null) it.put("pumpSerial", interfaceIDs.pumpSerial) + if (interfaceIDs.nightscoutId != null) it.put("_id", interfaceIDs.nightscoutId) + } + +/* + create fake object with nsID and isValid == false + */ +fun temporaryBasalFromNsIdForInvalidating(nsId: String): TemporaryBasal = + temporaryBasalFromJson( + JSONObject() + .put("mills", 1) + .put("absolute", 1.0) + .put("duration", 1.0) + .put("_id", nsId) + .put("isValid", false) + )!! + +fun temporaryBasalFromJson(jsonObject: JSONObject): TemporaryBasal? { + val timestamp = JsonHelper.safeGetLongAllowNull(jsonObject, "mills", null) ?: return null + val percent = JsonHelper.safeGetDoubleAllowNull(jsonObject, "percent") + val absolute = JsonHelper.safeGetDoubleAllowNull(jsonObject, "absolute") + val duration = JsonHelper.safeGetLongAllowNull(jsonObject, "duration") ?: return null + val type = fromString(JsonHelper.safeGetString(jsonObject, "type")) + val isValid = JsonHelper.safeGetBoolean(jsonObject, "isValid", true) + val id = JsonHelper.safeGetStringAllowNull(jsonObject, "_id", null) ?: return null + val pumpId = JsonHelper.safeGetLongAllowNull(jsonObject, "pumpId", null) + val endPumpId = JsonHelper.safeGetLongAllowNull(jsonObject, "endId", null) + val pumpType = InterfaceIDs.PumpType.fromString(JsonHelper.safeGetStringAllowNull(jsonObject, "pumpType", null)) + val pumpSerial = JsonHelper.safeGetStringAllowNull(jsonObject, "pumpSerial", null) + + val rate = if (percent != null) percent + 100 else absolute ?: return null + if (duration == 0L) return null + if (timestamp == 0L) return null + + return TemporaryBasal( + timestamp = timestamp, + rate = rate, + duration = T.mins(duration).msecs(), + type = type, + isAbsolute = percent == null, + isValid = isValid + ).also { + it.interfaceIDs.nightscoutId = id + it.interfaceIDs.pumpId = pumpId + it.interfaceIDs.endId = endPumpId + it.interfaceIDs.pumpType = pumpType + it.interfaceIDs.pumpSerial = pumpSerial + } +} + +fun TemporaryBasal.toStringShort(): String = + if (isAbsolute || type == TemporaryBasal.Type.FAKE_EXTENDED) to2Decimal(rate) + "U/h" + else "${to0Decimal(rate)}%" + +fun TemporaryBasal.iobCalc(time: Long, profile: Profile, insulinInterface: Insulin): IobTotal { + val result = IobTotal(time) + val realDuration: Int = getPassedDurationToTimeInMinutes(time) + var netBasalAmount = 0.0 + if (realDuration > 0) { + var netBasalRate: Double + val dia = profile.dia + val diaAgo = time - dia * 60 * 60 * 1000 + val aboutFiveMinIntervals = ceil(realDuration / 5.0).toInt() + val tempBolusSpacing = (realDuration / aboutFiveMinIntervals).toDouble() + for (j in 0L until aboutFiveMinIntervals) { + // find middle of the interval + val calcDate = (timestamp + j * tempBolusSpacing * 60 * 1000 + 0.5 * tempBolusSpacing * 60 * 1000).toLong() + val basalRate = profile.getBasal(calcDate) + netBasalRate = if (isAbsolute) { + rate - basalRate + } else { + (rate - 100) / 100.0 * basalRate + } + if (calcDate > diaAgo && calcDate <= time) { + val tempBolusSize = netBasalRate * tempBolusSpacing / 60.0 + netBasalAmount += tempBolusSize + val tempBolusPart = Bolus( + timestamp = calcDate, + amount = tempBolusSize, + type = Bolus.Type.NORMAL + ) + val aIOB = insulinInterface.iobCalcForTreatment(tempBolusPart, time, dia) + result.basaliob += aIOB.iobContrib + result.activity += aIOB.activityContrib + result.netbasalinsulin += tempBolusPart.amount + if (tempBolusPart.amount > 0) { + result.hightempinsulin += tempBolusPart.amount + } + } + result.netRatio = netBasalRate // ratio at the end of interval + } + } + result.netInsulin = netBasalAmount + return result +} + +fun TemporaryBasal.iobCalc(time: Long, profile: Profile, lastAutosensResult: AutosensResult, exercise_mode: Boolean, half_basal_exercise_target: Int, isTempTarget: Boolean, insulinInterface: Insulin): IobTotal { + val result = IobTotal(time) + val realDuration: Double = getPassedDurationToTimeInMinutes(time).toDouble() + var netBasalAmount = 0.0 + var sensitivityRatio = lastAutosensResult.ratio + val normalTarget = 100.0 + if (exercise_mode && isTempTarget && profile.targetMgdl >= normalTarget + 5) { + // w/ target 100, temp target 110 = .89, 120 = 0.8, 140 = 0.67, 160 = .57, and 200 = .44 + // e.g.: Sensitivity ratio set to 0.8 based on temp target of 120; Adjusting basal from 1.65 to 1.35; ISF from 58.9 to 73.6 + val c = half_basal_exercise_target - normalTarget + sensitivityRatio = c / (c + profile.targetMgdl - normalTarget) + } + if (realDuration > 0) { + var netBasalRate: Double + val dia = profile.dia + val diaAgo = time - dia * 60 * 60 * 1000 + val aboutFiveMinIntervals = ceil(realDuration / 5.0).toInt() + val tempBolusSpacing = realDuration / aboutFiveMinIntervals + for (j in 0L until aboutFiveMinIntervals) { + // find middle of the interval + val calcDate = (timestamp + j * tempBolusSpacing * 60 * 1000 + 0.5 * tempBolusSpacing * 60 * 1000).toLong() + var basalRate = profile.getBasal(calcDate) + basalRate *= sensitivityRatio + netBasalRate = if (isAbsolute) { + rate - basalRate + } else { + val abs: Double = rate / 100.0 * profile.getBasal(calcDate) + abs - basalRate + } + if (calcDate > diaAgo && calcDate <= time) { + val tempBolusSize = netBasalRate * tempBolusSpacing / 60.0 + netBasalAmount += tempBolusSize + val tempBolusPart = Bolus( + timestamp = calcDate, + amount = tempBolusSize, + type = Bolus.Type.NORMAL + ) + val aIOB = insulinInterface.iobCalcForTreatment(tempBolusPart, time, dia) + result.basaliob += aIOB.iobContrib + result.activity += aIOB.activityContrib + result.netbasalinsulin += tempBolusPart.amount + if (tempBolusPart.amount > 0) { + result.hightempinsulin += tempBolusPart.amount + } + } + result.netRatio = netBasalRate // ratio at the end of interval + } + } + result.netInsulin = netBasalAmount + return result +} diff --git a/core/src/main/java/info/nightscout/androidaps/utils/extensions/TemporaryTargetExtension.kt b/core/src/main/java/info/nightscout/androidaps/extensions/TemporaryTargetExtension.kt similarity index 76% rename from core/src/main/java/info/nightscout/androidaps/utils/extensions/TemporaryTargetExtension.kt rename to core/src/main/java/info/nightscout/androidaps/extensions/TemporaryTargetExtension.kt index b763d71b9b..4cea998153 100644 --- a/core/src/main/java/info/nightscout/androidaps/utils/extensions/TemporaryTargetExtension.kt +++ b/core/src/main/java/info/nightscout/androidaps/extensions/TemporaryTargetExtension.kt @@ -1,12 +1,14 @@ -package info.nightscout.androidaps.utils.extensions +package info.nightscout.androidaps.extensions import info.nightscout.androidaps.Constants import info.nightscout.androidaps.core.R import info.nightscout.androidaps.data.Profile import info.nightscout.androidaps.database.entities.TemporaryTarget -import info.nightscout.androidaps.plugins.general.nsclient.NSUpload +import info.nightscout.androidaps.database.entities.TherapyEvent +import info.nightscout.androidaps.utils.DateUtil import info.nightscout.androidaps.utils.DecimalFormatter import info.nightscout.androidaps.utils.JsonHelper +import info.nightscout.androidaps.utils.T import info.nightscout.androidaps.utils.resources.ResourceHelper import org.json.JSONObject import java.util.concurrent.TimeUnit @@ -37,7 +39,7 @@ fun temporaryTargetFromNsIdForInvalidating(nsId: String): TemporaryTarget = .put("duration", -1) .put("reason", "fake") .put("_id", nsId) - .put(NSUpload.ISVALID, false) + .put("isValid", false) )!! fun temporaryTargetFromJson(jsonObject: JSONObject): TemporaryTarget? { @@ -53,7 +55,9 @@ fun temporaryTargetFromJson(jsonObject: JSONObject): TemporaryTarget? { // this string can be localized from NS, it will not work in this case CUSTOM will be used val reason = TemporaryTarget.Reason.fromString(reasonString) val id = JsonHelper.safeGetStringAllowNull(jsonObject, "_id", null) ?: return null - val isValid = JsonHelper.safeGetBoolean(jsonObject, NSUpload.ISVALID, true) + val isValid = JsonHelper.safeGetBoolean(jsonObject, "isValid", true) + + if (timestamp == 0L) return null if (duration > 0L) { // not ending event @@ -81,4 +85,19 @@ fun temporaryTargetFromJson(jsonObject: JSONObject): TemporaryTarget? { ) tt.interfaceIDs.nightscoutId = id return tt -} \ No newline at end of file +} + +fun TemporaryTarget.toJson(units: String, dateUtil: DateUtil): JSONObject = + JSONObject() + .put("eventType", TherapyEvent.Type.TEMPORARY_TARGET.text) + .put("duration", T.msecs(duration).mins()) + .put("isValid", isValid) + .put("created_at", dateUtil.toISOString(timestamp)) + .put("enteredBy", "AndroidAPS").also { + if (lowTarget > 0) it + .put("reason", reason.text) + .put("targetBottom", Profile.fromMgdlToUnits(lowTarget, units)) + .put("targetTop", Profile.fromMgdlToUnits(highTarget, units)) + .put("units", units) + if (interfaceIDs.nightscoutId != null) it.put("_id", interfaceIDs.nightscoutId) + } diff --git a/core/src/main/java/info/nightscout/androidaps/utils/extensions/TherapyEventExtension.kt b/core/src/main/java/info/nightscout/androidaps/extensions/TherapyEventExtension.kt similarity index 77% rename from core/src/main/java/info/nightscout/androidaps/utils/extensions/TherapyEventExtension.kt rename to core/src/main/java/info/nightscout/androidaps/extensions/TherapyEventExtension.kt index ff6b27d1a3..6dcc11867f 100644 --- a/core/src/main/java/info/nightscout/androidaps/utils/extensions/TherapyEventExtension.kt +++ b/core/src/main/java/info/nightscout/androidaps/extensions/TherapyEventExtension.kt @@ -1,9 +1,8 @@ -package info.nightscout.androidaps.utils.extensions +package info.nightscout.androidaps.extensions import info.nightscout.androidaps.Constants import info.nightscout.androidaps.core.R import info.nightscout.androidaps.database.entities.TherapyEvent -import info.nightscout.androidaps.plugins.general.nsclient.NSUpload import info.nightscout.androidaps.plugins.general.nsclient.data.NSMbg import info.nightscout.androidaps.utils.DateUtil import info.nightscout.androidaps.utils.JsonHelper @@ -12,8 +11,8 @@ import info.nightscout.androidaps.utils.resources.ResourceHelper import org.json.JSONObject import java.util.concurrent.TimeUnit -fun TherapyEvent.age(useShortText: Boolean, resourceHelper: ResourceHelper): String { - val diff = DateUtil.computeDiff(timestamp, System.currentTimeMillis()) +fun TherapyEvent.age(useShortText: Boolean, resourceHelper: ResourceHelper, dateUtil: DateUtil): String { + val diff = dateUtil.computeDiff(timestamp, System.currentTimeMillis()) var days = " " + resourceHelper.gs(R.string.days) + " " var hours = " " + resourceHelper.gs(R.string.hours) + " " if (useShortText) { @@ -57,7 +56,7 @@ fun therapyEventFromNsIdForInvalidating(nsId: String): TherapyEvent = JSONObject() .put("mills", 1) .put("_id", nsId) - .put(NSUpload.ISVALID, false) + .put("isValid", false) )!! fun therapyEventFromJson(jsonObject: JSONObject): TherapyEvent? { @@ -70,7 +69,9 @@ fun therapyEventFromJson(jsonObject: JSONObject): TherapyEvent? { val enteredBy = JsonHelper.safeGetStringAllowNull(jsonObject, "enteredBy", null) val note = JsonHelper.safeGetStringAllowNull(jsonObject, "notes", null) val id = JsonHelper.safeGetStringAllowNull(jsonObject, "_id", null) ?: return null - val isValid = JsonHelper.safeGetBoolean(jsonObject, NSUpload.ISVALID, true) + val isValid = JsonHelper.safeGetBoolean(jsonObject, "isValid", true) + + if (timestamp == 0L) return null val te = TherapyEvent( timestamp = timestamp, @@ -87,6 +88,21 @@ fun therapyEventFromJson(jsonObject: JSONObject): TherapyEvent? { return te } +fun TherapyEvent.toJson(): JSONObject = + JSONObject() + .put("eventType", type.text) + .put("created_at", timestamp) + .put("enteredBy", enteredBy) + .put("units", if (glucoseUnit == TherapyEvent.GlucoseUnit.MGDL) Constants.MGDL else Constants.MMOL) + .also { + if (duration != 0L) it.put("duration", T.msecs(duration).mins()) + if (note != null) it.put("notes", note) + if (glucose != null) it.put("glucose", glucose) + if (glucoseType != null) it.put("glucoseType", glucoseType!!.text) + if (interfaceIDs.nightscoutId != null) it.put("_id", interfaceIDs.nightscoutId) + if (type == TherapyEvent.Type.ANNOUNCEMENT) it.put("isAnnouncement", true) + } + fun isEvent5minBack(list: List, time: Long): Boolean { for (i in list.indices) { val event = list[i] diff --git a/core/src/main/java/info/nightscout/androidaps/utils/extensions/TrendArrowIcon.kt b/core/src/main/java/info/nightscout/androidaps/extensions/TrendArrowIcon.kt similarity index 94% rename from core/src/main/java/info/nightscout/androidaps/utils/extensions/TrendArrowIcon.kt rename to core/src/main/java/info/nightscout/androidaps/extensions/TrendArrowIcon.kt index 51bc4e869f..01fbcbe91a 100644 --- a/core/src/main/java/info/nightscout/androidaps/utils/extensions/TrendArrowIcon.kt +++ b/core/src/main/java/info/nightscout/androidaps/extensions/TrendArrowIcon.kt @@ -1,4 +1,4 @@ -package info.nightscout.androidaps.utils.extensions +package info.nightscout.androidaps.extensions import info.nightscout.androidaps.core.R import info.nightscout.androidaps.database.entities.GlucoseValue diff --git a/core/src/main/java/info/nightscout/androidaps/utils/extensions/UIUtils.kt b/core/src/main/java/info/nightscout/androidaps/extensions/UIUtils.kt similarity index 83% rename from core/src/main/java/info/nightscout/androidaps/utils/extensions/UIUtils.kt rename to core/src/main/java/info/nightscout/androidaps/extensions/UIUtils.kt index 12aa4c031b..fcde955752 100644 --- a/core/src/main/java/info/nightscout/androidaps/utils/extensions/UIUtils.kt +++ b/core/src/main/java/info/nightscout/androidaps/extensions/UIUtils.kt @@ -1,4 +1,4 @@ -package info.nightscout.androidaps.utils.extensions +package info.nightscout.androidaps.extensions import android.os.Handler import android.os.Looper diff --git a/core/src/main/java/info/nightscout/androidaps/utils/extensions/UserEntryExt.kt b/core/src/main/java/info/nightscout/androidaps/extensions/UserEntryExt.kt similarity index 92% rename from core/src/main/java/info/nightscout/androidaps/utils/extensions/UserEntryExt.kt rename to core/src/main/java/info/nightscout/androidaps/extensions/UserEntryExt.kt index c0ce48e35f..f38e9f384d 100644 --- a/core/src/main/java/info/nightscout/androidaps/utils/extensions/UserEntryExt.kt +++ b/core/src/main/java/info/nightscout/androidaps/extensions/UserEntryExt.kt @@ -1,4 +1,4 @@ -package info.nightscout.androidaps.utils.extensions +package info.nightscout.androidaps.extensions import info.nightscout.androidaps.core.R import info.nightscout.androidaps.database.entities.UserEntry.* diff --git a/core/src/main/java/info/nightscout/androidaps/interfaces/APSInterface.kt b/core/src/main/java/info/nightscout/androidaps/interfaces/APS.kt similarity index 90% rename from core/src/main/java/info/nightscout/androidaps/interfaces/APSInterface.kt rename to core/src/main/java/info/nightscout/androidaps/interfaces/APS.kt index 38eb6dac20..cb2c2b4005 100644 --- a/core/src/main/java/info/nightscout/androidaps/interfaces/APSInterface.kt +++ b/core/src/main/java/info/nightscout/androidaps/interfaces/APS.kt @@ -2,7 +2,7 @@ package info.nightscout.androidaps.interfaces import info.nightscout.androidaps.plugins.aps.loop.APSResult -interface APSInterface { +interface APS { val lastAPSResult: APSResult? val lastAPSRun: Long diff --git a/core/src/main/java/info/nightscout/androidaps/interfaces/ActivePlugin.kt b/core/src/main/java/info/nightscout/androidaps/interfaces/ActivePlugin.kt new file mode 100644 index 0000000000..b007705b0b --- /dev/null +++ b/core/src/main/java/info/nightscout/androidaps/interfaces/ActivePlugin.kt @@ -0,0 +1,74 @@ +package info.nightscout.androidaps.interfaces + +import java.util.* + +interface ActivePlugin { + + /** + * Currently selected BgSource plugin + * Default to Dexcom + */ + val activeBgSource: BgSource + + /** + * Currently selected Profile plugin + * Default LocalProfile + */ + val activeProfileSource: ProfileSource + + /** + * Currently selected Insulin plugin + * Default RapidActing + */ + val activeInsulin: Insulin + + /** + * Currently selected APS plugin + * Default SMB + */ + val activeAPS: APS + + /** + * Currently selected Pump plugin + * Default VirtualPump + */ + val activePump: Pump + + /** + * Currently selected Sensitivity plugin + * Default Oref1 + */ + val activeSensitivity: Sensitivity + + /** + * Currently selected Treatments plugin + */ + val activeTreatments: TreatmentsInterface + + /** + * Currently selected Overview plugin + * Always OverviewPlugin + */ + val activeOverview: Overview + + /** + * List of all registered plugins + */ + fun getPluginsList(): ArrayList + + /** + * List of all plugins of type marked as ShowInList + * (for ConfigBuilder UI) + */ + fun getSpecificPluginsVisibleInList(type: PluginType): ArrayList + + /** + * List of all plugins implementing interface + */ + fun getSpecificPluginsListByInterface(interfaceClass: Class<*>): ArrayList + + /** + * Pre-process all plugin types and validate active plugins (ie. only only one plugin for type is selected) + */ + fun verifySelectionInCategories() +} \ No newline at end of file diff --git a/core/src/main/java/info/nightscout/androidaps/interfaces/ActivePluginProvider.kt b/core/src/main/java/info/nightscout/androidaps/interfaces/ActivePluginProvider.kt deleted file mode 100644 index ba13cd3888..0000000000 --- a/core/src/main/java/info/nightscout/androidaps/interfaces/ActivePluginProvider.kt +++ /dev/null @@ -1,22 +0,0 @@ -package info.nightscout.androidaps.interfaces - -import java.util.* - -interface ActivePluginProvider { - - val activeBgSource: BgSourceInterface // Forced to Dexcom - val activeProfileInterface: ProfileInterface // Forced to LocalProfile if not changed - val activeInsulin: InsulinInterface // Forced to RapidActing if not changed - val activeAPS: APSInterface // Forced to SMB - val activePump: PumpInterface // Use in places not reachable without active pump. Otherwise IllegalStateException is thrown - val activeSensitivity: SensitivityInterface // Forced to oref1 if not changed - val activeTreatments: TreatmentsInterface // Forced to treatments - val activeOverview: OverviewInterface // Forced to overview - - fun getPluginsList(): ArrayList - - fun getSpecificPluginsVisibleInListByInterface(interfaceClass: Class<*>, type: PluginType): ArrayList - fun getSpecificPluginsVisibleInList(type: PluginType): ArrayList - fun getSpecificPluginsListByInterface(interfaceClass: Class<*>): ArrayList - fun verifySelectionInCategories() -} \ No newline at end of file diff --git a/core/src/main/java/info/nightscout/androidaps/interfaces/BgSource.kt b/core/src/main/java/info/nightscout/androidaps/interfaces/BgSource.kt new file mode 100644 index 0000000000..91e4638353 --- /dev/null +++ b/core/src/main/java/info/nightscout/androidaps/interfaces/BgSource.kt @@ -0,0 +1,29 @@ +package info.nightscout.androidaps.interfaces + +import info.nightscout.androidaps.database.entities.GlucoseValue + +interface BgSource { + + /** + * Does bg source support advanced filtering ? Currently Dexcom native mode only + * + * @return true if supported + */ + fun advancedFilteringSupported(): Boolean = false + + /** + * Sensor battery level in % + * + * -1 if not supported + */ + val sensorBatteryLevel: Int + get() = -1 + + /** + * Decide if GlucoseValue should be uploaded to NS + * + * @param glucoseValue glucose value + * @return true if GlucoseValue should be uploaded to NS (supported by plugin and enabled in preferences) + */ + fun shouldUploadToNs(glucoseValue: GlucoseValue): Boolean +} \ No newline at end of file diff --git a/core/src/main/java/info/nightscout/androidaps/interfaces/BgSourceInterface.kt b/core/src/main/java/info/nightscout/androidaps/interfaces/BgSourceInterface.kt deleted file mode 100644 index 200b68102d..0000000000 --- a/core/src/main/java/info/nightscout/androidaps/interfaces/BgSourceInterface.kt +++ /dev/null @@ -1,11 +0,0 @@ -package info.nightscout.androidaps.interfaces - -/** - * Created by mike on 20.06.2016. - */ -interface BgSourceInterface { - - fun advancedFilteringSupported(): Boolean = false - val sensorBatteryLevel: Int - get() = -1 -} \ No newline at end of file diff --git a/core/src/main/java/info/nightscout/androidaps/interfaces/CommandQueueProvider.kt b/core/src/main/java/info/nightscout/androidaps/interfaces/CommandQueueProvider.kt index 877dac9809..049ce54013 100644 --- a/core/src/main/java/info/nightscout/androidaps/interfaces/CommandQueueProvider.kt +++ b/core/src/main/java/info/nightscout/androidaps/interfaces/CommandQueueProvider.kt @@ -22,8 +22,8 @@ interface CommandQueueProvider { fun stopPump(callback: Callback?) fun startPump(callback: Callback?) fun setTBROverNotification(callback: Callback?, enable: Boolean) - fun tempBasalAbsolute(absoluteRate: Double, durationInMinutes: Int, enforceNew: Boolean, profile: Profile, callback: Callback?): Boolean - fun tempBasalPercent(percent: Int, durationInMinutes: Int, enforceNew: Boolean, profile: Profile, callback: Callback?): Boolean + fun tempBasalAbsolute(absoluteRate: Double, durationInMinutes: Int, enforceNew: Boolean, profile: Profile, tbrType: PumpSync.TemporaryBasalType, callback: Callback?): Boolean + fun tempBasalPercent(percent: Int, durationInMinutes: Int, enforceNew: Boolean, profile: Profile, tbrType: PumpSync.TemporaryBasalType, callback: Callback?): Boolean fun extendedBolus(insulin: Double, durationInMinutes: Int, callback: Callback?): Boolean fun cancelTempBasal(enforceNew: Boolean, callback: Callback?): Boolean fun cancelExtended(callback: Callback?): Boolean diff --git a/core/src/main/java/info/nightscout/androidaps/interfaces/ConfigInterface.kt b/core/src/main/java/info/nightscout/androidaps/interfaces/Config.kt similarity index 86% rename from core/src/main/java/info/nightscout/androidaps/interfaces/ConfigInterface.kt rename to core/src/main/java/info/nightscout/androidaps/interfaces/Config.kt index cc4ba86182..9a694dc4e8 100644 --- a/core/src/main/java/info/nightscout/androidaps/interfaces/ConfigInterface.kt +++ b/core/src/main/java/info/nightscout/androidaps/interfaces/Config.kt @@ -1,6 +1,7 @@ package info.nightscout.androidaps.interfaces -interface ConfigInterface { +@Suppress("PropertyName") +interface Config { val SUPPORTEDNSVERSION: Int val APS: Boolean val NSCLIENT: Boolean diff --git a/core/src/main/java/info/nightscout/androidaps/interfaces/ConfigBuilderInterface.kt b/core/src/main/java/info/nightscout/androidaps/interfaces/ConfigBuilder.kt similarity index 78% rename from core/src/main/java/info/nightscout/androidaps/interfaces/ConfigBuilderInterface.kt rename to core/src/main/java/info/nightscout/androidaps/interfaces/ConfigBuilder.kt index 6b248fd7dc..2c7c9583d6 100644 --- a/core/src/main/java/info/nightscout/androidaps/interfaces/ConfigBuilderInterface.kt +++ b/core/src/main/java/info/nightscout/androidaps/interfaces/ConfigBuilder.kt @@ -1,6 +1,7 @@ package info.nightscout.androidaps.interfaces -interface ConfigBuilderInterface { +interface ConfigBuilder { + fun initialize() fun storeSettings(from: String) fun performPluginSwitch(changedPlugin: PluginBase, enabled: Boolean, type: PluginType) } \ No newline at end of file diff --git a/core/src/main/java/info/nightscout/androidaps/interfaces/ConfigExportImport.kt b/core/src/main/java/info/nightscout/androidaps/interfaces/ConfigExportImport.kt new file mode 100644 index 0000000000..c56ef1010c --- /dev/null +++ b/core/src/main/java/info/nightscout/androidaps/interfaces/ConfigExportImport.kt @@ -0,0 +1,19 @@ +package info.nightscout.androidaps.interfaces + +import org.json.JSONObject + +/** + * Allow export and import plugin configuration + */ +interface ConfigExportImport { + + /** + * Export configuration to JSON + */ + fun configuration(): JSONObject + + /** + * Import configuration from JSON and store it + */ + fun applyConfiguration(configuration: JSONObject) +} \ No newline at end of file diff --git a/core/src/main/java/info/nightscout/androidaps/interfaces/ConfigExportImportInterface.kt b/core/src/main/java/info/nightscout/androidaps/interfaces/ConfigExportImportInterface.kt deleted file mode 100644 index 5e4cee973b..0000000000 --- a/core/src/main/java/info/nightscout/androidaps/interfaces/ConfigExportImportInterface.kt +++ /dev/null @@ -1,9 +0,0 @@ -package info.nightscout.androidaps.interfaces - -import org.json.JSONObject - -interface ConfigExportImportInterface { - - fun configuration(): JSONObject - fun applyConfiguration(configuration: JSONObject) -} \ No newline at end of file diff --git a/core/src/main/java/info/nightscout/androidaps/interfaces/ConstraintsInterface.kt b/core/src/main/java/info/nightscout/androidaps/interfaces/Constraints.kt similarity index 82% rename from core/src/main/java/info/nightscout/androidaps/interfaces/ConstraintsInterface.kt rename to core/src/main/java/info/nightscout/androidaps/interfaces/Constraints.kt index 7142bf251a..708f734b73 100644 --- a/core/src/main/java/info/nightscout/androidaps/interfaces/ConstraintsInterface.kt +++ b/core/src/main/java/info/nightscout/androidaps/interfaces/Constraints.kt @@ -3,9 +3,17 @@ package info.nightscout.androidaps.interfaces import info.nightscout.androidaps.data.Profile /** - * Created by mike on 15.06.2016. + * Constraints interface + * + * Every function has a param from previous chained call + * Function can limit the value even more and add another reason of restriction + * + * see [info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker] + * which iterates over all registered plugins with [Constraints] implemented + * + * @return updated parameter */ -interface ConstraintsInterface { +interface Constraints { @JvmDefault fun isLoopInvocationAllowed(value: Constraint): Constraint = value @JvmDefault fun isClosedLoopAllowed(value: Constraint): Constraint = value diff --git a/core/src/main/java/info/nightscout/androidaps/interfaces/DanaRInterface.kt b/core/src/main/java/info/nightscout/androidaps/interfaces/Dana.kt similarity index 78% rename from core/src/main/java/info/nightscout/androidaps/interfaces/DanaRInterface.kt rename to core/src/main/java/info/nightscout/androidaps/interfaces/Dana.kt index 2ab57d52ed..f2ba34e703 100644 --- a/core/src/main/java/info/nightscout/androidaps/interfaces/DanaRInterface.kt +++ b/core/src/main/java/info/nightscout/androidaps/interfaces/Dana.kt @@ -2,9 +2,13 @@ package info.nightscout.androidaps.interfaces import info.nightscout.androidaps.data.PumpEnactResult -interface DanaRInterface { +/** + * Functionality supported by Dana* pumps only + */ +interface Dana { fun loadHistory(type: Byte): PumpEnactResult // for history browser fun loadEvents(): PumpEnactResult // events history to build treatments from fun setUserOptions(): PumpEnactResult // like AnyDana does + fun clearPairing() } \ No newline at end of file diff --git a/core/src/main/java/info/nightscout/androidaps/interfaces/DataSyncSelector.kt b/core/src/main/java/info/nightscout/androidaps/interfaces/DataSyncSelector.kt new file mode 100644 index 0000000000..1e1911b75e --- /dev/null +++ b/core/src/main/java/info/nightscout/androidaps/interfaces/DataSyncSelector.kt @@ -0,0 +1,69 @@ +package info.nightscout.androidaps.interfaces + +import info.nightscout.androidaps.database.entities.DeviceStatus +import info.nightscout.androidaps.database.entities.* + +interface DataSyncSelector { + + data class PairTemporaryTarget(val value: TemporaryTarget, val updateRecordId: Long) + data class PairGlucoseValue(val value: GlucoseValue, val updateRecordId: Long) + data class PairTherapyEvent(val value: TherapyEvent, val updateRecordId: Long) + data class PairFood(val value: Food, val updateRecordId: Long) + data class PairBolus(val value: Bolus, val updateRecordId: Long) + data class PairCarbs(val value: Carbs, val updateRecordId: Long) + data class PairBolusCalculatorResult(val value: BolusCalculatorResult, val updateRecordId: Long) + data class PairTemporaryBasal(val value: TemporaryBasal, val updateRecordId: Long) + data class PairExtendedBolus(val value: ExtendedBolus, val updateRecordId: Long) + + fun resetToNextFullSync() + + fun confirmLastBolusIdIfGreater(lastSynced: Long) + fun changedBoluses() : List + // Until NS v3 + fun processChangedBolusesCompat(): Boolean + + fun confirmLastCarbsIdIfGreater(lastSynced: Long) + fun changedCarbs() : List + // Until NS v3 + fun processChangedCarbsCompat(): Boolean + + fun confirmLastBolusCalculatorResultsIdIfGreater(lastSynced: Long) + fun changedBolusCalculatorResults() : List + // Until NS v3 + fun processChangedBolusCalculatorResultsCompat(): Boolean + + fun confirmLastTempTargetsIdIfGreater(lastSynced: Long) + fun changedTempTargets() : List + // Until NS v3 + fun processChangedTempTargetsCompat(): Boolean + + fun confirmLastGlucoseValueIdIfGreater(lastSynced: Long) + fun changedGlucoseValues() : List + // Until NS v3 + fun processChangedGlucoseValuesCompat(): Boolean + + fun confirmLastTherapyEventIdIfGreater(lastSynced: Long) + fun changedTherapyEvents() : List + // Until NS v3 + fun processChangedTherapyEventsCompat(): Boolean + + fun confirmLastFoodIdIfGreater(lastSynced: Long) + fun changedFoods() : List + // Until NS v3 + fun processChangedFoodsCompat(): Boolean + + fun confirmLastDeviceStatusIdIfGreater(lastSynced: Long) + fun changedDeviceStatuses() : List + // Until NS v3 + fun processChangedDeviceStatusesCompat(): Boolean + + fun confirmLastTemporaryBasalIdIfGreater(lastSynced: Long) + fun changedTemporaryBasals() : List + // Until NS v3 + fun processChangedTemporaryBasalsCompat(): Boolean + + fun confirmLastExtendedBolusIdIfGreater(lastSynced: Long) + fun changedExtendedBoluses() : List + // Until NS v3 + fun processChangedExtendedBolusesCompat(): Boolean +} \ No newline at end of file diff --git a/core/src/main/java/info/nightscout/androidaps/interfaces/DatabaseHelperInterface.kt b/core/src/main/java/info/nightscout/androidaps/interfaces/DatabaseHelperInterface.kt index 5864bd3754..b8fa2b631e 100644 --- a/core/src/main/java/info/nightscout/androidaps/interfaces/DatabaseHelperInterface.kt +++ b/core/src/main/java/info/nightscout/androidaps/interfaces/DatabaseHelperInterface.kt @@ -8,7 +8,6 @@ interface DatabaseHelperInterface { fun resetDatabases() - fun createOrUpdate(extendedBolus: ExtendedBolus): Boolean fun createOrUpdate(profileSwitch: ProfileSwitch) fun createOrUpdate(record: DanaRHistoryRecord) fun createOrUpdate(record: OmnipodHistoryRecord) @@ -22,7 +21,6 @@ interface DatabaseHelperInterface { fun size(table: String): Long fun deleteAllDbRequests() fun deleteDbRequest(id: String): Int - fun delete(tempBasal: TemporaryBasal) fun delete(extendedBolus: ExtendedBolus) fun delete(profileSwitch: ProfileSwitch) fun deleteDbRequestbyMongoId(action: String, _id: String) @@ -30,29 +28,25 @@ interface DatabaseHelperInterface { fun roundDateToSec(date: Long): Long fun createOrUpdateTDD(record: TDD) fun createOrUpdate(tempBasal: TemporaryBasal): Boolean - fun findTempBasalByPumpId(id: Long): TemporaryBasal + @Deprecated("Use new DB") + fun findTempBasalByPumpId(id: Long): TemporaryBasal? + @Deprecated("Use new DB") fun getTemporaryBasalsDataFromTime(mills: Long, ascending: Boolean): List - fun getExtendedBolusDataFromTime(mills: Long, ascending: Boolean): List fun getProfileSwitchEventsFromTime(from: Long, to: Long, ascending: Boolean): List fun getProfileSwitchEventsFromTime(mills: Long, ascending: Boolean): List fun getAllOmnipodHistoryRecordsFromTimestamp(timestamp: Long, ascending: Boolean): List fun findOmnipodHistoryRecordByPumpId(pumpId: Long): OmnipodHistoryRecord? fun getTDDsForLastXDays(days: Int): List fun getProfileSwitchData(from: Long, ascending: Boolean): List + @Deprecated("Use new DB") fun getExtendedBolusByPumpId(pumpId: Long): ExtendedBolus? - fun getAllExtendedBoluses(): List fun getAllProfileSwitches(): List fun getAllTDDs(): List - fun getAllTemporaryBasals(): List fun getAllOHQueueItems(maxEntries: Long): List fun resetProfileSwitch() // old DB model - fun deleteTempBasalById(_id: String) - fun deleteExtendedBolusById(_id: String) fun deleteProfileSwitchById(_id: String) - fun createTempBasalFromJsonIfNotExists(json: JSONObject) - fun createExtendedBolusFromJsonIfNotExists(json: JSONObject) fun createProfileSwitchFromJsonIfNotExists(trJson: JSONObject) fun getInsightBolusID(pumpSerial: String, bolusID: Int, timestamp: Long): InsightBolusID? diff --git a/core/src/main/java/info/nightscout/androidaps/interfaces/IconsProviderInterface.kt b/core/src/main/java/info/nightscout/androidaps/interfaces/IconsProvider.kt similarity index 75% rename from core/src/main/java/info/nightscout/androidaps/interfaces/IconsProviderInterface.kt rename to core/src/main/java/info/nightscout/androidaps/interfaces/IconsProvider.kt index 899aed4e59..a80fecee2c 100644 --- a/core/src/main/java/info/nightscout/androidaps/interfaces/IconsProviderInterface.kt +++ b/core/src/main/java/info/nightscout/androidaps/interfaces/IconsProvider.kt @@ -1,6 +1,6 @@ package info.nightscout.androidaps.interfaces -interface IconsProviderInterface { +interface IconsProvider { fun getIcon(): Int fun getNotificationIcon(): Int } \ No newline at end of file diff --git a/core/src/main/java/info/nightscout/androidaps/interfaces/ImportExportPrefsInterface.kt b/core/src/main/java/info/nightscout/androidaps/interfaces/ImportExportPrefs.kt similarity index 95% rename from core/src/main/java/info/nightscout/androidaps/interfaces/ImportExportPrefsInterface.kt rename to core/src/main/java/info/nightscout/androidaps/interfaces/ImportExportPrefs.kt index e003e02fcf..81782fbb88 100644 --- a/core/src/main/java/info/nightscout/androidaps/interfaces/ImportExportPrefsInterface.kt +++ b/core/src/main/java/info/nightscout/androidaps/interfaces/ImportExportPrefs.kt @@ -6,7 +6,7 @@ import info.nightscout.androidaps.database.entities.UserEntry import info.nightscout.androidaps.plugins.general.maintenance.PrefsFile import io.reactivex.Single -interface ImportExportPrefsInterface { +interface ImportExportPrefs { fun importSharedPreferences(activity: FragmentActivity, importFile: PrefsFile) fun importSharedPreferences(activity: FragmentActivity) diff --git a/core/src/main/java/info/nightscout/androidaps/interfaces/InsulinInterface.kt b/core/src/main/java/info/nightscout/androidaps/interfaces/Insulin.kt similarity index 59% rename from core/src/main/java/info/nightscout/androidaps/interfaces/InsulinInterface.kt rename to core/src/main/java/info/nightscout/androidaps/interfaces/Insulin.kt index 28a8ee8d0e..368587650b 100644 --- a/core/src/main/java/info/nightscout/androidaps/interfaces/InsulinInterface.kt +++ b/core/src/main/java/info/nightscout/androidaps/interfaces/Insulin.kt @@ -1,21 +1,22 @@ package info.nightscout.androidaps.interfaces import info.nightscout.androidaps.data.Iob -import info.nightscout.androidaps.db.Treatment -import org.json.JSONObject +import info.nightscout.androidaps.database.entities.Bolus -interface InsulinInterface : ConfigExportImportInterface{ +interface Insulin : ConfigExportImport { enum class InsulinType(val value: Int) { UNKNOWN(-1), - // int FASTACTINGINSULIN = 0; // old model no longer available - // int FASTACTINGINSULINPROLONGED = 1; // old model no longer available + + // int FAST_ACTING_INSULIN = 0; // old model no longer available + // int FAST_ACTING_INSULIN_PROLONGED = 1; // old model no longer available OREF_RAPID_ACTING(2), OREF_ULTRA_RAPID_ACTING(3), OREF_FREE_PEAK(4), OREF_LYUMJEV(5); companion object { + private val map = values().associateBy(InsulinType::value) fun fromInt(type: Int) = map[type] } @@ -26,5 +27,5 @@ interface InsulinInterface : ConfigExportImportInterface{ val comment: String val dia: Double - fun iobCalcForTreatment(treatment: Treatment, time: Long, dia: Double): Iob + fun iobCalcForTreatment(bolus: Bolus, time: Long, dia: Double): Iob } \ No newline at end of file diff --git a/core/src/main/java/info/nightscout/androidaps/interfaces/IobCobCalculator.kt b/core/src/main/java/info/nightscout/androidaps/interfaces/IobCobCalculator.kt new file mode 100644 index 0000000000..ffc9f77ad2 --- /dev/null +++ b/core/src/main/java/info/nightscout/androidaps/interfaces/IobCobCalculator.kt @@ -0,0 +1,98 @@ +package info.nightscout.androidaps.interfaces + +import info.nightscout.androidaps.data.IobTotal +import info.nightscout.androidaps.data.MealData +import info.nightscout.androidaps.data.Profile +import info.nightscout.androidaps.database.entities.ExtendedBolus +import info.nightscout.androidaps.database.entities.TemporaryBasal +import info.nightscout.androidaps.plugins.iob.iobCobCalculator.AutosensDataStore +import info.nightscout.androidaps.plugins.iob.iobCobCalculator.AutosensResult +import info.nightscout.androidaps.plugins.iob.iobCobCalculator.BasalData +import info.nightscout.androidaps.plugins.iob.iobCobCalculator.CobInfo +import info.nightscout.androidaps.plugins.iob.iobCobCalculator.data.AutosensData +import org.json.JSONArray + +interface IobCobCalculator { + + var ads: AutosensDataStore + + fun getMealDataWithWaitingForCalculationFinish(): MealData + fun getLastAutosensDataWithWaitForCalculationFinish(reason: String): AutosensData? + + fun calculateAbsInsulinFromTreatmentsAndTemps(fromTime: Long): IobTotal + fun calculateFromTreatmentsAndTemps(time: Long, profile: Profile): IobTotal + + fun getBasalData(profile: Profile, fromTime: Long): BasalData + + fun calculateIobArrayInDia(profile: Profile): Array + fun calculateIobArrayForSMB(lastAutosensResult: AutosensResult, exercise_mode: Boolean, half_basal_exercise_target: Int, isTempTarget: Boolean): Array + fun iobArrayToString(array: Array): String + fun convertToJSONArray(iobArray: Array): JSONArray + + /** + * Calculate CobInfo to now() + * + * @param waitForCalculationFinish access autosens data synchronized (wait for result if calculation is running) + * @param reason caller identification + * @return CobInfo + */ + fun getCobInfo(waitForCalculationFinish: Boolean, reason: String): CobInfo + + /** + * Calculate IobTotal from boluses and extended boluses to now(). + * NOTE: Only isValid == true boluses are included + * NOTE: if faking by TBR by extended boluses is enabled, extended boluses are not included + * and are calculated towards temporary basals + * + * @return calculated iob + */ + fun calculateIobFromBolus(): IobTotal + + /** + * Get running temporary basal at time + * + * @return running temporary basal or null if no tbr is running + */ + fun getTempBasal(timestamp: Long): TemporaryBasal? + + /** + * Get running temporary basal at time + * + * @return running temporary basal or null if no tbr is running + * If pump is faking extended boluses as temporary basals + * return extended converted to temporary basal with type == FAKE_EXTENDED + */ + fun getTempBasalIncludingConvertedExtended(timestamp: Long): TemporaryBasal? + + /** + * Get running extended bolus at time + * + * @return running extended bolus or null if no eb is running + */ + fun getExtendedBolus(timestamp: Long): ExtendedBolus? + + /** + * Calculate IOB of all insulin in the body to the time + * + * Running basal is added to the IOB !!! + * + * @param toTime + * @return IobTotal + */ + fun calculateAbsoluteIobTempBasals(toTime: Long): IobTotal + + /** + * Calculate IOB from Temporary basals and Extended boluses (if emulation is enabled) to the the time specified + * + * @param toTime time to calculate to + * @return IobTotal + */ + fun calculateIobToTimeFromTempBasalsIncludingConvertedExtended(toTime: Long): IobTotal + + /** + * Calculate IOB from Temporary basals and Extended boluses (if emulation is enabled) to now + * + * @return IobTotal + */ + fun calculateIobFromTempBasalsIncludingConvertedExtended(): IobTotal +} \ No newline at end of file diff --git a/core/src/main/java/info/nightscout/androidaps/interfaces/IobCobCalculatorInterface.kt b/core/src/main/java/info/nightscout/androidaps/interfaces/IobCobCalculatorInterface.kt deleted file mode 100644 index 740c19101f..0000000000 --- a/core/src/main/java/info/nightscout/androidaps/interfaces/IobCobCalculatorInterface.kt +++ /dev/null @@ -1,22 +0,0 @@ -package info.nightscout.androidaps.interfaces - -import androidx.collection.LongSparseArray -import info.nightscout.androidaps.data.IobTotal -import info.nightscout.androidaps.data.Profile -import info.nightscout.androidaps.database.entities.GlucoseValue -import info.nightscout.androidaps.plugins.iob.iobCobCalculator.CobInfo -import info.nightscout.androidaps.plugins.iob.iobCobCalculator.data.AutosensData - -interface IobCobCalculatorInterface { - - val dataLock: Any - var bgReadings: List - - fun getAutosensDataTable(): LongSparseArray - fun calculateIobArrayInDia(profile: Profile): Array - fun lastDataTime(): String - fun getAutosensData(fromTime: Long): AutosensData? - fun getLastAutosensData(reason: String): AutosensData? - fun getCobInfo(_synchronized: Boolean, reason: String): CobInfo - fun calculateFromTreatmentsAndTempsSynchronized(time: Long, profile: Profile?): IobTotal -} \ No newline at end of file diff --git a/core/src/main/java/info/nightscout/androidaps/interfaces/LoopInterface.kt b/core/src/main/java/info/nightscout/androidaps/interfaces/LoopInterface.kt index 1aac4769b2..fb6cb46594 100644 --- a/core/src/main/java/info/nightscout/androidaps/interfaces/LoopInterface.kt +++ b/core/src/main/java/info/nightscout/androidaps/interfaces/LoopInterface.kt @@ -2,17 +2,17 @@ package info.nightscout.androidaps.interfaces import info.nightscout.androidaps.data.PumpEnactResult import info.nightscout.androidaps.plugins.aps.loop.APSResult -import info.nightscout.androidaps.utils.DateUtil interface LoopInterface { class LastRun { + var request: APSResult? = null var constraintsProcessed: APSResult? = null var tbrSetByPump: PumpEnactResult? = null var smbSetByPump: PumpEnactResult? = null var source: String? = null - var lastAPSRun = DateUtil.now() + var lastAPSRun = System.currentTimeMillis() var lastTBREnact: Long = 0 var lastSMBEnact: Long = 0 var lastTBRRequest: Long = 0 diff --git a/core/src/main/java/info/nightscout/androidaps/interfaces/NotificationHolderInterface.kt b/core/src/main/java/info/nightscout/androidaps/interfaces/NotificationHolder.kt similarity index 87% rename from core/src/main/java/info/nightscout/androidaps/interfaces/NotificationHolderInterface.kt rename to core/src/main/java/info/nightscout/androidaps/interfaces/NotificationHolder.kt index 81e4b75503..b2f11d9d1c 100644 --- a/core/src/main/java/info/nightscout/androidaps/interfaces/NotificationHolderInterface.kt +++ b/core/src/main/java/info/nightscout/androidaps/interfaces/NotificationHolder.kt @@ -4,7 +4,7 @@ import android.app.Notification import android.app.PendingIntent import android.content.Context -interface NotificationHolderInterface { +interface NotificationHolder { val channelID : String val notificationID : Int var notification: Notification diff --git a/core/src/main/java/info/nightscout/androidaps/interfaces/Overview.kt b/core/src/main/java/info/nightscout/androidaps/interfaces/Overview.kt new file mode 100644 index 0000000000..23d43b35b0 --- /dev/null +++ b/core/src/main/java/info/nightscout/androidaps/interfaces/Overview.kt @@ -0,0 +1,3 @@ +package info.nightscout.androidaps.interfaces + +interface Overview : ConfigExportImport \ No newline at end of file diff --git a/core/src/main/java/info/nightscout/androidaps/interfaces/OverviewInterface.kt b/core/src/main/java/info/nightscout/androidaps/interfaces/OverviewInterface.kt deleted file mode 100644 index 7bc6dfa429..0000000000 --- a/core/src/main/java/info/nightscout/androidaps/interfaces/OverviewInterface.kt +++ /dev/null @@ -1,3 +0,0 @@ -package info.nightscout.androidaps.interfaces - -interface OverviewInterface : ConfigExportImportInterface \ No newline at end of file diff --git a/core/src/main/java/info/nightscout/androidaps/interfaces/PluginBase.kt b/core/src/main/java/info/nightscout/androidaps/interfaces/PluginBase.kt index b560353b3a..c0e83323a7 100644 --- a/core/src/main/java/info/nightscout/androidaps/interfaces/PluginBase.kt +++ b/core/src/main/java/info/nightscout/androidaps/interfaces/PluginBase.kt @@ -36,7 +36,7 @@ abstract class PluginBase( get() { if (pluginDescription.shortName == -1) return name val translatedName = resourceHelper.gs(pluginDescription.shortName) - return if (!translatedName.trim { it <= ' ' }.isEmpty()) translatedName else name + return if (translatedName.trim { it <= ' ' }.isNotEmpty()) translatedName else name // use long name as fallback } @@ -66,9 +66,8 @@ abstract class PluginBase( fun isDefault() = pluginDescription.defaultPlugin /** - * So far plugin can have it's main type + ConstraintInterface + ProfileInterface + * So far plugin can have it's main type + ConstraintInterface * ConstraintInterface is enabled if main plugin is enabled - * ProfileInterface can be enabled only if main iterface is enable */ fun setPluginEnabled(type: PluginType, newState: Boolean) { if (type == pluginDescription.mainType) { @@ -103,7 +102,7 @@ abstract class PluginBase( fun showInList(type: PluginType): Boolean { if (pluginDescription.mainType == type) return pluginDescription.showInList && specialShowInListCondition() - return if (type == PluginType.PROFILE && pluginDescription.mainType == PluginType.PUMP) isEnabled(PluginType.PUMP) else false + return false } open fun specialEnableCondition(): Boolean { diff --git a/core/src/main/java/info/nightscout/androidaps/interfaces/PluginType.kt b/core/src/main/java/info/nightscout/androidaps/interfaces/PluginType.kt index 68ea553a64..315c2d6809 100644 --- a/core/src/main/java/info/nightscout/androidaps/interfaces/PluginType.kt +++ b/core/src/main/java/info/nightscout/androidaps/interfaces/PluginType.kt @@ -1,5 +1,10 @@ package info.nightscout.androidaps.interfaces +/** + * Main plugin type + * + * set by [info.nightscout.androidaps.interfaces.PluginDescription.mainType] + */ enum class PluginType { GENERAL, TREATMENT, SENSITIVITY, PROFILE, APS, PUMP, CONSTRAINTS, LOOP, BGSOURCE, INSULIN } \ No newline at end of file diff --git a/core/src/main/java/info/nightscout/androidaps/interfaces/ProfileInterface.java b/core/src/main/java/info/nightscout/androidaps/interfaces/ProfileInterface.java deleted file mode 100644 index 5af03b863f..0000000000 --- a/core/src/main/java/info/nightscout/androidaps/interfaces/ProfileInterface.java +++ /dev/null @@ -1,12 +0,0 @@ -package info.nightscout.androidaps.interfaces; - -import androidx.annotation.Nullable; - -/** - * Created by mike on 14.06.2016. - */ -public interface ProfileInterface { - @Nullable - ProfileStore getProfile(); - String getProfileName(); -} diff --git a/core/src/main/java/info/nightscout/androidaps/interfaces/ProfileSource.kt b/core/src/main/java/info/nightscout/androidaps/interfaces/ProfileSource.kt new file mode 100644 index 0000000000..bba3402e19 --- /dev/null +++ b/core/src/main/java/info/nightscout/androidaps/interfaces/ProfileSource.kt @@ -0,0 +1,7 @@ +package info.nightscout.androidaps.interfaces + +interface ProfileSource { + + val profile: ProfileStore? + val profileName: String? +} \ No newline at end of file diff --git a/core/src/main/java/info/nightscout/androidaps/interfaces/Pump.kt b/core/src/main/java/info/nightscout/androidaps/interfaces/Pump.kt new file mode 100644 index 0000000000..cd0b20e8dd --- /dev/null +++ b/core/src/main/java/info/nightscout/androidaps/interfaces/Pump.kt @@ -0,0 +1,281 @@ +package info.nightscout.androidaps.interfaces + +import info.nightscout.androidaps.data.DetailedBolusInfo +import info.nightscout.androidaps.data.Profile +import info.nightscout.androidaps.data.PumpEnactResult +import info.nightscout.androidaps.plugins.common.ManufacturerType +import info.nightscout.androidaps.plugins.general.actions.defs.CustomAction +import info.nightscout.androidaps.plugins.general.actions.defs.CustomActionType +import info.nightscout.androidaps.plugins.pump.common.defs.PumpType +import info.nightscout.androidaps.queue.commands.CustomCommand +import info.nightscout.androidaps.utils.TimeChangeType +import org.json.JSONObject + +/** + * This interface defines the communication from AAPS-core to pump drivers. + * Pump drivers communicate data changes back to AAPS-core using [info.nightscout.androidaps.interfaces.PumpSync]. + * + * Created by mike on 04.06.2016. + */ +interface Pump { + + /** + * @return true if pump status has been read and is ready to accept commands + */ + fun isInitialized(): Boolean + + /** + * @return true if suspended (not delivering insulin) + */ + fun isSuspended(): Boolean + + /** + * @return true if pump is not ready to accept commands right now + */ + fun isBusy(): Boolean + + /** + * @return true if BT connection is established + */ + fun isConnected(): Boolean + + /** + * @return true if BT connection is in progress + */ + fun isConnecting(): Boolean + + /** + * @return true if BT is connected but initial handshake is still in progress + */ + fun isHandshakeInProgress(): Boolean + + /** + * set initial handshake completed (moved to connected state) + */ + @JvmDefault fun finishHandshaking() {} + + /** + * Perform BT connect, there is new command waiting in queue + * @param reason originator identification + */ + fun connect(reason: String) + + /** + * Perform BT disconnect, there is NO command waiting in queue + * @param reason originator identification + */ + fun disconnect(reason: String) + + /** + * @return # of second to wait before [disconnect] is send after last command + */ + @JvmDefault fun waitForDisconnectionInSeconds(): Int = 5 + + /** + * Stop connection process + */ + fun stopConnecting() + + /** + * Force reading of full pump status + * @param reason originator identification + */ + fun getPumpStatus(reason: String) + + /** + * Upload to pump new basal profile (and IC/ISF if supported by pump) + * + * @param profile new profile + */ + fun setNewBasalProfile(profile: Profile): PumpEnactResult + + /** + * @param profile profile to check + * + * @return true if pump is running the same profile as in param + */ + fun isThisProfileSet(profile: Profile): Boolean + + /** + * @return timestamp of last connection to the pump + */ + fun lastDataTime(): Long + + /** + * Currently running base basal rate [U/h] + */ + val baseBasalRate: Double + + /** + * Reservoir level at time of last connection [Units of insulin] + */ + val reservoirLevel: Double + + /** + * Battery level at time of last connection [%] + */ + val batteryLevel: Int + + /** + * 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. + * @return PumpEnactResult + */ + fun deliverTreatment(detailedBolusInfo: DetailedBolusInfo): PumpEnactResult + + /** + * Stopping of performed bolus requested by user + */ + fun stopBolusDelivering() + + /** + * Request a TRB in absolute units [U/h] + * + * Driver is responsible for conversion to % if absolute rate is not supported by pump + * + * @param absoluteRate rate in U/h + * @param durationInMinutes duration + * @param profile only help for for U/h -> % transformation + * @param enforceNew if true drive should force new TBR (ie. stop current, + * and set new even if the same rate is requested + * @param tbrType tbrType for storing to DB [NORMAL,EMULATED_PUMP_SUSPEND,PUMP_SUSPEND,SUPERBOLUS] + * @return PumpEnactResult.success if TBR set, + * PumpEnactResult.enacted if new TBR set + * (if the same TBR rate is requested && enforceNew == false driver can keep + * running TBR. In this case return will be success = true, enacted = false) + */ + fun setTempBasalAbsolute(absoluteRate: Double, durationInMinutes: Int, profile: Profile, enforceNew: Boolean, tbrType: PumpSync.TemporaryBasalType): PumpEnactResult + + /** + * Request a TRB in % + * + * Driver is responsible for conversion to u/h if % is not supported by pump + * + * @param percent rate in % (100% is equal to not running TBR, 0% is zero temping) + * @param durationInMinutes duration + * @param profile only help for for U/h -> % transformation + * @param enforceNew if true drive should force new TBR (ie. stop current, + * and set new even if the same rate is requested + * @param tbrType tbrType for storing to DB [NORMAL,EMULATED_PUMP_SUSPEND,PUMP_SUSPEND,SUPERBOLUS] + * @return PumpEnactResult.success if TBR set, + * PumpEnactResult.enacted if new TBR set + * (if the same TBR rate is requested && enforceNew == false driver can keep + * running TBR. In this case return will be success = true, enacted = false) + */ + fun setTempBasalPercent(percent: Int, durationInMinutes: Int, profile: Profile, enforceNew: Boolean, tbrType: PumpSync.TemporaryBasalType): PumpEnactResult + + /** + * Cancel current TBR if a TBR is running + * + * some pumps might set a very short temp close to 100% as cancelling a temp can be noisy + * when the cancel request is requested by the user (forced), the pump should always do a real cancel + * + * @param enforceNew if true disable workaround above + * @return PumpEnactResult.success if TBR is canceled + */ + fun cancelTempBasal(enforceNew: Boolean): PumpEnactResult + + fun setExtendedBolus(insulin: Double, durationInMinutes: Int): PumpEnactResult + fun cancelExtendedBolus(): PumpEnactResult + + /** + * Status to be passed to NS + * + * This info is displayed when user hover over pump pill in NS + * + * @return JSON with information + */ + fun getJSONStatus(profile: Profile, profileName: String, version: String): JSONObject + + /** + * Manufacturer type. Usually defined by used plugin + * + * @return ManufacturerType + */ + fun manufacturer(): ManufacturerType + + /** + * Pump model + * + * If new model is covered by driver, model and it's capabilities must be added to [info.nightscout.androidaps.plugins.pump.common.defs.PumpType] + * + * @return PumpType + */ + fun model(): PumpType + + /** + * Serial number + * + * Real serial number from device or "unique" generated for paired pump if not possible + */ + fun serialNumber(): String + + /** + * Pump capabilities + */ + val pumpDescription: PumpDescription + + /** + * Short info for SMS, Wear etc + */ + fun shortStatus(veryShort: Boolean): String + + /** + * @return true if pump is currently emulating temporary basals by extended boluses (usually to bypass 200% limit) + */ + val isFakingTempsByExtendedBoluses: Boolean + + /** + * Load TDDs and store them to the database + */ + fun loadTDDs(): PumpEnactResult + + /** + * @return true if pump handles DST changes by it self. In this case it's not necessary stop the loop + * after DST change + */ + fun canHandleDST(): Boolean + + /** + * Provides a list of custom actions to be displayed in the Actions tab. + * Please note that these actions will not be queued upon execution + * + * @return list of custom actions + */ + @JvmDefault fun getCustomActions(): List? = null + + /** + * Executes a custom action. Please note that these actions will not be queued + * + * @param customActionType action to be executed + */ + @JvmDefault fun executeCustomAction(customActionType: CustomActionType) {} + + /** + * Executes a custom queued command + * See [CommandQueueProvider.customCommand] for queuing a custom command. + * + * @param customCommand the custom command to be executed + * @return PumpEnactResult that represents the command execution result + */ + @JvmDefault fun executeCustomCommand(customCommand: CustomCommand): PumpEnactResult? = null + + /** + * This method will be called when time or Timezone changes, and pump driver can then do a specific action (for + * example update clock on pump). + */ + @JvmDefault fun timezoneOrDSTChanged(timeChangeType: TimeChangeType) {} + + /** + * Only used for pump types where hasCustomUnreachableAlertCheck=true + */ + @JvmDefault + fun isUnreachableAlertTimeoutExceeded(alertTimeoutMilliseconds: Long): Boolean = false + + /** + * if true APS set 100% basal before full hour to avoid pump beeping + */ + @JvmDefault fun setNeutralTempAtFullHour(): Boolean = false +} \ No newline at end of file diff --git a/core/src/main/java/info/nightscout/androidaps/interfaces/PumpDescription.kt b/core/src/main/java/info/nightscout/androidaps/interfaces/PumpDescription.kt index 26f42a646d..0aec8d7484 100644 --- a/core/src/main/java/info/nightscout/androidaps/interfaces/PumpDescription.kt +++ b/core/src/main/java/info/nightscout/androidaps/interfaces/PumpDescription.kt @@ -10,7 +10,7 @@ class PumpDescription() { setPumpDescription(pumpType) } - var pumpType = PumpType.GenericAAPS + var pumpType = PumpType.GENERIC_AAPS var isBolusCapable = false var bolusStep = 0.0 var isExtendedBolusCapable = false @@ -72,29 +72,27 @@ class PumpDescription() { fun setPumpDescription(pumpType: PumpType) { resetSettings() this.pumpType = pumpType - val pumpCapability = pumpType.pumpCapability + val pumpCapability = pumpType.pumpCapability ?: return isBolusCapable = pumpCapability.hasCapability(PumpCapability.Bolus) bolusStep = pumpType.bolusSize isExtendedBolusCapable = pumpCapability.hasCapability(PumpCapability.ExtendedBolus) - extendedBolusStep = pumpType.extendedBolusSettings.step - extendedBolusDurationStep = pumpType.extendedBolusSettings.durationStep.toDouble() - extendedBolusMaxDuration = pumpType.extendedBolusSettings.maxDuration.toDouble() + pumpType.extendedBolusSettings?.step?.let { extendedBolusStep = it } + pumpType.extendedBolusSettings?.durationStep?.let { extendedBolusDurationStep = it.toDouble() } + pumpType.extendedBolusSettings?.maxDuration?.let { extendedBolusMaxDuration = it.toDouble() } isTempBasalCapable = pumpCapability.hasCapability(PumpCapability.TempBasal) if (pumpType.pumpTempBasalType == PumpTempBasalType.Percent) { tempBasalStyle = PERCENT - maxTempPercent = pumpType.tbrSettings.maxDose.toInt() - tempPercentStep = pumpType.tbrSettings.step.toInt() + pumpType.tbrSettings?.maxDose?.let { maxTempPercent = it.toInt() } + pumpType.tbrSettings?.step?.let { tempPercentStep = it.toInt() } } else { tempBasalStyle = ABSOLUTE - maxTempAbsolute = pumpType.tbrSettings.maxDose - tempAbsoluteStep = pumpType.tbrSettings.step + pumpType.tbrSettings?.maxDose?.let { maxTempAbsolute = it } + pumpType.tbrSettings?.step?.let { tempAbsoluteStep = it } } - tempDurationStep = pumpType.tbrSettings.durationStep - tempMaxDuration = pumpType.tbrSettings.maxDuration - tempDurationStep15mAllowed = pumpType.specialBasalDurations - .hasCapability(PumpCapability.BasalRate_Duration15minAllowed) - tempDurationStep30mAllowed = pumpType.specialBasalDurations - .hasCapability(PumpCapability.BasalRate_Duration30minAllowed) + pumpType.tbrSettings?.durationStep?.let { tempDurationStep = it } + pumpType.tbrSettings?.maxDuration?.let { tempMaxDuration = it } + pumpType.specialBasalDurations?.hasCapability(PumpCapability.BasalRate_Duration15minAllowed)?.let { tempDurationStep15mAllowed = it } + pumpType.specialBasalDurations?.hasCapability(PumpCapability.BasalRate_Duration30minAllowed)?.let { tempDurationStep30mAllowed = it } isSetBasalProfileCapable = pumpCapability.hasCapability(PumpCapability.BasalProfileSet) basalStep = pumpType.baseBasalStep basalMinimumRate = pumpType.baseBasalMinValue diff --git a/core/src/main/java/info/nightscout/androidaps/interfaces/PumpInterface.kt b/core/src/main/java/info/nightscout/androidaps/interfaces/PumpInterface.kt deleted file mode 100644 index a57003433a..0000000000 --- a/core/src/main/java/info/nightscout/androidaps/interfaces/PumpInterface.kt +++ /dev/null @@ -1,102 +0,0 @@ -package info.nightscout.androidaps.interfaces - -import info.nightscout.androidaps.data.DetailedBolusInfo -import info.nightscout.androidaps.data.Profile -import info.nightscout.androidaps.data.PumpEnactResult -import info.nightscout.androidaps.plugins.common.ManufacturerType -import info.nightscout.androidaps.plugins.general.actions.defs.CustomAction -import info.nightscout.androidaps.plugins.general.actions.defs.CustomActionType -import info.nightscout.androidaps.plugins.pump.common.defs.PumpType -import info.nightscout.androidaps.queue.commands.CustomCommand -import info.nightscout.androidaps.utils.TimeChangeType -import org.json.JSONObject - -/** - * Created by mike on 04.06.2016. - */ -interface PumpInterface { - - fun isInitialized(): Boolean // true if pump status has been read and is ready to accept commands - fun isSuspended(): Boolean // true if suspended (not delivering insulin) - fun isBusy(): Boolean // if true pump is not ready to accept commands right now - fun isConnected(): Boolean // true if BT connection is established - fun isConnecting(): Boolean // true if BT connection is in progress - fun isHandshakeInProgress(): Boolean // true if BT is connected but initial handshake is still in progress - @JvmDefault fun finishHandshaking() {} // set initial handshake completed - fun connect(reason: String) - fun disconnect(reason: String) - @JvmDefault fun waitForDisconnectionInSeconds(): Int = 5 // wait [x] second after last command before sending disconnect - fun stopConnecting() - fun getPumpStatus(reason: String) - - // Upload to pump new basal profile - fun setNewBasalProfile(profile: Profile): PumpEnactResult - fun isThisProfileSet(profile: Profile): Boolean - fun lastDataTime(): Long - - val baseBasalRate: Double // base basal rate, not temp basal - val reservoirLevel: Double - val batteryLevel: Int // in percent as integer - - fun deliverTreatment(detailedBolusInfo: DetailedBolusInfo): PumpEnactResult - fun stopBolusDelivering() - fun setTempBasalAbsolute(absoluteRate: Double, durationInMinutes: Int, profile: Profile, enforceNew: Boolean): PumpEnactResult - fun setTempBasalPercent(percent: Int, durationInMinutes: Int, profile: Profile, enforceNew: Boolean): PumpEnactResult - fun setExtendedBolus(insulin: Double, durationInMinutes: Int): PumpEnactResult - - //some pumps might set a very short temp close to 100% as cancelling a temp can be noisy - //when the cancel request is requested by the user (forced), the pump should always do a real cancel - fun cancelTempBasal(enforceNew: Boolean): PumpEnactResult - fun cancelExtendedBolus(): PumpEnactResult - - // Status to be passed to NS - fun getJSONStatus(profile: Profile, profileName: String, version: String): JSONObject - fun manufacturer(): ManufacturerType - fun model(): PumpType - fun serialNumber(): String - - // Pump capabilities - val pumpDescription: PumpDescription - - // Short info for SMS, Wear etc - fun shortStatus(veryShort: Boolean): String - val isFakingTempsByExtendedBoluses: Boolean - fun loadTDDs(): PumpEnactResult - fun canHandleDST(): Boolean - - /** - * Provides a list of custom actions to be displayed in the Actions tab. - * Please note that these actions will not be queued upon execution - * - * @return list of custom actions - */ - @JvmDefault fun getCustomActions(): List? = null - - /** - * Executes a custom action. Please note that these actions will not be queued - * - * @param customActionType action to be executed - */ - @JvmDefault fun executeCustomAction(customActionType: CustomActionType) {} - - /** - * Executes a custom queued command - * See [CommandQueueProvider.customCommand] for queuing a custom command. - * - * @param customCommand the custom command to be executed - * @return PumpEnactResult that represents the command execution result - */ - @JvmDefault fun executeCustomCommand(customCommand: CustomCommand): PumpEnactResult? = null - - /** - * This method will be called when time or Timezone changes, and pump driver can then do a specific action (for - * example update clock on pump). - */ - @JvmDefault fun timezoneOrDSTChanged(timeChangeType: TimeChangeType) {} - - /* Only used for pump types where hasCustomUnreachableAlertCheck=true */ - @JvmDefault - fun isUnreachableAlertTimeoutExceeded(alertTimeoutMilliseconds: Long): Boolean = false - - @JvmDefault fun setNeutralTempAtFullHour(): Boolean = false -} \ No newline at end of file diff --git a/core/src/main/java/info/nightscout/androidaps/interfaces/PumpPluginBase.kt b/core/src/main/java/info/nightscout/androidaps/interfaces/PumpPluginBase.kt index c4e2384e90..2def7e2aff 100644 --- a/core/src/main/java/info/nightscout/androidaps/interfaces/PumpPluginBase.kt +++ b/core/src/main/java/info/nightscout/androidaps/interfaces/PumpPluginBase.kt @@ -16,10 +16,10 @@ abstract class PumpPluginBase( override fun onStart() { super.onStart() if (getType() == PluginType.PUMP) { - Thread(Runnable { + Thread { SystemClock.sleep(3000) commandQueue.readStatus("Pump driver changed.", null) - }).start() + }.start() } } } \ No newline at end of file diff --git a/core/src/main/java/info/nightscout/androidaps/interfaces/PumpSync.kt b/core/src/main/java/info/nightscout/androidaps/interfaces/PumpSync.kt new file mode 100644 index 0000000000..a8fba66edc --- /dev/null +++ b/core/src/main/java/info/nightscout/androidaps/interfaces/PumpSync.kt @@ -0,0 +1,339 @@ +package info.nightscout.androidaps.interfaces + +import info.nightscout.androidaps.data.DetailedBolusInfo +import info.nightscout.androidaps.data.Profile +import info.nightscout.androidaps.database.entities.TemporaryBasal +import info.nightscout.androidaps.plugins.pump.common.defs.PumpType + +/** + * This interface allows pump drivers to push data changes (creation and update of treatments, temporary basals and extended boluses) back to AAPS-core. + * + * Intended use cases for handling bolus treatments: + * + * - for pumps that have a reliable history that can be read and which therefore issue a bolus on the pump, + * read the history back and add new bolus entries on the pump, the method [syncBolusWithPumpId] + * are used to inform AAPS-core of a new bolus. + * [info.nightscout.androidaps.danars.DanaRSPlugin] is a pump driver that + * takes this approach. + * - for pumps that don't support history or take rather long to complete a bolus, the methods + * [addBolusWithTempId] and [syncBolusWithTempId] provide a mechanism to notify AAPS-core of a started + * bolus, so AAPS-core can operate under the assumption the bolus will be delivered and effect IOB until delivery + * completed. Upon completion, the pump driver will call the second method to turn a temporary bolus into a finished + * bolus. + */ +interface PumpSync { + + /** + * Reset stored identification of last used pump + * + * Call this function when new pump is paired to accept data from new pump + * to prevent overlapping pump histories + */ + fun connectNewPump() + + /* + * GENERAL STATUS + */ + + /** + * Query expected pump state + * + * Driver may query AAPS for expecting state of the pump and use it for sanity check + * or generation of status for NS + * + * TemporaryBasal + * duration in milliseconds + * rate in U/h or % where 100% is equal to no TBR + * + * ExtendedBolus + * duration in milliseconds + * amount in U + * rate in U/h (synthetic only) + * + * @return data from database. + * temporaryBasal (and extendedBolus) is null if there is no record in progress based on data in database + * bolus is null when there is no record in database + */ + data class PumpState(val temporaryBasal: TemporaryBasal?, val extendedBolus: ExtendedBolus?, val bolus: Bolus?, val profile: Profile?) { + data class TemporaryBasal(val timestamp: Long, val duration: Long, val rate: Double, val isAbsolute: Boolean, val type: TemporaryBasalType, val id: Long, val pumpId: Long?) + data class ExtendedBolus(val timestamp: Long, val duration: Long, val amount: Double, val rate: Double) + data class Bolus(val timestamp: Long, val amount: Double) + } + fun expectedPumpState(): PumpState + + /* + * BOLUSES & CARBS + */ + + /** + * Create bolus with temporary id + * + * Search for combination of temporaryId, PumpType, pumpSerial + * + * If db record doesn't exist, new record is created. + * If exists false is returned and data is ignored + * + * USAGE: + * Generate unique temporaryId + * Call before bolus when no pumpId is known (provide timestamp, amount, temporaryId, type, pumpType, pumpSerial) + * After reading record from history or completed bolus call syncBolusWithTempId with the same temporaryId provided + * If syncBolusWithTempId is not called afterwards record remains valid and is calculated towards iob + * + * @param timestamp timestamp of event from pump history + * @param amount amount of insulin + * @param temporaryId temporary id generated when pump id in not know yet + * @param type type of bolus (NORMAL, SMB, PRIME) + * @param pumpType pump type like PumpType.ACCU_CHEK_COMBO + * @param pumpSerial pump serial number + * @return true if new record is created + **/ + fun addBolusWithTempId(timestamp: Long, amount: Double, temporaryId: Long, type: DetailedBolusInfo.BolusType, pumpType: PumpType, pumpSerial: String): Boolean + + /** + * Synchronization of boluses with temporary id + * + * Search for combination of temporaryId, PumpType, pumpSerial + * + * If db record doesn't exist data is ignored and false returned. + * If exists, amount and timestamp is updated, type and pumpId only if provided + * isValid field is preserved + * + * USAGE: + * After reading record from history or completed bolus call syncBolusWithTempId and + * provide updated timestamp, amount, pumpId (if known), type (if change needed) with the same temporaryId, pumpType, pumpSerial + * + * @param timestamp timestamp of event from pump history + * @param amount amount of insulin + * @param temporaryId temporary id generated when pump id in not know yet + * @param type type of bolus (NORMAL, SMB, PRIME) + * @param pumpId pump id from history + * @param pumpType pump type like PumpType.ACCU_CHEK_COMBO + * @param pumpSerial pump serial number + * @return true if record is successfully updated + **/ + fun syncBolusWithTempId(timestamp: Long, amount: Double, temporaryId: Long, type: DetailedBolusInfo.BolusType?, pumpId: Long?, pumpType: PumpType, pumpSerial: String): Boolean + + /** + * Synchronization of boluses + * + * Search for combination of pumpId, PumpType, pumpSerial + * + * If db record doesn't exist, new record is created. + * If exists, amount, type (if provided) and timestamp is updated + * isValid field is preserved + * + * @param timestamp timestamp of event from pump history + * @param amount amount of insulin + * @param type type of bolus (NORMAL, SMB, PRIME) + * @param pumpId pump id from history + * @param pumpType pump type like PumpType.ACCU_CHEK_COMBO + * @param pumpSerial pump serial number + * @return true if new record is created + **/ + fun syncBolusWithPumpId(timestamp: Long, amount: Double, type: DetailedBolusInfo.BolusType?, pumpId: Long, pumpType: PumpType, pumpSerial: String): Boolean + + /** + * Synchronization of carbs + * + * Assuming there will be no clash on timestamp from different pumps or UI + * only timestamp is compared + * + * If db record doesn't exist, new record is created. + * If exists, data is ignored + * + * @param timestamp timestamp of event from pump history + * @param amount amount of carbs + * @param pumpId pump id from history if coming form pump history + * @param pumpType pump type like PumpType.ACCU_CHEK_COMBO + * @param pumpSerial pump serial number + * @return true if new record is created + **/ + fun syncCarbsWithTimestamp(timestamp: Long, amount: Double, pumpId: Long?, pumpType: PumpType, pumpSerial: String): Boolean + + /* + * THERAPY EVENTS + */ + + /** + * Synchronization of events like CANNULA_CHANGE + * + * Assuming there will be no clash on timestamp from different pumps + * only timestamp and type is compared + * + * If db record doesn't exist, new record is created. + * If exists, data is ignored + * + * @param timestamp timestamp of event from pump history + * @param type type like CANNULA_CHANGE, INSULIN_CHANGE + * @param note note + * @param pumpId pump id from history if available + * @param pumpType pump type like PumpType.ACCU_CHEK_COMBO + * @param pumpSerial pump serial number + * @return true if new record is created + **/ + fun insertTherapyEventIfNewWithTimestamp(timestamp: Long, type: DetailedBolusInfo.EventType, note: String? = null, pumpId: Long? = null, pumpType: PumpType, pumpSerial: String) : Boolean + + /** + * Create an announcement + * + * It's common TherapyEvent NOTE + * Event is sent to NS as an announcement + * + * Common use is report failures like occlusion, empty reservoir etc + * + * Created with now() as a timestamp + * + * @param error error message + * @param pumpId pump id from history if available + * @param pumpType pump type like PumpType.ACCU_CHEK_COMBO + * @param pumpSerial pump serial number + **/ + fun insertAnnouncement(error: String, pumpId: Long? = null, pumpType: PumpType, pumpSerial: String) + + /* + * TEMPORARY BASALS + */ + + enum class TemporaryBasalType { + NORMAL, + EMULATED_PUMP_SUSPEND, // Initiated by AAPS as zero TBR + PUMP_SUSPEND, // Initiated on PUMP + SUPERBOLUS; + + fun toDbType(): TemporaryBasal.Type = + when (this) { + NORMAL -> TemporaryBasal.Type.NORMAL + EMULATED_PUMP_SUSPEND -> TemporaryBasal.Type.EMULATED_PUMP_SUSPEND + PUMP_SUSPEND -> TemporaryBasal.Type.PUMP_SUSPEND + SUPERBOLUS -> TemporaryBasal.Type.SUPERBOLUS + } + + companion object { + + fun fromDbType(dbType: TemporaryBasal.Type) = values().firstOrNull { it.name == dbType.name } ?: NORMAL + } + + } + + /** + * Synchronization of temporary basals + * + * Search for combination of pumpId, PumpType, pumpSerial + * + * If exists, timestamp, duration, rate and type (if provided) is updated + * If db record doesn't exist, new record is created. + * If overlap another running TBR, running is cut off + * isValid field is preserved + * + * if driver does cut of ended TBR by itself use only [syncTemporaryBasalWithPumpId] + * if driver send another [syncTemporaryBasalWithPumpId] to cut previous by AAPS it's necessary + * to send [syncTemporaryBasalWithPumpId] sorted by timestamp for proper cutting + * + * if driver use combination of start [syncTemporaryBasalWithPumpId] and end [syncStopTemporaryBasalWithPumpId] + * events AAPS does the cutting itself. Events must be sorted by timestamp + * if db record already has endPumpId assigned by [syncStopTemporaryBasalWithPumpId] other updates + * are ignored + * + * see [info.nightscout.androidaps.database.transactions.SyncPumpTemporaryBasalTransaction] + * + * @param timestamp timestamp of event from pump history + * @param rate TBR rate in U/h or % (value of 100% is equal to no TBR) + * @param duration duration in milliseconds + * @param isAbsolute is TBR in U/h or % ? + * @param type type of TBR, from request sent to the driver + * @param pumpId pump id from history + * @param pumpType pump type like PumpType.ACCU_CHEK_COMBO + * @param pumpSerial pump serial number + * @return true if new record is created + **/ + + fun syncTemporaryBasalWithPumpId(timestamp: Long, rate: Double, duration: Long, isAbsolute: Boolean, type: TemporaryBasalType?, pumpId: Long, pumpType: PumpType, pumpSerial: String): Boolean + + /** + * Synchronization of temporary basals end event + * (for pumps having separate event for end of TBR or not having history) + * (not useful for pump modifying duration in history log) + * + * Search first for a TBR with combination of endPumpId, pumpType, pumpSerial + * if found assume, some running TBR has been already cut off and ignore data. False is returned + * + * Search for running TBR with combination of pumpType, pumpSerial + * + * If exists, + * currently running record is cut off by provided timestamp (ie duration is adjusted) + * endPumpId is stored to running record + * If db record doesn't exist data is ignored and false returned + * + * see [info.nightscout.androidaps.database.transactions.SyncPumpCancelTemporaryBasalIfAnyTransaction] + * + * @param timestamp timestamp of event from pump history + * @param endPumpId pump id of ending event from history + * @param pumpType pump type like PumpType.ACCU_CHEK_COMBO + * @param pumpSerial pump serial number + * @return true if running record is found and ended by changing duration + **/ + fun syncStopTemporaryBasalWithPumpId(timestamp: Long, endPumpId: Long, pumpType: PumpType, pumpSerial: String): Boolean + + /** + * Invalidate of temporary basals that failed to start + * EROS specific, replace by setting duration to zero ???? + * + * If exists, isValid is set false + * If db record doesn't exist data is ignored and false returned + * + * + * @param pumpId pump id of ending event from history + * @param pumpType pump type like PumpType.ACCU_CHEK_COMBO + * @param pumpSerial pump serial number + * @return true if running record is found and invalidated + **/ + fun invalidateTemporaryBasal(id: Long): Boolean + + /** + * Synchronization of extended bolus + * + * Search for combination of pumpId, PumpType, pumpSerial + * + * If exists and endId is null (ie. has not been cut off), timestamp, duration, amount is updated + * If overlap another running EB, running is cut off and new record is created + * If db record doesn't exist, new record is created. + * isValid field is preserved + * + * see [info.nightscout.androidaps.database.transactions.SyncPumpExtendedBolusTransaction] + * + * @param timestamp timestamp of event from pump history + * @param amount EB total amount in U + * @param duration duration in milliseconds + * @param pumpId pump id from history + * @param pumpType pump type like PumpType.ACCU_CHEK_COMBO + * @param pumpSerial pump serial number + * @return true if new record is created + **/ + + fun syncExtendedBolusWithPumpId(timestamp: Long, amount: Double, duration: Long, isEmulatingTB: Boolean, pumpId: Long, pumpType: PumpType, pumpSerial: String): Boolean + + /** + * Synchronization of extended bolus end event + * (for pumps having separate event for end of EB or not having history) + * (not useful for pump modifying duration in history log) + * + * Search first for a TBR with combination of endPumpId, pumpType, pumpSerial + * if found assume, some running EB has been already cut off and ignore data. False is returned + * + * Search for running EB with combination of pumpType, pumpSerial + * + * If exists, + * currently running record is cut off by provided timestamp (ie duration and amount is adjusted) + * endPumpId is stored to running record + * If db record doesn't exist data is ignored and false returned + * + * see [info.nightscout.androidaps.database.transactions.SyncPumpCancelExtendedBolusIfAnyTransaction] + * + * @param timestamp timestamp of event from pump history + * @param endPumpId pump id of ending event from history + * @param pumpType pump type like PumpType.ACCU_CHEK_COMBO + * @param pumpSerial pump serial number + * @return true if running record is found and ended by changing duration + **/ + fun syncStopExtendedBolusWithPumpId(timestamp: Long, endPumpId: Long, pumpType: PumpType, pumpSerial: String): Boolean +} \ No newline at end of file diff --git a/core/src/main/java/info/nightscout/androidaps/interfaces/SensitivityInterface.kt b/core/src/main/java/info/nightscout/androidaps/interfaces/Sensitivity.kt similarity index 72% rename from core/src/main/java/info/nightscout/androidaps/interfaces/SensitivityInterface.kt rename to core/src/main/java/info/nightscout/androidaps/interfaces/Sensitivity.kt index 7fa096bef4..b15d2a976c 100644 --- a/core/src/main/java/info/nightscout/androidaps/interfaces/SensitivityInterface.kt +++ b/core/src/main/java/info/nightscout/androidaps/interfaces/Sensitivity.kt @@ -1,9 +1,9 @@ package info.nightscout.androidaps.interfaces +import info.nightscout.androidaps.plugins.iob.iobCobCalculator.AutosensDataStore import info.nightscout.androidaps.plugins.iob.iobCobCalculator.AutosensResult -import org.json.JSONObject -interface SensitivityInterface : ConfigExportImportInterface { +interface Sensitivity : ConfigExportImport { enum class SensitivityType(val value: Int) { UNKNOWN(-1), @@ -12,15 +12,17 @@ interface SensitivityInterface : ConfigExportImportInterface { SENSITIVITY_OREF1(2); companion object { + private val map = values().associateBy(SensitivityType::value) fun fromInt(type: Int) = map[type] } } val id: SensitivityType - fun detectSensitivity(plugin: IobCobCalculatorInterface, fromTime: Long, toTime: Long): AutosensResult + fun detectSensitivity(ads: AutosensDataStore, fromTime: Long, toTime: Long): AutosensResult companion object { + const val MIN_HOURS = 1.0 const val MIN_HOURS_FULL_AUTOSENS = 4.0 } diff --git a/core/src/main/java/info/nightscout/androidaps/interfaces/SmsCommunicatorInterface.kt b/core/src/main/java/info/nightscout/androidaps/interfaces/SmsCommunicator.kt similarity index 74% rename from core/src/main/java/info/nightscout/androidaps/interfaces/SmsCommunicatorInterface.kt rename to core/src/main/java/info/nightscout/androidaps/interfaces/SmsCommunicator.kt index 9e201728ec..e753ea049f 100644 --- a/core/src/main/java/info/nightscout/androidaps/interfaces/SmsCommunicatorInterface.kt +++ b/core/src/main/java/info/nightscout/androidaps/interfaces/SmsCommunicator.kt @@ -1,6 +1,6 @@ package info.nightscout.androidaps.interfaces -interface SmsCommunicatorInterface { +interface SmsCommunicator { fun sendNotificationToAllNumbers(text: String): Boolean } \ No newline at end of file diff --git a/core/src/main/java/info/nightscout/androidaps/interfaces/TreatmentServiceInterface.kt b/core/src/main/java/info/nightscout/androidaps/interfaces/TreatmentServiceInterface.kt index ff3aaa114f..3c6b9ae8eb 100644 --- a/core/src/main/java/info/nightscout/androidaps/interfaces/TreatmentServiceInterface.kt +++ b/core/src/main/java/info/nightscout/androidaps/interfaces/TreatmentServiceInterface.kt @@ -4,15 +4,6 @@ import info.nightscout.androidaps.db.Treatment interface TreatmentServiceInterface { - fun getTreatmentDataFromTime(mills: Long, ascending: Boolean): List - fun getTreatmentDataFromTime(from: Long, to: Long, ascending: Boolean): List - fun getTreatmentData(): List - fun getLastBolus(excludeSMB: Boolean): Treatment? - fun getLastCarb(): Treatment? fun createOrUpdateMedtronic(treatment: Treatment, fromNightScout: Boolean): UpdateReturn fun createOrUpdate(treatment: Treatment): UpdateReturn - fun resetTreatments() - fun delete(data: Treatment) - fun update(data: Treatment) - fun count(): Long } \ No newline at end of file diff --git a/core/src/main/java/info/nightscout/androidaps/interfaces/TreatmentsInterface.java b/core/src/main/java/info/nightscout/androidaps/interfaces/TreatmentsInterface.java index 89406a9992..e41e39da45 100644 --- a/core/src/main/java/info/nightscout/androidaps/interfaces/TreatmentsInterface.java +++ b/core/src/main/java/info/nightscout/androidaps/interfaces/TreatmentsInterface.java @@ -22,50 +22,11 @@ public interface TreatmentsInterface { TreatmentServiceInterface getService(); - void updateTotalIOBTreatments(); - - void updateTotalIOBTempBasals(); - - IobTotal getLastCalculationTreatments(); - - IobTotal getCalculationToTimeTreatments(long time); - - IobTotal getLastCalculationTempBasals(); - - IobTotal getCalculationToTimeTempBasals(long time); - - List getTreatmentsFromHistory(); - - List getCarbTreatments5MinBackFromHistory(long time); - + @Deprecated List getTreatmentsFromHistoryAfterTimestamp(long timestamp); - long getLastBolusTime(); - - long getLastBolusTime(boolean excludeSMB); - - // real basals (not faked by extended bolus) - boolean isInHistoryRealTempBasalInProgress(); - - TemporaryBasal getRealTempBasalFromHistory(long time); - boolean addToHistoryTempBasal(TemporaryBasal tempBasal); - // basal that can be faked by extended boluses - boolean isTempBasalInProgress(); - - TemporaryBasal getTempBasalFromHistory(long time); - - NonOverlappingIntervals getTemporaryBasalsFromHistory(); - - void removeTempBasal(TemporaryBasal temporaryBasal); - - boolean isInHistoryExtendedBolusInProgress(); - - ExtendedBolus getExtendedBolusFromHistory(long time); - - Intervals getExtendedBolusesFromHistory(); - boolean addToHistoryExtendedBolus(ExtendedBolus extendedBolus); boolean addToHistoryTreatment(DetailedBolusInfo detailedBolusInfo, boolean allowUpdate); @@ -80,8 +41,6 @@ public interface TreatmentsInterface { void doProfileSwitch(final int duration, final int percentage, final int timeShift); - long oldestDataAvailable(); - TreatmentUpdateReturn createOrUpdateMedtronic(Treatment treatment, boolean fromNightScout); } \ No newline at end of file diff --git a/core/src/main/java/info/nightscout/androidaps/logging/LTag.kt b/core/src/main/java/info/nightscout/androidaps/logging/LTag.kt index 3e67466663..02e8904f00 100644 --- a/core/src/main/java/info/nightscout/androidaps/logging/LTag.kt +++ b/core/src/main/java/info/nightscout/androidaps/logging/LTag.kt @@ -9,8 +9,6 @@ enum class LTag(val tag: String, val defaultValue : Boolean = true, val requires CONFIGBUILDER("CONFIGBUILDER"), CONSTRAINTS("CONSTRAINTS"), DATABASE("DATABASE"), - DATAFOOD("DATAFOOD", defaultValue = false), - DATASERVICE("DATASERVICE"), DATATREATMENTS("DATATREATMENTS"), EVENTS("EVENTS", defaultValue = false, requiresRestart = true), GLUCOSE("GLUCOSE", defaultValue = false), diff --git a/core/src/main/java/info/nightscout/androidaps/logging/StacktraceLoggerWrapper.kt b/core/src/main/java/info/nightscout/androidaps/logging/StacktraceLoggerWrapper.kt index 38b2b84f9f..ab574661e0 100644 --- a/core/src/main/java/info/nightscout/androidaps/logging/StacktraceLoggerWrapper.kt +++ b/core/src/main/java/info/nightscout/androidaps/logging/StacktraceLoggerWrapper.kt @@ -32,10 +32,6 @@ class StacktraceLoggerWrapper(private val delegate: Logger) : Logger by delegate // all other methods will be implemented by delegate companion object { - @JvmStatic - @Deprecated("please inject AAPSLogger") - fun getLogger(ltag: LTag) = StacktraceLoggerWrapper(LoggerFactory.getLogger(ltag.name)) - @JvmStatic @Deprecated("please inject AAPSLogger") fun getLogger(clazz: Class<*>) = StacktraceLoggerWrapper(LoggerFactory.getLogger(clazz)) diff --git a/core/src/main/java/info/nightscout/androidaps/logging/UserEntryLogger.kt b/core/src/main/java/info/nightscout/androidaps/logging/UserEntryLogger.kt index 96a02cf3df..9bed01b2f0 100644 --- a/core/src/main/java/info/nightscout/androidaps/logging/UserEntryLogger.kt +++ b/core/src/main/java/info/nightscout/androidaps/logging/UserEntryLogger.kt @@ -1,10 +1,13 @@ package info.nightscout.androidaps.logging -import info.nightscout.androidaps.Constants import info.nightscout.androidaps.database.AppRepository -import info.nightscout.androidaps.database.entities.UserEntry.* +import info.nightscout.androidaps.database.entities.ValueWithUnit +import info.nightscout.androidaps.database.entities.UserEntry.Action +import info.nightscout.androidaps.database.entities.UserEntry.Sources import info.nightscout.androidaps.database.transactions.UserEntryTransaction import info.nightscout.androidaps.utils.rx.AapsSchedulers +import info.nightscout.androidaps.utils.userEntry.UserEntryMapper +import info.nightscout.androidaps.utils.userEntry.ValueWithUnitMapper import io.reactivex.disposables.CompositeDisposable import io.reactivex.rxkotlin.plusAssign import io.reactivex.rxkotlin.subscribeBy @@ -20,66 +23,30 @@ class UserEntryLogger @Inject constructor( private val compositeDisposable = CompositeDisposable() - fun log(action: Action, s: String? ="", vararg listvalues: ValueWithUnit) { - val values = mutableListOf() - for (v in listvalues){ - if (v.condition) values.add(v) - } + fun log(action: Action, source: Sources, note: String? ="", vararg listvalues: ValueWithUnit?) = log(action, source, note, listvalues.toList()) + + fun log(action: Action, source: Sources, vararg listvalues: ValueWithUnit?) = log(action, source,"", listvalues.toList()) + + fun log(action: Action, source: Sources, note: String? ="", listvalues: List = listOf()) { + val filteredValues = listvalues.toList().filter { it != null} compositeDisposable += repository.runTransaction(UserEntryTransaction( action = action, - s = s ?:"", - values = values + source = source, + note = note ?: "", + values = filteredValues )) .subscribeOn(aapsSchedulers.io) .observeOn(aapsSchedulers.io) .subscribeBy( - onError = { aapsLogger.debug("ERRORED USER ENTRY: $action $s $values") }, - onComplete = { aapsLogger.debug("USER ENTRY: $action $s $values") } + onError = { aapsLogger.debug("ERRORED USER ENTRY: $action $source $note $filteredValues") }, + onComplete = { aapsLogger.debug("USER ENTRY: $action $source $note $filteredValues") } ) } - fun log(action: Action, vararg listvalues: ValueWithUnit) { - val values = mutableListOf() - for (v in listvalues){ - if (v.condition) values.add(v) - } - compositeDisposable += repository.runTransaction(UserEntryTransaction( - action = action, - s = "", - values = values - )) - .subscribeOn(aapsSchedulers.io) - .observeOn(aapsSchedulers.io) - .subscribeBy( - onError = { aapsLogger.debug("ERRORED USER ENTRY: $action $values") }, - onComplete = { aapsLogger.debug("USER ENTRY: $action $values") } - ) - } + fun log(action: UserEntryMapper.Action, source: UserEntryMapper.Sources, note: String? ="", vararg listvalues: ValueWithUnitMapper?) = log(action.db, source.db, note, listvalues.toList().map {it?.db()}) - fun log(action: Action, s: String? = "") { - compositeDisposable += repository.runTransaction(UserEntryTransaction( - action = action, - s = s ?:"" - )) - .subscribeOn(aapsSchedulers.io) - .observeOn(aapsSchedulers.io) - .subscribeBy( - onError = { aapsLogger.debug("ERRORED USER ENTRY: $action") }, - onComplete = { aapsLogger.debug("USER ENTRY: $action") } - ) - } + fun log(action: UserEntryMapper.Action, source: UserEntryMapper.Sources, vararg listvalues: ValueWithUnitMapper?) = log(action.db, source.db, "", listvalues.toList().map {it?.db()}) + + fun log(action: UserEntryMapper.Action, source: UserEntryMapper.Sources, note: String? ="", listvalues: List = listOf()) = log(action.db, source.db, note, listvalues.map {it?.db()}) - fun log(action: Action, s: String? = "", values: MutableList) { - compositeDisposable += repository.runTransaction(UserEntryTransaction( - action = action, - s = s ?:"", - values = values - )) - .subscribeOn(aapsSchedulers.io) - .observeOn(aapsSchedulers.io) - .subscribeBy( - onError = { aapsLogger.debug("ERRORED USER ENTRY: $action $s $values") }, - onComplete = { aapsLogger.debug("USER ENTRY: $action $s $values") } - ) - } } \ No newline at end of file diff --git a/core/src/main/java/info/nightscout/androidaps/plugins/aps/loop/APSResult.kt b/core/src/main/java/info/nightscout/androidaps/plugins/aps/loop/APSResult.kt index b7f1048464..989ecdcdd0 100644 --- a/core/src/main/java/info/nightscout/androidaps/plugins/aps/loop/APSResult.kt +++ b/core/src/main/java/info/nightscout/androidaps/plugins/aps/loop/APSResult.kt @@ -3,19 +3,21 @@ package info.nightscout.androidaps.plugins.aps.loop import android.text.Spanned import dagger.android.HasAndroidInjector import info.nightscout.androidaps.core.R -import info.nightscout.androidaps.data.GlucoseValueDataPoint import info.nightscout.androidaps.data.IobTotal import info.nightscout.androidaps.database.entities.GlucoseValue -import info.nightscout.androidaps.interfaces.ActivePluginProvider +import info.nightscout.androidaps.interfaces.ActivePlugin import info.nightscout.androidaps.interfaces.Constraint +import info.nightscout.androidaps.interfaces.IobCobCalculator import info.nightscout.androidaps.interfaces.ProfileFunction import info.nightscout.androidaps.interfaces.PumpDescription -import info.nightscout.androidaps.interfaces.TreatmentsInterface import info.nightscout.androidaps.logging.AAPSLogger import info.nightscout.androidaps.logging.LTag import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker +import info.nightscout.androidaps.utils.DateUtil import info.nightscout.androidaps.utils.DecimalFormatter import info.nightscout.androidaps.utils.HtmlHelper.fromHtml +import info.nightscout.androidaps.extensions.convertedToAbsolute +import info.nightscout.androidaps.extensions.convertedToPercent import info.nightscout.androidaps.utils.resources.ResourceHelper import info.nightscout.androidaps.utils.sharedPreferences.SP import org.json.JSONException @@ -33,10 +35,11 @@ open class APSResult @Inject constructor(val injector: HasAndroidInjector) { @Inject lateinit var aapsLogger: AAPSLogger @Inject lateinit var constraintChecker: ConstraintChecker @Inject lateinit var sp: SP - @Inject lateinit var activePlugin: ActivePluginProvider - @Inject lateinit var treatmentsPlugin: TreatmentsInterface + @Inject lateinit var activePlugin: ActivePlugin + @Inject lateinit var iobCobCalculator: IobCobCalculator @Inject lateinit var profileFunction: ProfileFunction @Inject lateinit var resourceHelper: ResourceHelper + @Inject lateinit var dateUtil: DateUtil var date: Long = 0 var reason: String? = null @@ -183,9 +186,9 @@ open class APSResult @Inject constructor(val injector: HasAndroidInjector) { return json } - val predictions: MutableList + val predictions: MutableList get() { - val array: MutableList = ArrayList() + val array: MutableList = ArrayList() val startTime = date json?.let { json -> if (json.has("predBGs")) { @@ -201,7 +204,7 @@ open class APSResult @Inject constructor(val injector: HasAndroidInjector) { sourceSensor = GlucoseValue.SourceSensor.IOB_PREDICTION, trendArrow = GlucoseValue.TrendArrow.NONE ) - array.add(GlucoseValueDataPoint(injector, gv)) + array.add(gv) } } if (predBGs.has("aCOB")) { @@ -212,10 +215,10 @@ open class APSResult @Inject constructor(val injector: HasAndroidInjector) { noise = 0.0, value = iob.getInt(i).toDouble(), timestamp = startTime + i * 5 * 60 * 1000L, - sourceSensor = GlucoseValue.SourceSensor.aCOB_PREDICTION, + sourceSensor = GlucoseValue.SourceSensor.A_COB_PREDICTION, trendArrow = GlucoseValue.TrendArrow.NONE ) - array.add(GlucoseValueDataPoint(injector, gv)) + array.add(gv) } } if (predBGs.has("COB")) { @@ -229,7 +232,7 @@ open class APSResult @Inject constructor(val injector: HasAndroidInjector) { sourceSensor = GlucoseValue.SourceSensor.COB_PREDICTION, trendArrow = GlucoseValue.TrendArrow.NONE ) - array.add(GlucoseValueDataPoint(injector, gv)) + array.add(gv) } } if (predBGs.has("UAM")) { @@ -243,7 +246,7 @@ open class APSResult @Inject constructor(val injector: HasAndroidInjector) { sourceSensor = GlucoseValue.SourceSensor.UAM_PREDICTION, trendArrow = GlucoseValue.TrendArrow.NONE ) - array.add(GlucoseValueDataPoint(injector, gv)) + array.add(gv) } } if (predBGs.has("ZT")) { @@ -257,7 +260,7 @@ open class APSResult @Inject constructor(val injector: HasAndroidInjector) { sourceSensor = GlucoseValue.SourceSensor.ZT_PREDICTION, trendArrow = GlucoseValue.TrendArrow.NONE ) - array.add(GlucoseValueDataPoint(injector, gv)) + array.add(gv) } } } @@ -315,7 +318,7 @@ open class APSResult @Inject constructor(val injector: HasAndroidInjector) { return false } val now = System.currentTimeMillis() - val activeTemp = treatmentsPlugin.getTempBasalFromHistory(now) + val activeTemp = iobCobCalculator.getTempBasalIncludingConvertedExtended(now) val pump = activePlugin.activePump val profile = profileFunction.getProfile() if (profile == null) { @@ -327,7 +330,7 @@ open class APSResult @Inject constructor(val injector: HasAndroidInjector) { aapsLogger.debug(LTag.APS, "FALSE: No temp running, asking cancel temp") return false } - if (activeTemp != null && abs(percent - activeTemp.tempBasalConvertedToPercent(now, profile)) < pump.pumpDescription.basalStep) { + if (activeTemp != null && abs(percent - activeTemp.convertedToPercent(now, profile)) < pump.pumpDescription.basalStep) { aapsLogger.debug(LTag.APS, "FALSE: Temp equal") return false } @@ -338,7 +341,7 @@ open class APSResult @Inject constructor(val injector: HasAndroidInjector) { } // always report hightemp if (pump.pumpDescription.tempBasalStyle == PumpDescription.PERCENT) { - val pumpLimit = pump.pumpDescription.pumpType.tbrSettings.maxDose + val pumpLimit = pump.pumpDescription.pumpType.tbrSettings?.maxDose ?: 0.0 if (percent.toDouble() == pumpLimit) { aapsLogger.debug(LTag.APS, "TRUE: Pump limit") return true @@ -350,7 +353,7 @@ open class APSResult @Inject constructor(val injector: HasAndroidInjector) { val lowThreshold = 1 - percentMinChangeChange val highThreshold = 1 + percentMinChangeChange var change = percent / 100.0 - if (activeTemp != null) change = percent / activeTemp.tempBasalConvertedToPercent(now, profile).toDouble() + if (activeTemp != null) change = percent / activeTemp.convertedToPercent(now, profile).toDouble() if (change < lowThreshold || change > highThreshold) { aapsLogger.debug(LTag.APS, "TRUE: Outside allowed range " + change * 100.0 + "%") true @@ -363,7 +366,7 @@ open class APSResult @Inject constructor(val injector: HasAndroidInjector) { aapsLogger.debug(LTag.APS, "FALSE: No temp running, asking cancel temp") return false } - if (activeTemp != null && abs(rate - activeTemp.tempBasalConvertedToAbsolute(now, profile)) < pump.pumpDescription.basalStep) { + if (activeTemp != null && abs(rate - activeTemp.convertedToAbsolute(now, profile)) < pump.pumpDescription.basalStep) { aapsLogger.debug(LTag.APS, "FALSE: Temp equal") return false } @@ -374,7 +377,7 @@ open class APSResult @Inject constructor(val injector: HasAndroidInjector) { } // always report hightemp if (pump.pumpDescription.tempBasalStyle == PumpDescription.ABSOLUTE) { - val pumpLimit = pump.pumpDescription.pumpType.tbrSettings.maxDose + val pumpLimit = pump.pumpDescription.pumpType.tbrSettings?.maxDose ?: 0.0 if (rate == pumpLimit) { aapsLogger.debug(LTag.APS, "TRUE: Pump limit") return true @@ -386,7 +389,7 @@ open class APSResult @Inject constructor(val injector: HasAndroidInjector) { val lowThreshold = 1 - percentMinChangeChange val highThreshold = 1 + percentMinChangeChange var change = rate / profile.basal - if (activeTemp != null) change = rate / activeTemp.tempBasalConvertedToAbsolute(now, profile) + if (activeTemp != null) change = rate / activeTemp.convertedToAbsolute(now, profile) if (change < lowThreshold || change > highThreshold) { aapsLogger.debug(LTag.APS, "TRUE: Outside allowed range " + change * 100.0 + "%") true diff --git a/core/src/main/java/info/nightscout/androidaps/plugins/configBuilder/ConstraintChecker.kt b/core/src/main/java/info/nightscout/androidaps/plugins/configBuilder/ConstraintChecker.kt index 0ceee93a06..d16aae526a 100644 --- a/core/src/main/java/info/nightscout/androidaps/plugins/configBuilder/ConstraintChecker.kt +++ b/core/src/main/java/info/nightscout/androidaps/plugins/configBuilder/ConstraintChecker.kt @@ -2,15 +2,15 @@ package info.nightscout.androidaps.plugins.configBuilder import info.nightscout.androidaps.Constants import info.nightscout.androidaps.data.Profile -import info.nightscout.androidaps.interfaces.ActivePluginProvider +import info.nightscout.androidaps.interfaces.ActivePlugin import info.nightscout.androidaps.interfaces.Constraint -import info.nightscout.androidaps.interfaces.ConstraintsInterface +import info.nightscout.androidaps.interfaces.Constraints import info.nightscout.androidaps.interfaces.PluginType import javax.inject.Inject import javax.inject.Singleton @Singleton -open class ConstraintChecker @Inject constructor(private val activePlugin: ActivePluginProvider) : ConstraintsInterface { +class ConstraintChecker @Inject constructor(private val activePlugin: ActivePlugin) : Constraints { fun isLoopInvocationAllowed(): Constraint = isLoopInvocationAllowed(Constraint(true)) @@ -61,9 +61,9 @@ open class ConstraintChecker @Inject constructor(private val activePlugin: Activ isAutomationEnabled(Constraint(true)) override fun isLoopInvocationAllowed(value: Constraint): Constraint { - val constraintsPlugins = activePlugin.getSpecificPluginsListByInterface(ConstraintsInterface::class.java) + val constraintsPlugins = activePlugin.getSpecificPluginsListByInterface(Constraints::class.java) for (p in constraintsPlugins) { - val constraint = p as ConstraintsInterface + val constraint = p as Constraints if (!p.isEnabled(PluginType.CONSTRAINTS)) continue constraint.isLoopInvocationAllowed(value) } @@ -71,9 +71,9 @@ open class ConstraintChecker @Inject constructor(private val activePlugin: Activ } override fun isClosedLoopAllowed(value: Constraint): Constraint { - val constraintsPlugins = activePlugin.getSpecificPluginsListByInterface(ConstraintsInterface::class.java) + val constraintsPlugins = activePlugin.getSpecificPluginsListByInterface(Constraints::class.java) for (p in constraintsPlugins) { - val constraint = p as ConstraintsInterface + val constraint = p as Constraints if (!p.isEnabled(PluginType.CONSTRAINTS)) continue constraint.isClosedLoopAllowed(value) } @@ -81,9 +81,9 @@ open class ConstraintChecker @Inject constructor(private val activePlugin: Activ } override fun isLgsAllowed(value: Constraint): Constraint { - val constraintsPlugins = activePlugin.getSpecificPluginsListByInterface(ConstraintsInterface::class.java) + val constraintsPlugins = activePlugin.getSpecificPluginsListByInterface(Constraints::class.java) for (p in constraintsPlugins) { - val constraint = p as ConstraintsInterface + val constraint = p as Constraints if (!p.isEnabled(PluginType.CONSTRAINTS)) continue constraint.isLgsAllowed(value) } @@ -91,9 +91,9 @@ open class ConstraintChecker @Inject constructor(private val activePlugin: Activ } override fun isAutosensModeEnabled(value: Constraint): Constraint { - val constraintsPlugins = activePlugin.getSpecificPluginsListByInterface(ConstraintsInterface::class.java) + val constraintsPlugins = activePlugin.getSpecificPluginsListByInterface(Constraints::class.java) for (p in constraintsPlugins) { - val constraint = p as ConstraintsInterface + val constraint = p as Constraints if (!p.isEnabled(PluginType.CONSTRAINTS)) continue constraint.isAutosensModeEnabled(value) } @@ -101,9 +101,9 @@ open class ConstraintChecker @Inject constructor(private val activePlugin: Activ } override fun isAMAModeEnabled(value: Constraint): Constraint { - val constraintsPlugins = activePlugin.getSpecificPluginsListByInterface(ConstraintsInterface::class.java) + val constraintsPlugins = activePlugin.getSpecificPluginsListByInterface(Constraints::class.java) for (p in constraintsPlugins) { - val constrain = p as ConstraintsInterface + val constrain = p as Constraints if (!p.isEnabled(PluginType.CONSTRAINTS)) continue constrain.isAMAModeEnabled(value) } @@ -111,9 +111,9 @@ open class ConstraintChecker @Inject constructor(private val activePlugin: Activ } override fun isSMBModeEnabled(value: Constraint): Constraint { - val constraintsPlugins = activePlugin.getSpecificPluginsListByInterface(ConstraintsInterface::class.java) + val constraintsPlugins = activePlugin.getSpecificPluginsListByInterface(Constraints::class.java) for (p in constraintsPlugins) { - val constraint = p as ConstraintsInterface + val constraint = p as Constraints if (!p.isEnabled(PluginType.CONSTRAINTS)) continue constraint.isSMBModeEnabled(value) } @@ -121,9 +121,9 @@ open class ConstraintChecker @Inject constructor(private val activePlugin: Activ } override fun isUAMEnabled(value: Constraint): Constraint { - val constraintsPlugins = activePlugin.getSpecificPluginsListByInterface(ConstraintsInterface::class.java) + val constraintsPlugins = activePlugin.getSpecificPluginsListByInterface(Constraints::class.java) for (p in constraintsPlugins) { - val constraint = p as ConstraintsInterface + val constraint = p as Constraints if (!p.isEnabled(PluginType.CONSTRAINTS)) continue constraint.isUAMEnabled(value) } @@ -131,9 +131,9 @@ open class ConstraintChecker @Inject constructor(private val activePlugin: Activ } override fun isAdvancedFilteringEnabled(value: Constraint): Constraint { - val constraintsPlugins = activePlugin.getSpecificPluginsListByInterface(ConstraintsInterface::class.java) + val constraintsPlugins = activePlugin.getSpecificPluginsListByInterface(Constraints::class.java) for (p in constraintsPlugins) { - val constraint = p as ConstraintsInterface + val constraint = p as Constraints if (!p.isEnabled(PluginType.CONSTRAINTS)) continue constraint.isAdvancedFilteringEnabled(value) } @@ -141,9 +141,9 @@ open class ConstraintChecker @Inject constructor(private val activePlugin: Activ } override fun isSuperBolusEnabled(value: Constraint): Constraint { - val constraintsPlugins = activePlugin.getSpecificPluginsListByInterface(ConstraintsInterface::class.java) + val constraintsPlugins = activePlugin.getSpecificPluginsListByInterface(Constraints::class.java) for (p in constraintsPlugins) { - val constraint = p as ConstraintsInterface + val constraint = p as Constraints if (!p.isEnabled(PluginType.CONSTRAINTS)) continue constraint.isSuperBolusEnabled(value) } @@ -151,9 +151,9 @@ open class ConstraintChecker @Inject constructor(private val activePlugin: Activ } override fun applyBasalConstraints(absoluteRate: Constraint, profile: Profile): Constraint { - val constraintsPlugins = activePlugin.getSpecificPluginsListByInterface(ConstraintsInterface::class.java) + val constraintsPlugins = activePlugin.getSpecificPluginsListByInterface(Constraints::class.java) for (p in constraintsPlugins) { - val constraint = p as ConstraintsInterface + val constraint = p as Constraints if (!p.isEnabled(PluginType.CONSTRAINTS)) continue constraint.applyBasalConstraints(absoluteRate, profile) } @@ -161,9 +161,9 @@ open class ConstraintChecker @Inject constructor(private val activePlugin: Activ } override fun applyBasalPercentConstraints(percentRate: Constraint, profile: Profile): Constraint { - val constraintsPlugins = activePlugin.getSpecificPluginsListByInterface(ConstraintsInterface::class.java) + val constraintsPlugins = activePlugin.getSpecificPluginsListByInterface(Constraints::class.java) for (p in constraintsPlugins) { - val constrain = p as ConstraintsInterface + val constrain = p as Constraints if (!p.isEnabled(PluginType.CONSTRAINTS)) continue constrain.applyBasalPercentConstraints(percentRate, profile) } @@ -171,9 +171,9 @@ open class ConstraintChecker @Inject constructor(private val activePlugin: Activ } override fun applyBolusConstraints(insulin: Constraint): Constraint { - val constraintsPlugins = activePlugin.getSpecificPluginsListByInterface(ConstraintsInterface::class.java) + val constraintsPlugins = activePlugin.getSpecificPluginsListByInterface(Constraints::class.java) for (p in constraintsPlugins) { - val constrain = p as ConstraintsInterface + val constrain = p as Constraints if (!p.isEnabled(PluginType.CONSTRAINTS)) continue constrain.applyBolusConstraints(insulin) } @@ -181,9 +181,9 @@ open class ConstraintChecker @Inject constructor(private val activePlugin: Activ } override fun applyExtendedBolusConstraints(insulin: Constraint): Constraint { - val constraintsPlugins = activePlugin.getSpecificPluginsListByInterface(ConstraintsInterface::class.java) + val constraintsPlugins = activePlugin.getSpecificPluginsListByInterface(Constraints::class.java) for (p in constraintsPlugins) { - val constrain = p as ConstraintsInterface + val constrain = p as Constraints if (!p.isEnabled(PluginType.CONSTRAINTS)) continue constrain.applyExtendedBolusConstraints(insulin) } @@ -191,9 +191,9 @@ open class ConstraintChecker @Inject constructor(private val activePlugin: Activ } override fun applyCarbsConstraints(carbs: Constraint): Constraint { - val constraintsPlugins = activePlugin.getSpecificPluginsListByInterface(ConstraintsInterface::class.java) + val constraintsPlugins = activePlugin.getSpecificPluginsListByInterface(Constraints::class.java) for (p in constraintsPlugins) { - val constrain = p as ConstraintsInterface + val constrain = p as Constraints if (!p.isEnabled(PluginType.CONSTRAINTS)) continue constrain.applyCarbsConstraints(carbs) } @@ -201,9 +201,9 @@ open class ConstraintChecker @Inject constructor(private val activePlugin: Activ } override fun applyMaxIOBConstraints(maxIob: Constraint): Constraint { - val constraintsPlugins = activePlugin.getSpecificPluginsListByInterface(ConstraintsInterface::class.java) + val constraintsPlugins = activePlugin.getSpecificPluginsListByInterface(Constraints::class.java) for (p in constraintsPlugins) { - val constrain = p as ConstraintsInterface + val constrain = p as Constraints if (!p.isEnabled(PluginType.CONSTRAINTS)) continue constrain.applyMaxIOBConstraints(maxIob) } @@ -211,9 +211,9 @@ open class ConstraintChecker @Inject constructor(private val activePlugin: Activ } override fun isAutomationEnabled(value: Constraint): Constraint { - val constraintsPlugins = activePlugin.getSpecificPluginsListByInterface(ConstraintsInterface::class.java) + val constraintsPlugins = activePlugin.getSpecificPluginsListByInterface(Constraints::class.java) for (p in constraintsPlugins) { - val constraint = p as ConstraintsInterface + val constraint = p as Constraints if (!p.isEnabled(PluginType.CONSTRAINTS)) continue constraint.isAutomationEnabled(value) } diff --git a/core/src/main/java/info/nightscout/androidaps/plugins/configBuilder/ProfileFunctionImplementation.kt b/core/src/main/java/info/nightscout/androidaps/plugins/configBuilder/ProfileFunctionImplementation.kt index 4966ccc85a..0712d5987a 100644 --- a/core/src/main/java/info/nightscout/androidaps/plugins/configBuilder/ProfileFunctionImplementation.kt +++ b/core/src/main/java/info/nightscout/androidaps/plugins/configBuilder/ProfileFunctionImplementation.kt @@ -9,7 +9,7 @@ import info.nightscout.androidaps.data.Profile import info.nightscout.androidaps.db.ProfileSwitch import info.nightscout.androidaps.db.Source import info.nightscout.androidaps.interfaces.ProfileStore -import info.nightscout.androidaps.interfaces.ActivePluginProvider +import info.nightscout.androidaps.interfaces.ActivePlugin import info.nightscout.androidaps.interfaces.ProfileFunction import info.nightscout.androidaps.interfaces.TreatmentsInterface import info.nightscout.androidaps.logging.AAPSLogger @@ -27,8 +27,9 @@ class ProfileFunctionImplementation @Inject constructor( private val aapsLogger: AAPSLogger, private val sp: SP, private val resourceHelper: ResourceHelper, - private val activePlugin: ActivePluginProvider, - private val fabricPrivacy: FabricPrivacy + private val activePlugin: ActivePlugin, + private val fabricPrivacy: FabricPrivacy, + private val dateUtil: DateUtil ) : ProfileFunction { override fun getProfileName(): String = @@ -41,7 +42,7 @@ class ProfileFunctionImplementation @Inject constructor( var profileName = resourceHelper.gs(R.string.noprofileselected) val activeTreatments = activePlugin.activeTreatments - val activeProfile = activePlugin.activeProfileInterface + val activeProfile = activePlugin.activeProfileSource val profileSwitch = activeTreatments.getProfileSwitchFromHistory(time) if (profileSwitch != null) { @@ -56,7 +57,7 @@ class ProfileFunctionImplementation @Inject constructor( } if (showRemainingTime && profileSwitch.durationInMinutes != 0) { - profileName += DateUtil.untilString(profileSwitch.originalEnd(), resourceHelper) + profileName += dateUtil.untilString(profileSwitch.originalEnd(), resourceHelper) } } return profileName @@ -74,7 +75,7 @@ class ProfileFunctionImplementation @Inject constructor( override fun getProfile(time: Long): Profile? = getProfile(time, activePlugin.activeTreatments) override fun getProfile(time: Long, activeTreatments: TreatmentsInterface): Profile? { - val activeProfile = activePlugin.activeProfileInterface + val activeProfile = activePlugin.activeProfileSource //log.debug("Profile for: " + new Date(time).toLocaleString() + " : " + getProfileName(time)); val profileSwitch = activeTreatments.getProfileSwitchFromHistory(time) diff --git a/core/src/main/java/info/nightscout/androidaps/plugins/configBuilder/RunningConfiguration.kt b/core/src/main/java/info/nightscout/androidaps/plugins/configBuilder/RunningConfiguration.kt index bfc9014b0b..cf3b151d4d 100644 --- a/core/src/main/java/info/nightscout/androidaps/plugins/configBuilder/RunningConfiguration.kt +++ b/core/src/main/java/info/nightscout/androidaps/plugins/configBuilder/RunningConfiguration.kt @@ -1,11 +1,11 @@ package info.nightscout.androidaps.plugins.configBuilder import info.nightscout.androidaps.core.R -import info.nightscout.androidaps.interfaces.ActivePluginProvider -import info.nightscout.androidaps.interfaces.ConfigBuilderInterface -import info.nightscout.androidaps.interfaces.InsulinInterface +import info.nightscout.androidaps.interfaces.ActivePlugin +import info.nightscout.androidaps.interfaces.ConfigBuilder +import info.nightscout.androidaps.interfaces.Insulin import info.nightscout.androidaps.interfaces.PluginType -import info.nightscout.androidaps.interfaces.SensitivityInterface +import info.nightscout.androidaps.interfaces.Sensitivity import info.nightscout.androidaps.logging.AAPSLogger import info.nightscout.androidaps.logging.LTag import info.nightscout.androidaps.plugins.pump.common.defs.PumpType @@ -18,8 +18,8 @@ import javax.inject.Singleton @Singleton class RunningConfiguration @Inject constructor( - private val activePlugin: ActivePluginProvider, - private val configBuilder: ConfigBuilderInterface, + private val activePlugin: ActivePlugin, + private val configBuilder: ConfigBuilder, private val sp: SP, private val aapsLogger: AAPSLogger ) { @@ -52,9 +52,9 @@ class RunningConfiguration @Inject constructor( // called in NSClient mode only fun apply(configuration: JSONObject) { if (configuration.has("insulin")) { - val insulin = InsulinInterface.InsulinType.fromInt(JsonHelper.safeGetInt(configuration, "insulin", InsulinInterface.InsulinType.UNKNOWN.value)) - for (p in activePlugin.getSpecificPluginsListByInterface(InsulinInterface::class.java)) { - val insulinPlugin = p as InsulinInterface + val insulin = Insulin.InsulinType.fromInt(JsonHelper.safeGetInt(configuration, "insulin", Insulin.InsulinType.UNKNOWN.value)) + for (p in activePlugin.getSpecificPluginsListByInterface(Insulin::class.java)) { + val insulinPlugin = p as Insulin if (insulinPlugin.id == insulin) { if (!p.isEnabled()) { aapsLogger.debug(LTag.CORE, "Changing insulin plugin to ${insulin.name}") @@ -66,9 +66,9 @@ class RunningConfiguration @Inject constructor( } if (configuration.has("sensitivity")) { - val sensitivity = SensitivityInterface.SensitivityType.fromInt(JsonHelper.safeGetInt(configuration, "sensitivity", SensitivityInterface.SensitivityType.UNKNOWN.value)) - for (p in activePlugin.getSpecificPluginsListByInterface(SensitivityInterface::class.java)) { - val sensitivityPlugin = p as SensitivityInterface + val sensitivity = Sensitivity.SensitivityType.fromInt(JsonHelper.safeGetInt(configuration, "sensitivity", Sensitivity.SensitivityType.UNKNOWN.value)) + for (p in activePlugin.getSpecificPluginsListByInterface(Sensitivity::class.java)) { + val sensitivityPlugin = p as Sensitivity if (sensitivityPlugin.id == sensitivity) { if (!p.isEnabled()) { aapsLogger.debug(LTag.CORE, "Changing sensitivity plugin to ${sensitivity.name}") @@ -80,7 +80,7 @@ class RunningConfiguration @Inject constructor( } if (configuration.has("pump")) { - val pumpType = JsonHelper.safeGetString(configuration, "pump", PumpType.GenericAAPS.description) + val pumpType = JsonHelper.safeGetString(configuration, "pump", PumpType.GENERIC_AAPS.description) sp.putString(R.string.key_virtualpump_type, pumpType) activePlugin.activePump.pumpDescription.setPumpDescription(PumpType.getByDescription(pumpType)) aapsLogger.debug(LTag.CORE, "Changing pump type to $pumpType") diff --git a/core/src/main/java/info/nightscout/androidaps/plugins/constraints/versionChecker/VersionCheckerUtils.kt b/core/src/main/java/info/nightscout/androidaps/plugins/constraints/versionChecker/VersionCheckerUtils.kt index 8368c47dea..edf712bb52 100644 --- a/core/src/main/java/info/nightscout/androidaps/plugins/constraints/versionChecker/VersionCheckerUtils.kt +++ b/core/src/main/java/info/nightscout/androidaps/plugins/constraints/versionChecker/VersionCheckerUtils.kt @@ -3,7 +3,7 @@ package info.nightscout.androidaps.plugins.constraints.versionChecker import android.content.Context import android.net.ConnectivityManager import info.nightscout.androidaps.core.R -import info.nightscout.androidaps.interfaces.ConfigInterface +import info.nightscout.androidaps.interfaces.Config import info.nightscout.androidaps.logging.AAPSLogger import info.nightscout.androidaps.logging.LTag import info.nightscout.androidaps.plugins.bus.RxBusWrapper @@ -23,7 +23,7 @@ class VersionCheckerUtils @Inject constructor( val sp: SP, val resourceHelper: ResourceHelper, val rxBus: RxBusWrapper, - private val config: ConfigInterface, + private val config: Config, val context: Context ) { diff --git a/core/src/main/java/info/nightscout/androidaps/plugins/general/maintenance/PrefFileListProvider.kt b/core/src/main/java/info/nightscout/androidaps/plugins/general/maintenance/PrefFileListProvider.kt index 8de45514ba..86208dce3e 100644 --- a/core/src/main/java/info/nightscout/androidaps/plugins/general/maintenance/PrefFileListProvider.kt +++ b/core/src/main/java/info/nightscout/androidaps/plugins/general/maintenance/PrefFileListProvider.kt @@ -2,7 +2,7 @@ package info.nightscout.androidaps.plugins.general.maintenance import android.os.Environment import info.nightscout.androidaps.core.R -import info.nightscout.androidaps.interfaces.ConfigInterface +import info.nightscout.androidaps.interfaces.Config import info.nightscout.androidaps.plugins.constraints.versionChecker.VersionCheckerUtils import info.nightscout.androidaps.plugins.general.maintenance.formats.* import info.nightscout.androidaps.utils.resources.ResourceHelper @@ -20,7 +20,7 @@ import kotlin.math.abs @Singleton class PrefFileListProvider @Inject constructor( private val resourceHelper: ResourceHelper, - private val config: ConfigInterface, + private val config: Config, private val classicPrefsFormat: ClassicPrefsFormat, private val encryptedPrefsFormat: EncryptedPrefsFormat, private val storage: Storage, diff --git a/core/src/main/java/info/nightscout/androidaps/plugins/general/maintenance/activities/PrefImportListActivity.kt b/core/src/main/java/info/nightscout/androidaps/plugins/general/maintenance/activities/PrefImportListActivity.kt index f4cbc1dc91..77c361d869 100644 --- a/core/src/main/java/info/nightscout/androidaps/plugins/general/maintenance/activities/PrefImportListActivity.kt +++ b/core/src/main/java/info/nightscout/androidaps/plugins/general/maintenance/activities/PrefImportListActivity.kt @@ -19,7 +19,7 @@ import info.nightscout.androidaps.plugins.general.maintenance.PrefsFileContract import info.nightscout.androidaps.plugins.general.maintenance.PrefsFormatsHandler import info.nightscout.androidaps.plugins.general.maintenance.formats.PrefsMetadataKey import info.nightscout.androidaps.plugins.general.maintenance.formats.PrefsStatus -import info.nightscout.androidaps.utils.extensions.toVisibility +import info.nightscout.androidaps.extensions.toVisibility import info.nightscout.androidaps.utils.locale.LocaleHelper import info.nightscout.androidaps.utils.resources.ResourceHelper import javax.inject.Inject diff --git a/core/src/main/java/info/nightscout/androidaps/plugins/general/maintenance/formats/ClassicPrefsFormat.kt b/core/src/main/java/info/nightscout/androidaps/plugins/general/maintenance/formats/ClassicPrefsFormat.kt index e4229966d6..83d699015d 100644 --- a/core/src/main/java/info/nightscout/androidaps/plugins/general/maintenance/formats/ClassicPrefsFormat.kt +++ b/core/src/main/java/info/nightscout/androidaps/plugins/general/maintenance/formats/ClassicPrefsFormat.kt @@ -3,11 +3,7 @@ package info.nightscout.androidaps.plugins.general.maintenance.formats import info.nightscout.androidaps.Constants import info.nightscout.androidaps.core.R import info.nightscout.androidaps.database.entities.UserEntry -import info.nightscout.androidaps.database.entities.UserEntry.* -import info.nightscout.androidaps.interfaces.ProfileFunction -import info.nightscout.androidaps.utils.DateUtil -import info.nightscout.androidaps.utils.DecimalFormatter -import info.nightscout.androidaps.utils.Translator +import info.nightscout.androidaps.utils.userEntry.UserEntryPresentationHelper import info.nightscout.androidaps.utils.resources.ResourceHelper import info.nightscout.androidaps.utils.storage.Storage import java.io.File @@ -19,9 +15,7 @@ import javax.inject.Singleton @Singleton class ClassicPrefsFormat @Inject constructor( private var resourceHelper: ResourceHelper, - private var dateUtil: DateUtil, - private var translator: Translator, - private var profileFunction: ProfileFunction, + private var userEntryPresentationHelper: UserEntryPresentationHelper, private var storage: Storage ) : PrefsFormat { @@ -78,7 +72,7 @@ class ClassicPrefsFormat @Inject constructor( fun saveCsv(file: File, userEntries: List) { try { - val contents = UserEntriesToCsv(userEntries) + val contents = userEntryPresentationHelper.userEntriesToCsv(userEntries) storage.putFileContents(file, contents) } catch (e: FileNotFoundException) { throw PrefFileNotFoundError(file.absolutePath) @@ -86,47 +80,4 @@ class ClassicPrefsFormat @Inject constructor( throw PrefIOError(file.absolutePath) } } - - fun UserEntriesToCsv(userEntries: List): String { - val userEntryHeader = resourceHelper.gs(R.string.ue_csv_header) + "\n" - return userEntryHeader + userEntries.joinToString("\n") { entry -> - if (entry.values.size > 0) { - entry.values.joinToString("\n") { value -> - entry.timestamp.toString() + ";" + - dateUtil.dateAndTimeAndSecondsString(entry.timestamp) + ";" + - dateUtil.timeString(entry.utcOffset) + ";" + - csvString(entry.action) + ";" + - csvString(entry.s) + ";" + - valueWithUnitToCsv(value) - } - } else { - entry.timestamp.toString() + ";" + - dateUtil.dateAndTimeAndSecondsString(entry.timestamp) + ";" + - dateUtil.timeString(entry.utcOffset) + ";" + - csvString(entry.action) + ";" + - csvString(entry.s) + ";;" - } - } - } - - fun valueWithUnitToCsv(v: ValueWithUnit): String { - return when (v.unit) { - Units.Timestamp -> dateUtil.dateAndTimeAndSecondsString(v.lValue) + ";" + csvString(R.string.date) - Units.TherapyEvent -> csvString(translator.translate(v.sValue)) + ";" - Units.R_String -> if (v.lValue.toInt() == 0) csvString(v.iValue) + ";" else ";" //If lValue > 0 it's a formated string, so hidden for - Units.Mg_Dl -> if (profileFunction.getUnits()==Constants.MGDL) DecimalFormatter.to0Decimal(v.dValue) + ";" + csvString(Units.Mg_Dl) else DecimalFormatter.to1Decimal(v.dValue/Constants.MMOLL_TO_MGDL) + ";" + csvString(Units.Mmol_L) - Units.Mmol_L -> if (profileFunction.getUnits()==Constants.MGDL) DecimalFormatter.to0Decimal(v.dValue*Constants.MMOLL_TO_MGDL) + ";" + csvString(Units.Mg_Dl) else DecimalFormatter.to1Decimal(v.dValue) + ";" + csvString(Units.Mmol_L) - Units.U_H, Units.U -> DecimalFormatter.to2Decimal(v.dValue) + ";" + csvString(v.unit) - Units.G, Units.M, Units.H, Units.Percent - -> v.iValue.toString() + ";" + csvString(v.unit) - else -> if (v.sValue != "") { csvString(v.sValue) + ";" + csvString(v.unit)} - else if (v.iValue != 0) { v.iValue.toString() + ";" + csvString(v.unit)} - else ";" - } - } - - private fun csvString(action: Action): String = "\"" + translator.translate(action.name).replace("\"", "\"\"") + "\"" - private fun csvString(unit: Units): String = "\"" + translator.translate(unit.name).replace("\"", "\"\"") + "\"" - private fun csvString(id: Int): String = if (id != 0) "\"" + resourceHelper.gs(id).replace("\"", "\"\"") + "\"" else "" - private fun csvString(s: String): String = if (s != "") "\"" + s.replace("\"", "\"\"") + "\"" else "" } \ No newline at end of file diff --git a/core/src/main/java/info/nightscout/androidaps/plugins/general/maintenance/formats/EncryptedPrefsFormat.kt b/core/src/main/java/info/nightscout/androidaps/plugins/general/maintenance/formats/EncryptedPrefsFormat.kt index 2cc83d410c..532b4eab00 100644 --- a/core/src/main/java/info/nightscout/androidaps/plugins/general/maintenance/formats/EncryptedPrefsFormat.kt +++ b/core/src/main/java/info/nightscout/androidaps/plugins/general/maintenance/formats/EncryptedPrefsFormat.kt @@ -2,8 +2,8 @@ package info.nightscout.androidaps.plugins.general.maintenance.formats import info.nightscout.androidaps.core.R import info.nightscout.androidaps.utils.CryptoUtil -import info.nightscout.androidaps.utils.extensions.hexStringToByteArray -import info.nightscout.androidaps.utils.extensions.toHex +import info.nightscout.androidaps.extensions.hexStringToByteArray +import info.nightscout.androidaps.extensions.toHex import info.nightscout.androidaps.utils.resources.ResourceHelper import info.nightscout.androidaps.utils.storage.Storage import org.json.JSONException 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 78887a73b9..85a2ef044b 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,46 +1,18 @@ package info.nightscout.androidaps.plugins.general.nsclient; -import android.os.Build; - -import androidx.annotation.Nullable; - -import org.apache.commons.lang3.StringUtils; import org.json.JSONException; import org.json.JSONObject; -import java.util.Date; - import javax.inject.Inject; import javax.inject.Singleton; -import info.nightscout.androidaps.Constants; 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.GlucoseValue; -import info.nightscout.androidaps.database.entities.TemporaryTarget; 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.IobCobCalculatorInterface; -import info.nightscout.androidaps.interfaces.LoopInterface; -import info.nightscout.androidaps.interfaces.ProfileFunction; -import info.nightscout.androidaps.interfaces.ProfileStore; -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.JsonHelper; -import info.nightscout.androidaps.utils.T; -import info.nightscout.androidaps.utils.resources.ResourceHelper; import info.nightscout.androidaps.utils.sharedPreferences.SP; /** @@ -50,281 +22,34 @@ import info.nightscout.androidaps.utils.sharedPreferences.SP; public class NSUpload { private final AAPSLogger aapsLogger; - private final ResourceHelper resourceHelper; private final SP sp; private final UploadQueueInterface uploadQueue; - private final RunningConfiguration runningConfiguration; - private final ProfileFunction profileFunction; - - public static String ISVALID = "isValid"; @Inject public NSUpload( AAPSLogger aapsLogger, - ResourceHelper resourceHelper, SP sp, - UploadQueueInterface uploadQueue, - RunningConfiguration runningConfiguration, - ProfileFunction profileFunction + UploadQueueInterface uploadQueue ) { this.aapsLogger = aapsLogger; - this.resourceHelper = resourceHelper; this.sp = sp; this.uploadQueue = uploadQueue; - this.runningConfiguration = runningConfiguration; - this.profileFunction = profileFunction; } - public void uploadTempBasalStartAbsolute(TemporaryBasal temporaryBasal, Double originalExtendedAmount) { + public void uploadProfileSwitch(ProfileSwitch profileSwitch, long nsClientId, DateUtil dateUtil) { try { - JSONObject data = new JSONObject(); - data.put("eventType", TherapyEvent.Type.TEMPORARY_BASAL.getText()); - data.put("duration", temporaryBasal.durationInMinutes); - data.put("absolute", temporaryBasal.absoluteRate); - data.put("rate", temporaryBasal.absoluteRate); - if (temporaryBasal.pumpId != 0) - data.put("pumpId", temporaryBasal.pumpId); - data.put("created_at", DateUtil.toISOString(temporaryBasal.date)); - data.put("enteredBy", "openaps://" + "AndroidAPS"); - if (originalExtendedAmount != null) - data.put("originalExtendedAmount", originalExtendedAmount); // for back synchronization - uploadQueue.add(new DbRequest("dbAdd", "treatments", data, temporaryBasal.date)); + JSONObject data = getJson(profileSwitch, dateUtil); + DbRequest dbr = new DbRequest("dbAdd", "treatments", data, nsClientId); + aapsLogger.debug("Prepared: " + dbr.log()); + uploadQueue.add(dbr); } catch (JSONException e) { aapsLogger.error("Unhandled exception", e); } } - public void uploadTempBasalStartPercent(TemporaryBasal temporaryBasal, Profile profile) { + public void updateProfileSwitch(ProfileSwitch profileSwitch, DateUtil dateUtil) { try { - boolean useAbsolute = sp.getBoolean(R.string.key_ns_sync_use_absolute, false); - double absoluteRate = 0; - if (profile != null) { - absoluteRate = profile.getBasal(temporaryBasal.date) * temporaryBasal.percentRate / 100d; - } - if (useAbsolute) { - TemporaryBasal t = temporaryBasal.clone(); - t.isAbsolute = true; - if (profile != null) { - t.absoluteRate = absoluteRate; - uploadTempBasalStartAbsolute(t, null); - } - } else { - JSONObject data = new JSONObject(); - data.put("eventType", TherapyEvent.Type.TEMPORARY_BASAL.getText()); - data.put("duration", temporaryBasal.durationInMinutes); - data.put("percent", temporaryBasal.percentRate - 100); - if (profile != null) - data.put("rate", absoluteRate); - if (temporaryBasal.pumpId != 0) - data.put("pumpId", temporaryBasal.pumpId); - data.put("created_at", DateUtil.toISOString(temporaryBasal.date)); - data.put("enteredBy", "openaps://" + "AndroidAPS"); - uploadQueue.add(new DbRequest("dbAdd", "treatments", data, temporaryBasal.date)); - } - } catch (JSONException e) { - aapsLogger.error("Unhandled exception", e); - } - } - - public void uploadTempBasalEnd(long time, boolean isFakedTempBasal, long pumpId) { - try { - JSONObject data = new JSONObject(); - data.put("eventType", TherapyEvent.Type.TEMPORARY_BASAL.getText()); - data.put("created_at", DateUtil.toISOString(time)); - data.put("enteredBy", "openaps://" + "AndroidAPS"); - if (isFakedTempBasal) - data.put("isFakedTempBasal", isFakedTempBasal); - if (pumpId != 0) - data.put("pumpId", pumpId); - uploadQueue.add(new DbRequest("dbAdd", "treatments", data, time)); - } catch (JSONException e) { - aapsLogger.error("Unhandled exception", e); - } - } - - public void uploadExtendedBolus(ExtendedBolus extendedBolus) { - try { - JSONObject data = new JSONObject(); - data.put("eventType", TherapyEvent.Type.COMBO_BOLUS.getText()); - data.put("duration", extendedBolus.durationInMinutes); - data.put("splitNow", 0); - data.put("splitExt", 100); - data.put("enteredinsulin", extendedBolus.insulin); - data.put("relative", extendedBolus.insulin / extendedBolus.durationInMinutes * 60); // U/h - if (extendedBolus.pumpId != 0) - data.put("pumpId", extendedBolus.pumpId); - data.put("created_at", DateUtil.toISOString(extendedBolus.date)); - data.put("enteredBy", "openaps://" + "AndroidAPS"); - uploadQueue.add(new DbRequest("dbAdd", "treatments", data, extendedBolus.date)); - } catch (JSONException e) { - aapsLogger.error("Unhandled exception", e); - } - } - - public void uploadExtendedBolusEnd(long time, long pumpId) { - try { - JSONObject data = new JSONObject(); - data.put("eventType", TherapyEvent.Type.COMBO_BOLUS.getText()); - data.put("duration", 0); - data.put("splitNow", 0); - data.put("splitExt", 100); - data.put("enteredinsulin", 0); - data.put("relative", 0); - data.put("created_at", DateUtil.toISOString(time)); - data.put("enteredBy", "openaps://" + "AndroidAPS"); - if (pumpId != 0) - data.put("pumpId", pumpId); - uploadQueue.add(new DbRequest("dbAdd", "treatments", data, time)); - } catch (JSONException e) { - aapsLogger.error("Unhandled exception", e); - } - } - - public void uploadDeviceStatus(LoopInterface loopPlugin, IobCobCalculatorInterface 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) { - JSONObject data = new JSONObject(); - try { - data.put("eventType", detailedBolusInfo.eventType); - if (detailedBolusInfo.insulin != 0d) data.put("insulin", detailedBolusInfo.insulin); - if (detailedBolusInfo.carbs != 0d) data.put("carbs", (int) detailedBolusInfo.carbs); - data.put("created_at", DateUtil.toISOString(detailedBolusInfo.date)); - data.put("date", detailedBolusInfo.date); - data.put("isSMB", detailedBolusInfo.isSMB); - if (detailedBolusInfo.pumpId != 0) - data.put("pumpId", detailedBolusInfo.pumpId); - if (detailedBolusInfo.glucose != 0d) - data.put("glucose", detailedBolusInfo.glucose); - if (!detailedBolusInfo.glucoseType.equals("")) - data.put("glucoseType", detailedBolusInfo.glucoseType); - if (detailedBolusInfo.boluscalc != null) - data.put("boluscalc", detailedBolusInfo.boluscalc); - if (detailedBolusInfo.carbTime != 0) - data.put("preBolus", detailedBolusInfo.carbTime); - if (!StringUtils.isEmpty(detailedBolusInfo.notes)) { - data.put("notes", detailedBolusInfo.notes); - } - } catch (JSONException e) { - aapsLogger.error("Unhandled exception", e); - } - uploadCareportalEntryToNS(data, detailedBolusInfo.date); - } - - public void uploadProfileSwitch(ProfileSwitch profileSwitch, long nsClientId) { - try { - JSONObject data = getJson(profileSwitch); - uploadCareportalEntryToNS(data, nsClientId); - } catch (JSONException e) { - aapsLogger.error("Unhandled exception", e); - } - } - - public void uploadTempTarget(TemporaryTarget tempTarget) { - try { - JSONObject data = new JSONObject(); - data.put("eventType", TherapyEvent.Type.TEMPORARY_TARGET.getText()); - data.put("duration", T.msecs(tempTarget.getDuration()).mins()); - data.put(ISVALID, tempTarget.isValid()); - if (tempTarget.getLowTarget() > 0) { - data.put("reason", tempTarget.getReason().getText()); - data.put("targetBottom", Profile.fromMgdlToUnits(tempTarget.getLowTarget(), profileFunction.getUnits())); - data.put("targetTop", Profile.fromMgdlToUnits(tempTarget.getHighTarget(), profileFunction.getUnits())); - data.put("units", profileFunction.getUnits()); - } - data.put("created_at", DateUtil.toISOString(tempTarget.getTimestamp())); - data.put("enteredBy", "AndroidAPS"); - uploadCareportalEntryToNS(data, tempTarget.getTimestamp()); - } catch (JSONException e) { - aapsLogger.error("Unhandled exception", e); - } - } - - public void updateTempTarget(TemporaryTarget tempTarget) { - try { - JSONObject data = new JSONObject(); - data.put("eventType", TherapyEvent.Type.TEMPORARY_TARGET.getText()); - data.put("duration", T.msecs(tempTarget.getDuration()).mins()); - data.put(ISVALID, tempTarget.isValid()); - if (tempTarget.getLowTarget() > 0) { - data.put("reason", tempTarget.getReason().getText()); - data.put("targetBottom", Profile.fromMgdlToUnits(tempTarget.getLowTarget(), profileFunction.getUnits())); - data.put("targetTop", Profile.fromMgdlToUnits(tempTarget.getHighTarget(), profileFunction.getUnits())); - data.put("units", profileFunction.getUnits()); - } - data.put("created_at", DateUtil.toISOString(tempTarget.getTimestamp())); - data.put("enteredBy", "AndroidAPS"); - uploadQueue.add(new DbRequest("dbUpdate", "treatments", tempTarget.getInterfaceIDs().getNightscoutId(), data, tempTarget.getTimestamp())); - } catch (JSONException e) { - aapsLogger.error("Unhandled exception", e); - } - } - - public void updateProfileSwitch(ProfileSwitch profileSwitch) { - try { - JSONObject data = getJson(profileSwitch); + JSONObject data = getJson(profileSwitch, dateUtil); if (profileSwitch._id != null) { uploadQueue.add(new DbRequest("dbUpdate", "treatments", profileSwitch._id, data, profileSwitch.date)); } @@ -333,7 +58,7 @@ public class NSUpload { } } - private static JSONObject getJson(ProfileSwitch profileSwitch) throws JSONException { + private static JSONObject getJson(ProfileSwitch profileSwitch, DateUtil dateUtil) throws JSONException { JSONObject data = new JSONObject(); data.put("eventType", TherapyEvent.Type.PROFILE_SWITCH.getText()); data.put("duration", profileSwitch.durationInMinutes); @@ -345,171 +70,23 @@ public class NSUpload { data.put("timeshift", profileSwitch.timeshift); data.put("percentage", profileSwitch.percentage); } - data.put("created_at", DateUtil.toISOString(profileSwitch.date)); + data.put("created_at", dateUtil.toISOString(profileSwitch.date)); data.put("enteredBy", "AndroidAPS"); return data; } - public void uploadCareportalEntryToNS(JSONObject data, long nsClientId) { - try { - if (data.has("preBolus") && data.has("carbs")) { - JSONObject prebolus = new JSONObject(); - prebolus.put("carbs", data.get("carbs")); - data.remove("carbs"); - prebolus.put("eventType", data.get("eventType")); - if (data.has("enteredBy")) prebolus.put("enteredBy", data.get("enteredBy")); - if (data.has("notes")) prebolus.put("notes", data.get("notes")); - long mills = DateUtil.fromISODateString(data.getString("created_at")).getTime(); - Date preBolusDate = new Date(mills + data.getInt("preBolus") * 60000L + 1000L); - prebolus.put("created_at", DateUtil.toISOString(preBolusDate)); - uploadCareportalEntryToNS(prebolus, preBolusDate.getTime()); - } - DbRequest dbr = new DbRequest("dbAdd", "treatments", data, nsClientId); - aapsLogger.debug("Prepared: " + dbr.log()); - uploadQueue.add(dbr); - } catch (Exception e) { - aapsLogger.error("Unhandled exception", e); - } - - } - - // TODO replace with seting isValid = false + // TODO replace with setting isValid = false public void removeCareportalEntryFromNS(String _id) { uploadQueue.add(new DbRequest("dbRemove", "treatments", _id, System.currentTimeMillis())); } - public void uploadError(String error) { - uploadError(error, new Date()); - } - - public void uploadError(String error, Date date) { - JSONObject data = new JSONObject(); - try { - data.put("eventType", "Announcement"); - data.put("created_at", DateUtil.toISOString(date)); - data.put("enteredBy", sp.getString("careportal_enteredby", "AndroidAPS")); - data.put("notes", error); - data.put("isAnnouncement", true); - } catch (JSONException e) { - aapsLogger.error("Unhandled exception", e); - } - uploadQueue.add(new DbRequest("dbAdd", "treatments", data, date.getTime())); - } - - public void uploadBg(GlucoseValue reading, String source) { - JSONObject data = new JSONObject(); - try { - data.put("device", source); - data.put("date", reading.getTimestamp()); - data.put("dateString", DateUtil.toISOString(reading.getTimestamp())); - data.put("sgv", reading.getValue()); - data.put("direction", reading.getTrendArrow().getText()); - data.put("type", "sgv"); - } catch (JSONException e) { - aapsLogger.error("Unhandled exception", e); - } - uploadQueue.add(new DbRequest("dbAdd", "entries", data, reading.getTimestamp())); - } - - public void updateBg(GlucoseValue reading, String source) { - JSONObject data = new JSONObject(); - try { - data.put("device", source); - data.put("date", reading.getTimestamp()); - data.put("dateString", DateUtil.toISOString(reading.getTimestamp())); - data.put("sgv", reading.getValue()); - data.put("direction", reading.getTrendArrow().getText()); - data.put("type", "sgv"); - if (reading.getInterfaceIDs().getNightscoutId() != null) { - uploadQueue.add(new DbRequest("dbUpdate", "entries", reading.getInterfaceIDs().getNightscoutId(), data, System.currentTimeMillis())); - } - } catch (JSONException e) { - aapsLogger.error("Unhandled exception", e); - } - } - - public void uploadAppStart() { - if (sp.getBoolean(R.string.key_ns_logappstartedevent, true)) { - JSONObject data = new JSONObject(); - try { - data.put("eventType", "Note"); - data.put("created_at", DateUtil.toISOString(new Date())); - data.put("notes", resourceHelper.gs(R.string.androidaps_start) + " - " + Build.MANUFACTURER + " " + Build.MODEL); - } catch (JSONException e) { - aapsLogger.error("Unhandled exception", e); - } - uploadQueue.add(new DbRequest("dbAdd", "treatments", data, System.currentTimeMillis())); - } - } - public void uploadProfileStore(JSONObject profileStore) { if (sp.getBoolean(R.string.key_ns_uploadlocalprofile, false)) { uploadQueue.add(new DbRequest("dbAdd", "profile", profileStore, System.currentTimeMillis())); } } - public void uploadEvent(String careportalEvent, long time, @Nullable String notes) { - JSONObject data = new JSONObject(); - try { - data.put("eventType", careportalEvent); - data.put("created_at", DateUtil.toISOString(time)); - data.put("enteredBy", sp.getString("careportal_enteredby", "AndroidAPS")); - data.put("units", profileFunction.getUnits()); - if (notes != null) { - data.put("notes", notes); - } - } catch (JSONException e) { - aapsLogger.error("Unhandled exception", e); - } - uploadQueue.add(new DbRequest("dbAdd", "treatments", data, time)); - } - - public void uploadEvent(TherapyEvent event) { - JSONObject data = new JSONObject(); - try { - data.put("eventType", event.getType().getText()); - data.put("created_at", event.getTimestamp()); - data.put("enteredBy", event.getEnteredBy()); - if (event.getGlucoseUnit() == TherapyEvent.GlucoseUnit.MGDL) - data.put("units", Constants.MGDL); - else data.put("units", Constants.MMOL); - if (event.getDuration() != 0) data.put("duration", T.msecs(event.getDuration()).mins()); - if (event.getNote() != null) data.put("notes", event.getNote()); - if (event.getGlucose() != null) data.put("glucose", event.getGlucose()); - if (event.getGlucoseType() != null) - data.put("glucoseType", event.getGlucoseType().getText()); - } catch (JSONException e) { - aapsLogger.error("Unhandled exception", e); - } - uploadQueue.add(new DbRequest("dbAdd", "treatments", data, event.getTimestamp())); - } - - public void removeFoodFromNS(String _id) { - try { - uploadQueue.add(new DbRequest("dbRemove", "food", _id, System.currentTimeMillis())); - } catch (Exception e) { - aapsLogger.error("Unhandled exception", e); - } - - } - - public void createNSTreatment(JSONObject data, ProfileStore profileStore, ProfileFunction profileFunction, long eventTime) { - if (JsonHelper.safeGetString(data, "eventType", "").equals(TherapyEvent.Type.PROFILE_SWITCH.getText())) { - ProfileSwitch profileSwitch = profileFunction.prepareProfileSwitch( - profileStore, - JsonHelper.safeGetString(data, "profile"), - JsonHelper.safeGetInt(data, "duration"), - JsonHelper.safeGetInt(data, "percentage"), - JsonHelper.safeGetInt(data, "timeshift"), - eventTime - ); - uploadProfileSwitch(profileSwitch, eventTime); - } else { - uploadCareportalEntryToNS(data, eventTime); - } - } - public static boolean isIdValid(String _id) { if (_id == null) return false; diff --git a/core/src/main/java/info/nightscout/androidaps/plugins/general/overview/events/EventOverviewBolusProgress.kt b/core/src/main/java/info/nightscout/androidaps/plugins/general/overview/events/EventOverviewBolusProgress.kt index fe43913333..5230bc979c 100644 --- a/core/src/main/java/info/nightscout/androidaps/plugins/general/overview/events/EventOverviewBolusProgress.kt +++ b/core/src/main/java/info/nightscout/androidaps/plugins/general/overview/events/EventOverviewBolusProgress.kt @@ -1,9 +1,11 @@ package info.nightscout.androidaps.plugins.general.overview.events -import info.nightscout.androidaps.db.Treatment import info.nightscout.androidaps.events.Event object EventOverviewBolusProgress : Event() { + + data class Treatment constructor(@JvmField var insulin: Double = 0.0, @JvmField var carbs: Int = 0, @JvmField var isSMB: Boolean) + var status = "" var t: Treatment? = null var percent = 0 diff --git a/core/src/main/java/info/nightscout/androidaps/plugins/general/overview/graphExtensions/PointsWithLabelGraphSeries.java b/core/src/main/java/info/nightscout/androidaps/plugins/general/overview/graphExtensions/PointsWithLabelGraphSeries.java index db18fc2a5f..8c950b774a 100644 --- a/core/src/main/java/info/nightscout/androidaps/plugins/general/overview/graphExtensions/PointsWithLabelGraphSeries.java +++ b/core/src/main/java/info/nightscout/androidaps/plugins/general/overview/graphExtensions/PointsWithLabelGraphSeries.java @@ -18,15 +18,12 @@ package info.nightscout.androidaps.plugins.general.overview.graphExtensions; * You should have received a copy of the GNU General Public License * with the "Linking Exception" along with this program; if not, * write to the author Jonas Gehring . - *

+ */ + +/* * Added by mike */ -/** - * Added by mike - */ - -import android.content.Context; import android.graphics.Canvas; import android.graphics.Paint; import android.graphics.Path; @@ -61,6 +58,7 @@ public class PointsWithLabelGraphSeries e TRIANGLE, RECTANGLE, BOLUS, + CARBS, SMB, EXTENDEDBOLUS, PROFILE, @@ -72,7 +70,8 @@ public class PointsWithLabelGraphSeries e GENERAL, GENERALWITHDURATION, COBFAILOVER, - IOBPREDICTION + IOBPREDICTION, + BUCKETED_BG } /** @@ -202,7 +201,7 @@ public class PointsWithLabelGraphSeries e mPaint.setStyle(Paint.Style.FILL); mPaint.setStrokeWidth(0); canvas.drawCircle(endX, endY, value.getSize() * scaledPxSize, mPaint); - } else if (value.getShape() == Shape.BG || value.getShape() == Shape.IOBPREDICTION) { + } else if (value.getShape() == Shape.BG || value.getShape() == Shape.IOBPREDICTION || value.getShape() == Shape.BUCKETED_BG) { mPaint.setColor(value.getColor()); mPaint.setStyle(Paint.Style.FILL); mPaint.setStrokeWidth(0); @@ -233,7 +232,18 @@ public class PointsWithLabelGraphSeries e mPaint.setStyle(Paint.Style.FILL_AND_STROKE); drawArrows(points, canvas, mPaint); if (value.getLabel() != null) { - drawLabel45(endX, endY, value, canvas, scaledPxSize, scaledTextSize); + drawLabel45Right(endX, endY, value, canvas, scaledPxSize, scaledTextSize); + } + } else if (value.getShape() == Shape.CARBS) { + mPaint.setStrokeWidth(0); + Point[] points = new Point[3]; + points[0] = new Point((int) endX, (int) (endY - scaledPxSize)); + points[1] = new Point((int) (endX + scaledPxSize), (int) (endY + scaledPxSize * 0.67)); + points[2] = new Point((int) (endX - scaledPxSize), (int) (endY + scaledPxSize * 0.67)); + mPaint.setStyle(Paint.Style.FILL_AND_STROKE); + drawArrows(points, canvas, mPaint); + if (value.getLabel() != null) { + drawLabel45Left(endX, endY, value, canvas, scaledPxSize, scaledTextSize); } } else if (value.getShape() == Shape.SMB) { mPaint.setStrokeWidth(2); @@ -282,21 +292,21 @@ public class PointsWithLabelGraphSeries e mPaint.setStrokeWidth(0); canvas.drawCircle(endX, endY, scaledPxSize, mPaint); if (value.getLabel() != null) { - drawLabel45(endX, endY, value, canvas, scaledPxSize, scaledTextSize); + drawLabel45Right(endX, endY, value, canvas, scaledPxSize, scaledTextSize); } } else if (value.getShape() == Shape.ANNOUNCEMENT) { mPaint.setStyle(Paint.Style.FILL_AND_STROKE); mPaint.setStrokeWidth(0); canvas.drawCircle(endX, endY, scaledPxSize, mPaint); if (value.getLabel() != null) { - drawLabel45(endX, endY, value, canvas, scaledPxSize, scaledTextSize); + drawLabel45Right(endX, endY, value, canvas, scaledPxSize, scaledTextSize); } } else if (value.getShape() == Shape.GENERAL) { mPaint.setStyle(Paint.Style.FILL_AND_STROKE); mPaint.setStrokeWidth(0); canvas.drawCircle(endX, endY, scaledPxSize, mPaint); if (value.getLabel() != null) { - drawLabel45(endX, endY, value, canvas, scaledPxSize, scaledTextSize); + drawLabel45Right(endX, endY, value, canvas, scaledPxSize, scaledTextSize); } } else if (value.getShape() == Shape.EXERCISE) { mPaint.setStrokeWidth(0); @@ -380,29 +390,29 @@ public class PointsWithLabelGraphSeries e canvas.restore(); } - void drawLabel45(float endX, float endY, E value, Canvas canvas, Float scaledPxSize, Float scaledTextSize) { - if (value.getLabel().startsWith("~")) { - float px = endX; - float py = endY + scaledPxSize; - canvas.save(); - canvas.rotate(-45, px, py); - mPaint.setTextSize((float) (scaledTextSize * 0.8)); - mPaint.setTypeface(Typeface.create(Typeface.DEFAULT, Typeface.NORMAL)); - mPaint.setFakeBoldText(true); - mPaint.setTextAlign(Paint.Align.RIGHT); - canvas.drawText(value.getLabel().substring(1), px - scaledPxSize, py, mPaint); - mPaint.setTextAlign(Paint.Align.LEFT); - canvas.restore(); - } else { - float px = endX; - float py = endY - scaledPxSize; - canvas.save(); - canvas.rotate(-45, px, py); - mPaint.setTextSize((float) (scaledTextSize * 0.8)); - mPaint.setTypeface(Typeface.create(Typeface.DEFAULT, Typeface.NORMAL)); - mPaint.setFakeBoldText(true); - canvas.drawText(value.getLabel(), px + scaledPxSize, py, mPaint); - canvas.restore(); - } + void drawLabel45Right(float endX, float endY, E value, Canvas canvas, Float scaledPxSize, Float scaledTextSize) { + float px = endX; + float py = endY - scaledPxSize; + canvas.save(); + canvas.rotate(-45, px, py); + mPaint.setTextSize((float) (scaledTextSize * 0.8)); + mPaint.setTypeface(Typeface.create(Typeface.DEFAULT, Typeface.NORMAL)); + mPaint.setFakeBoldText(true); + canvas.drawText(value.getLabel(), px + scaledPxSize, py, mPaint); + canvas.restore(); } -} + + void drawLabel45Left(float endX, float endY, E value, Canvas canvas, Float scaledPxSize, Float scaledTextSize) { + float px = endX; + float py = endY + scaledPxSize; + canvas.save(); + canvas.rotate(-45, px, py); + mPaint.setTextSize((float) (scaledTextSize * 0.8)); + mPaint.setTypeface(Typeface.create(Typeface.DEFAULT, Typeface.NORMAL)); + mPaint.setFakeBoldText(true); + mPaint.setTextAlign(Paint.Align.RIGHT); + canvas.drawText(value.getLabel(), px - scaledPxSize, py, mPaint); + mPaint.setTextAlign(Paint.Align.LEFT); + canvas.restore(); + } +} diff --git a/core/src/main/java/info/nightscout/androidaps/plugins/general/overview/notifications/Notification.kt b/core/src/main/java/info/nightscout/androidaps/plugins/general/overview/notifications/Notification.kt index 7858abeffe..ea2e753fb5 100644 --- a/core/src/main/java/info/nightscout/androidaps/plugins/general/overview/notifications/Notification.kt +++ b/core/src/main/java/info/nightscout/androidaps/plugins/general/overview/notifications/Notification.kt @@ -121,6 +121,8 @@ open class Notification { const val OMNIPOD_UNKNOWN_TBR = 68 const val OMNIPOD_STARTUP_STATUS_REFRESH_FAILED = 69 const val OMNIPOD_TIME_OUT_OF_SYNC = 70 + const val UNSUPPORTED_ACTION_IN_PUMP = 71 + const val WRONG_PUMP_DATA = 71 const val USER_MESSAGE = 1000 diff --git a/core/src/main/java/info/nightscout/androidaps/plugins/iob/iobCobCalculator/AutosensDataStore.kt b/core/src/main/java/info/nightscout/androidaps/plugins/iob/iobCobCalculator/AutosensDataStore.kt new file mode 100644 index 0000000000..ee892ac0ed --- /dev/null +++ b/core/src/main/java/info/nightscout/androidaps/plugins/iob/iobCobCalculator/AutosensDataStore.kt @@ -0,0 +1,350 @@ +package info.nightscout.androidaps.plugins.iob.iobCobCalculator + +import androidx.collection.LongSparseArray +import info.nightscout.androidaps.data.InMemoryGlucoseValue +import info.nightscout.androidaps.database.AppRepository +import info.nightscout.androidaps.database.entities.GlucoseValue +import info.nightscout.androidaps.logging.AAPSLogger +import info.nightscout.androidaps.logging.LTag +import info.nightscout.androidaps.plugins.iob.iobCobCalculator.data.AutosensData +import info.nightscout.androidaps.utils.DateUtil +import info.nightscout.androidaps.utils.T +import kotlin.math.abs +import kotlin.math.roundToLong + +class AutosensDataStore { + + private val dataLock = Any() + private var lastUsed5minCalculation: Boolean? = null // true if used 5min bucketed data + + // we need to make sure that bucketed_data will always have the same timestamp for correct use of cached values + // once referenceTime != null all bucketed data should be (x * 5min) from referenceTime + var referenceTime: Long = -1 + + var bgReadings: List = listOf() // newest at index 0 + @Synchronized set + @Synchronized get + + var autosensDataTable = LongSparseArray() // oldest at index 0 + @Synchronized set + @Synchronized get + + var bucketedData: MutableList? = null + @Synchronized set + @Synchronized get + + fun clone(): AutosensDataStore = + AutosensDataStore().also { + synchronized(dataLock) { + it.bgReadings = this.bgReadings.toMutableList() + it.autosensDataTable = this.autosensDataTable.clone() + it.bucketedData = this.bucketedData?.toMutableList() + } + } + + fun getBucketedDataTableCopy(): MutableList? = synchronized(dataLock) { bucketedData?.toMutableList() } + fun getBgReadingsDataTableCopy(): List = synchronized(dataLock) { bgReadings.toMutableList() } + + fun reset() { + synchronized(autosensDataTable) { autosensDataTable = LongSparseArray() } + } + + fun newHistoryData(time: Long, aapsLogger: AAPSLogger, dateUtil: DateUtil) { + synchronized(autosensDataTable) { + for (index in autosensDataTable.size() - 1 downTo 0) { + if (autosensDataTable.keyAt(index) > time) { + aapsLogger.debug(LTag.AUTOSENS, "Removing from autosensDataTable: " + dateUtil.dateAndTimeAndSecondsString(autosensDataTable.keyAt(index))) + autosensDataTable.removeAt(index) + } else { + break + } + } + } + } + + // roundup to whole minute + fun roundUpTime(time: Long): Long { + return if (time % 60000 == 0L) time else (time / 60000 + 1) * 60000 + } + + /** + * Return last valid (>39) GlucoseValue from database or null if db is empty + * + * @return GlucoseValue or null + */ + fun lastBg(): GlucoseValue? = + synchronized(dataLock) { + if (bgReadings.isNotEmpty()) bgReadings[0] + else null + } + + /** + * Provide last GlucoseValue or null if none exists withing last 9 minutes + * + * @return GlucoseValue or null + */ + fun actualBg(): GlucoseValue? { + val lastBg = lastBg() ?: return null + return if (lastBg.timestamp > System.currentTimeMillis() - T.mins(9).msecs()) lastBg else null + } + + fun lastDataTime(dateUtil: DateUtil): String = + synchronized(dataLock) { + if (autosensDataTable.size() > 0) dateUtil.dateAndTimeAndSecondsString(autosensDataTable.valueAt(autosensDataTable.size() - 1).time) + else "autosensDataTable empty" + } + + fun findPreviousTimeFromBucketedData(time: Long): Long? { + val bData = bucketedData ?: return null + for (index in bData.indices) { + if (bData[index].timestamp <= time) return bData[index].timestamp + } + return null + } + + fun getAutosensDataAtTime(fromTime: Long): AutosensData? { + synchronized(dataLock) { + val now = System.currentTimeMillis() + if (fromTime > now) return null + val previous = findPreviousTimeFromBucketedData(fromTime) ?: return null + return autosensDataTable[roundUpTime(previous)] + } + } + + fun getLastAutosensData(reason: String, aapsLogger: AAPSLogger, dateUtil: DateUtil): AutosensData? { + synchronized(dataLock) { + if (autosensDataTable.size() < 1) { + aapsLogger.debug(LTag.AUTOSENS, "AUTOSENSDATA null: autosensDataTable empty ($reason)") + return null + } + val data: AutosensData? = try { + autosensDataTable.valueAt(autosensDataTable.size() - 1) + } catch (e: Exception) { + // data can be processed on the background + // in this rare case better return null and do not block UI + // APS plugin should use getLastAutosensDataSynchronized where the blocking is not an issue + aapsLogger.error("AUTOSENSDATA null: Exception caught ($reason)") + return null + } + if (data == null) { + aapsLogger.error("AUTOSENSDATA null: data==null") + return null + } + return if (data.time < System.currentTimeMillis() - 11 * 60 * 1000) { + aapsLogger.debug(LTag.AUTOSENS, "AUTOSENSDATA null: data is old (" + reason + ") size()=" + autosensDataTable.size() + " lastData=" + dateUtil.dateAndTimeAndSecondsString(data.time)) + null + } else { + aapsLogger.debug(LTag.AUTOSENS, "AUTOSENSDATA ($reason) $data") + data + } + } + } + + private fun adjustToReferenceTime(someTime: Long): Long { + if (referenceTime == -1L) { + referenceTime = someTime + return someTime + } + var diff = abs(someTime - referenceTime) + diff %= T.mins(5).msecs() + if (diff > T.mins(2).plus(T.secs(30)).msecs()) diff -= T.mins(5).msecs() + return someTime + diff + } + + fun loadBgData(to: Long, repository: AppRepository, aapsLogger: AAPSLogger, dateUtil: DateUtil) { + synchronized(dataLock) { + val start = to - T.hours((24 + 10 /* max dia */).toLong()).msecs() + // there can be some readings with time in close future (caused by wrong time setting on sensor) + // so add 2 minutes + bgReadings = repository + .compatGetBgReadingsDataFromTime(start, to + T.mins(2).msecs(), false) + .blockingGet() + .filter { it.value >= 39 } + aapsLogger.debug(LTag.AUTOSENS, "BG data loaded. Size: " + bgReadings.size + " Start date: " + dateUtil.dateAndTimeString(start) + " End date: " + dateUtil.dateAndTimeString(to)) + createBucketedData(aapsLogger, dateUtil) + } + } + + fun isAbout5minData(aapsLogger: AAPSLogger): Boolean { + synchronized(dataLock) { + if (bgReadings.size < 3) return true + + var totalDiff: Long = 0 + for (i in 1 until bgReadings.size) { + val bgTime = bgReadings[i].timestamp + val lastBgTime = bgReadings[i - 1].timestamp + var diff = lastBgTime - bgTime + diff %= T.mins(5).msecs() + if (diff > T.mins(2).plus(T.secs(30)).msecs()) diff -= T.mins(5).msecs() + totalDiff += diff + diff = abs(diff) + if (diff > T.secs(30).msecs()) { + aapsLogger.debug(LTag.AUTOSENS, "Interval detection: values: " + bgReadings.size + " diff: " + diff / 1000 + "[s] is5minData: " + false) + return false + } + } + val averageDiff = totalDiff / bgReadings.size / 1000 + val is5minData = averageDiff < 1 + aapsLogger.debug(LTag.AUTOSENS, "Interval detection: values: " + bgReadings.size + " averageDiff: " + averageDiff + "[s] is5minData: " + is5minData) + return is5minData + } + } + + fun createBucketedData(aapsLogger: AAPSLogger, dateUtil: DateUtil) { + val fiveMinData = isAbout5minData(aapsLogger) + if (lastUsed5minCalculation != null && lastUsed5minCalculation != fiveMinData) { + // changing mode => clear cache + aapsLogger.debug("Invalidating cached data because of changed mode.") + reset() + } + lastUsed5minCalculation = fiveMinData + if (fiveMinData) createBucketedData5min(aapsLogger, dateUtil) else createBucketedDataRecalculated(aapsLogger, dateUtil) + } + + fun findNewer(time: Long): GlucoseValue? { + var lastFound = bgReadings[0] + if (lastFound.timestamp < time) return null + for (i in 1 until bgReadings.size) { + if (bgReadings[i].timestamp == time) return bgReadings[i] + if (bgReadings[i].timestamp > time) continue + lastFound = bgReadings[i - 1] + if (bgReadings[i].timestamp < time) break + } + return lastFound + } + + fun findOlder(time: Long): GlucoseValue? { + var lastFound = bgReadings[bgReadings.size - 1] + if (lastFound.timestamp > time) return null + for (i in bgReadings.size - 2 downTo 0) { + if (bgReadings[i].timestamp == time) return bgReadings[i] + if (bgReadings[i].timestamp < time) continue + lastFound = bgReadings[i + 1] + if (bgReadings[i].timestamp > time) break + } + return lastFound + } + + private fun createBucketedDataRecalculated(aapsLogger: AAPSLogger, dateUtil: DateUtil) { + if (bgReadings.size < 3) { + bucketedData = null + return + } + val newBucketedData = ArrayList() + var currentTime = bgReadings[0].timestamp - bgReadings[0].timestamp % T.mins(5).msecs() + currentTime = adjustToReferenceTime(currentTime) + aapsLogger.debug("Adjusted time " + dateUtil.dateAndTimeAndSecondsString(currentTime)) + //log.debug("First reading: " + new Date(currentTime).toLocaleString()); + while (true) { + // test if current value is older than current time + val newer = findNewer(currentTime) + val older = findOlder(currentTime) + if (newer == null || older == null) break + if (older.timestamp == newer.timestamp) { // direct hit + newBucketedData.add(InMemoryGlucoseValue(newer)) + } else { + val bgDelta = newer.value - older.value + val timeDiffToNew = newer.timestamp - currentTime + val currentBg = newer.value - timeDiffToNew.toDouble() / (newer.timestamp - older.timestamp) * bgDelta + val newBgReading = InMemoryGlucoseValue(currentTime, currentBg.roundToLong().toDouble(), true) + newBucketedData.add(newBgReading) + //log.debug("BG: " + newBgReading.value + " (" + new Date(newBgReading.date).toLocaleString() + ") Prev: " + older.value + " (" + new Date(older.date).toLocaleString() + ") Newer: " + newer.value + " (" + new Date(newer.date).toLocaleString() + ")"); + } + currentTime -= T.mins(5).msecs() + } + bucketedData = newBucketedData + } + + private fun createBucketedData5min(aapsLogger: AAPSLogger, dateUtil: DateUtil) { + if (bgReadings.size < 3) { + bucketedData = null + return + } + val bData: MutableList = ArrayList() + bData.add(InMemoryGlucoseValue(bgReadings[0])) + aapsLogger.debug(LTag.AUTOSENS, "Adding. bgTime: " + dateUtil.toISOString(bgReadings[0].timestamp) + " lastBgTime: " + "none-first-value" + " " + bgReadings[0].toString()) + var j = 0 + for (i in 1 until bgReadings.size) { + val bgTime = bgReadings[i].timestamp + var lastBgTime = bgReadings[i - 1].timestamp + //log.error("Processing " + i + ": " + new Date(bgTime).toString() + " " + bgReadings.get(i).value + " Previous: " + new Date(lastBgTime).toString() + " " + bgReadings.get(i - 1).value); + var elapsedMinutes = (bgTime - lastBgTime) / (60 * 1000) + when { + abs(elapsedMinutes) > 8 -> { + // interpolate missing data points + var lastBg = bgReadings[i - 1].value + elapsedMinutes = abs(elapsedMinutes) + //console.error(elapsed_minutes); + var nextBgTime: Long + while (elapsedMinutes > 5) { + nextBgTime = lastBgTime - 5 * 60 * 1000 + j++ + val gapDelta = bgReadings[i].value - lastBg + //console.error(gapDelta, lastBg, elapsed_minutes); + val nextBg = lastBg + 5.0 / elapsedMinutes * gapDelta + val newBgReading = InMemoryGlucoseValue(nextBgTime, nextBg.roundToLong().toDouble(), true) + //console.error("Interpolated", bData[j]); + bData.add(newBgReading) + aapsLogger.debug(LTag.AUTOSENS, "Adding. bgTime: " + dateUtil.toISOString(bgTime) + " lastBgTime: " + dateUtil.toISOString(lastBgTime) + " " + newBgReading.toString()) + elapsedMinutes -= 5 + lastBg = nextBg + lastBgTime = nextBgTime + } + j++ + val newBgReading = InMemoryGlucoseValue(bgTime, bgReadings[i].value) + bData.add(newBgReading) + aapsLogger.debug(LTag.AUTOSENS, "Adding. bgTime: " + dateUtil.toISOString(bgTime) + " lastBgTime: " + dateUtil.toISOString(lastBgTime) + " " + newBgReading.toString()) + } + + abs(elapsedMinutes) > 2 -> { + j++ + val newBgReading = InMemoryGlucoseValue(bgTime, bgReadings[i].value) + bData.add(newBgReading) + aapsLogger.debug(LTag.AUTOSENS, "Adding. bgTime: " + dateUtil.toISOString(bgTime) + " lastBgTime: " + dateUtil.toISOString(lastBgTime) + " " + newBgReading.toString()) + } + + else -> { + bData[j].value = (bData[j].value + bgReadings[i].value) / 2 + //log.error("***** Average"); + } + } + } + + // Normalize bucketed data + val oldest = bData[bData.size - 1] + oldest.timestamp = adjustToReferenceTime(oldest.timestamp) + aapsLogger.debug("Adjusted time " + dateUtil.dateAndTimeAndSecondsString(oldest.timestamp)) + for (i in bData.size - 2 downTo 0) { + val current = bData[i] + val previous = bData[i + 1] + val mSecDiff = current.timestamp - previous.timestamp + val adjusted = (mSecDiff - T.mins(5).msecs()) / 1000 + aapsLogger.debug(LTag.AUTOSENS, "Adjusting bucketed data time. Current: " + dateUtil.dateAndTimeAndSecondsString(current.timestamp) + " to: " + dateUtil.dateAndTimeAndSecondsString(previous.timestamp + T.mins(5).msecs()) + " by " + adjusted + " sec") + if (abs(adjusted) > 90) { + // too big adjustment, fallback to non 5 min data + aapsLogger.debug(LTag.AUTOSENS, "Fallback to non 5 min data") + createBucketedDataRecalculated(aapsLogger, dateUtil) + return + } + current.timestamp = previous.timestamp + T.mins(5).msecs() + } + aapsLogger.debug(LTag.AUTOSENS, "Bucketed data created. Size: " + bData.size) + bucketedData = bData + } + + fun slowAbsorptionPercentage(timeInMinutes: Int): Double { + var sum = 0.0 + var count = 0 + val valuesToProcess = timeInMinutes / 5 + synchronized(dataLock) { + var i = autosensDataTable.size() - 1 + while (i >= 0 && count < valuesToProcess) { + if (autosensDataTable.valueAt(i).failoverToMinAbsorbtionRate) sum++ + count++ + i-- + } + } + return if (count != 0) sum / count else 0.0 + } + +} \ No newline at end of file diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/iob/iobCobCalculator/BasalData.kt b/core/src/main/java/info/nightscout/androidaps/plugins/iob/iobCobCalculator/BasalData.kt similarity index 100% rename from app/src/main/java/info/nightscout/androidaps/plugins/iob/iobCobCalculator/BasalData.kt rename to core/src/main/java/info/nightscout/androidaps/plugins/iob/iobCobCalculator/BasalData.kt diff --git a/core/src/main/java/info/nightscout/androidaps/plugins/iob/iobCobCalculator/GlucoseStatusProvider.kt b/core/src/main/java/info/nightscout/androidaps/plugins/iob/iobCobCalculator/GlucoseStatusProvider.kt index a19eebb28b..1fc6e5f934 100644 --- a/core/src/main/java/info/nightscout/androidaps/plugins/iob/iobCobCalculator/GlucoseStatusProvider.kt +++ b/core/src/main/java/info/nightscout/androidaps/plugins/iob/iobCobCalculator/GlucoseStatusProvider.kt @@ -1,7 +1,7 @@ package info.nightscout.androidaps.plugins.iob.iobCobCalculator import dagger.Reusable -import info.nightscout.androidaps.interfaces.IobCobCalculatorInterface +import info.nightscout.androidaps.interfaces.IobCobCalculator import info.nightscout.androidaps.logging.AAPSLogger import info.nightscout.androidaps.logging.LTag import info.nightscout.androidaps.utils.DateUtil @@ -10,92 +10,94 @@ import javax.inject.Inject import kotlin.math.roundToLong @Reusable -class GlucoseStatusProvider @Inject constructor(private val aapsLogger: AAPSLogger, private val iobCobCalculatorPlugin: IobCobCalculatorInterface) { +class GlucoseStatusProvider @Inject constructor( + private val aapsLogger: AAPSLogger, + private val iobCobCalculator: IobCobCalculator, + private val dateUtil: DateUtil +) { val glucoseStatusData: GlucoseStatus? get() = getGlucoseStatusData() fun getGlucoseStatusData(allowOldData: Boolean = false): GlucoseStatus? { - synchronized(iobCobCalculatorPlugin.dataLock) { - val data = iobCobCalculatorPlugin.bgReadings - val sizeRecords = data.size - if (sizeRecords == 0) { - aapsLogger.debug(LTag.GLUCOSE, "sizeRecords==0") - return null - } - if (data[0].timestamp < DateUtil.now() - 7 * 60 * 1000L && !allowOldData) { - aapsLogger.debug(LTag.GLUCOSE, "oldData") - return null - } - val now = data[0] - val nowDate = now.timestamp - var change: Double - if (sizeRecords == 1) { - aapsLogger.debug(LTag.GLUCOSE, "sizeRecords==1") - return GlucoseStatus( - glucose = now.value, - noise = 0.0, - delta = 0.0, - shortAvgDelta = 0.0, - longAvgDelta = 0.0, - date = nowDate - ).asRounded() - } - val nowValueList = ArrayList() - val lastDeltas = ArrayList() - val shortDeltas = ArrayList() - val longDeltas = ArrayList() - - // Use the latest sgv value in the now calculations - nowValueList.add(now.value) - for (i in 1 until sizeRecords) { - if (data[i].value > 38) { - val then = data[i] - val thenDate = then.timestamp - - val minutesAgo = ((nowDate - thenDate) / (1000.0 * 60)).roundToLong() - // multiply by 5 to get the same units as delta, i.e. mg/dL/5m - change = now.value - then.value - val avgDel = change / minutesAgo * 5 - aapsLogger.debug(LTag.GLUCOSE, "$then minutesAgo=$minutesAgo avgDelta=$avgDel") - - // use the average of all data points in the last 2.5m for all further "now" calculations - if (0 < minutesAgo && minutesAgo < 2.5) { - // Keep and average all values within the last 2.5 minutes - nowValueList.add(then.value) - now.value = average(nowValueList) - // short_deltas are calculated from everything ~5-15 minutes ago - } else if (2.5 < minutesAgo && minutesAgo < 17.5) { - //console.error(minutesAgo, avgDelta); - shortDeltas.add(avgDel) - // last_deltas are calculated from everything ~5 minutes ago - if (2.5 < minutesAgo && minutesAgo < 7.5) { - lastDeltas.add(avgDel) - } - // long_deltas are calculated from everything ~20-40 minutes ago - } else if (17.5 < minutesAgo && minutesAgo < 42.5) { - longDeltas.add(avgDel) - } else { - // Do not process any more records after >= 42.5 minutes - break - } - } - } - val shortAverageDelta = average(shortDeltas) - val delta = if (lastDeltas.isEmpty()) { - shortAverageDelta - } else { - average(lastDeltas) - } + val data = iobCobCalculator.ads.getBgReadingsDataTableCopy() + val sizeRecords = data.size + if (sizeRecords == 0) { + aapsLogger.debug(LTag.GLUCOSE, "sizeRecords==0") + return null + } + if (data[0].timestamp < dateUtil.now() - 7 * 60 * 1000L && !allowOldData) { + aapsLogger.debug(LTag.GLUCOSE, "oldData") + return null + } + val now = data[0] + val nowDate = now.timestamp + var change: Double + if (sizeRecords == 1) { + aapsLogger.debug(LTag.GLUCOSE, "sizeRecords==1") return GlucoseStatus( glucose = now.value, - date = nowDate, - noise = 0.0, //for now set to nothing as not all CGMs report noise - shortAvgDelta = shortAverageDelta, - delta = delta, - longAvgDelta = average(longDeltas), - ).also { aapsLogger.debug(LTag.GLUCOSE, it.log()) }.asRounded() + noise = 0.0, + delta = 0.0, + shortAvgDelta = 0.0, + longAvgDelta = 0.0, + date = nowDate + ).asRounded() } + val nowValueList = ArrayList() + val lastDeltas = ArrayList() + val shortDeltas = ArrayList() + val longDeltas = ArrayList() + + // Use the latest sgv value in the now calculations + nowValueList.add(now.value) + for (i in 1 until sizeRecords) { + if (data[i].value > 38) { + val then = data[i] + val thenDate = then.timestamp + + val minutesAgo = ((nowDate - thenDate) / (1000.0 * 60)).roundToLong() + // multiply by 5 to get the same units as delta, i.e. mg/dL/5m + change = now.value - then.value + val avgDel = change / minutesAgo * 5 + aapsLogger.debug(LTag.GLUCOSE, "$then minutesAgo=$minutesAgo avgDelta=$avgDel") + + // use the average of all data points in the last 2.5m for all further "now" calculations + if (0 < minutesAgo && minutesAgo < 2.5) { + // Keep and average all values within the last 2.5 minutes + nowValueList.add(then.value) + now.value = average(nowValueList) + // short_deltas are calculated from everything ~5-15 minutes ago + } else if (2.5 < minutesAgo && minutesAgo < 17.5) { + //console.error(minutesAgo, avgDelta); + shortDeltas.add(avgDel) + // last_deltas are calculated from everything ~5 minutes ago + if (2.5 < minutesAgo && minutesAgo < 7.5) { + lastDeltas.add(avgDel) + } + // long_deltas are calculated from everything ~20-40 minutes ago + } else if (17.5 < minutesAgo && minutesAgo < 42.5) { + longDeltas.add(avgDel) + } else { + // Do not process any more records after >= 42.5 minutes + break + } + } + } + val shortAverageDelta = average(shortDeltas) + val delta = if (lastDeltas.isEmpty()) { + shortAverageDelta + } else { + average(lastDeltas) + } + return GlucoseStatus( + glucose = now.value, + date = nowDate, + noise = 0.0, //for now set to nothing as not all CGMs report noise + shortAvgDelta = shortAverageDelta, + delta = delta, + longAvgDelta = average(longDeltas), + ).also { aapsLogger.debug(LTag.GLUCOSE, it.log()) }.asRounded() } companion object { diff --git a/core/src/main/java/info/nightscout/androidaps/plugins/iob/iobCobCalculator/data/AutosensData.java b/core/src/main/java/info/nightscout/androidaps/plugins/iob/iobCobCalculator/data/AutosensData.java index f791d96f1a..73741edd79 100644 --- a/core/src/main/java/info/nightscout/androidaps/plugins/iob/iobCobCalculator/data/AutosensData.java +++ b/core/src/main/java/info/nightscout/androidaps/plugins/iob/iobCobCalculator/data/AutosensData.java @@ -12,7 +12,7 @@ import dagger.android.HasAndroidInjector; import info.nightscout.androidaps.Constants; import info.nightscout.androidaps.core.R; import info.nightscout.androidaps.data.Profile; -import info.nightscout.androidaps.db.Treatment; +import info.nightscout.androidaps.database.entities.Carbs; import info.nightscout.androidaps.interfaces.ProfileFunction; import info.nightscout.androidaps.logging.AAPSLogger; import info.nightscout.androidaps.logging.LTag; @@ -47,17 +47,17 @@ public class AutosensData implements DataPointWithLabelInterface { public double min5minCarbImpact; double remaining; - public CarbsInPast(Treatment t, boolean isAAPSOrWeighted) { - time = t.date; - carbs = t.carbs; - remaining = t.carbs; + public CarbsInPast(Carbs t, boolean isAAPSOrWeighted) { + time = t.getTimestamp(); + carbs = t.getAmount(); + remaining = t.getAmount(); if (isAAPSOrWeighted) { double maxAbsorptionHours = sp.getDouble(R.string.key_absorption_maxtime, Constants.DEFAULT_MAX_ABSORPTION_TIME); - Profile profile = profileFunction.getProfile(t.date); - double sens = profile.getIsfMgdl(t.date); - double ic = profile.getIc(t.date); - min5minCarbImpact = t.carbs / (maxAbsorptionHours * 60 / 5) * sens / ic; - aapsLogger.debug(LTag.AUTOSENS, "Min 5m carbs impact for " + carbs + "g @" + dateUtil.dateAndTimeString(t.date) + " for " + maxAbsorptionHours + "h calculated to " + min5minCarbImpact + " ISF: " + sens + " IC: " + ic); + Profile profile = profileFunction.getProfile(t.getTimestamp()); + double sens = profile.getIsfMgdl(t.getTimestamp()); + double ic = profile.getIc(t.getTimestamp()); + min5minCarbImpact = t.getAmount() / (maxAbsorptionHours * 60 / 5) * sens / ic; + aapsLogger.debug(LTag.AUTOSENS, "Min 5m carbs impact for " + carbs + "g @" + dateUtil.dateAndTimeString(t.getTimestamp()) + " for " + maxAbsorptionHours + "h calculated to " + min5minCarbImpact + " ISF: " + sens + " IC: " + ic); } else { min5minCarbImpact = sp.getDouble(R.string.key_openapsama_min_5m_carbimpact, SMBDefaults.min_5m_carbimpact); } diff --git a/core/src/main/java/info/nightscout/androidaps/plugins/pump/PumpSyncImplementation.kt b/core/src/main/java/info/nightscout/androidaps/plugins/pump/PumpSyncImplementation.kt new file mode 100644 index 0000000000..f51cbcedc7 --- /dev/null +++ b/core/src/main/java/info/nightscout/androidaps/plugins/pump/PumpSyncImplementation.kt @@ -0,0 +1,326 @@ +package info.nightscout.androidaps.plugins.pump + +import info.nightscout.androidaps.core.R +import info.nightscout.androidaps.data.DetailedBolusInfo +import info.nightscout.androidaps.database.AppRepository +import info.nightscout.androidaps.database.ValueWrapper +import info.nightscout.androidaps.database.embedments.InterfaceIDs +import info.nightscout.androidaps.database.entities.Bolus +import info.nightscout.androidaps.database.entities.Carbs +import info.nightscout.androidaps.database.entities.ExtendedBolus +import info.nightscout.androidaps.database.entities.TemporaryBasal +import info.nightscout.androidaps.database.entities.TherapyEvent +import info.nightscout.androidaps.database.transactions.* +import info.nightscout.androidaps.interfaces.ProfileFunction +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 +import info.nightscout.androidaps.plugins.general.overview.events.EventNewNotification +import info.nightscout.androidaps.plugins.general.overview.notifications.Notification +import info.nightscout.androidaps.plugins.pump.common.defs.PumpType +import info.nightscout.androidaps.utils.DateUtil +import info.nightscout.androidaps.utils.T +import info.nightscout.androidaps.utils.resources.ResourceHelper +import info.nightscout.androidaps.utils.sharedPreferences.SP +import io.reactivex.disposables.CompositeDisposable +import io.reactivex.rxkotlin.plusAssign +import javax.inject.Inject + +class PumpSyncImplementation @Inject constructor( + private val aapsLogger: AAPSLogger, + private val dateUtil: DateUtil, + private val sp: SP, + private val rxBus: RxBusWrapper, + private val resourceHelper: ResourceHelper, + private val profileFunction: ProfileFunction, + private val repository: AppRepository +) : PumpSync { + + private val disposable = CompositeDisposable() + + override fun connectNewPump() { + sp.remove(R.string.key_active_pump_type) + sp.remove(R.string.key_active_pump_serial_number) + sp.remove(R.string.key_active_pump_change_timestamp) + } + + /** + * Check if data is coming from currently active pump to prevent overlapping pump histories + * + * @param timestamp timestamp of data coming from pump + * @param type timestamp of of pump + * @param serialNumber serial number of of pump + * @return true if data is allowed + */ + private fun confirmActivePump(timestamp: Long, type: PumpType, serialNumber: String) : Boolean { + val storedType = sp.getString(R.string.key_active_pump_type, "") + val storedSerial = sp.getString(R.string.key_active_pump_serial_number, "") + val storedTimestamp = sp.getLong(R.string.key_active_pump_change_timestamp, 0L) + + // If no value stored assume we start using new pump from now + if (storedType.isEmpty() || storedSerial.isEmpty()) { + aapsLogger.debug(LTag.PUMP, "Registering new pump ${type.description} $serialNumber") + sp.putString(R.string.key_active_pump_type, type.description) + sp.putString(R.string.key_active_pump_serial_number, serialNumber) + sp.putLong(R.string.key_active_pump_change_timestamp, dateUtil.now()) // allow only data newer than register time (ie. ignore older history) + return timestamp > dateUtil.now() - T.mins(1).msecs() // allow first record to be 1 min old + } + + if (type.description == storedType && serialNumber == storedSerial && timestamp >= storedTimestamp) { + // data match + return true + } + + if (type.description != storedType || serialNumber != storedSerial) + rxBus.send(EventNewNotification(Notification(Notification.WRONG_PUMP_DATA, resourceHelper.gs(R.string.wrong_pump_data), Notification.URGENT))) + aapsLogger.error(LTag.PUMP, "Ignoring pump history record $timestamp ${type.description} $serialNumber. Registered pump: $storedType $storedSerial") + return false + } + + override fun expectedPumpState(): PumpSync.PumpState { + val bolus = repository.getLastBolusRecord() + val temporaryBasal = repository.getTemporaryBasalActiveAt(dateUtil.now()).blockingGet() + val extendedBolus = repository.getExtendedBolusActiveAt(dateUtil.now()).blockingGet() + + return PumpSync.PumpState( + temporaryBasal = + if (temporaryBasal is ValueWrapper.Existing) + PumpSync.PumpState.TemporaryBasal( + id = temporaryBasal.value.id, + timestamp = temporaryBasal.value.timestamp, + duration = temporaryBasal.value.duration, + rate = temporaryBasal.value.rate, + isAbsolute = temporaryBasal.value.isAbsolute, + type = PumpSync.TemporaryBasalType.fromDbType(temporaryBasal.value.type), + pumpId = temporaryBasal.value.interfaceIDs.pumpId + ) + else null, + extendedBolus = + if (extendedBolus is ValueWrapper.Existing) + PumpSync.PumpState.ExtendedBolus( + timestamp = extendedBolus.value.timestamp, + duration = extendedBolus.value.duration, + amount = extendedBolus.value.amount, + rate = extendedBolus.value.rate + ) + else null, + bolus = + bolus?.let { + PumpSync.PumpState.Bolus( + timestamp = bolus.timestamp, + amount = bolus.amount + ) + }, + profile = profileFunction.getProfile() + ) + } + + override fun addBolusWithTempId(timestamp: Long, amount: Double, temporaryId: Long, type: DetailedBolusInfo.BolusType, pumpType: PumpType, pumpSerial: String): Boolean { + if (!confirmActivePump(timestamp, pumpType, pumpSerial)) return false + val bolus = Bolus( + timestamp = timestamp, + amount = amount, + type = type.toDBbBolusType(), + interfaceIDs_backing = InterfaceIDs( + temporaryId = temporaryId, + pumpType = pumpType.toDbPumpType(), + pumpSerial = pumpSerial + ) + ) + repository.runTransactionForResult(InsertPumpBolusWithTempIdTransaction(bolus)) + .doOnError { aapsLogger.error(LTag.DATABASE, "Error while saving bolus", it) } + .blockingGet() + .also { result -> + result.inserted.forEach { aapsLogger.debug(LTag.DATABASE, "Inserted bolus $it") } + return result.inserted.size > 0 + } + } + + override fun syncBolusWithTempId(timestamp: Long, amount: Double, temporaryId: Long, type: DetailedBolusInfo.BolusType?, pumpId: Long?, pumpType: PumpType, pumpSerial: String): Boolean { + if (!confirmActivePump(timestamp, pumpType, pumpSerial)) return false + val bolus = Bolus( + timestamp = timestamp, + amount = amount, + type = Bolus.Type.NORMAL, // not used for update + interfaceIDs_backing = InterfaceIDs( + temporaryId = temporaryId, + pumpId = pumpId, + pumpType = pumpType.toDbPumpType(), + pumpSerial = pumpSerial + ) + ) + repository.runTransactionForResult(SyncPumpBolusWithTempIdTransaction(bolus, type?.toDBbBolusType())) + .doOnError { aapsLogger.error(LTag.DATABASE, "Error while saving bolus", it) } + .blockingGet() + .also { result -> + result.updated.forEach { aapsLogger.debug(LTag.DATABASE, "Updated bolus $it") } + return result.updated.size > 0 + } + } + + override fun syncBolusWithPumpId(timestamp: Long, amount: Double, type: DetailedBolusInfo.BolusType?, pumpId: Long, pumpType: PumpType, pumpSerial: String): Boolean { + if (!confirmActivePump(timestamp, pumpType, pumpSerial)) return false + val bolus = Bolus( + timestamp = timestamp, + amount = amount, + type = type?.toDBbBolusType() ?: Bolus.Type.NORMAL, + interfaceIDs_backing = InterfaceIDs( + pumpId = pumpId, + pumpType = pumpType.toDbPumpType(), + pumpSerial = pumpSerial + ) + ) + repository.runTransactionForResult(SyncPumpBolusTransaction(bolus, type?.toDBbBolusType())) + .doOnError { aapsLogger.error(LTag.DATABASE, "Error while saving bolus", it) } + .blockingGet() + .also { result -> + result.inserted.forEach { aapsLogger.debug(LTag.DATABASE, "Inserted bolus $it") } + result.updated.forEach { aapsLogger.debug(LTag.DATABASE, "Updated bolus $it") } + return result.inserted.size > 0 + } + } + + override fun syncCarbsWithTimestamp(timestamp: Long, amount: Double, pumpId: Long?, pumpType: PumpType, pumpSerial: String): Boolean { + if (!confirmActivePump(timestamp, pumpType, pumpSerial)) return false + val carbs = Carbs( + timestamp = timestamp, + amount = amount, + duration = 0, + interfaceIDs_backing = InterfaceIDs( + pumpId = pumpId, + pumpType = pumpType.toDbPumpType(), + pumpSerial = pumpSerial) + ) + repository.runTransactionForResult(InsertIfNewByTimestampCarbsTransaction(carbs)) + .doOnError { aapsLogger.error(LTag.DATABASE, "Error while saving carbs", it) } + .blockingGet() + .also { result -> + result.inserted.forEach { aapsLogger.debug(LTag.DATABASE, "Inserted carbs $it") } + return result.inserted.size > 0 + } + } + + override fun insertTherapyEventIfNewWithTimestamp(timestamp: Long, type: DetailedBolusInfo.EventType, note: String?, pumpId: Long?, pumpType: PumpType, pumpSerial: String): Boolean { + if (!confirmActivePump(timestamp, pumpType, pumpSerial)) return false + val therapyEvent = TherapyEvent( + timestamp = timestamp, + type = type.toDBbEventType(), + duration = 0, + note = null, + enteredBy = "AndroidAPS", + glucose = null, + glucoseType = null, + glucoseUnit = TherapyEvent.GlucoseUnit.MGDL, + interfaceIDs_backing = InterfaceIDs( + pumpId = pumpId, + pumpType = pumpType.toDbPumpType(), + pumpSerial = pumpSerial) + ) + repository.runTransactionForResult(InsertIfNewByTimestampTherapyEventTransaction(therapyEvent)) + .doOnError { + aapsLogger.error(LTag.DATABASE, "Error while saving therapy event", it) + } + .blockingGet() + .also { result -> + result.inserted.forEach { aapsLogger.debug(LTag.DATABASE, "Inserted therapy event $it") } + return result.inserted.size > 0 + } + } + + override fun insertAnnouncement(error: String, pumpId: Long?, pumpType: PumpType, pumpSerial: String) { + if (!confirmActivePump(dateUtil.now(), pumpType, pumpSerial)) return + disposable += repository.runTransaction(InsertTherapyEventAnnouncementTransaction(error, pumpId, pumpType.toDbPumpType(), pumpSerial)) + .subscribe() + } + + /* + * TEMPORARY BASALS + */ + + override fun syncTemporaryBasalWithPumpId(timestamp: Long, rate: Double, duration: Long, isAbsolute: Boolean, type: PumpSync.TemporaryBasalType?, pumpId: Long, pumpType: PumpType, pumpSerial: String): Boolean { + if (!confirmActivePump(timestamp, pumpType, pumpSerial)) return false + val temporaryBasal = TemporaryBasal( + timestamp = timestamp, + rate = rate, + duration = duration, + type = type?.toDbType() ?: TemporaryBasal.Type.NORMAL, + isAbsolute = isAbsolute, + interfaceIDs_backing = InterfaceIDs( + pumpId = pumpId, + pumpType = pumpType.toDbPumpType(), + pumpSerial = pumpSerial + ) + ) + repository.runTransactionForResult(SyncPumpTemporaryBasalTransaction(temporaryBasal, type?.toDbType())) + .doOnError { aapsLogger.error(LTag.DATABASE, "Error while temporary basal", it) } + .blockingGet() + .also { result -> + result.inserted.forEach { aapsLogger.debug(LTag.DATABASE, "Inserted temporary basal $it") } + result.updated.forEach { aapsLogger.debug(LTag.DATABASE, "Updated temporary basal $it") } + return result.inserted.size > 0 + } + } + + override fun syncStopTemporaryBasalWithPumpId(timestamp: Long, endPumpId: Long, pumpType: PumpType, pumpSerial: String): Boolean { + if (!confirmActivePump(timestamp, pumpType, pumpSerial)) return false + repository.runTransactionForResult(SyncPumpCancelTemporaryBasalIfAnyTransaction(timestamp, endPumpId, pumpType.toDbPumpType(), pumpSerial)) + .doOnError { aapsLogger.error(LTag.DATABASE, "Error while saving temporary basal", it) } + .blockingGet() + .also { result -> + result.updated.forEach { + aapsLogger.debug(LTag.DATABASE, "Updated temporary basal $it") + } + return result.updated.size > 0 + } + } + + override fun invalidateTemporaryBasal(id: Long): Boolean { + repository.runTransactionForResult(InvalidateTemporaryBasalTransaction(id)) + .doOnError { aapsLogger.error(LTag.DATABASE, "Error while invalidating temporary basal", it) } + .blockingGet() + .also { result -> + result.invalidated.forEach { + aapsLogger.debug(LTag.DATABASE, "Invalidated temporary basal $it") + } + return result.invalidated.size > 0 + } + } + + override fun syncExtendedBolusWithPumpId(timestamp: Long, amount: Double, duration: Long, isEmulatingTB: Boolean, pumpId: Long, pumpType: PumpType, pumpSerial: String): Boolean { + if (!confirmActivePump(timestamp, pumpType, pumpSerial)) return false + val extendedBolus = ExtendedBolus( + timestamp = timestamp, + amount = amount, + duration = duration, + isEmulatingTempBasal = isEmulatingTB, + interfaceIDs_backing = InterfaceIDs( + pumpId = pumpId, + pumpType = pumpType.toDbPumpType(), + pumpSerial = pumpSerial + ) + ) + repository.runTransactionForResult(SyncPumpExtendedBolusTransaction(extendedBolus)) + .doOnError { aapsLogger.error(LTag.DATABASE, "Error while extended bolus", it) } + .blockingGet() + .also { result -> + result.inserted.forEach { aapsLogger.debug(LTag.DATABASE, "Inserted extended bolus $it") } + result.updated.forEach { aapsLogger.debug(LTag.DATABASE, "Updated extended bolus $it") } + return result.inserted.size > 0 + } + } + + override fun syncStopExtendedBolusWithPumpId(timestamp: Long, endPumpId: Long, pumpType: PumpType, pumpSerial: String): Boolean { + if (!confirmActivePump(timestamp, pumpType, pumpSerial)) return false + repository.runTransactionForResult(SyncPumpCancelExtendedBolusIfAnyTransaction(timestamp, endPumpId, pumpType.toDbPumpType(), pumpSerial)) + .doOnError { aapsLogger.error(LTag.DATABASE, "Error while saving extended bolus", it) } + .blockingGet() + .also { result -> + result.updated.forEach { + aapsLogger.debug(LTag.DATABASE, "Updated extended bolus $it") + } + return result.updated.size > 0 + } + } + +} \ No newline at end of file diff --git a/core/src/main/java/info/nightscout/androidaps/plugins/pump/common/bolusInfo/DetailedBolusInfoStorage.kt b/core/src/main/java/info/nightscout/androidaps/plugins/pump/common/bolusInfo/DetailedBolusInfoStorage.kt index b74fc2ac00..062d41191f 100644 --- a/core/src/main/java/info/nightscout/androidaps/plugins/pump/common/bolusInfo/DetailedBolusInfoStorage.kt +++ b/core/src/main/java/info/nightscout/androidaps/plugins/pump/common/bolusInfo/DetailedBolusInfoStorage.kt @@ -12,7 +12,7 @@ import kotlin.math.abs @Singleton class DetailedBolusInfoStorage @Inject constructor( val aapsLogger: AAPSLogger -){ +) { val store = ArrayList() @@ -27,8 +27,8 @@ class DetailedBolusInfoStorage @Inject constructor( // Look for info with bolus for (i in store.indices) { val d = store[i] - aapsLogger.debug(LTag.PUMP, "Existing bolus info: " + store[i]) - if (bolusTime > d.date - T.mins(1).msecs() && bolusTime < d.date + T.mins(1).msecs() && abs(store[i].insulin - bolus) < 0.01) { + //aapsLogger.debug(LTag.PUMP, "Existing bolus info: " + store[i]) + if (bolusTime > d.timestamp - T.mins(1).msecs() && bolusTime < d.timestamp + T.mins(1).msecs() && abs(store[i].insulin - bolus) < 0.01) { aapsLogger.debug(LTag.PUMP, "Using & removing bolus info: ${store[i]}") store.removeAt(i) return d @@ -37,7 +37,7 @@ class DetailedBolusInfoStorage @Inject constructor( // If not found use time only for (i in store.indices) { val d = store[i] - if (bolusTime > d.date - T.mins(1).msecs() && bolusTime < d.date + T.mins(1).msecs() && bolus <= store[i].insulin + 0.01) { + if (bolusTime > d.timestamp - T.mins(1).msecs() && bolusTime < d.timestamp + T.mins(1).msecs() && bolus <= store[i].insulin + 0.01) { aapsLogger.debug(LTag.PUMP, "Using TIME-ONLY & removing bolus info: ${store[i]}") store.removeAt(i) return d @@ -53,7 +53,7 @@ class DetailedBolusInfoStorage @Inject constructor( } } //Not found - aapsLogger.debug(LTag.PUMP, "Bolus info not found") + //aapsLogger.debug(LTag.PUMP, "Bolus info not found") return null } } \ No newline at end of file diff --git a/core/src/main/java/info/nightscout/androidaps/plugins/pump/common/bolusInfo/TemporaryBasalStorage.kt b/core/src/main/java/info/nightscout/androidaps/plugins/pump/common/bolusInfo/TemporaryBasalStorage.kt new file mode 100644 index 0000000000..0a5ac50f67 --- /dev/null +++ b/core/src/main/java/info/nightscout/androidaps/plugins/pump/common/bolusInfo/TemporaryBasalStorage.kt @@ -0,0 +1,59 @@ +package info.nightscout.androidaps.plugins.pump.common.bolusInfo + +import info.nightscout.androidaps.interfaces.PumpSync +import info.nightscout.androidaps.logging.AAPSLogger +import info.nightscout.androidaps.logging.LTag +import info.nightscout.androidaps.utils.T +import java.util.* +import javax.inject.Inject +import javax.inject.Singleton +import kotlin.math.abs + +@Singleton +class TemporaryBasalStorage @Inject constructor( + val aapsLogger: AAPSLogger +) { + + val store = ArrayList() + + @Synchronized + fun add(temporaryBasal: PumpSync.PumpState.TemporaryBasal) { + aapsLogger.debug("Stored temporary basal info: $temporaryBasal") + store.add(temporaryBasal) + } + + @Synchronized + fun findTemporaryBasal(time: Long, rate: Double): PumpSync.PumpState.TemporaryBasal? { + // Look for info with temporary basal + for (i in store.indices) { + val d = store[i] + //aapsLogger.debug(LTag.PUMP, "Existing temporary basal info: " + store[i]) + if (time > d.timestamp - T.mins(1).msecs() && time < d.timestamp + T.mins(1).msecs() && abs(store[i].rate - rate) < 0.01) { + aapsLogger.debug(LTag.PUMP, "Using & removing temporary basal info: ${store[i]}") + store.removeAt(i) + return d + } + } + // If not found use time only + for (i in store.indices) { + val d = store[i] + if (time > d.timestamp - T.mins(1).msecs() && time < d.timestamp + T.mins(1).msecs() && rate <= store[i].rate + 0.01) { + aapsLogger.debug(LTag.PUMP, "Using TIME-ONLY & removing temporary basal info: ${store[i]}") + store.removeAt(i) + return d + } + } + // If not found, use last record if amount is the same + if (store.size > 0) { + val d = store[store.size - 1] + if (abs(d.rate - rate) < 0.01) { + aapsLogger.debug(LTag.PUMP, "Using LAST & removing temporary basal info: $d") + store.removeAt(store.size - 1) + return d + } + } + //Not found + //aapsLogger.debug(LTag.PUMP, "Temporary basal info not found") + return null + } +} \ No newline at end of file diff --git a/core/src/main/java/info/nightscout/androidaps/plugins/pump/common/data/DoseSettings.java b/core/src/main/java/info/nightscout/androidaps/plugins/pump/common/data/DoseSettings.java deleted file mode 100644 index b617e5e3ee..0000000000 --- a/core/src/main/java/info/nightscout/androidaps/plugins/pump/common/data/DoseSettings.java +++ /dev/null @@ -1,49 +0,0 @@ -package info.nightscout.androidaps.plugins.pump.common.data; - -/** - * Created by andy on 02/05/2018. - */ - -public class DoseSettings { - - private final double step; - private final int durationStep; - private final int maxDuration; - private final double minDose; - private final Double maxDose; - - public DoseSettings(double step, int durationStep, int maxDuration, double minDose, Double maxDose) - { - this.step = step; - this.durationStep = durationStep; - this.maxDuration = maxDuration; - this.minDose = minDose; - this.maxDose = maxDose; - } - - public DoseSettings(double step, int durationStep, int maxDuration, double minDose) - { - this(step, durationStep, maxDuration, minDose, Double.MAX_VALUE); - } - - - public double getStep() { - return step; - } - - public int getDurationStep() { - return durationStep; - } - - public int getMaxDuration() { - return maxDuration; - } - - public double getMinDose() { - return minDose; - } - - public Double getMaxDose() { - return maxDose; - } -} diff --git a/core/src/main/java/info/nightscout/androidaps/plugins/pump/common/data/TempBasalPair.java b/core/src/main/java/info/nightscout/androidaps/plugins/pump/common/data/TempBasalPair.java deleted file mode 100644 index 5a1e0b4249..0000000000 --- a/core/src/main/java/info/nightscout/androidaps/plugins/pump/common/data/TempBasalPair.java +++ /dev/null @@ -1,72 +0,0 @@ -package info.nightscout.androidaps.plugins.pump.common.data; - -import com.google.gson.annotations.Expose; - -public class TempBasalPair { - - @Expose - protected double insulinRate = 0.0d; - @Expose - protected int durationMinutes = 0; - @Expose - protected boolean isPercent = false; - - private Long start; - private Long end; - - public TempBasalPair() { - } - - - public TempBasalPair(double insulinRate, boolean isPercent, int durationMinutes) { - this.insulinRate = insulinRate; - this.isPercent = isPercent; - this.durationMinutes = durationMinutes; - } - - - public double getInsulinRate() { - return insulinRate; - } - - - public void setInsulinRate(double insulinRate) { - this.insulinRate = insulinRate; - } - - - public int getDurationMinutes() { - return durationMinutes; - } - - - public void setDurationMinutes(int durationMinutes) { - this.durationMinutes = durationMinutes; - } - - - public boolean isPercent() { - return isPercent; - } - - - public void setIsPercent(boolean yesIsPercent) { - this.isPercent = yesIsPercent; - } - - public void setStartTime(Long startTime) { - this.start = startTime; - } - - - public void setEndTime(Long endTime) { - this.end = endTime; - } - - - @Override - public String toString() { - return "TempBasalPair [" + "Rate=" + insulinRate + ", DurationMinutes=" + durationMinutes + ", IsPercent=" - + isPercent + "]"; - } -} diff --git a/core/src/main/java/info/nightscout/androidaps/plugins/pump/common/defs/DoseSettings.kt b/core/src/main/java/info/nightscout/androidaps/plugins/pump/common/defs/DoseSettings.kt new file mode 100644 index 0000000000..c1a9b18167 --- /dev/null +++ b/core/src/main/java/info/nightscout/androidaps/plugins/pump/common/defs/DoseSettings.kt @@ -0,0 +1,3 @@ +package info.nightscout.androidaps.plugins.pump.common.defs + +class DoseSettings constructor(val step: Double, val durationStep: Int, val maxDuration: Int, val minDose: Double, val maxDose: Double = Double.MAX_VALUE) \ No newline at end of file diff --git a/core/src/main/java/info/nightscout/androidaps/plugins/pump/common/defs/DoseStepSize.java b/core/src/main/java/info/nightscout/androidaps/plugins/pump/common/defs/DoseStepSize.java deleted file mode 100644 index 095c11de65..0000000000 --- a/core/src/main/java/info/nightscout/androidaps/plugins/pump/common/defs/DoseStepSize.java +++ /dev/null @@ -1,100 +0,0 @@ -package info.nightscout.androidaps.plugins.pump.common.defs; - -import java.util.Locale; - -/** - * Created by andy on 02/05/2018. - */ - -public enum DoseStepSize { - - ComboBasal( // - new DoseStepSizeEntry(0f, 1f, 0.01f), // - new DoseStepSizeEntry(1f, 10f, 0.05f), // - new DoseStepSizeEntry(10f, Double.MAX_VALUE, 0.1f)), // - - InsightBolus( - new DoseStepSizeEntry(0f, 2f, 0.05f), // - new DoseStepSizeEntry(2f, 5f, 0.1f), // - new DoseStepSizeEntry(5f, 10f, 0.2f), // - new DoseStepSizeEntry(10f, Double.MAX_VALUE, 0.5f)), - - InsightBasal( - new DoseStepSizeEntry(0f, 5f, 0.01f), - new DoseStepSizeEntry(5f, Double.MAX_VALUE, 0.1f)), - - MedtronicVeoBasal( // - new DoseStepSizeEntry(0f, 1f, 0.025f), // - new DoseStepSizeEntry(1f, 10f, 0.05f), // - new DoseStepSizeEntry(10f, Double.MAX_VALUE, 0.1f)), // - - YpsopumpBasal( // - new DoseStepSizeEntry(0.0f, 1f, 0.01f), // - new DoseStepSizeEntry(1f, 2f, 0.02f), // - new DoseStepSizeEntry(2f, 15f, 0.1f), // - new DoseStepSizeEntry(15f, 40f, 0.5f) - ) - ; - - - DoseStepSizeEntry[] entries; - - - DoseStepSize(DoseStepSizeEntry... entries) { - this.entries = entries; - } - - - public double getStepSizeForAmount(double amount) { - for (DoseStepSizeEntry entry : entries) { - if (entry.from <= amount && entry.to > amount) - return entry.value; - } - - // should never come to this - return entries[entries.length - 1].value; - } - - - public String getDescription() { - StringBuilder sb = new StringBuilder(); - boolean first = true; - for (DoseStepSizeEntry entry : entries) { - - if (first) { - first = false; - } else { - sb.append(", "); - } - - sb.append(String.format(Locale.ENGLISH, "%.3f", entry.value)); - sb.append(" {"); - sb.append(String.format(Locale.ENGLISH,"%.3f", entry.from)); - sb.append("-"); - - if (entry.to == Double.MAX_VALUE) { - sb.append("~}"); - } else { - sb.append(String.format(Locale.ENGLISH, "%.3f", entry.to)); - sb.append("}"); - } - } - - return sb.toString(); - } - - - static class DoseStepSizeEntry { - double from; - double to; - double value; - - // to = this value is not included, but would actually mean <, so for rates between 0.025-0.975 u/h, we would have [from=0, to=10] - DoseStepSizeEntry(double from, double to, double value) { - this.from = from; - this.to = to; - this.value = value; - } - } - -} diff --git a/core/src/main/java/info/nightscout/androidaps/plugins/pump/common/defs/DoseStepSize.kt b/core/src/main/java/info/nightscout/androidaps/plugins/pump/common/defs/DoseStepSize.kt new file mode 100644 index 0000000000..179be45dc8 --- /dev/null +++ b/core/src/main/java/info/nightscout/androidaps/plugins/pump/common/defs/DoseStepSize.kt @@ -0,0 +1,56 @@ +package info.nightscout.androidaps.plugins.pump.common.defs + +import java.util.* + +enum class DoseStepSize(private val entries: Array) { + + ComboBasal(arrayOf( + DoseStepSizeEntry(0.0, 1.0, 0.01), + DoseStepSizeEntry(1.0, 10.0, 0.05), + DoseStepSizeEntry(10.0, Double.MAX_VALUE, 0.1))), + InsightBolus(arrayOf( + DoseStepSizeEntry(0.0, 2.0, 0.05), + DoseStepSizeEntry(2.0, 5.0, 0.1), + DoseStepSizeEntry(5.0, 10.0, 0.2), + DoseStepSizeEntry(10.0, Double.MAX_VALUE, 0.5))), + InsightBasal(arrayOf( + DoseStepSizeEntry(0.0, 5.0, 0.01), + DoseStepSizeEntry(5.0, Double.MAX_VALUE, 0.1))), + MedtronicVeoBasal(arrayOf( + DoseStepSizeEntry(0.0, 1.0, 0.025), + DoseStepSizeEntry(1.0, 10.0, 0.05), + DoseStepSizeEntry(10.0, Double.MAX_VALUE, 0.1))), + YpsopumpBasal(arrayOf( + DoseStepSizeEntry(0.0, 1.0, 0.01), + DoseStepSizeEntry(1.0, 2.0, 0.02), + DoseStepSizeEntry(2.0, 15.0, 0.1), + DoseStepSizeEntry(15.0, 40.0, 0.5)) + ); + + fun getStepSizeForAmount(amount: Double): Double { + for (entry in entries) + if (entry.from <= amount && entry.to > amount) return entry.value + + // should never come to this + return entries[entries.size - 1].value + } + + val description: String + get() = StringBuilder().also { sb -> + var first = true + for (entry in entries) { + if (first) first = false else sb.append(", ") + + sb.append(String.format(Locale.ENGLISH, "%.3f", entry.value)) + .append(" {") + .append(String.format(Locale.ENGLISH, "%.3f", entry.from)) + .append("-") + if (entry.to == Double.MAX_VALUE) sb.append("~}") + else sb.append(String.format(Locale.ENGLISH, "%.3f", entry.to)).append("}") + } + }.toString() + + // to = this value is not included, but would actually mean <, so for rates between 0.025-0.975 u/h, we would have [from=0, to=10] + internal class DoseStepSizeEntry(var from: Double, var to: Double, var value: Double) + +} \ No newline at end of file diff --git a/core/src/main/java/info/nightscout/androidaps/plugins/pump/common/defs/PumpCapability.java b/core/src/main/java/info/nightscout/androidaps/plugins/pump/common/defs/PumpCapability.java deleted file mode 100644 index 183cfbe8d9..0000000000 --- a/core/src/main/java/info/nightscout/androidaps/plugins/pump/common/defs/PumpCapability.java +++ /dev/null @@ -1,69 +0,0 @@ -package info.nightscout.androidaps.plugins.pump.common.defs; - -/** - * Created by andy on 03/05/2018. - */ - -public enum PumpCapability { - - Bolus, // isBolusCapable - ExtendedBolus, // isExtendedBolusCapable - TempBasal, // isTempBasalCapable - BasalProfileSet, // isSetBasalProfileCapable - Refill, // isRefillingCapable - ReplaceBattery, // isBatteryReplaceable - StoreCarbInfo, // storesCarbInfo - TDD, // supportsTDDs - ManualTDDLoad, // needsManualTDDLoad - BasalRate30min, // is30minBasalRatesCapable - - // grouped by pump - VirtualPumpCapabilities(Bolus, ExtendedBolus, TempBasal, BasalProfileSet, Refill, ReplaceBattery), // - ComboCapabilities(Bolus, TempBasal, BasalProfileSet, Refill, ReplaceBattery, TDD, ManualTDDLoad), // - DanaCapabilities(Bolus, ExtendedBolus, TempBasal, BasalProfileSet, Refill, ReplaceBattery, TDD, ManualTDDLoad), // - DanaWithHistoryCapabilities(Bolus, ExtendedBolus, TempBasal, BasalProfileSet, Refill, ReplaceBattery, StoreCarbInfo, TDD, ManualTDDLoad), // - InsightCapabilities(Bolus, ExtendedBolus, TempBasal, BasalProfileSet, Refill, ReplaceBattery, TDD, BasalRate30min), // - MedtronicCapabilities(Bolus, TempBasal, BasalProfileSet, Refill, ReplaceBattery, TDD), // - OmnipodCapabilities(Bolus, TempBasal, BasalProfileSet, BasalRate30min), // - YpsomedCapabilities(Bolus, ExtendedBolus, TempBasal, BasalProfileSet, Refill, ReplaceBattery, TDD, ManualTDDLoad), - - // BasalRates (separately grouped) - BasalRate_Duration15minAllowed, // - BasalRate_Duration30minAllowed, // - BasalRate_Duration15and30minAllowed(BasalRate_Duration15minAllowed, BasalRate_Duration30minAllowed), // - BasalRate_Duration15and30minNotAllowed, // - ; - - PumpCapability[] children; - - - PumpCapability() { - } - - - PumpCapability(PumpCapability... children) { - this.children = children; - } - - - public boolean hasCapability(PumpCapability capability) { - // we can only check presense of simple capabilities - if (capability.children != null) - return false; - - if (this == capability) - return true; - - if (this.children != null) { - for (PumpCapability child : children) { - if (child == capability) - return true; - } - - return false; - } else - return false; - } - - -} diff --git a/core/src/main/java/info/nightscout/androidaps/plugins/pump/common/defs/PumpCapability.kt b/core/src/main/java/info/nightscout/androidaps/plugins/pump/common/defs/PumpCapability.kt new file mode 100644 index 0000000000..b8e74bb0a6 --- /dev/null +++ b/core/src/main/java/info/nightscout/androidaps/plugins/pump/common/defs/PumpCapability.kt @@ -0,0 +1,42 @@ +package info.nightscout.androidaps.plugins.pump.common.defs + +enum class PumpCapability { + + Bolus, // isBolusCapable + ExtendedBolus, // isExtendedBolusCapable + TempBasal, // isTempBasalCapable + BasalProfileSet, // isSetBasalProfileCapable + Refill, // isRefillingCapable + ReplaceBattery, // isBatteryReplaceable + StoreCarbInfo, // storesCarbInfo + TDD, // supportsTDDs + ManualTDDLoad, // needsManualTDDLoad + BasalRate30min, // is30minBasalRatesCapable + + // grouped by pump + MDI(arrayOf(Bolus)), + VirtualPumpCapabilities(arrayOf(Bolus, ExtendedBolus, TempBasal, BasalProfileSet, Refill, ReplaceBattery)), + ComboCapabilities(arrayOf(Bolus, TempBasal, BasalProfileSet, Refill, ReplaceBattery, TDD, ManualTDDLoad)), + DanaCapabilities(arrayOf(Bolus, ExtendedBolus, TempBasal, BasalProfileSet, Refill, ReplaceBattery, TDD, ManualTDDLoad)), + DanaWithHistoryCapabilities(arrayOf(Bolus, ExtendedBolus, TempBasal, BasalProfileSet, Refill, ReplaceBattery, StoreCarbInfo, TDD, ManualTDDLoad)), + InsightCapabilities(arrayOf(Bolus, ExtendedBolus, TempBasal, BasalProfileSet, Refill, ReplaceBattery, TDD, BasalRate30min)), + MedtronicCapabilities(arrayOf(Bolus, TempBasal, BasalProfileSet, Refill, ReplaceBattery, TDD)), + OmnipodCapabilities(arrayOf(Bolus, TempBasal, BasalProfileSet, BasalRate30min)), + YpsomedCapabilities(arrayOf(Bolus, ExtendedBolus, TempBasal, BasalProfileSet, Refill, ReplaceBattery, TDD, ManualTDDLoad)), // BasalRates (separately grouped) + BasalRate_Duration15minAllowed, + BasalRate_Duration30minAllowed, + BasalRate_Duration15and30minAllowed(arrayOf(BasalRate_Duration15minAllowed, BasalRate_Duration30minAllowed)), + BasalRate_Duration15and30minNotAllowed; + + var children: ArrayList = ArrayList() + + constructor() { + children.add(this) + } + + constructor(list: Array) { + children.addAll(list) + } + + fun hasCapability(capability: PumpCapability): Boolean = children.contains(capability) +} \ No newline at end of file diff --git a/core/src/main/java/info/nightscout/androidaps/plugins/pump/common/defs/PumpDeviceState.java b/core/src/main/java/info/nightscout/androidaps/plugins/pump/common/defs/PumpDeviceState.java deleted file mode 100644 index 4a9814c490..0000000000 --- a/core/src/main/java/info/nightscout/androidaps/plugins/pump/common/defs/PumpDeviceState.java +++ /dev/null @@ -1,29 +0,0 @@ -package info.nightscout.androidaps.plugins.pump.common.defs; - -import info.nightscout.androidaps.core.R; - -/** - * Created by andy on 6/11/18. - */ -public enum PumpDeviceState { - - NeverContacted(R.string.pump_status_never_contacted), // - Sleeping(R.string.pump_status_sleeping), // - WakingUp(R.string.pump_status_waking_up), // - Active(R.string.pump_status_active), // - ErrorWhenCommunicating(R.string.pump_status_error_comm), // - TimeoutWhenCommunicating(R.string.pump_status_timeout_comm), // - // ProblemContacting(R.string.medtronic_pump_status_problem_contacting), // - PumpUnreachable(R.string.pump_status_pump_unreachable), // - InvalidConfiguration(R.string.pump_status_invalid_config); - - Integer resourceId; - - PumpDeviceState(int resourceId) { - this.resourceId = resourceId; - } - - public Integer getResourceId() { - return resourceId; - } -} diff --git a/core/src/main/java/info/nightscout/androidaps/plugins/pump/common/defs/PumpDriverState.java b/core/src/main/java/info/nightscout/androidaps/plugins/pump/common/defs/PumpDriverState.java deleted file mode 100644 index 460c8dd3db..0000000000 --- a/core/src/main/java/info/nightscout/androidaps/plugins/pump/common/defs/PumpDriverState.java +++ /dev/null @@ -1,26 +0,0 @@ -package info.nightscout.androidaps.plugins.pump.common.defs; - -/** - * Created by andy on 10/15/18. - */ - -public enum PumpDriverState { - - NotInitialized, // - Connecting, // - Connected, // - Initialized, // - Ready, - Busy, // - Suspended, // - ; - - public static boolean isConnected(PumpDriverState pumpState) { - return pumpState == Connected || pumpState == Initialized || pumpState == Busy || pumpState == Suspended; - } - - - public static boolean isInitialized(PumpDriverState pumpState) { - return pumpState == Initialized || pumpState == Busy || pumpState == Suspended; - } -} diff --git a/core/src/main/java/info/nightscout/androidaps/plugins/pump/common/defs/PumpStatusType.java b/core/src/main/java/info/nightscout/androidaps/plugins/pump/common/defs/PumpStatusType.java deleted file mode 100644 index d32d6bb57f..0000000000 --- a/core/src/main/java/info/nightscout/androidaps/plugins/pump/common/defs/PumpStatusType.java +++ /dev/null @@ -1,23 +0,0 @@ -package info.nightscout.androidaps.plugins.pump.common.defs; - -/** - * Created by andy on 5/12/18. - */ - -public enum PumpStatusType { - Running("normal"), // - Suspended("suspended") // - ; - - private final String statusString; - - - PumpStatusType(String statusString) { - this.statusString = statusString; - } - - - public String getStatus() { - return statusString; - } -} diff --git a/core/src/main/java/info/nightscout/androidaps/plugins/pump/common/defs/PumpTempBasalType.java b/core/src/main/java/info/nightscout/androidaps/plugins/pump/common/defs/PumpTempBasalType.java deleted file mode 100644 index 90304ca45f..0000000000 --- a/core/src/main/java/info/nightscout/androidaps/plugins/pump/common/defs/PumpTempBasalType.java +++ /dev/null @@ -1,10 +0,0 @@ -package info.nightscout.androidaps.plugins.pump.common.defs; - -/** - * Created by andy on 02/05/2018. - */ - -public enum PumpTempBasalType { - Percent, // - Absolute, -} diff --git a/core/src/main/java/info/nightscout/androidaps/plugins/pump/common/defs/PumpTempBasalType.kt b/core/src/main/java/info/nightscout/androidaps/plugins/pump/common/defs/PumpTempBasalType.kt new file mode 100644 index 0000000000..20003df6ef --- /dev/null +++ b/core/src/main/java/info/nightscout/androidaps/plugins/pump/common/defs/PumpTempBasalType.kt @@ -0,0 +1,7 @@ +package info.nightscout.androidaps.plugins.pump.common.defs + +enum class PumpTempBasalType { + + Percent, + Absolute +} \ No newline at end of file diff --git a/core/src/main/java/info/nightscout/androidaps/plugins/pump/common/defs/PumpType.java b/core/src/main/java/info/nightscout/androidaps/plugins/pump/common/defs/PumpType.java deleted file mode 100644 index 670ec3fae1..0000000000 --- a/core/src/main/java/info/nightscout/androidaps/plugins/pump/common/defs/PumpType.java +++ /dev/null @@ -1,481 +0,0 @@ -package info.nightscout.androidaps.plugins.pump.common.defs; - - -import java.util.HashMap; -import java.util.Map; - -import info.nightscout.androidaps.core.R; -import info.nightscout.androidaps.plugins.common.ManufacturerType; -import info.nightscout.androidaps.plugins.pump.common.data.DoseSettings; -import info.nightscout.androidaps.utils.Round; -import info.nightscout.androidaps.utils.resources.ResourceHelper; - - -/** - * Created by andy on 02/05/2018. - *

- * Most of this defintions is intended for VirtualPump only, but they can be used by other plugins. - */ - -public enum PumpType { - - GenericAAPS("Generic AAPS", ManufacturerType.AndroidAPS, "VirutalPump", 0.1d, null, // - new DoseSettings(0.05d, 30, 8 * 60, 0.05d), // - PumpTempBasalType.Percent, // - new DoseSettings(10, 30, 24 * 60, 0d, 500d), PumpCapability.BasalRate_Duration15and30minAllowed, // - 0.01d, 0.01d, null, PumpCapability.VirtualPumpCapabilities), // - - // Cellnovo - - Cellnovo1("Cellnovo", ManufacturerType.Cellnovo, "Cellnovo", 0.05d, null, // - new DoseSettings(0.05d, 30, 24 * 60, 1d, null), - PumpTempBasalType.Percent, - new DoseSettings(5, 30, 24 * 60, 0d, 200d), PumpCapability.BasalRate_Duration30minAllowed, // - 0.05d, 0.05d, null, PumpCapability.VirtualPumpCapabilities), // - - // Accu-Chek - - AccuChekCombo("Accu-Chek Combo", ManufacturerType.Roche, "Combo", 0.1d, null, // - new DoseSettings(0.1d, 15, 12 * 60, 0.1d), // - PumpTempBasalType.Percent, - new DoseSettings(10, 15, 12 * 60, 0d, 500d), PumpCapability.BasalRate_Duration15and30minAllowed, // - 0.01d, 0.01d, DoseStepSize.ComboBasal, PumpCapability.ComboCapabilities), // - - AccuChekSpirit("Accu-Chek Spirit", ManufacturerType.Roche, "Spirit", 0.1d, null, // - new DoseSettings(0.1d, 15, 12 * 60, 0.1d), // - PumpTempBasalType.Percent, - new DoseSettings(10, 15, 12 * 60, 0d, 500d), PumpCapability.BasalRate_Duration15and30minAllowed, // - 0.01d, 0.1d, null, PumpCapability.VirtualPumpCapabilities), // - - AccuChekInsight("Accu-Chek Insight", ManufacturerType.Roche, "Insight", 0.05d, DoseStepSize.InsightBolus, // - new DoseSettings(0.05d, 15, 24 * 60, 0.05d), // - PumpTempBasalType.Percent, - new DoseSettings(10, 15, 24 * 60, 0d, 250d), PumpCapability.BasalRate_Duration15and30minAllowed, // - 0.02d, 0.01d, null, PumpCapability.InsightCapabilities), // - - AccuChekInsightBluetooth("Accu-Chek Insight", ManufacturerType.Roche, "Insight", 0.01d, null, // - new DoseSettings(0.01d, 15, 24 * 60, 0.05d), // - PumpTempBasalType.Percent, - new DoseSettings(10, 15, 24 * 60, 0d, 250d), PumpCapability.BasalRate_Duration15and30minAllowed, // - 0.02d, null, 0.01d, DoseStepSize.InsightBolus, PumpCapability.InsightCapabilities), // - - AccuChekSolo("Accu-Chek Solo", ManufacturerType.Roche, "Solo", 0.01d, null, // - new DoseSettings(0.01d, 15, 24 * 60, 0.05d), // - PumpTempBasalType.Percent, - new DoseSettings(10, 15, 24 * 60, 0d, 250d), PumpCapability.BasalRate_Duration15and30minAllowed, // - 0.02d, null, 0.01d, DoseStepSize.InsightBolus, PumpCapability.InsightCapabilities), // - - - // Animas - AnimasVibe("Animas Vibe", ManufacturerType.Animas, "Vibe", 0.05d, null, // AnimasBolus? - new DoseSettings(0.05d, 30, 12 * 60, 0.05d), // - PumpTempBasalType.Percent, // - new DoseSettings(10, 30, 24 * 60, 0d, 300d), PumpCapability.BasalRate_Duration30minAllowed, // - 0.025d, 5d, 0d, null, PumpCapability.VirtualPumpCapabilities), // - - AnimasPing("Animas Ping", "Ping", AnimasVibe), - - // Dana - DanaR("DanaR", ManufacturerType.Sooil, "DanaR", 0.05d, null, // - new DoseSettings(0.05d, 30, 8 * 60, 0.05d), // - PumpTempBasalType.Percent, // - new DoseSettings(10d, 60, 24 * 60, 0d, 200d), PumpCapability.BasalRate_Duration15and30minNotAllowed, // - 0.04d, 0.01d, null, PumpCapability.DanaCapabilities), - - DanaRKorean("DanaR Korean", ManufacturerType.Sooil, "DanaRKorean", 0.05d, null, // - new DoseSettings(0.05d, 30, 8 * 60, 0.05d), // - PumpTempBasalType.Percent, // - new DoseSettings(10d, 60, 24 * 60, 0d, 200d), PumpCapability.BasalRate_Duration15and30minNotAllowed, // - 0.1d, 0.01d, null, PumpCapability.DanaCapabilities), - - DanaRS("DanaRS", ManufacturerType.Sooil, "DanaRS", 0.05d, null, // - new DoseSettings(0.05d, 30, 8 * 60, 0.05d), // - PumpTempBasalType.Percent, // - new DoseSettings(10d, 60, 24 * 60, 0d, 200d), PumpCapability.BasalRate_Duration15and30minAllowed, // - 0.04d, 0.01d, null, PumpCapability.DanaWithHistoryCapabilities), - - DanaRv2("DanaRv2", "DanaRv2", DanaRS), - - - // Insulet - Omnipod_Eros("Omnipod", ManufacturerType.Insulet, "Eros", 0.05d, null, // - new DoseSettings(0.05d, 30, 8 * 60, 0.05d), // - PumpTempBasalType.Absolute, // - new DoseSettings(0.05d, 30, 12 * 60, 0d, 30.0d), PumpCapability.BasalRate_Duration30minAllowed, // - 0.05d, null, 0.05d, null, PumpCapability.OmnipodCapabilities, true), - - Omnipod_Dash("Omnipod", ManufacturerType.Insulet, "Dash", 0.05d, null, // - new DoseSettings(0.05d, 30, 8 * 60, 0.05d), // - PumpTempBasalType.Absolute, // - new DoseSettings(0.05d, 30, 12 * 60, 0d, 30.0d), PumpCapability.BasalRate_Duration30minAllowed, // - 0.05d, null, 0.05d, null, PumpCapability.OmnipodCapabilities, false), - - - // Medtronic - Medtronic_512_712("Medtronic 512/712", ManufacturerType.Medtronic, "512/712", 0.1d, null, // - new DoseSettings(0.05d, 30, 8 * 60, 0.05d), // - PumpTempBasalType.Absolute, // - new DoseSettings(0.05d, 30, 24 * 60, 0d, 35d), PumpCapability.BasalRate_Duration30minAllowed, // - 0.05d, 0.05d, null, PumpCapability.MedtronicCapabilities), // - - Medtronic_515_715("Medtronic 515/715", "515/715", Medtronic_512_712), - Medtronic_522_722("Medtronic 522/722", "522/722", Medtronic_512_712), - - Medtronic_523_723_Revel("Medtronic 523/723 (Revel)", ManufacturerType.Medtronic, "523/723 (Revel)", 0.05d, null, // - new DoseSettings(0.05d, 30, 8 * 60, 0.05d), // - PumpTempBasalType.Absolute, // - new DoseSettings(0.05d, 30, 24 * 60, 0d, 35d), PumpCapability.BasalRate_Duration30minAllowed, // - 0.025d, 0.025d, DoseStepSize.MedtronicVeoBasal, PumpCapability.MedtronicCapabilities), // - - Medtronic_554_754_Veo("Medtronic 554/754 (Veo)", "554/754 (Veo)", Medtronic_523_723_Revel), // TODO - - Medtronic_640G("Medtronic 640G", ManufacturerType.Medtronic, "640G", 0.025d, null, // - new DoseSettings(0.05d, 30, 8 * 60, 0.05d), // - PumpTempBasalType.Absolute, // - new DoseSettings(0.05d, 30, 24 * 60, 0d, 35d), PumpCapability.BasalRate_Duration30minAllowed, // - 0.025d, 0.025d, DoseStepSize.MedtronicVeoBasal, PumpCapability.VirtualPumpCapabilities), // - - // Tandem - TandemTSlim("Tandem t:slim", ManufacturerType.Tandem, "t:slim", 0.01d, null, // - new DoseSettings(0.01d, 15, 8 * 60, 0.4d), - PumpTempBasalType.Percent, - new DoseSettings(1, 15, 8 * 60, 0d, 250d), PumpCapability.BasalRate_Duration15and30minAllowed, // - 0.1d, 0.001d, null, PumpCapability.VirtualPumpCapabilities), - - TandemTFlex("Tandem t:flex", "t:flex", TandemTSlim), // - TandemTSlimG4("Tandem t:slim G4", "t:slim G4", TandemTSlim), // - TandemTSlimX2("Tandem t:slim X2", "t:slim X2", TandemTSlim), // - - // Ypsomed/myLife - YpsoPump("YpsoPump", ManufacturerType.Ypsomed, "Ypsopump", 0.1d, null, // - new DoseSettings(0.1d, 15, 12 * 60, 0.1d), // - PumpTempBasalType.Percent, - new DoseSettings(1, 15, 24 * 60, 0d, 500d), PumpCapability.BasalRate_Duration15and30minAllowed, // - 0.02d, 40.0d, 0.01d, DoseStepSize.YpsopumpBasal, PumpCapability.YpsomedCapabilities), - - - // MDI - MDI("MDI", ManufacturerType.AndroidAPS, "MDI"); - - - private final String description; - private ManufacturerType manufacturer; - private String model; - private double bolusSize; - private DoseStepSize specialBolusSize; - private DoseSettings extendedBolusSettings; - private PumpTempBasalType pumpTempBasalType; - private DoseSettings tbrSettings; - private PumpCapability specialBasalDurations; - private double baseBasalMinValue; // - private Double baseBasalMaxValue; - private double baseBasalStep; // - private DoseStepSize baseBasalSpecialSteps; // - private PumpCapability pumpCapability; - private boolean hasCustomUnreachableAlertCheck; - - private PumpType parent; - private static final Map mapByDescription; - - static { - mapByDescription = new HashMap<>(); - - for (PumpType pumpType : values()) { - mapByDescription.put(pumpType.getDescription(), pumpType); - } - } - - - PumpType(String description, String model, PumpType parent) { - this.description = description; - this.parent = parent; - this.model = model; - } - - - PumpType(String description, ManufacturerType manufacturer, String model) { - this.description = description; - this.manufacturer = manufacturer; - this.model = model; - } - - - PumpType(String description, String model, PumpType parent, PumpCapability pumpCapability) { - this.description = description; - this.parent = parent; - this.pumpCapability = pumpCapability; - parent.model = model; - } - - PumpType(String description, - ManufacturerType manufacturer, - String model, - double bolusSize, - DoseStepSize specialBolusSize, // - DoseSettings extendedBolusSettings, // - PumpTempBasalType pumpTempBasalType, - DoseSettings tbrSettings, - PumpCapability specialBasalDurations, // - double baseBasalMinValue, - double baseBasalStep, - DoseStepSize baseBasalSpecialSteps, - PumpCapability pumpCapability) { - this(description, manufacturer, model, bolusSize, specialBolusSize, extendedBolusSettings, pumpTempBasalType, tbrSettings, specialBasalDurations, baseBasalMinValue, null, baseBasalStep, baseBasalSpecialSteps, pumpCapability); - } - - PumpType(String description, - ManufacturerType manufacturer, - String model, - double bolusSize, - DoseStepSize specialBolusSize, // - DoseSettings extendedBolusSettings, // - PumpTempBasalType pumpTempBasalType, - DoseSettings tbrSettings, - PumpCapability specialBasalDurations, // - double baseBasalMinValue, - Double baseBasalMaxValue, - double baseBasalStep, - DoseStepSize baseBasalSpecialSteps, - PumpCapability pumpCapability) { - this(description, manufacturer, model, bolusSize, specialBolusSize, extendedBolusSettings, pumpTempBasalType, - tbrSettings, specialBasalDurations, baseBasalMinValue, null, baseBasalStep, - baseBasalSpecialSteps, pumpCapability, false); - } - - - PumpType(String description, - ManufacturerType manufacturer, - String model, - double bolusSize, - DoseStepSize specialBolusSize, // - DoseSettings extendedBolusSettings, // - PumpTempBasalType pumpTempBasalType, - DoseSettings tbrSettings, - PumpCapability specialBasalDurations, // - double baseBasalMinValue, - Double baseBasalMaxValue, - double baseBasalStep, - DoseStepSize baseBasalSpecialSteps, // - PumpCapability pumpCapability, - boolean hasCustomUnreachableAlertCheck) { - this.description = description; - this.manufacturer = manufacturer; - this.model = model; - this.bolusSize = bolusSize; - this.specialBolusSize = specialBolusSize; - this.extendedBolusSettings = extendedBolusSettings; - this.pumpTempBasalType = pumpTempBasalType; - this.tbrSettings = tbrSettings; - this.specialBasalDurations = specialBasalDurations; - this.baseBasalMinValue = baseBasalMinValue; - this.baseBasalMaxValue = baseBasalMaxValue; - this.baseBasalStep = baseBasalStep; - this.baseBasalSpecialSteps = baseBasalSpecialSteps; - this.pumpCapability = pumpCapability; - this.hasCustomUnreachableAlertCheck = hasCustomUnreachableAlertCheck; - } - - public boolean getHasCustomUnreachableAlertCheck() { - return hasCustomUnreachableAlertCheck; - } - - public String getDescription() { - return description; - } - - public ManufacturerType getManufacturer() { - return isParentSet() ? parent.manufacturer : manufacturer; - } - - public String getModel() { - return isParentSet() ? parent.model : model; - } - - public PumpCapability getPumpCapability() { - - if (isParentSet()) - return this.pumpCapability == null ? parent.pumpCapability : pumpCapability; - else - return this.pumpCapability; - } - - public double getBolusSize() { - return isParentSet() ? parent.bolusSize : bolusSize; - } - - - public DoseStepSize getSpecialBolusSize() { - return isParentSet() ? parent.specialBolusSize : specialBolusSize; - } - - - public DoseSettings getExtendedBolusSettings() { - return isParentSet() ? parent.extendedBolusSettings : extendedBolusSettings; - } - - - public PumpTempBasalType getPumpTempBasalType() { - return isParentSet() ? parent.pumpTempBasalType : pumpTempBasalType; - } - - - public DoseSettings getTbrSettings() { - return isParentSet() ? parent.tbrSettings : tbrSettings; - } - - - public double getBaseBasalMinValue() { - return isParentSet() ? parent.baseBasalMinValue : baseBasalMinValue; - } - - - public Double getBaseBasalMaxValue() { - return isParentSet() ? parent.baseBasalMaxValue : baseBasalMaxValue; - } - - - public double getBaseBasalStep() { - return isParentSet() ? parent.baseBasalStep : baseBasalStep; - } - - - public DoseStepSize getBaseBasalSpecialSteps() { - return isParentSet() ? parent.baseBasalSpecialSteps : baseBasalSpecialSteps; - } - - - public PumpType getParent() { - return parent; - } - - - private boolean isParentSet() { - return this.parent != null; - } - - - public static PumpType getByDescription(String desc) { - if (mapByDescription.containsKey(desc)) { - return mapByDescription.get(desc); - } else { - return PumpType.GenericAAPS; - } - } - - - public String getFullDescription(String i18nTemplate, boolean hasExtendedBasals, ResourceHelper resourceHelper) { - - String unit = getPumpTempBasalType() == PumpTempBasalType.Percent ? "%" : ""; - - DoseSettings eb = getExtendedBolusSettings(); - DoseSettings tbr = getTbrSettings(); - - String extendedNote = hasExtendedBasals ? resourceHelper.gs(R.string.def_extended_note) : ""; - - return String.format(i18nTemplate, // - getStep("" + getBolusSize(), getSpecialBolusSize()), // - eb.getStep(), eb.getDurationStep(), eb.getMaxDuration() / 60, // - getStep(getBaseBasalRange(), getBaseBasalSpecialSteps()), // - tbr.getMinDose() + unit + "-" + tbr.getMaxDose() + unit, tbr.getStep() + unit, - tbr.getDurationStep(), tbr.getMaxDuration() / 60, extendedNote); - } - - - private String getBaseBasalRange() { - Double maxValue = getBaseBasalMaxValue(); - - return maxValue == null ? "" + getBaseBasalMinValue() : getBaseBasalMinValue() + "-" + maxValue; - } - - - private String getStep(String step, DoseStepSize stepSize) { - if (stepSize != null) - return step + " [" + stepSize.getDescription() + "] *"; - else - return "" + step; - } - - - public boolean hasExtendedBasals() { - return ((getBaseBasalSpecialSteps() != null) || (getSpecialBolusSize() != null)); - } - - - public PumpCapability getSpecialBasalDurations() { - - if (isParentSet()) { - return parent.getSpecialBasalDurations(); - } else { - return specialBasalDurations == null ? // - PumpCapability.BasalRate_Duration15and30minNotAllowed : specialBasalDurations; - } - } - - public double determineCorrectBolusSize(double bolusAmount) { - if (bolusAmount == 0.0d) { - return bolusAmount; - } - - double bolusStepSize = getBolusSize(); - - if (getSpecialBolusSize() != null) { - DoseStepSize specialBolusSize = getSpecialBolusSize(); - bolusStepSize = specialBolusSize.getStepSizeForAmount(bolusAmount); - } - - return Round.roundTo(bolusAmount, bolusStepSize); - } - - - public double determineCorrectBolusStepSize(double bolusAmount) { - DoseStepSize specialBolusSize = getSpecialBolusSize(); - if (specialBolusSize != null) - return specialBolusSize.getStepSizeForAmount(bolusAmount); - return getBolusSize(); - } - - public double determineCorrectExtendedBolusSize(double bolusAmount) { - if (bolusAmount == 0.0d) { - return bolusAmount; - } - - double bolusStepSize; - - if (getExtendedBolusSettings() == null) { // this should be never null - return 0.0d; - } - - DoseSettings extendedBolusSettings = getExtendedBolusSettings(); - - bolusStepSize = extendedBolusSettings.getStep(); - - if (bolusAmount > extendedBolusSettings.getMaxDose()) { - bolusAmount = extendedBolusSettings.getMaxDose(); - } - - return Round.roundTo(bolusAmount, bolusStepSize); - } - - - public double determineCorrectBasalSize(double basalAmount) { - if (basalAmount == 0.0d) { - return basalAmount; - } - - double basalStepSize; - - if (getBaseBasalSpecialSteps() == null) { - basalStepSize = getBaseBasalStep(); - } else { - DoseStepSize specialBolusSize = getBaseBasalSpecialSteps(); - - basalStepSize = specialBolusSize.getStepSizeForAmount(basalAmount); - } - - if (basalAmount > getTbrSettings().getMaxDose()) - basalAmount = getTbrSettings().getMaxDose().doubleValue(); - - return Round.roundTo(basalAmount, basalStepSize); - - } -} diff --git a/core/src/main/java/info/nightscout/androidaps/plugins/pump/common/defs/PumpType.kt b/core/src/main/java/info/nightscout/androidaps/plugins/pump/common/defs/PumpType.kt new file mode 100644 index 0000000000..d372c84c6b --- /dev/null +++ b/core/src/main/java/info/nightscout/androidaps/plugins/pump/common/defs/PumpType.kt @@ -0,0 +1,448 @@ +package info.nightscout.androidaps.plugins.pump.common.defs + +import info.nightscout.androidaps.core.R +import info.nightscout.androidaps.database.embedments.InterfaceIDs +import info.nightscout.androidaps.plugins.common.ManufacturerType +import info.nightscout.androidaps.utils.Round +import info.nightscout.androidaps.utils.resources.ResourceHelper +import kotlin.math.min + +@Suppress("unused") +enum class PumpType { + + GENERIC_AAPS(description = "Generic AAPS", + manufacturer = ManufacturerType.AndroidAPS, + model = "VirtualPump", + bolusSize = 0.1, + specialBolusSize = null, + extendedBolusSettings = DoseSettings(0.05, 30, 8 * 60, 0.05), + pumpTempBasalType = PumpTempBasalType.Percent, + tbrSettings = DoseSettings(10.0, 30, 24 * 60, 0.0, 500.0), + specialBasalDurations = PumpCapability.BasalRate_Duration15and30minAllowed, + baseBasalMinValue = 0.01, + baseBasalStep = 0.01, + baseBasalSpecialSteps = null, + pumpCapability = PumpCapability.VirtualPumpCapabilities), + + CELLNOVO(description = "Cellnovo", + manufacturer = ManufacturerType.Cellnovo, + model = "Cellnovo", + bolusSize = 0.05, + specialBolusSize = null, + extendedBolusSettings = DoseSettings(0.05, 30, 24 * 60, 1.0), + pumpTempBasalType = PumpTempBasalType.Percent, + tbrSettings = DoseSettings(5.0, 30, 24 * 60, 0.0, 200.0), + specialBasalDurations = PumpCapability.BasalRate_Duration30minAllowed, + baseBasalMinValue = 0.05, + baseBasalStep = 0.05, + baseBasalSpecialSteps = null, + pumpCapability = PumpCapability.VirtualPumpCapabilities), + + ACCU_CHEK_COMBO(description = "Accu-Chek Combo", + manufacturer = ManufacturerType.Roche, + model = "Combo", + bolusSize = 0.1, + specialBolusSize = null, + extendedBolusSettings = DoseSettings(0.1, 15, 12 * 60, 0.1), + pumpTempBasalType = PumpTempBasalType.Percent, + tbrSettings = DoseSettings(10.0, 15, 12 * 60, 0.0, 500.0), + specialBasalDurations = PumpCapability.BasalRate_Duration15and30minAllowed, + baseBasalMinValue = 0.01, + baseBasalStep = 0.01, + baseBasalSpecialSteps = DoseStepSize.ComboBasal, + pumpCapability = PumpCapability.ComboCapabilities), + ACCU_CHEK_SPIRIT(description = "Accu-Chek Spirit", + manufacturer = ManufacturerType.Roche, + model = "Spirit", + bolusSize = 0.1, + specialBolusSize = null, + extendedBolusSettings = DoseSettings(0.1, 15, 12 * 60, 0.1), + pumpTempBasalType = PumpTempBasalType.Percent, + tbrSettings = DoseSettings(10.0, 15, 12 * 60, 0.0, 500.0), + specialBasalDurations = PumpCapability.BasalRate_Duration15and30minAllowed, + baseBasalMinValue = 0.01, + baseBasalStep = 0.1, + baseBasalSpecialSteps = null, + pumpCapability = PumpCapability.VirtualPumpCapabilities), + ACCU_CHEK_INSIGHT(description = "Accu-Chek Insight", + manufacturer = ManufacturerType.Roche, + model = "Insight", + bolusSize = 0.05, + specialBolusSize = DoseStepSize.InsightBolus, + extendedBolusSettings = DoseSettings(0.05, 15, 24 * 60, 0.05), + pumpTempBasalType = PumpTempBasalType.Percent, + tbrSettings = DoseSettings(10.0, 15, 24 * 60, 0.0, 250.0), + specialBasalDurations = PumpCapability.BasalRate_Duration15and30minAllowed, + baseBasalMinValue = 0.02, + baseBasalStep = 0.01, + baseBasalSpecialSteps = null, + pumpCapability = PumpCapability.InsightCapabilities), + ACCU_CHEK_INSIGHT_BLUETOOTH(description = "Accu-Chek Insight", + manufacturer = ManufacturerType.Roche, + model = "Insight", + bolusSize = 0.01, + specialBolusSize = null, + extendedBolusSettings = DoseSettings(0.01, 15, 24 * 60, 0.05), + pumpTempBasalType = PumpTempBasalType.Percent, + tbrSettings = DoseSettings(10.0, 15, 24 * 60, 0.0, 250.0), + specialBasalDurations = PumpCapability.BasalRate_Duration15and30minAllowed, + baseBasalMinValue = 0.02, + baseBasalMaxValue = null, + baseBasalStep = 0.01, + baseBasalSpecialSteps = DoseStepSize.InsightBolus, + pumpCapability = PumpCapability.InsightCapabilities), + ACCU_CHEK_SOLO(description = "Accu-Chek Solo", + manufacturer = ManufacturerType.Roche, + model = "Solo", + bolusSize = 0.01, + specialBolusSize = null, + extendedBolusSettings = DoseSettings(0.01, 15, 24 * 60, 0.05), + pumpTempBasalType = PumpTempBasalType.Percent, + tbrSettings = DoseSettings(10.0, 15, 24 * 60, 0.0, 250.0), + specialBasalDurations = PumpCapability.BasalRate_Duration15and30minAllowed, + baseBasalMinValue = 0.02, + baseBasalMaxValue = null, + baseBasalStep = 0.01, + baseBasalSpecialSteps = DoseStepSize.InsightBolus, + pumpCapability = PumpCapability.InsightCapabilities), + + ANIMAS_VIBE(description = "Animas Vibe", + manufacturer = ManufacturerType.Animas, + model = "Vibe", + bolusSize = 0.05, + specialBolusSize = null, + extendedBolusSettings = DoseSettings(0.05, 30, 12 * 60, 0.05), + pumpTempBasalType = PumpTempBasalType.Percent, + tbrSettings = DoseSettings(10.0, 30, 24 * 60, 0.0, 300.0), + specialBasalDurations = PumpCapability.BasalRate_Duration30minAllowed, + baseBasalMinValue = 0.025, + baseBasalMaxValue = 5.0, + baseBasalStep = 0.0, + baseBasalSpecialSteps = null, + pumpCapability = PumpCapability.VirtualPumpCapabilities), + ANIMAS_PING(description = "Animas Ping", model = "Ping", parent = ANIMAS_VIBE), + DANA_R(description = "DanaR", + manufacturer = ManufacturerType.Sooil, + model = "DanaR", + bolusSize = 0.05, + specialBolusSize = null, + extendedBolusSettings = DoseSettings(0.05, 30, 8 * 60, 0.05), + pumpTempBasalType = PumpTempBasalType.Percent, + tbrSettings = DoseSettings(10.0, 60, 24 * 60, 0.0, 200.0), + specialBasalDurations = PumpCapability.BasalRate_Duration15and30minNotAllowed, + baseBasalMinValue = 0.04, + baseBasalStep = 0.01, + baseBasalSpecialSteps = null, + pumpCapability = PumpCapability.DanaCapabilities), + DANA_R_KOREAN(description = "DanaR Korean", + manufacturer = ManufacturerType.Sooil, + model = "DanaRKorean", + bolusSize = 0.05, + specialBolusSize = null, + extendedBolusSettings = DoseSettings(0.05, 30, 8 * 60, 0.05), + pumpTempBasalType = PumpTempBasalType.Percent, + tbrSettings = DoseSettings(10.0, 60, 24 * 60, 0.0, 200.0), + specialBasalDurations = PumpCapability.BasalRate_Duration15and30minNotAllowed, + baseBasalMinValue = 0.1, + baseBasalStep = 0.01, + baseBasalSpecialSteps = null, + pumpCapability = PumpCapability.DanaCapabilities), + DANA_RS(description = "DanaRS", + manufacturer = ManufacturerType.Sooil, + model = "DanaRS", + bolusSize = 0.05, + specialBolusSize = null, + extendedBolusSettings = DoseSettings(0.05, 30, 8 * 60, 0.05), + pumpTempBasalType = PumpTempBasalType.Percent, + tbrSettings = DoseSettings(10.0, 60, 24 * 60, 0.0, 200.0), + specialBasalDurations = PumpCapability.BasalRate_Duration15and30minAllowed, + baseBasalMinValue = 0.04, + baseBasalStep = 0.01, + baseBasalSpecialSteps = null, + pumpCapability = PumpCapability.DanaWithHistoryCapabilities), + DANA_RS_KOREAN(description = "DanaRSKorean", model = "DanaRSKorean", parent = DANA_RS), + DANA_I(description = "DanaI", model = "DanaI", parent = DANA_RS), + DANA_RV2(description = "DanaRv2", model = "DanaRv2", parent = DANA_RS), + OMNIPOD_EROS(description = "Omnipod Eros", + manufacturer = ManufacturerType.Insulet, + model = "Eros", + bolusSize = 0.05, + specialBolusSize = null, + extendedBolusSettings = DoseSettings(0.05, 30, 8 * 60, 0.05), + pumpTempBasalType = PumpTempBasalType.Absolute, + tbrSettings = DoseSettings(0.05, 30, 12 * 60, 0.0, 30.0), + specialBasalDurations = PumpCapability.BasalRate_Duration30minAllowed, + baseBasalMinValue = 0.05, + baseBasalMaxValue = null, + baseBasalStep = 0.05, + baseBasalSpecialSteps = null, + pumpCapability = PumpCapability.OmnipodCapabilities, + hasCustomUnreachableAlertCheck = true), + OMNIPOD_DASH(description = "Omnipod Dash", + manufacturer = ManufacturerType.Insulet, + model = "Dash", + bolusSize = 0.05, + specialBolusSize = null, + extendedBolusSettings = DoseSettings(0.05, 30, 8 * 60, 0.05), + pumpTempBasalType = PumpTempBasalType.Absolute, + tbrSettings = DoseSettings(0.05, 30, 12 * 60, 0.0, 30.0), + specialBasalDurations = PumpCapability.BasalRate_Duration30minAllowed, + baseBasalMinValue = 0.05, + baseBasalMaxValue = null, + baseBasalStep = 0.05, + baseBasalSpecialSteps = null, + pumpCapability = PumpCapability.OmnipodCapabilities, + hasCustomUnreachableAlertCheck = false), + MEDTRONIC_512_712(description = "Medtronic 512/712", + manufacturer = ManufacturerType.Medtronic, + model = "512/712", + bolusSize = 0.1, + specialBolusSize = null, + extendedBolusSettings = DoseSettings(0.05, 30, 8 * 60, 0.05), + pumpTempBasalType = PumpTempBasalType.Absolute, + tbrSettings = DoseSettings(0.05, 30, 24 * 60, 0.0, 35.0), + specialBasalDurations = PumpCapability.BasalRate_Duration30minAllowed, + baseBasalMinValue = 0.05, + baseBasalStep = 0.05, + baseBasalSpecialSteps = null, + pumpCapability = PumpCapability.MedtronicCapabilities), + MEDTRONIC_515_715(description = "Medtronic 515/715", + model = "515/715", + parent = MEDTRONIC_512_712), + MEDTRONIC_522_722(description = "Medtronic 522/722", + model = "522/722", + parent = MEDTRONIC_512_712), + MEDTRONIC_523_723_REVEL(description = "Medtronic 523/723 (Revel)", + manufacturer = ManufacturerType.Medtronic, + model = "523/723 (Revel)", + bolusSize = 0.05, + specialBolusSize = null, + extendedBolusSettings = DoseSettings(0.05, 30, 8 * 60, 0.05), + pumpTempBasalType = PumpTempBasalType.Absolute, + tbrSettings = DoseSettings(0.05, 30, 24 * 60, 0.0, 35.0), + specialBasalDurations = PumpCapability.BasalRate_Duration30minAllowed, + baseBasalMinValue = 0.025, + baseBasalStep = 0.025, + baseBasalSpecialSteps = DoseStepSize.MedtronicVeoBasal, + pumpCapability = PumpCapability.MedtronicCapabilities), + MEDTRONIC_554_754_VEO(description = "Medtronic 554/754 (Veo)", model = "554/754 (Veo)", parent = MEDTRONIC_523_723_REVEL), + MEDTRONIC_640G(description = "Medtronic 640G", + manufacturer = ManufacturerType.Medtronic, + model = "640G", + bolusSize = 0.025, + specialBolusSize = null, + extendedBolusSettings = DoseSettings(0.05, 30, 8 * 60, 0.05), + pumpTempBasalType = PumpTempBasalType.Absolute, + tbrSettings = DoseSettings(0.05, 30, 24 * 60, 0.0, 35.0), + specialBasalDurations = PumpCapability.BasalRate_Duration30minAllowed, + baseBasalMinValue = 0.025, + baseBasalStep = 0.025, + baseBasalSpecialSteps = DoseStepSize.MedtronicVeoBasal, + pumpCapability = PumpCapability.VirtualPumpCapabilities), + + TANDEM_T_SLIM(description = "Tandem t:slim", + manufacturer = ManufacturerType.Tandem, + model = "t:slim", + bolusSize = 0.01, + specialBolusSize = null, + extendedBolusSettings = DoseSettings(0.01, 15, 8 * 60, 0.4), + pumpTempBasalType = PumpTempBasalType.Percent, + tbrSettings = DoseSettings(1.0, 15, 8 * 60, 0.0, 250.0), + specialBasalDurations = PumpCapability.BasalRate_Duration15and30minAllowed, + baseBasalMinValue = 0.1, + baseBasalStep = 0.001, + baseBasalSpecialSteps = null, + pumpCapability = PumpCapability.VirtualPumpCapabilities), + TANDEM_T_FLEX(description = "Tandem t:flex", model = "t:flex", parent = TANDEM_T_SLIM), + TANDEM_T_SLIM_G4(description = "Tandem t:slim G4", model = "t:slim G4", parent = TANDEM_T_SLIM), + TANDEM_T_SLIM_X2(description = "Tandem t:slim X2", model = "t:slim X2", parent = TANDEM_T_SLIM), + + YPSOPUMP(description = "YpsoPump", + manufacturer = ManufacturerType.Ypsomed, + model = "Ypsopump", + bolusSize = 0.1, + specialBolusSize = null, + extendedBolusSettings = DoseSettings(0.1, 15, 12 * 60, 0.1), + pumpTempBasalType = PumpTempBasalType.Percent, + tbrSettings = DoseSettings(1.0, 15, 24 * 60, 0.0, 500.0), + specialBasalDurations = PumpCapability.BasalRate_Duration15and30minAllowed, + baseBasalMinValue = 0.02, + baseBasalMaxValue = 40.0, + baseBasalStep = 0.01, + baseBasalSpecialSteps = DoseStepSize.YpsopumpBasal, + pumpCapability = PumpCapability.YpsomedCapabilities), + MDI(description = "MDI", + manufacturer = ManufacturerType.AndroidAPS, + model = "MDI", + tbrSettings = DoseSettings(1.0, 15, 24 * 60, 0.0, 500.0), + extendedBolusSettings = DoseSettings(0.1, 15, 12 * 60, 0.1), + pumpCapability = PumpCapability.MDI), + + // Not real pump. Used for User as a source + USER(description = "USER", + manufacturer = ManufacturerType.AndroidAPS, + model = "USER", + tbrSettings = DoseSettings(1.0, 15, 24 * 60, 0.0, 500.0), + extendedBolusSettings = DoseSettings(0.1, 15, 12 * 60, 0.1), + pumpCapability = PumpCapability.MDI); + + val description: String + var manufacturer: ManufacturerType? = null + get() = parent?.manufacturer ?: field + private set + var model: String = "NONE" + get() = parent?.model ?: field + private set + var bolusSize = 0.0 + get() = parent?.bolusSize ?: field + private var specialBolusSize: DoseStepSize? = null + get() = parent?.specialBolusSize ?: field + var extendedBolusSettings: DoseSettings? = null + get() = parent?.extendedBolusSettings ?: field + private set + var pumpTempBasalType: PumpTempBasalType? = null + get() = parent?.pumpTempBasalType ?: field + private set + var tbrSettings: DoseSettings? = null + get() = parent?.tbrSettings ?: field + private set + var specialBasalDurations: PumpCapability? = null + get() = parent?.specialBasalDurations ?: field + ?: PumpCapability.BasalRate_Duration15and30minNotAllowed + private set + var baseBasalMinValue = 0.01 + get() = parent?.baseBasalMinValue ?: field + private set + private var baseBasalMaxValue: Double? = null + get() = parent?.baseBasalMaxValue ?: field + var baseBasalStep = 1.0 + get() = parent?.baseBasalStep ?: field + private set + private var baseBasalSpecialSteps: DoseStepSize? = null + get() = parent?.baseBasalSpecialSteps ?: field + var pumpCapability: PumpCapability? = null + get() = parent?.pumpCapability ?: field + private set + var hasCustomUnreachableAlertCheck = false + private set + private var parent: PumpType? = null + + companion object { + + fun getByDescription(desc: String): PumpType = + values().firstOrNull { it.description == desc } ?: GENERIC_AAPS + } + + constructor(description: String, model: String, parent: PumpType, pumpCapability: PumpCapability? = null) { + this.description = description + this.parent = parent + this.pumpCapability = pumpCapability + parent.model = model + } + + constructor(description: String, + manufacturer: ManufacturerType, + model: String, + bolusSize: Double = 0.0, + specialBolusSize: DoseStepSize? = null, + extendedBolusSettings: DoseSettings, + pumpTempBasalType: PumpTempBasalType? = null, + tbrSettings: DoseSettings, + specialBasalDurations: PumpCapability? = null, + baseBasalMinValue: Double = 0.01, + baseBasalMaxValue: Double? = null, + baseBasalStep: Double = 1.0, + baseBasalSpecialSteps: DoseStepSize? = null, + pumpCapability: PumpCapability, + hasCustomUnreachableAlertCheck: Boolean = false) { + this.description = description + this.manufacturer = manufacturer + this.model = model + this.bolusSize = bolusSize + this.specialBolusSize = specialBolusSize + this.extendedBolusSettings = extendedBolusSettings + this.pumpTempBasalType = pumpTempBasalType + this.tbrSettings = tbrSettings + this.specialBasalDurations = specialBasalDurations + this.baseBasalMinValue = baseBasalMinValue + this.baseBasalMaxValue = baseBasalMaxValue + this.baseBasalStep = baseBasalStep + this.baseBasalSpecialSteps = baseBasalSpecialSteps + this.pumpCapability = pumpCapability + this.hasCustomUnreachableAlertCheck = hasCustomUnreachableAlertCheck + } + + fun getFullDescription(i18nTemplate: String, hasExtendedBasals: Boolean, resourceHelper: ResourceHelper): String { + val unit = if (pumpTempBasalType == PumpTempBasalType.Percent) "%" else "" + val eb = extendedBolusSettings ?: return "INVALID" + val tbr = tbrSettings ?: return "INVALID" + val extendedNote = if (hasExtendedBasals) resourceHelper.gs(R.string.def_extended_note) else "" + return String.format(i18nTemplate, + getStep("" + bolusSize, specialBolusSize), + eb.step, eb.durationStep, eb.maxDuration / 60, + getStep(baseBasalRange(), baseBasalSpecialSteps), + tbr.minDose.toString() + unit + "-" + tbr.maxDose + unit, tbr.step.toString() + unit, + tbr.durationStep, tbr.maxDuration / 60, extendedNote) + } + + private fun baseBasalRange(): String = + if (baseBasalMaxValue == null) baseBasalMinValue.toString() + else baseBasalMinValue.toString() + "-" + baseBasalMaxValue.toString() + + private fun getStep(step: String, stepSize: DoseStepSize?): String = + if (stepSize != null) step + " [" + stepSize.description + "] *" + else step + + fun hasExtendedBasals(): Boolean = baseBasalSpecialSteps != null || specialBolusSize != null + + fun determineCorrectBolusSize(bolusAmount: Double): Double = + Round.roundTo(bolusAmount, specialBolusSize?.getStepSizeForAmount(bolusAmount) ?: bolusSize) + + fun determineCorrectBolusStepSize(bolusAmount: Double): Double = + specialBolusSize?.getStepSizeForAmount(bolusAmount) ?: bolusSize + + fun determineCorrectExtendedBolusSize(bolusAmount: Double): Double { + val ebSettings = extendedBolusSettings ?: throw IllegalStateException() + return Round.roundTo(min(bolusAmount, ebSettings.maxDose), ebSettings.step) + } + + fun determineCorrectBasalSize(basalAmount: Double): Double { + val tSettings = tbrSettings ?: throw IllegalStateException() + return Round.roundTo(min(basalAmount, tSettings.maxDose), baseBasalSpecialSteps?.getStepSizeForAmount(basalAmount) + ?: baseBasalStep) + } + + fun toDbPumpType(): InterfaceIDs.PumpType = + when (this) { + GENERIC_AAPS -> InterfaceIDs.PumpType.GENERIC_AAPS + CELLNOVO -> InterfaceIDs.PumpType.CELLNOVO + ACCU_CHEK_COMBO -> InterfaceIDs.PumpType.ACCU_CHEK_COMBO + ACCU_CHEK_SPIRIT -> InterfaceIDs.PumpType.ACCU_CHEK_SPIRIT + ACCU_CHEK_INSIGHT -> InterfaceIDs.PumpType.ACCU_CHEK_INSIGHT + ACCU_CHEK_INSIGHT_BLUETOOTH -> InterfaceIDs.PumpType.ACCU_CHEK_INSIGHT_BLUETOOTH + ACCU_CHEK_SOLO -> InterfaceIDs.PumpType.ACCU_CHEK_SOLO + ANIMAS_VIBE -> InterfaceIDs.PumpType.ANIMAS_VIBE + ANIMAS_PING -> InterfaceIDs.PumpType.ANIMAS_PING + DANA_R -> InterfaceIDs.PumpType.DANA_R + DANA_R_KOREAN -> InterfaceIDs.PumpType.DANA_R_KOREAN + DANA_RS -> InterfaceIDs.PumpType.DANA_RS + DANA_RS_KOREAN -> InterfaceIDs.PumpType.DANA_RS_KOREAN + DANA_RV2 -> InterfaceIDs.PumpType.DANA_RV2 + DANA_I -> InterfaceIDs.PumpType.DANA_I + OMNIPOD_EROS -> InterfaceIDs.PumpType.OMNIPOD_EROS + OMNIPOD_DASH -> InterfaceIDs.PumpType.OMNIPOD_DASH + MEDTRONIC_512_712 -> InterfaceIDs.PumpType.MEDTRONIC_512_517 + MEDTRONIC_515_715 -> InterfaceIDs.PumpType.MEDTRONIC_515_715 + MEDTRONIC_522_722 -> InterfaceIDs.PumpType.MEDTRONIC_522_722 + MEDTRONIC_523_723_REVEL -> InterfaceIDs.PumpType.MEDTRONIC_523_723_REVEL + MEDTRONIC_554_754_VEO -> InterfaceIDs.PumpType.MEDTRONIC_554_754_VEO + MEDTRONIC_640G -> InterfaceIDs.PumpType.MEDTRONIC_640G + TANDEM_T_SLIM -> InterfaceIDs.PumpType.TANDEM_T_SLIM + TANDEM_T_SLIM_G4 -> InterfaceIDs.PumpType.TANDEM_T_SLIM_G4 + TANDEM_T_FLEX -> InterfaceIDs.PumpType.TANDEM_T_FLEX + TANDEM_T_SLIM_X2 -> InterfaceIDs.PumpType.TANDEM_T_SLIM_X2 + YPSOPUMP -> InterfaceIDs.PumpType.YPSOPUMP + MDI -> InterfaceIDs.PumpType.MDI + USER -> InterfaceIDs.PumpType.USER + } +} \ No newline at end of file diff --git a/core/src/main/java/info/nightscout/androidaps/plugins/treatments/TreatmentUpdateReturn.java b/core/src/main/java/info/nightscout/androidaps/plugins/treatments/TreatmentUpdateReturn.java index 42b71b0217..c56a1c4441 100644 --- a/core/src/main/java/info/nightscout/androidaps/plugins/treatments/TreatmentUpdateReturn.java +++ b/core/src/main/java/info/nightscout/androidaps/plugins/treatments/TreatmentUpdateReturn.java @@ -1,7 +1,5 @@ package info.nightscout.androidaps.plugins.treatments; -import info.nightscout.androidaps.db.Treatment; - public class TreatmentUpdateReturn { public TreatmentUpdateReturn(boolean success, boolean newRecord) { diff --git a/core/src/main/java/info/nightscout/androidaps/queue/commands/Command.kt b/core/src/main/java/info/nightscout/androidaps/queue/commands/Command.kt index 1b90b24da4..0692ac68e3 100644 --- a/core/src/main/java/info/nightscout/androidaps/queue/commands/Command.kt +++ b/core/src/main/java/info/nightscout/androidaps/queue/commands/Command.kt @@ -3,6 +3,7 @@ package info.nightscout.androidaps.queue.commands import dagger.android.HasAndroidInjector import info.nightscout.androidaps.core.R import info.nightscout.androidaps.data.PumpEnactResult +import info.nightscout.androidaps.database.AppRepository import info.nightscout.androidaps.logging.AAPSLogger import info.nightscout.androidaps.logging.LTag import info.nightscout.androidaps.queue.Callback @@ -17,6 +18,7 @@ abstract class Command( @Inject lateinit var aapsLogger: AAPSLogger @Inject lateinit var resourceHelper: ResourceHelper + @Inject lateinit var repository: AppRepository enum class CommandType { BOLUS, diff --git a/core/src/main/java/info/nightscout/androidaps/receivers/ReceiverStatusStore.kt b/core/src/main/java/info/nightscout/androidaps/receivers/ReceiverStatusStore.kt index 897360a01b..30090d386f 100644 --- a/core/src/main/java/info/nightscout/androidaps/receivers/ReceiverStatusStore.kt +++ b/core/src/main/java/info/nightscout/androidaps/receivers/ReceiverStatusStore.kt @@ -9,7 +9,7 @@ import javax.inject.Inject import javax.inject.Singleton @Singleton -open class ReceiverStatusStore @Inject constructor(val context: Context, val rxBus: RxBusWrapper) { +class ReceiverStatusStore @Inject constructor(val context: Context, val rxBus: RxBusWrapper) { var lastNetworkEvent: EventNetworkChange? = null diff --git a/core/src/main/java/info/nightscout/androidaps/services/AlarmSoundService.kt b/core/src/main/java/info/nightscout/androidaps/services/AlarmSoundService.kt index 4c6ce89400..6480189f41 100644 --- a/core/src/main/java/info/nightscout/androidaps/services/AlarmSoundService.kt +++ b/core/src/main/java/info/nightscout/androidaps/services/AlarmSoundService.kt @@ -10,7 +10,7 @@ import android.os.IBinder import dagger.android.DaggerService import info.nightscout.androidaps.activities.ErrorHelperActivity import info.nightscout.androidaps.core.R -import info.nightscout.androidaps.interfaces.NotificationHolderInterface +import info.nightscout.androidaps.interfaces.NotificationHolder import info.nightscout.androidaps.logging.AAPSLogger import info.nightscout.androidaps.logging.LTag import info.nightscout.androidaps.utils.resources.ResourceHelper @@ -23,7 +23,7 @@ class AlarmSoundService : DaggerService() { @Inject lateinit var aapsLogger: AAPSLogger @Inject lateinit var resourceHelper: ResourceHelper - @Inject lateinit var notificationHolder: NotificationHolderInterface + @Inject lateinit var notificationHolder: NotificationHolder @Inject lateinit var sp: SP private var player: MediaPlayer? = null diff --git a/core/src/main/java/info/nightscout/androidaps/services/AlarmSoundServiceHelper.kt b/core/src/main/java/info/nightscout/androidaps/services/AlarmSoundServiceHelper.kt index 5da7968e88..f045f876ea 100644 --- a/core/src/main/java/info/nightscout/androidaps/services/AlarmSoundServiceHelper.kt +++ b/core/src/main/java/info/nightscout/androidaps/services/AlarmSoundServiceHelper.kt @@ -6,7 +6,7 @@ import android.content.Intent import android.content.ServiceConnection import android.os.IBinder import info.nightscout.androidaps.activities.ErrorHelperActivity -import info.nightscout.androidaps.interfaces.NotificationHolderInterface +import info.nightscout.androidaps.interfaces.NotificationHolder import info.nightscout.androidaps.logging.AAPSLogger import info.nightscout.androidaps.logging.LTag import javax.inject.Inject @@ -25,7 +25,7 @@ import javax.inject.Singleton @Singleton class AlarmSoundServiceHelper @Inject constructor( private val aapsLogger: AAPSLogger, - private val notificationHolder: NotificationHolderInterface + private val notificationHolder: NotificationHolder ) { fun startAlarm(context: Context, sound: Int) { diff --git a/core/src/main/java/info/nightscout/androidaps/utils/CryptoUtil.kt b/core/src/main/java/info/nightscout/androidaps/utils/CryptoUtil.kt index e78b112615..563db53270 100644 --- a/core/src/main/java/info/nightscout/androidaps/utils/CryptoUtil.kt +++ b/core/src/main/java/info/nightscout/androidaps/utils/CryptoUtil.kt @@ -1,7 +1,7 @@ package info.nightscout.androidaps.utils import info.nightscout.androidaps.logging.AAPSLogger -import info.nightscout.androidaps.utils.extensions.toHex +import info.nightscout.androidaps.extensions.toHex import org.spongycastle.util.encoders.Base64 import java.nio.ByteBuffer import java.security.MessageDigest diff --git a/core/src/main/java/info/nightscout/androidaps/utils/DateUtil.java b/core/src/main/java/info/nightscout/androidaps/utils/DateUtil.java deleted file mode 100644 index 61f669e196..0000000000 --- a/core/src/main/java/info/nightscout/androidaps/utils/DateUtil.java +++ /dev/null @@ -1,394 +0,0 @@ -package info.nightscout.androidaps.utils; - -import android.content.Context; - -import androidx.collection.LongSparseArray; - -import org.joda.time.DateTime; -import org.joda.time.format.DateTimeFormat; -import org.joda.time.format.DateTimeFormatter; -import org.joda.time.format.ISODateTimeFormat; - -import java.text.DateFormat; -import java.text.DecimalFormat; -import java.text.DecimalFormatSymbols; -import java.text.SimpleDateFormat; -import java.util.ArrayList; -import java.util.Calendar; -import java.util.Collections; -import java.util.Date; -import java.util.EnumSet; -import java.util.GregorianCalendar; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Locale; -import java.util.Map; -import java.util.TimeZone; -import java.util.concurrent.TimeUnit; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -import javax.inject.Inject; -import javax.inject.Singleton; - -import info.nightscout.androidaps.core.R; -import info.nightscout.androidaps.utils.resources.ResourceHelper; - -/** - * The Class DateUtil. A simple wrapper around SimpleDateFormat to ease the handling of iso date string <-> date obj - * with TZ - */ - -@Singleton -public class DateUtil { - private final Context context; - - @Inject - public DateUtil(Context context) { - this.context = context; - } - - /** - * The date format in iso. - */ - private static final String FORMAT_DATE_ISO_OUT = "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"; - - /** - * Takes in an ISO date string of the following format: - * yyyy-mm-ddThh:mm:ss.ms+HoMo - * - * @param isoDateString the iso date string - * @return the date - */ - public static Date fromISODateString(String isoDateString) { - - DateTimeFormatter parser = ISODateTimeFormat.dateTimeParser(); - DateTime dateTime = DateTime.parse(isoDateString, parser); - return dateTime.toDate(); - } - - /** - * Render date - * - * @param date the date obj - * @param format - if not specified, will use FORMAT_DATE_ISO - * @param tz - tz to set to, if not specified uses local timezone - * @return the iso-formatted date string - */ - public static String toISOString(Date date, String format, TimeZone tz) { - if (format == null) format = FORMAT_DATE_ISO_OUT; - if (tz == null) tz = TimeZone.getDefault(); - DateFormat f = new SimpleDateFormat(format, Locale.getDefault()); - f.setTimeZone(tz); - return f.format(date); - } - - public static String toISOString(Date date) { - return toISOString(date, FORMAT_DATE_ISO_OUT, TimeZone.getTimeZone("UTC")); - } - - public static String toISOString(long date) { - return toISOString(new Date(date), FORMAT_DATE_ISO_OUT, TimeZone.getTimeZone("UTC")); - } - - public static String toISOAsUTC(final long timestamp) { - final SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'0000Z'", Locale.US); - format.setTimeZone(TimeZone.getTimeZone("UTC")); - return format.format(timestamp); - } - - public static String toISONoZone(final long timestamp) { - final SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss", Locale.US); - format.setTimeZone(TimeZone.getDefault()); - return format.format(timestamp); - } - - public static Date toDate(Integer seconds) { - Calendar calendar = new GregorianCalendar(); - calendar.set(Calendar.MONTH, 0); // Set january to be sure we miss DST changing - calendar.set(Calendar.HOUR_OF_DAY, seconds / 60 / 60); - calendar.set(Calendar.MINUTE, (seconds / 60) % 60); - calendar.set(Calendar.SECOND, 0); - return calendar.getTime(); - } - - public static int toSeconds(String hh_colon_mm) { - Pattern p = Pattern.compile("(\\d+):(\\d+)( a.m.| p.m.| AM| PM|AM|PM|)"); - Matcher m = p.matcher(hh_colon_mm); - int retval = 0; - - if (m.find()) { - retval = SafeParse.stringToInt(m.group(1)) * 60 * 60 + SafeParse.stringToInt(m.group(2)) * 60; - if ((m.group(3).equals(" a.m.") || m.group(3).equals(" AM") || m.group(3).equals("AM")) && m.group(1).equals("12")) - retval -= 12 * 60 * 60; - if ((m.group(3).equals(" p.m.") || m.group(3).equals(" PM") || m.group(3).equals("PM")) && !(m.group(1).equals("12"))) - retval += 12 * 60 * 60; - } - return retval; - } - - public static long toTodayTime(String hh_colon_mm) { - Pattern p = Pattern.compile("(\\d+):(\\d+)( a.m.| p.m.| AM| PM|AM|PM|)"); - Matcher m = p.matcher(hh_colon_mm); - long retval = 0; - - if (m.find()) { - int hours = SafeParse.stringToInt(m.group(1)); - int minutes = SafeParse.stringToInt(m.group(2)); - if ((m.group(3).equals(" a.m.") || m.group(3).equals(" AM") || m.group(3).equals("AM")) && m.group(1).equals("12")) - hours -= 12; - if ((m.group(3).equals(" p.m.") || m.group(3).equals(" PM") || m.group(3).equals("PM")) && !(m.group(1).equals("12"))) - hours += 12; - DateTime t = new DateTime() - .withHourOfDay(hours) - .withMinuteOfHour(minutes) - .withSecondOfMinute(0) - .withMillisOfSecond(0); - retval = t.getMillis(); - } - return retval; - } - - public static String dateString(Date date) { - DateFormat df = DateFormat.getDateInstance(DateFormat.SHORT); - return df.format(date); - } - - public static String dateString(long mills) { - DateFormat df = DateFormat.getDateInstance(DateFormat.SHORT); - return df.format(mills); - } - - public String dateStringShort(long mills) { - String format = "MM/dd"; - if (android.text.format.DateFormat.is24HourFormat(context)) { - format = "dd/MM"; - } - return new DateTime(mills).toString(DateTimeFormat.forPattern(format)); - } - - public String timeString(Date date) { - String format = "hh:mma"; - if (android.text.format.DateFormat.is24HourFormat(context)) { - format = "HH:mm"; - } - return new DateTime(date).toString(DateTimeFormat.forPattern(format)); - } - - public String timeString(long mills) { - String format = "hh:mma"; - if (android.text.format.DateFormat.is24HourFormat(context)) { - format = "HH:mm"; - } - return new DateTime(mills).toString(DateTimeFormat.forPattern(format)); - } - - public String timeStringWithSeconds(long mills) { - String format = "hh:mm:ssa"; - if (android.text.format.DateFormat.is24HourFormat(context)) { - format = "HH:mm:ss"; - } - return new DateTime(mills).toString(DateTimeFormat.forPattern(format)); - } - - public String dateAndTimeString(Date date) { - return dateString(date) + " " + timeString(date); - } - - public String dateAndTimeRangeString(long start, long end) { - return dateAndTimeString(start) + " - " + timeString(end); - } - - public String dateAndTimeString(long mills) { - if (mills == 0) return ""; - return dateString(mills) + " " + timeString(mills); - } - - public String dateAndTimeAndSecondsString(long mills) { - if (mills == 0) return ""; - return dateString(mills) + " " + timeStringWithSeconds(mills); - } - - public static String minAgo(ResourceHelper resourceHelper, long time) { - int mins = (int) ((now() - time) / 1000 / 60); - return resourceHelper.gs(R.string.minago, mins); - } - - public static String minAgoShort(long time) { - int mins = (int) ((time - now()) / 1000 / 60); - return (mins > 0 ? "+" : "") + mins; - } - - public static String hourAgo(long time, ResourceHelper resourceHelper) { - double hours = (now() - time) / 1000d / 60 / 60; - return resourceHelper.gs(R.string.hoursago, hours); - } - - private static final LongSparseArray timeStrings = new LongSparseArray<>(); - - public String timeStringFromSeconds(int seconds) { - String cached = timeStrings.get(seconds); - if (cached != null) - return cached; - String t = timeString(toDate(seconds)); - timeStrings.put(seconds, t); - return t; - } - - - public static String timeFrameString(long timeInMillis, ResourceHelper resourceHelper) { - long remainingTimeMinutes = timeInMillis / (1000 * 60); - long remainingTimeHours = remainingTimeMinutes / 60; - remainingTimeMinutes = remainingTimeMinutes % 60; - return "(" + ((remainingTimeHours > 0) ? (remainingTimeHours + resourceHelper.gs(R.string.shorthour) + " ") : "") + remainingTimeMinutes + "')"; - } - - public static String sinceString(long timestamp, ResourceHelper resourceHelper) { - return timeFrameString(System.currentTimeMillis() - timestamp, resourceHelper); - } - - public static String untilString(long timestamp, ResourceHelper resourceHelper) { - return timeFrameString(timestamp - System.currentTimeMillis(), resourceHelper); - } - - public long _now() { - return System.currentTimeMillis(); - } - - public long nowWithoutMilliseconds() { - long n = System.currentTimeMillis(); - n = n - n % 1000; - return n; - } - - public static long now() { - return System.currentTimeMillis(); - } - - public static long roundDateToSec(long date) { - return date - date % 1000; - } - - public static boolean isCloseToNow(long date) { - long diff = Math.abs(date - now()); - return diff < T.mins(2).msecs(); - } - - public static boolean isOlderThan(long date, long minutes) { - long diff = now() - date; - return diff > T.mins(minutes).msecs(); - } - - public static long getTimeZoneOffsetMs() { - return new GregorianCalendar().getTimeZone().getRawOffset(); - } - - public static int getTimeZoneOffsetMinutes(final long timestamp) { - return TimeZone.getDefault().getOffset(timestamp) / 60000; - } - - //Map:{DAYS=1, HOURS=3, MINUTES=46, SECONDS=40, MILLISECONDS=0, MICROSECONDS=0, NANOSECONDS=0} - public static Map computeDiff(long date1, long date2) { - long diffInMillies = date2 - date1; - List units = new ArrayList<>(EnumSet.allOf(TimeUnit.class)); - Collections.reverse(units); - Map result = new LinkedHashMap<>(); - long milliesRest = diffInMillies; - for (TimeUnit unit : units) { - long diff = unit.convert(milliesRest, TimeUnit.MILLISECONDS); - long diffInMilliesForUnit = unit.toMillis(diff); - milliesRest = milliesRest - diffInMilliesForUnit; - result.put(unit, diff); - } - return result; - } - - public static String age(long milliseconds, boolean useShortText, ResourceHelper resourceHelper) { - Map diff = computeDiff(0L, milliseconds); - - String days = " " + resourceHelper.gs(R.string.days) + " "; - String hours = " " + resourceHelper.gs(R.string.hours) + " "; - String minutes = " " + resourceHelper.gs(R.string.unit_minutes) + " "; - - if (useShortText) { - days = resourceHelper.gs(R.string.shortday); - hours = resourceHelper.gs(R.string.shorthour); - minutes = resourceHelper.gs(R.string.shortminute); - } - - String result = ""; - if (diff.get(TimeUnit.DAYS) > 0) result += diff.get(TimeUnit.DAYS) + days; - if (diff.get(TimeUnit.HOURS) > 0) result += diff.get(TimeUnit.HOURS) + hours; - if (diff.get(TimeUnit.DAYS) == 0) result += diff.get(TimeUnit.MINUTES) + minutes; - return result; - } - - public static String niceTimeScalar(long t, ResourceHelper resourceHelper) { - String unit = resourceHelper.gs(R.string.unit_second); - t = t / 1000; - if (t != 1) unit = resourceHelper.gs(R.string.unit_seconds); - if (t > 59) { - unit = resourceHelper.gs(R.string.unit_minute); - t = t / 60; - if (t != 1) unit = resourceHelper.gs(R.string.unit_minutes); - if (t > 59) { - unit = resourceHelper.gs(R.string.unit_hour); - t = t / 60; - if (t != 1) unit = resourceHelper.gs(R.string.unit_hours); - if (t > 24) { - unit = resourceHelper.gs(R.string.unit_day); - t = t / 24; - if (t != 1) unit = resourceHelper.gs(R.string.unit_days); - if (t > 28) { - unit = resourceHelper.gs(R.string.unit_week); - t = t / 7; - if (t != 1) unit = resourceHelper.gs(R.string.unit_weeks); - } - } - } - } - //if (t != 1) unit = unit + "s"; //implemented plurality in every step, because in other languages plurality of time is not every time adding the same character - return qs((double) t, 0) + " " + unit; - } - - // singletons to avoid repeated allocation - private static DecimalFormatSymbols dfs; - private static DecimalFormat df; - - public static String qs(double x, int digits) { - - if (digits == -1) { - digits = 0; - if (((int) x != x)) { - digits++; - if ((((int) x * 10) / 10 != x)) { - digits++; - if ((((int) x * 100) / 100 != x)) digits++; - } - } - } - - if (dfs == null) { - final DecimalFormatSymbols local_dfs = new DecimalFormatSymbols(); - local_dfs.setDecimalSeparator('.'); - dfs = local_dfs; // avoid race condition - } - - final DecimalFormat this_df; - // use singleton if on ui thread otherwise allocate new as DecimalFormat is not thread safe - if (Thread.currentThread().getId() == 1) { - if (df == null) { - final DecimalFormat local_df = new DecimalFormat("#", dfs); - local_df.setMinimumIntegerDigits(1); - df = local_df; // avoid race condition - } - this_df = df; - } else { - this_df = new DecimalFormat("#", dfs); - } - - this_df.setMaximumFractionDigits(digits); - return this_df.format(x); - } - -} diff --git a/core/src/main/java/info/nightscout/androidaps/utils/DateUtil.kt b/core/src/main/java/info/nightscout/androidaps/utils/DateUtil.kt new file mode 100644 index 0000000000..f5ef60d7f1 --- /dev/null +++ b/core/src/main/java/info/nightscout/androidaps/utils/DateUtil.kt @@ -0,0 +1,304 @@ +package info.nightscout.androidaps.utils + +import android.content.Context +import androidx.collection.LongSparseArray +import info.nightscout.androidaps.core.R +import info.nightscout.androidaps.utils.resources.ResourceHelper +import org.joda.time.DateTime +import org.joda.time.format.DateTimeFormat +import org.joda.time.format.ISODateTimeFormat +import java.text.DateFormat +import java.text.DecimalFormat +import java.text.DecimalFormatSymbols +import java.text.SimpleDateFormat +import java.util.* +import java.util.concurrent.TimeUnit +import java.util.regex.Pattern +import javax.inject.Inject +import javax.inject.Singleton +import kotlin.math.abs + +/** + * The Class DateUtil. A simple wrapper around SimpleDateFormat to ease the handling of iso date string <-> date obj + * with TZ + */ +@Singleton +open class DateUtil @Inject constructor(private val context: Context) { + + /** + * The date format in iso. + */ + @Suppress("PrivatePropertyName") + private val FORMAT_DATE_ISO_OUT = "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'" + + /** + * Takes in an ISO date string of the following format: + * yyyy-mm-ddThh:mm:ss.ms+HoMo + * + * @param isoDateString the iso date string + * @return the date + */ + fun fromISODateString(isoDateString: String): Long { + val parser = ISODateTimeFormat.dateTimeParser() + val dateTime = DateTime.parse(isoDateString, parser) + return dateTime.toDate().time + } + + /** + * Render date + * + * @param date the date obj + * @param format - if not specified, will use FORMAT_DATE_ISO + * @param tz - tz to set to, if not specified uses local timezone + * @return the iso-formatted date string + */ + @JvmOverloads + fun toISOString(date: Long, format: String = FORMAT_DATE_ISO_OUT, tz: TimeZone = TimeZone.getTimeZone("UTC")): String { + val f: DateFormat = SimpleDateFormat(format, Locale.getDefault()) + f.timeZone = tz + return f.format(date) + } + + fun toISOAsUTC(timestamp: Long): String { + val format = SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'0000Z'", Locale.US) + format.timeZone = TimeZone.getTimeZone("UTC") + return format.format(timestamp) + } + + fun toISONoZone(timestamp: Long): String { + val format = SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss", Locale.US) + format.timeZone = TimeZone.getDefault() + return format.format(timestamp) + } + + fun secondsOfTheDayToMilliseconds(seconds: Int): Long { + val calendar: Calendar = GregorianCalendar() + calendar[Calendar.MONTH] = 0 // Set january to be sure we miss DST changing + calendar[Calendar.HOUR_OF_DAY] = seconds / 60 / 60 + calendar[Calendar.MINUTE] = seconds / 60 % 60 + calendar[Calendar.SECOND] = 0 + return calendar.timeInMillis + } + + fun toSeconds(hh_colon_mm: String): Int { + val p = Pattern.compile("(\\d+):(\\d+)( a.m.| p.m.| AM| PM|AM|PM|)") + val m = p.matcher(hh_colon_mm) + var retval = 0 + if (m.find()) { + retval = SafeParse.stringToInt(m.group(1)) * 60 * 60 + SafeParse.stringToInt(m.group(2)) * 60 + if ((m.group(3) == " a.m." || m.group(3) == " AM" || m.group(3) == "AM") && m.group(1) == "12") retval -= 12 * 60 * 60 + if ((m.group(3) == " p.m." || m.group(3) == " PM" || m.group(3) == "PM") && m.group(1) != "12") retval += 12 * 60 * 60 + } + return retval + } + + fun dateString(mills: Long): String { + val df = DateFormat.getDateInstance(DateFormat.SHORT) + return df.format(mills) + } + + fun dateStringShort(mills: Long): String { + var format = "MM/dd" + if (android.text.format.DateFormat.is24HourFormat(context)) { + format = "dd/MM" + } + return DateTime(mills).toString(DateTimeFormat.forPattern(format)) + } + + fun timeString(mills: Long): String { + var format = "hh:mma" + if (android.text.format.DateFormat.is24HourFormat(context)) { + format = "HH:mm" + } + return DateTime(mills).toString(DateTimeFormat.forPattern(format)) + } + + private fun timeStringWithSeconds(mills: Long): String { + var format = "hh:mm:ssa" + if (android.text.format.DateFormat.is24HourFormat(context)) { + format = "HH:mm:ss" + } + return DateTime(mills).toString(DateTimeFormat.forPattern(format)) + } + + fun dateAndTimeRangeString(start: Long, end: Long): String { + return dateAndTimeString(start) + " - " + timeString(end) + } + + fun dateAndTimeString(mills: Long): String { + return if (mills == 0L) "" else dateString(mills) + " " + timeString(mills) + } + + fun dateAndTimeAndSecondsString(mills: Long): String { + return if (mills == 0L) "" else dateString(mills) + " " + timeStringWithSeconds(mills) + } + + fun minAgo(resourceHelper: ResourceHelper, time: Long): String { + val mins = ((now() - time) / 1000 / 60).toInt() + return resourceHelper.gs(R.string.minago, mins) + } + + fun minAgoShort(time: Long): String { + val mins = ((time - now()) / 1000 / 60).toInt() + return (if (mins > 0) "+" else "") + mins + } + + fun hourAgo(time: Long, resourceHelper: ResourceHelper): String { + val hours = (now() - time) / 1000.0 / 60 / 60 + return resourceHelper.gs(R.string.hoursago, hours) + } + + fun timeStringFromSeconds(seconds: Int): String { + val cached = timeStrings[seconds.toLong()] + if (cached != null) return cached + val t = timeString(secondsOfTheDayToMilliseconds(seconds)) + timeStrings.put(seconds.toLong(), t) + return t + } + + fun timeFrameString(timeInMillis: Long, resourceHelper: ResourceHelper): String { + var remainingTimeMinutes = timeInMillis / (1000 * 60) + val remainingTimeHours = remainingTimeMinutes / 60 + remainingTimeMinutes %= 60 + return "(" + (if (remainingTimeHours > 0) remainingTimeHours.toString() + resourceHelper.gs(R.string.shorthour) + " " else "") + remainingTimeMinutes + "')" + } + + fun sinceString(timestamp: Long, resourceHelper: ResourceHelper): String { + return timeFrameString(System.currentTimeMillis() - timestamp, resourceHelper) + } + + fun untilString(timestamp: Long, resourceHelper: ResourceHelper): String { + return timeFrameString(timestamp - System.currentTimeMillis(), resourceHelper) + } + + fun now(): Long { + return System.currentTimeMillis() + } + + fun nowWithoutMilliseconds(): Long { + var n = System.currentTimeMillis() + n -= n % 1000 + return n + } + + fun isCloseToNow(date: Long): Boolean { + val diff = abs(date - now()) + return diff < T.mins(2L).msecs() + } + + fun isOlderThan(date: Long, minutes: Long): Boolean { + val diff = now() - date + return diff > T.mins(minutes).msecs() + } + + fun getTimeZoneOffsetMs(): Long { + return GregorianCalendar().timeZone.rawOffset.toLong() + } + + fun getTimeZoneOffsetMinutes(timestamp: Long): Int { + return TimeZone.getDefault().getOffset(timestamp) / 60000 + } + + //Map:{DAYS=1, HOURS=3, MINUTES=46, SECONDS=40, MILLISECONDS=0, MICROSECONDS=0, NANOSECONDS=0} + fun computeDiff(date1: Long, date2: Long): Map { + val units: MutableList = ArrayList(EnumSet.allOf(TimeUnit::class.java)) + units.reverse() + val result: MutableMap = LinkedHashMap() + var millisecondsRest = date2 - date1 + for (unit in units) { + val diff = unit.convert(millisecondsRest, TimeUnit.MILLISECONDS) + val diffInMillisecondsForUnit = unit.toMillis(diff) + millisecondsRest -= diffInMillisecondsForUnit + result[unit] = diff + } + return result + } + + fun age(milliseconds: Long, useShortText: Boolean, resourceHelper: ResourceHelper): String { + val diff = computeDiff(0L, milliseconds) + var days = " " + resourceHelper.gs(R.string.days) + " " + var hours = " " + resourceHelper.gs(R.string.hours) + " " + var minutes = " " + resourceHelper.gs(R.string.unit_minutes) + " " + if (useShortText) { + days = resourceHelper.gs(R.string.shortday) + hours = resourceHelper.gs(R.string.shorthour) + minutes = resourceHelper.gs(R.string.shortminute) + } + var result = "" + if (diff[TimeUnit.DAYS]!! > 0) result += diff[TimeUnit.DAYS].toString() + days + if (diff[TimeUnit.HOURS]!! > 0) result += diff[TimeUnit.HOURS].toString() + hours + if (diff[TimeUnit.DAYS] == 0L) result += diff[TimeUnit.MINUTES].toString() + minutes + return result + } + + fun niceTimeScalar(time: Long, resourceHelper: ResourceHelper): String { + var t = time + var unit = resourceHelper.gs(R.string.unit_second) + t /= 1000 + if (t != 1L) unit = resourceHelper.gs(R.string.unit_seconds) + if (t > 59) { + unit = resourceHelper.gs(R.string.unit_minute) + t /= 60 + if (t != 1L) unit = resourceHelper.gs(R.string.unit_minutes) + if (t > 59) { + unit = resourceHelper.gs(R.string.unit_hour) + t /= 60 + if (t != 1L) unit = resourceHelper.gs(R.string.unit_hours) + if (t > 24) { + unit = resourceHelper.gs(R.string.unit_day) + t /= 24 + if (t != 1L) unit = resourceHelper.gs(R.string.unit_days) + if (t > 28) { + unit = resourceHelper.gs(R.string.unit_week) + t /= 7 + if (t != 1L) unit = resourceHelper.gs(R.string.unit_weeks) + } + } + } + } + //if (t != 1) unit = unit + "s"; //implemented plurality in every step, because in other languages plurality of time is not every time adding the same character + return qs(t.toDouble(), 0) + " " + unit + } + + fun qs(x: Double, numDigits: Int): String { + var digits = numDigits + if (digits == -1) { + digits = 0 + if ((x.toInt() % x == 0.0)) { + digits++ + if ((x.toInt() * 10 / 10).toDouble() != x) { + digits++ + if ((x.toInt() * 100 / 100).toDouble() != x) digits++ + } + } + } + if (dfs == null) { + val localDfs = DecimalFormatSymbols() + localDfs.decimalSeparator = '.' + dfs = localDfs // avoid race condition + } + val thisDf: DecimalFormat? + // use singleton if on ui thread otherwise allocate new as DecimalFormat is not thread safe + if (Thread.currentThread().id == 1L) { + if (df == null) { + val localDf = DecimalFormat("#", dfs) + localDf.minimumIntegerDigits = 1 + df = localDf // avoid race condition + } + thisDf = df + } else { + thisDf = DecimalFormat("#", dfs) + } + thisDf!!.maximumFractionDigits = digits + return thisDf.format(x) + } + + companion object { + + private val timeStrings = LongSparseArray() + + // singletons to avoid repeated allocation + private var dfs: DecimalFormatSymbols? = null + private var df: DecimalFormat? = null + } +} \ No newline at end of file diff --git a/core/src/main/java/info/nightscout/androidaps/utils/DecimalFormatter.kt b/core/src/main/java/info/nightscout/androidaps/utils/DecimalFormatter.kt index 7d04cb8447..280e8a348e 100644 --- a/core/src/main/java/info/nightscout/androidaps/utils/DecimalFormatter.kt +++ b/core/src/main/java/info/nightscout/androidaps/utils/DecimalFormatter.kt @@ -1,7 +1,7 @@ package info.nightscout.androidaps.utils import info.nightscout.androidaps.core.R -import info.nightscout.androidaps.interfaces.PumpInterface +import info.nightscout.androidaps.interfaces.Pump import info.nightscout.androidaps.utils.resources.ResourceHelper import java.text.DecimalFormat @@ -20,7 +20,7 @@ object DecimalFormatter { fun to2Decimal(value: Double, unit: String): String = format2dec.format(value) + unit fun to3Decimal(value: Double): String = format3dec.format(value) fun to3Decimal(value: Double, unit: String): String = format3dec.format(value) + unit - fun toPumpSupportedBolus(value: Double, pump: PumpInterface): String = if (pump.pumpDescription.bolusStep <= 0.051) to2Decimal(value) else to1Decimal(value) - fun toPumpSupportedBolus(value: Double, pump: PumpInterface, resourceHelper: ResourceHelper): String = if (pump.pumpDescription.bolusStep <= 0.051) resourceHelper.gs(R.string.formatinsulinunits, value) else resourceHelper.gs(R.string.formatinsulinunits1, value) - fun pumpSupportedBolusFormat(pump: PumpInterface): DecimalFormat = if (pump.pumpDescription.bolusStep <= 0.051) DecimalFormat("0.00") else DecimalFormat("0.0") + fun toPumpSupportedBolus(value: Double, pump: Pump): String = if (pump.pumpDescription.bolusStep <= 0.051) to2Decimal(value) else to1Decimal(value) + fun toPumpSupportedBolus(value: Double, pump: Pump, resourceHelper: ResourceHelper): String = if (pump.pumpDescription.bolusStep <= 0.051) resourceHelper.gs(R.string.formatinsulinunits, value) else resourceHelper.gs(R.string.formatinsulinunits1, value) + fun pumpSupportedBolusFormat(pump: Pump): DecimalFormat = if (pump.pumpDescription.bolusStep <= 0.051) DecimalFormat("0.00") else DecimalFormat("0.0") } \ No newline at end of file diff --git a/core/src/main/java/info/nightscout/androidaps/utils/T.java b/core/src/main/java/info/nightscout/androidaps/utils/T.java deleted file mode 100644 index 5671f0725c..0000000000 --- a/core/src/main/java/info/nightscout/androidaps/utils/T.java +++ /dev/null @@ -1,79 +0,0 @@ -package info.nightscout.androidaps.utils; - -/** - * Created by mike on 26.03.2018. - */ - -public class T { - private long time; // in msec - - public static T now() { - T t = new T(); - t.time = System.currentTimeMillis(); - return t; - } - - public static T msecs(long msec) { - T t = new T(); - t.time = msec; - return t; - } - - public static T secs(long sec) { - T t = new T(); - t.time = sec * 1000L; - return t; - } - - public static T mins(long min) { - T t = new T(); - t.time = min * 60 * 1000L; - return t; - } - - public static T hours(long hour) { - T t = new T(); - t.time = hour * 60 * 60 * 1000L; - return t; - } - - public static T days(long day) { - T t = new T(); - t.time = day * 24 * 60 * 60 * 1000L; - return t; - } - - public static T months(long month) { - T t = new T(); - t.time = month * 31 * 24 * 60 * 60 * 1000L; - return t; - } - - public long msecs() { - return time; - } - - public long secs() { - return time / 1000L; - } - - public long mins() { - return time / 60 / 1000L; - } - - public long hours() { - return time / 60 / 60 / 1000L; - } - - public long days() { - return time / 24 / 60 / 60 / 1000L; - } - - public T plus(T plus) { - return T.msecs(time + plus.time); - } - - public T minus(T minus) { - return T.msecs(time - minus.time); - } -} diff --git a/core/src/main/java/info/nightscout/androidaps/utils/T.kt b/core/src/main/java/info/nightscout/androidaps/utils/T.kt new file mode 100644 index 0000000000..29915386f1 --- /dev/null +++ b/core/src/main/java/info/nightscout/androidaps/utils/T.kt @@ -0,0 +1,25 @@ +package info.nightscout.androidaps.utils + +@Suppress("SpellCheckingInspection") +class T(val time: Long = 0L) { + + fun msecs(): Long = time + fun secs(): Long = time / 1000L + fun mins(): Long = time / 60 / 1000L + fun hours(): Long = time / 60 / 60 / 1000L + fun days(): Long = time / 24 / 60 / 60 / 1000L + + operator fun plus(plus: T): T = T(time + plus.time) + operator fun minus(minus: T): T = T(time - minus.time) + + companion object { + + @JvmStatic fun now(): T = T(System.currentTimeMillis()) + @JvmStatic fun msecs(msec: Long): T = T(msec) + @JvmStatic fun secs(sec: Long): T = T(sec * 1000L) + @JvmStatic fun mins(min: Long): T = T(min * 60 * 1000L) + @JvmStatic fun hours(hour: Long): T = T(hour * 60 * 60 * 1000L) + @JvmStatic fun days(day: Long): T = T(day * 24 * 60 * 60 * 1000L) + @JvmStatic fun months(month: Long): T = T(month * 31 * 24 * 60 * 60 * 1000L) + } +} \ No newline at end of file diff --git a/core/src/main/java/info/nightscout/androidaps/utils/TimerUtil.kt b/core/src/main/java/info/nightscout/androidaps/utils/TimerUtil.kt index 054064efe0..d1977090ac 100644 --- a/core/src/main/java/info/nightscout/androidaps/utils/TimerUtil.kt +++ b/core/src/main/java/info/nightscout/androidaps/utils/TimerUtil.kt @@ -12,11 +12,12 @@ import javax.inject.Singleton class TimerUtil @Inject constructor( private val context: Context, private val resourceHelper: ResourceHelper, + private val dateUtil: DateUtil ) { fun scheduleReminder(time: Long, text: String? = null) { Intent(AlarmClock.ACTION_SET_TIMER).apply { - val length: Int = ((time - DateUtil.now()) / 1000).toInt() + val length: Int = ((time - dateUtil.now()) / 1000).toInt() flags = flags or Intent.FLAG_ACTIVITY_NEW_TASK putExtra(AlarmClock.EXTRA_LENGTH, length) putExtra(AlarmClock.EXTRA_SKIP_UI, true) diff --git a/core/src/main/java/info/nightscout/androidaps/utils/Translator.kt b/core/src/main/java/info/nightscout/androidaps/utils/Translator.kt index 02aaecbbf3..b95247ddf6 100644 --- a/core/src/main/java/info/nightscout/androidaps/utils/Translator.kt +++ b/core/src/main/java/info/nightscout/androidaps/utils/Translator.kt @@ -3,7 +3,9 @@ package info.nightscout.androidaps.utils import info.nightscout.androidaps.core.R import info.nightscout.androidaps.database.entities.TemporaryTarget import info.nightscout.androidaps.database.entities.TherapyEvent -import info.nightscout.androidaps.database.entities.UserEntry.* +import info.nightscout.androidaps.database.entities.UserEntry.Action +import info.nightscout.androidaps.database.entities.UserEntry.Sources +import info.nightscout.androidaps.database.entities.ValueWithUnit import info.nightscout.androidaps.utils.resources.ResourceHelper import javax.inject.Inject import javax.inject.Singleton @@ -13,142 +15,268 @@ class Translator @Inject internal constructor( private val resourceHelper: ResourceHelper ) { - fun translate(text: String): String = - when (text) { - TherapyEvent.Type.FINGER_STICK_BG_VALUE.text -> resourceHelper.gs(R.string.careportal_bgcheck) - TherapyEvent.Type.SNACK_BOLUS.text -> resourceHelper.gs(R.string.careportal_snackbolus) - TherapyEvent.Type.MEAL_BOLUS.text -> resourceHelper.gs(R.string.careportal_mealbolus) - TherapyEvent.Type.CORRECTION_BOLUS.text -> resourceHelper.gs(R.string.careportal_correctionbolus) - TherapyEvent.Type.CARBS_CORRECTION.text -> resourceHelper.gs(R.string.careportal_carbscorrection) - TherapyEvent.Type.BOLUS_WIZARD.text -> resourceHelper.gs(R.string.boluswizard) - TherapyEvent.Type.COMBO_BOLUS.text -> resourceHelper.gs(R.string.careportal_combobolus) - TherapyEvent.Type.ANNOUNCEMENT.text -> resourceHelper.gs(R.string.careportal_announcement) - TherapyEvent.Type.NOTE.text -> resourceHelper.gs(R.string.careportal_note) - TherapyEvent.Type.QUESTION.text -> resourceHelper.gs(R.string.careportal_question) - TherapyEvent.Type.EXERCISE.text -> resourceHelper.gs(R.string.careportal_exercise) - TherapyEvent.Type.CANNULA_CHANGE.text -> resourceHelper.gs(R.string.careportal_pumpsitechange) - TherapyEvent.Type.PUMP_BATTERY_CHANGE.text -> resourceHelper.gs(R.string.careportal_pumpbatterychange) - TherapyEvent.Type.SENSOR_STARTED.text -> resourceHelper.gs(R.string.careportal_cgmsensorstart) - TherapyEvent.Type.SENSOR_STOPPED.text -> resourceHelper.gs(R.string.careportal_cgm_sensor_stop) - TherapyEvent.Type.SENSOR_CHANGE.text -> resourceHelper.gs(R.string.careportal_cgmsensorinsert) - TherapyEvent.Type.INSULIN_CHANGE.text -> resourceHelper.gs(R.string.careportal_insulincartridgechange) - TherapyEvent.Type.DAD_ALERT.text -> resourceHelper.gs(R.string.careportal_dad_alert) - TherapyEvent.Type.TEMPORARY_BASAL_START.text -> resourceHelper.gs(R.string.careportal_tempbasalstart) - TherapyEvent.Type.TEMPORARY_BASAL_END.text -> resourceHelper.gs(R.string.careportal_tempbasalend) - TherapyEvent.Type.PROFILE_SWITCH.text -> resourceHelper.gs(R.string.careportal_profileswitch) - TherapyEvent.Type.TEMPORARY_TARGET.text -> resourceHelper.gs(R.string.careportal_temporarytarget) - TherapyEvent.Type.TEMPORARY_TARGET_CANCEL.text -> resourceHelper.gs(R.string.careportal_temporarytargetcancel) - TherapyEvent.Type.APS_OFFLINE.text -> resourceHelper.gs(R.string.careportal_openapsoffline) - TherapyEvent.Type.NS_MBG.text -> resourceHelper.gs(R.string.careportal_mbg) - TherapyEvent.MeterType.FINGER.text -> resourceHelper.gs(R.string.glucosetype_finger) - TherapyEvent.MeterType.SENSOR.text -> resourceHelper.gs(R.string.glucosetype_sensor) - TherapyEvent.MeterType.MANUAL.text -> resourceHelper.gs(R.string.manual) + @Deprecated("use type instead of string") + fun translate(text: String): String = text - TemporaryTarget.Reason.CUSTOM.text -> resourceHelper.gs(R.string.custom) - TemporaryTarget.Reason.HYPOGLYCEMIA.text -> resourceHelper.gs(R.string.hypo) - TemporaryTarget.Reason.EATING_SOON.text -> resourceHelper.gs(R.string.eatingsoon) - TemporaryTarget.Reason.ACTIVITY.text -> resourceHelper.gs(R.string.activity) - TemporaryTarget.Reason.AUTOMATION.text -> resourceHelper.gs(R.string.automation) - TemporaryTarget.Reason.WEAR.text -> resourceHelper.gs(R.string.wear) + fun translate(action: Action): String = when(action) { + Action.BOLUS -> resourceHelper.gs(R.string.uel_bolus) + Action.SMB -> resourceHelper.gs(R.string.smb_shortname) + Action.BOLUS_ADVISOR -> resourceHelper.gs(R.string.uel_bolus_advisor) + Action.EXTENDED_BOLUS -> resourceHelper.gs(R.string.uel_extended_bolus) + Action.SUPERBOLUS_TBR -> resourceHelper.gs(R.string.uel_superbolus_tbr) + Action.CARBS -> resourceHelper.gs(R.string.uel_carbs) + Action.EXTENDED_CARBS -> resourceHelper.gs(R.string.uel_extended_carbs) + Action.TEMP_BASAL -> resourceHelper.gs(R.string.uel_temp_basal) + Action.TT -> resourceHelper.gs(R.string.uel_tt) + Action.NEW_PROFILE -> resourceHelper.gs(R.string.uel_new_profile) + Action.CLONE_PROFILE -> resourceHelper.gs(R.string.uel_clone_profile) + Action.STORE_PROFILE -> resourceHelper.gs(R.string.uel_store_profile) + Action.PROFILE_SWITCH -> resourceHelper.gs(R.string.uel_profile_switch) + Action.PROFILE_SWITCH_CLONED -> resourceHelper.gs(R.string.uel_profile_switch_cloned) + Action.CLOSED_LOOP_MODE -> resourceHelper.gs(R.string.uel_closed_loop_mode) + Action.LGS_LOOP_MODE -> resourceHelper.gs(R.string.uel_lgs_loop_mode) + Action.OPEN_LOOP_MODE -> resourceHelper.gs(R.string.uel_open_loop_mode) + Action.LOOP_DISABLED -> resourceHelper.gs(R.string.uel_loop_disabled) + Action.LOOP_ENABLED -> resourceHelper.gs(R.string.uel_loop_enabled) + Action.RECONNECT -> resourceHelper.gs(R.string.uel_reconnect) + Action.DISCONNECT -> resourceHelper.gs(R.string.uel_disconnect) + Action.RESUME -> resourceHelper.gs(R.string.uel_resume) + Action.SUSPEND -> resourceHelper.gs(R.string.uel_suspend) + Action.HW_PUMP_ALLOWED -> resourceHelper.gs(R.string.uel_hw_pump_allowed) + Action.CLEAR_PAIRING_KEYS -> resourceHelper.gs(R.string.uel_clear_pairing_keys) + Action.ACCEPTS_TEMP_BASAL -> resourceHelper.gs(R.string.uel_accepts_temp_basal) + Action.CANCEL_TEMP_BASAL -> resourceHelper.gs(R.string.uel_cancel_temp_basal) + Action.CANCEL_EXTENDED_BOLUS -> resourceHelper.gs(R.string.uel_cancel_extended_bolus) + Action.CANCEL_TT -> resourceHelper.gs(R.string.uel_cancel_tt) + Action.CAREPORTAL -> resourceHelper.gs(R.string.uel_careportal) + Action.SITE_CHANGE -> resourceHelper.gs(R.string.uel_site_change) + Action.RESERVOIR_CHANGE -> resourceHelper.gs(R.string.uel_reservoir_change) + Action.CALIBRATION -> resourceHelper.gs(R.string.uel_calibration) + Action.PRIME_BOLUS -> resourceHelper.gs(R.string.uel_prime_bolus) + Action.TREATMENT -> resourceHelper.gs(R.string.uel_treatment) + Action.CAREPORTAL_NS_REFRESH -> resourceHelper.gs(R.string.uel_careportal_ns_refresh) + Action.PROFILE_SWITCH_NS_REFRESH -> resourceHelper.gs(R.string.uel_profile_switch_ns_refresh) + Action.TREATMENTS_NS_REFRESH -> resourceHelper.gs(R.string.uel_treatments_ns_refresh) + Action.TT_NS_REFRESH -> resourceHelper.gs(R.string.uel_tt_ns_refresh) + Action.AUTOMATION_REMOVED -> resourceHelper.gs(R.string.uel_automation_removed) + Action.BG_REMOVED -> resourceHelper.gs(R.string.uel_bg_removed) + Action.CAREPORTAL_REMOVED -> resourceHelper.gs(R.string.uel_careportal_removed) + Action.BOLUS_REMOVED -> resourceHelper.gs(R.string.uel_bolus_removed) + Action.CARBS_REMOVED -> resourceHelper.gs(R.string.uel_carbs_removed) + Action.TEMP_BASAL_REMOVED -> resourceHelper.gs(R.string.uel_temp_basal_removed) + Action.EXTENDED_BOLUS_REMOVED -> resourceHelper.gs(R.string.uel_extended_bolus_removed) + Action.FOOD -> resourceHelper.gs(R.string.uel_food) + Action.FOOD_REMOVED -> resourceHelper.gs(R.string.uel_food_removed) + Action.PROFILE_REMOVED -> resourceHelper.gs(R.string.uel_profile_removed) + Action.PROFILE_SWITCH_REMOVED -> resourceHelper.gs(R.string.uel_profile_switch_removed) + Action.RESTART_EVENTS_REMOVED -> resourceHelper.gs(R.string.uel_restart_events_removed) + Action.TREATMENT_REMOVED -> resourceHelper.gs(R.string.uel_treatment_removed) + Action.TT_REMOVED -> resourceHelper.gs(R.string.uel_tt_removed) + Action.NS_PAUSED -> resourceHelper.gs(R.string.uel_ns_paused) + Action.NS_RESUME -> resourceHelper.gs(R.string.uel_ns_resume) + Action.NS_QUEUE_CLEARED -> resourceHelper.gs(R.string.uel_ns_queue_cleared) + Action.NS_SETTINGS_COPIED -> resourceHelper.gs(R.string.uel_ns_settings_copied) + Action.ERROR_DIALOG_OK -> resourceHelper.gs(R.string.uel_error_dialog_ok) + Action.ERROR_DIALOG_MUTE -> resourceHelper.gs(R.string.uel_error_dialog_mute) + Action.ERROR_DIALOG_MUTE_5MIN -> resourceHelper.gs(R.string.uel_error_dialog_mute_5min) + Action.OBJECTIVE_STARTED -> resourceHelper.gs(R.string.uel_objective_started) + Action.OBJECTIVE_UNSTARTED -> resourceHelper.gs(R.string.uel_objective_unstarted) + Action.OBJECTIVES_SKIPPED -> resourceHelper.gs(R.string.uel_objectives_skipped) + Action.STAT_RESET -> resourceHelper.gs(R.string.uel_stat_reset) + Action.DELETE_LOGS -> resourceHelper.gs(R.string.uel_delete_logs) + Action.DELETE_FUTURE_TREATMENTS -> resourceHelper.gs(R.string.uel_delete_future_treatments) + Action.EXPORT_SETTINGS -> resourceHelper.gs(R.string.uel_export_settings) + Action.IMPORT_SETTINGS -> resourceHelper.gs(R.string.uel_import_settings) + Action.RESET_DATABASES -> resourceHelper.gs(R.string.uel_reset_databases) + Action.EXPORT_DATABASES -> resourceHelper.gs(R.string.uel_export_databases) + Action.IMPORT_DATABASES -> resourceHelper.gs(R.string.uel_import_databases) + Action.OTP_EXPORT -> resourceHelper.gs(R.string.uel_otp_export) + Action.OTP_RESET -> resourceHelper.gs(R.string.uel_otp_reset) + Action.EXPORT_CSV -> resourceHelper.gs(R.string.uel_export_csv) + Action.STOP_SMS -> resourceHelper.gs(R.string.uel_stop_sms) + Action.START_AAPS -> resourceHelper.gs(R.string.uel_start_aaps) + Action.EXIT_AAPS -> resourceHelper.gs(R.string.uel_exit_aaps) + Action.PLUGIN_ENABLED -> resourceHelper.gs(R.string.uel_plugin_enabled) + Action.PLUGIN_DISABLED -> resourceHelper.gs(R.string.uel_plugin_disabled) + Action.UNKNOWN -> resourceHelper.gs(R.string.unknown) + } - Action.BOLUS.name -> resourceHelper.gs(R.string.uel_bolus) - Action.BOLUS_ADVISOR.name -> resourceHelper.gs(R.string.uel_bolus_advisor) - Action.BOLUS_RECORD.name -> resourceHelper.gs(R.string.uel_bolus_record) - Action.EXTENDED_BOLUS.name -> resourceHelper.gs(R.string.uel_extended_bolus) - Action.SUPERBOLUS_TBR.name -> resourceHelper.gs(R.string.uel_superbolus_tbr) - Action.CARBS.name -> resourceHelper.gs(R.string.uel_carbs) - Action.EXTENDED_CARBS.name -> resourceHelper.gs(R.string.uel_extended_carbs) - Action.TEMP_BASAL.name -> resourceHelper.gs(R.string.uel_temp_basal) - Action.TT.name -> resourceHelper.gs(R.string.uel_tt) - Action.NEW_PROFILE.name -> resourceHelper.gs(R.string.uel_new_profile) - Action.CLONE_PROFILE.name -> resourceHelper.gs(R.string.uel_clone_profile) - Action.STORE_PROFILE.name -> resourceHelper.gs(R.string.uel_store_profile) - Action.PROFILE_SWITCH.name -> resourceHelper.gs(R.string.uel_profile_switch) - Action.PROFILE_SWITCH_CLONED.name -> resourceHelper.gs(R.string.uel_profile_switch_cloned) - Action.CLOSED_LOOP_MODE.name -> resourceHelper.gs(R.string.uel_closed_loop_mode) - Action.LGS_LOOP_MODE.name -> resourceHelper.gs(R.string.uel_lgs_loop_mode) - Action.OPEN_LOOP_MODE.name -> resourceHelper.gs(R.string.uel_open_loop_mode) - Action.LOOP_DISABLED.name -> resourceHelper.gs(R.string.uel_loop_disabled) - Action.LOOP_ENABLED.name -> resourceHelper.gs(R.string.uel_loop_enabled) - Action.RECONNECT.name -> resourceHelper.gs(R.string.uel_reconnect) - Action.DISCONNECT.name -> resourceHelper.gs(R.string.uel_disconnect) - Action.RESUME.name -> resourceHelper.gs(R.string.uel_resume) - Action.SUSPEND.name -> resourceHelper.gs(R.string.uel_suspend) - Action.HW_PUMP_ALLOWED.name -> resourceHelper.gs(R.string.uel_hw_pump_allowed) - Action.CLEAR_PAIRING_KEYS.name -> resourceHelper.gs(R.string.uel_clear_pairing_keys) - Action.ACCEPTS_TEMP_BASAL.name -> resourceHelper.gs(R.string.uel_accepts_temp_basal) - Action.CANCEL_TEMP_BASAL.name -> resourceHelper.gs(R.string.uel_cancel_temp_basal) - Action.CANCEL_EXTENDED_BOLUS.name -> resourceHelper.gs(R.string.uel_cancel_extended_bolus) - Action.CANCEL_TT.name -> resourceHelper.gs(R.string.uel_cancel_tt) - Action.CAREPORTAL.name -> resourceHelper.gs(R.string.uel_careportal) - Action.CALIBRATION.name -> resourceHelper.gs(R.string.uel_calibration) - Action.PRIME_BOLUS.name -> resourceHelper.gs(R.string.uel_prime_bolus) - Action.TREATMENT.name -> resourceHelper.gs(R.string.uel_treatment) - Action.CAREPORTAL_NS_REFRESH.name -> resourceHelper.gs(R.string.uel_careportal_ns_refresh) - Action.PROFILE_SWITCH_NS_REFRESH.name -> resourceHelper.gs(R.string.uel_profile_switch_ns_refresh) - Action.TREATMENTS_NS_REFRESH.name -> resourceHelper.gs(R.string.uel_treatments_ns_refresh) - Action.TT_NS_REFRESH.name -> resourceHelper.gs(R.string.uel_tt_ns_refresh) - Action.AUTOMATION_REMOVED.name -> resourceHelper.gs(R.string.uel_automation_removed) - Action.BG_REMOVED.name -> resourceHelper.gs(R.string.uel_bg_removed) - Action.CAREPORTAL_REMOVED.name -> resourceHelper.gs(R.string.uel_careportal_removed) - Action.EXTENDED_BOLUS_REMOVED.name -> resourceHelper.gs(R.string.uel_extended_bolus_removed) - Action.FOOD_REMOVED.name -> resourceHelper.gs(R.string.uel_food_removed) - Action.PROFILE_REMOVED.name -> resourceHelper.gs(R.string.uel_profile_removed) - Action.PROFILE_SWITCH_REMOVED.name -> resourceHelper.gs(R.string.uel_profile_switch_removed) - Action.RESTART_EVENTS_REMOVED.name -> resourceHelper.gs(R.string.uel_restart_events_removed) - Action.TREATMENT_REMOVED.name -> resourceHelper.gs(R.string.uel_treatment_removed) - Action.TT_REMOVED.name -> resourceHelper.gs(R.string.uel_tt_removed) - Action.NS_PAUSED.name -> resourceHelper.gs(R.string.uel_ns_paused) - Action.NS_RESUME.name -> resourceHelper.gs(R.string.uel_ns_resume) - Action.NS_QUEUE_CLEARED.name -> resourceHelper.gs(R.string.uel_ns_queue_cleared) - Action.NS_SETTINGS_COPIED.name -> resourceHelper.gs(R.string.uel_ns_settings_copied) - Action.ERROR_DIALOG_OK.name -> resourceHelper.gs(R.string.uel_error_dialog_ok) - Action.ERROR_DIALOG_MUTE.name -> resourceHelper.gs(R.string.uel_error_dialog_mute) - Action.ERROR_DIALOG_MUTE_5MIN.name -> resourceHelper.gs(R.string.uel_error_dialog_mute_5min) - Action.OBJECTIVE_STARTED.name -> resourceHelper.gs(R.string.uel_objective_started) - Action.OBJECTIVE_UNSTARTED.name -> resourceHelper.gs(R.string.uel_objective_unstarted) - Action.OBJECTIVES_SKIPPED.name -> resourceHelper.gs(R.string.uel_objectives_skipped) - Action.STAT_RESET.name -> resourceHelper.gs(R.string.uel_stat_reset) - Action.DELETE_LOGS.name -> resourceHelper.gs(R.string.uel_delete_logs) - Action.DELETE_FUTURE_TREATMENTS.name -> resourceHelper.gs(R.string.uel_delete_future_treatments) - Action.EXPORT_SETTINGS.name -> resourceHelper.gs(R.string.uel_export_settings) - Action.IMPORT_SETTINGS.name -> resourceHelper.gs(R.string.uel_import_settings) - Action.RESET_DATABASES.name -> resourceHelper.gs(R.string.uel_reset_databases) - Action.EXPORT_DATABASES.name -> resourceHelper.gs(R.string.uel_export_databases) - Action.IMPORT_DATABASES.name -> resourceHelper.gs(R.string.uel_import_databases) - Action.OTP_EXPORT.name -> resourceHelper.gs(R.string.uel_otp_export) - Action.OTP_RESET.name -> resourceHelper.gs(R.string.uel_otp_reset) - Action.SMS_BASAL.name -> resourceHelper.gs(R.string.uel_sms_basal) - Action.SMS_BOLUS.name -> resourceHelper.gs(R.string.uel_sms_bolus) - Action.SMS_CAL.name -> resourceHelper.gs(R.string.uel_sms_cal) - Action.SMS_CARBS.name -> resourceHelper.gs(R.string.uel_sms_carbs) - Action.SMS_EXTENDED_BOLUS.name -> resourceHelper.gs(R.string.uel_sms_extended_bolus) - Action.SMS_LOOP_DISABLED.name -> resourceHelper.gs(R.string.uel_sms_loop_disabled) - Action.SMS_LOOP_ENABLED.name -> resourceHelper.gs(R.string.uel_sms_loop_enabled) - Action.SMS_LOOP_RESUME.name -> resourceHelper.gs(R.string.uel_sms_loop_resume) - Action.SMS_LOOP_SUSPEND.name -> resourceHelper.gs(R.string.uel_sms_loop_suspend) - Action.SMS_PROFILE.name -> resourceHelper.gs(R.string.uel_sms_profile) - Action.SMS_PUMP_CONNECT.name -> resourceHelper.gs(R.string.uel_sms_pump_connect) - Action.SMS_PUMP_DISCONNECT.name -> resourceHelper.gs(R.string.uel_sms_pump_disconnect) - Action.SMS_SMS.name -> resourceHelper.gs(R.string.uel_sms_sms) - Action.SMS_TT.name -> resourceHelper.gs(R.string.uel_sms_tt) - Action.TT_DELETED_FROM_NS.name -> resourceHelper.gs(R.string.uel_tt_deleted_from_ns) - Action.TT_FROM_NS.name -> resourceHelper.gs(R.string.uel_tt_from_ns) - Action.TT_CANCELED_FROM_NS.name -> resourceHelper.gs(R.string.uel_tt_canceleted_from_ns) - Action.CAREPORTAL_DELETED_FROM_NS.name -> resourceHelper.gs(R.string.uel_careportal_deleted_from_ns) - Action.CAREPORTAL_FROM_NS.name -> resourceHelper.gs(R.string.uel_careportal_from_ns) - Action.EXPORT_CSV.name -> resourceHelper.gs(R.string.uel_export_csv) + fun translate(units: ValueWithUnit?): String = when(units) { + is ValueWithUnit.Gram -> resourceHelper.gs(R.string.shortgram) + is ValueWithUnit.Hour -> resourceHelper.gs(R.string.shorthour) + is ValueWithUnit.Insulin -> resourceHelper.gs(R.string.insulin_unit_shortname) + is ValueWithUnit.Mgdl -> resourceHelper.gs(R.string.mgdl) + is ValueWithUnit.Minute -> resourceHelper.gs(R.string.shortminute) + is ValueWithUnit.Mmoll -> resourceHelper.gs(R.string.mmol) + is ValueWithUnit.Percent -> resourceHelper.gs(R.string.shortpercent) + is ValueWithUnit.UnitPerHour -> resourceHelper.gs(R.string.profile_ins_units_per_hour) + else -> "" + } - Units.Mg_Dl.name -> resourceHelper.gs(R.string.mgdl) - Units.Mmol_L.name -> resourceHelper.gs(R.string.mmol) - Units.U.name -> resourceHelper.gs(R.string.insulin_unit_shortname) - Units.U_H.name -> resourceHelper.gs(R.string.profile_ins_units_per_hour) - Units.G.name -> resourceHelper.gs(R.string.shortgram) - Units.M.name -> resourceHelper.gs(R.string.shortminute) - Units.H.name -> resourceHelper.gs(R.string.shorthour) - Units.Percent.name -> resourceHelper.gs(R.string.shortpercent) - Units.None.name -> "" + fun translate(meterType: TherapyEvent.MeterType): String = when(meterType) { + TherapyEvent.MeterType.FINGER -> resourceHelper.gs(R.string.glucosetype_finger) + TherapyEvent.MeterType.SENSOR -> resourceHelper.gs(R.string.glucosetype_sensor) + TherapyEvent.MeterType.MANUAL -> resourceHelper.gs(R.string.manual) - else -> resourceHelper.gs(R.string.unknown) - } + else -> resourceHelper.gs(R.string.unknown) + } + + fun translate(type: TherapyEvent.Type): String = when(type) { + TherapyEvent.Type.FINGER_STICK_BG_VALUE -> resourceHelper.gs(R.string.careportal_bgcheck) + TherapyEvent.Type.SNACK_BOLUS -> resourceHelper.gs(R.string.careportal_snackbolus) + TherapyEvent.Type.MEAL_BOLUS -> resourceHelper.gs(R.string.careportal_mealbolus) + TherapyEvent.Type.CORRECTION_BOLUS -> resourceHelper.gs(R.string.careportal_correctionbolus) + TherapyEvent.Type.CARBS_CORRECTION -> resourceHelper.gs(R.string.careportal_carbscorrection) + TherapyEvent.Type.BOLUS_WIZARD -> resourceHelper.gs(R.string.boluswizard) + TherapyEvent.Type.COMBO_BOLUS -> resourceHelper.gs(R.string.careportal_combobolus) + TherapyEvent.Type.ANNOUNCEMENT -> resourceHelper.gs(R.string.careportal_announcement) + TherapyEvent.Type.NOTE -> resourceHelper.gs(R.string.careportal_note) + TherapyEvent.Type.QUESTION -> resourceHelper.gs(R.string.careportal_question) + TherapyEvent.Type.EXERCISE -> resourceHelper.gs(R.string.careportal_exercise) + TherapyEvent.Type.CANNULA_CHANGE -> resourceHelper.gs(R.string.careportal_pumpsitechange) + TherapyEvent.Type.PUMP_BATTERY_CHANGE -> resourceHelper.gs(R.string.careportal_pumpbatterychange) + TherapyEvent.Type.SENSOR_STARTED -> resourceHelper.gs(R.string.careportal_cgmsensorstart) + TherapyEvent.Type.SENSOR_STOPPED -> resourceHelper.gs(R.string.careportal_cgm_sensor_stop) + TherapyEvent.Type.SENSOR_CHANGE -> resourceHelper.gs(R.string.careportal_cgmsensorinsert) + TherapyEvent.Type.INSULIN_CHANGE -> resourceHelper.gs(R.string.careportal_insulincartridgechange) + TherapyEvent.Type.DAD_ALERT -> resourceHelper.gs(R.string.careportal_dad_alert) + TherapyEvent.Type.TEMPORARY_BASAL_START -> resourceHelper.gs(R.string.careportal_tempbasalstart) + TherapyEvent.Type.TEMPORARY_BASAL_END -> resourceHelper.gs(R.string.careportal_tempbasalend) + TherapyEvent.Type.PROFILE_SWITCH -> resourceHelper.gs(R.string.careportal_profileswitch) + TherapyEvent.Type.TEMPORARY_TARGET -> resourceHelper.gs(R.string.careportal_temporarytarget) + TherapyEvent.Type.TEMPORARY_TARGET_CANCEL -> resourceHelper.gs(R.string.careportal_temporarytargetcancel) + TherapyEvent.Type.APS_OFFLINE -> resourceHelper.gs(R.string.careportal_openapsoffline) + TherapyEvent.Type.NS_MBG -> resourceHelper.gs(R.string.careportal_mbg) +/* + TherapyEvent.Type.TEMPORARY_BASAL -> TODO() + TherapyEvent.Type.TUBE_CHANGE -> TODO() + TherapyEvent.Type.FALLING_ASLEEP -> TODO() + TherapyEvent.Type.BATTERY_EMPTY -> TODO() + TherapyEvent.Type.RESERVOIR_EMPTY -> TODO() + TherapyEvent.Type.OCCLUSION -> TODO() + TherapyEvent.Type.PUMP_STOPPED -> TODO() + TherapyEvent.Type.PUMP_STARTED -> TODO() + TherapyEvent.Type.PUMP_PAUSED -> TODO() + TherapyEvent.Type.WAKING_UP -> TODO() + TherapyEvent.Type.SICKNESS -> TODO() + TherapyEvent.Type.STRESS -> TODO() + TherapyEvent.Type.PRE_PERIOD -> TODO() + TherapyEvent.Type.ALCOHOL -> TODO() + TherapyEvent.Type.CORTISONE -> TODO() + TherapyEvent.Type.FEELING_LOW -> TODO() + TherapyEvent.Type.FEELING_HIGH -> TODO() + TherapyEvent.Type.LEAKING_INFUSION_SET -> TODO() + */ + TherapyEvent.Type.NONE -> resourceHelper.gs(R.string.unknown) + + else -> resourceHelper.gs(R.string.unknown) + } + + fun translate(reason: TemporaryTarget.Reason): String = when(reason) { + TemporaryTarget.Reason.CUSTOM -> resourceHelper.gs(R.string.custom) + TemporaryTarget.Reason.HYPOGLYCEMIA -> resourceHelper.gs(R.string.hypo) + TemporaryTarget.Reason.EATING_SOON -> resourceHelper.gs(R.string.eatingsoon) + TemporaryTarget.Reason.ACTIVITY -> resourceHelper.gs(R.string.activity) + TemporaryTarget.Reason.AUTOMATION -> resourceHelper.gs(R.string.automation) + TemporaryTarget.Reason.WEAR -> resourceHelper.gs(R.string.wear) + + else -> resourceHelper.gs(R.string.unknown) + } + + fun translate(source: Sources): String = when(source) { + /* + Sources.TreatmentDialog -> TODO() + Sources.InsulinDialog -> TODO() + Sources.CarbDialog -> TODO() + Sources.WizardDialog -> TODO() + Sources.QuickWizard -> TODO() + Sources.ExtendedBolusDialog -> TODO() + Sources.TTDialog -> TODO() + Sources.ProfileSwitchDialog -> TODO() + Sources.LoopDialog -> TODO() + Sources.TempBasalDialog -> TODO() + Sources.CalibrationDialog -> TODO() + Sources.FillDialog -> TODO() + + Sources.BgCheck -> TODO() + Sources.SensorInsert -> TODO() + Sources.BatteryChange -> TODO() + Sources.Note -> TODO() + Sources.Exercise -> TODO() + Sources.Question -> TODO() + Sources.Announcement -> TODO() + Sources.Actions -> TODO() + Sources.BG -> TODO() + Sources.LocalProfile -> TODO() + Sources.Maintenance -> TODO() + Sources.NSProfile -> TODO() + Sources.Objectives -> TODO() + Sources.Treatments -> TODO() + Sources.Food -> TODO() + Sources.ConfigBuilder -> TODO() + Sources.Overview -> TODO() + Sources.Stats -> TODO() + Sources.TreatmentDialog -> TODO() + Sources.InsulinDialog -> TODO() + Sources.CarbDialog -> TODO() + Sources.WizardDialog -> TODO() + Sources.QuickWizard -> TODO() + Sources.ExtendedBolusDialog -> TODO() + Sources.TTDialog -> TODO() + Sources.ProfileSwitchDialog -> TODO() + Sources.LoopDialog -> TODO() + Sources.TempBasalDialog -> TODO() + Sources.CalibrationDialog -> TODO() + Sources.FillDialog -> TODO() + Sources.BgCheck -> TODO() + Sources.SensorInsert -> TODO() + Sources.BatteryChange -> TODO() + Sources.Note -> TODO() + Sources.Exercise -> TODO() + Sources.Question -> TODO() + Sources.Announcement -> TODO() + Sources.Actions -> TODO() + Sources.BG -> TODO() + Sources.Dexcom -> TODO() + Sources.Eversense -> TODO() + Sources.Glimp -> TODO() + Sources.MM640g -> TODO() + Sources.NSClientSource -> TODO() + Sources.PocTech -> TODO() + Sources.Tomato -> TODO() + Sources.Xdrip -> TODO() + Sources.LocalProfile -> TODO() + Sources.Maintenance -> TODO() + Sources.NSProfile -> TODO() + Sources.Objectives -> TODO() + Sources.Dana -> TODO() + Sources.DanaR -> TODO() + Sources.DanaRC -> TODO() + Sources.DanaRv2 -> TODO() + Sources.DanaRS -> TODO() + Sources.Insight -> TODO() + Sources.Combo -> TODO() + Sources.Medtronic -> TODO() + Sources.Omnipod -> TODO() + Sources.OmnipodEros -> TODO() + Sources.OmnipodDash -> TODO() + Sources.MDI -> TODO() + Sources.VirtualPump -> TODO() + Sources.Treatments -> TODO() + Sources.Food -> TODO() + Sources.ConfigBuilder -> TODO() + Sources.Overview -> TODO() + Sources.Stats -> TODO() + Sources.Aaps -> TODO() + */ + Sources.Automation -> resourceHelper.gs(R.string.automation) + Sources.Loop -> resourceHelper.gs(R.string.loop) + Sources.NSClient -> resourceHelper.gs(R.string.ns) + Sources.Pump -> resourceHelper.gs(R.string.pump) + Sources.SMS -> resourceHelper.gs(R.string.smb_shortname) + Sources.Wear -> resourceHelper.gs(R.string.wear) + Sources.Unknown -> resourceHelper.gs(R.string.unknown) + + else -> source.name + } } \ No newline at end of file diff --git a/core/src/main/java/info/nightscout/androidaps/utils/WarnColors.kt b/core/src/main/java/info/nightscout/androidaps/utils/WarnColors.kt index c1b072234f..e61b6bd327 100644 --- a/core/src/main/java/info/nightscout/androidaps/utils/WarnColors.kt +++ b/core/src/main/java/info/nightscout/androidaps/utils/WarnColors.kt @@ -4,7 +4,7 @@ import android.graphics.Color import android.widget.TextView import info.nightscout.androidaps.core.R import info.nightscout.androidaps.database.entities.TherapyEvent -import info.nightscout.androidaps.utils.extensions.isOlderThan +import info.nightscout.androidaps.extensions.isOlderThan import info.nightscout.androidaps.utils.resources.ResourceHelper import javax.inject.Inject import javax.inject.Singleton diff --git a/core/src/main/java/info/nightscout/androidaps/utils/alertDialogs/OKDialog.kt b/core/src/main/java/info/nightscout/androidaps/utils/alertDialogs/OKDialog.kt index 373935fb94..76e64ebaf3 100644 --- a/core/src/main/java/info/nightscout/androidaps/utils/alertDialogs/OKDialog.kt +++ b/core/src/main/java/info/nightscout/androidaps/utils/alertDialogs/OKDialog.kt @@ -7,7 +7,7 @@ import android.os.SystemClock import android.text.Spanned import androidx.fragment.app.FragmentActivity import info.nightscout.androidaps.core.R -import info.nightscout.androidaps.utils.extensions.runOnUiThread +import info.nightscout.androidaps.extensions.runOnUiThread object OKDialog { diff --git a/core/src/main/java/info/nightscout/androidaps/utils/alertDialogs/WarningDialog.kt b/core/src/main/java/info/nightscout/androidaps/utils/alertDialogs/WarningDialog.kt index 2894f1b8d4..38f3314667 100644 --- a/core/src/main/java/info/nightscout/androidaps/utils/alertDialogs/WarningDialog.kt +++ b/core/src/main/java/info/nightscout/androidaps/utils/alertDialogs/WarningDialog.kt @@ -6,7 +6,7 @@ import android.content.DialogInterface import android.os.SystemClock import androidx.annotation.StringRes import info.nightscout.androidaps.core.R -import info.nightscout.androidaps.utils.extensions.runOnUiThread +import info.nightscout.androidaps.extensions.runOnUiThread // if you need error dialog - duplicate to ErrorDialog and make it and use: AppThemeErrorDialog & R.drawable.ic_header_error instead diff --git a/core/src/main/java/info/nightscout/androidaps/utils/protection/BiometricCheck.kt b/core/src/main/java/info/nightscout/androidaps/utils/protection/BiometricCheck.kt index b74b3377dc..fe46155c8b 100644 --- a/core/src/main/java/info/nightscout/androidaps/utils/protection/BiometricCheck.kt +++ b/core/src/main/java/info/nightscout/androidaps/utils/protection/BiometricCheck.kt @@ -5,7 +5,7 @@ import androidx.biometric.BiometricPrompt.* import androidx.fragment.app.FragmentActivity import info.nightscout.androidaps.core.R import info.nightscout.androidaps.utils.ToastUtils -import info.nightscout.androidaps.utils.extensions.runOnUiThread +import info.nightscout.androidaps.extensions.runOnUiThread import java.util.concurrent.Executors object BiometricCheck { diff --git a/core/src/main/java/info/nightscout/androidaps/utils/resources/ResourceHelper.kt b/core/src/main/java/info/nightscout/androidaps/utils/resources/ResourceHelper.kt index 7701def98d..7a068c57ee 100644 --- a/core/src/main/java/info/nightscout/androidaps/utils/resources/ResourceHelper.kt +++ b/core/src/main/java/info/nightscout/androidaps/utils/resources/ResourceHelper.kt @@ -10,6 +10,7 @@ interface ResourceHelper { fun gs(@StringRes id: Int): String fun gs(@StringRes id: Int, vararg args: Any?): String fun gq(@PluralsRes id: Int, quantity: Int, vararg args: Any?): String + fun gsNotLocalised(@StringRes id: Int, vararg args: Any?): String fun gc(@ColorRes id: Int): Int fun gd(@DrawableRes id: Int): Drawable? fun gb(@BoolRes id :Int) : Boolean diff --git a/core/src/main/java/info/nightscout/androidaps/utils/resources/ResourceHelperImplementation.kt b/core/src/main/java/info/nightscout/androidaps/utils/resources/ResourceHelperImplementation.kt index 3e2c3bf461..214ccc8b53 100644 --- a/core/src/main/java/info/nightscout/androidaps/utils/resources/ResourceHelperImplementation.kt +++ b/core/src/main/java/info/nightscout/androidaps/utils/resources/ResourceHelperImplementation.kt @@ -3,6 +3,7 @@ package info.nightscout.androidaps.utils.resources import android.annotation.SuppressLint import android.content.Context import android.content.res.AssetFileDescriptor +import android.content.res.Configuration import android.graphics.Bitmap import android.graphics.BitmapFactory import android.graphics.drawable.Drawable @@ -10,6 +11,7 @@ import android.util.DisplayMetrics import androidx.annotation.* import androidx.core.content.ContextCompat import info.nightscout.androidaps.core.R +import java.util.* import javax.inject.Inject /** @@ -24,6 +26,12 @@ class ResourceHelperImplementation @Inject constructor(private val context: Cont override fun gq(@PluralsRes id: Int, quantity: Int, vararg args: Any?): String = context.resources.getQuantityString(id, quantity, *args) + override fun gsNotLocalised(@StringRes id: Int, vararg args: Any?) : String = + with(Configuration(context.resources.configuration)) { + setLocale(Locale.ENGLISH) + context.createConfigurationContext(this).getString(id, args) + } + override fun gc(@ColorRes id: Int): Int = ContextCompat.getColor(context, id) override fun gd(@DrawableRes id: Int): Drawable? = context.getDrawable(id) diff --git a/core/src/main/java/info/nightscout/androidaps/utils/serialisation/SealedClassHelper.kt b/core/src/main/java/info/nightscout/androidaps/utils/serialisation/SealedClassHelper.kt new file mode 100644 index 0000000000..a3fd471bd2 --- /dev/null +++ b/core/src/main/java/info/nightscout/androidaps/utils/serialisation/SealedClassHelper.kt @@ -0,0 +1,52 @@ +package info.nightscout.androidaps.utils.serialisation + +import com.google.gson.Gson +import com.google.gson.GsonBuilder +import com.google.gson.TypeAdapter +import com.google.gson.TypeAdapterFactory +import com.google.gson.reflect.TypeToken +import com.google.gson.stream.JsonReader +import com.google.gson.stream.JsonWriter +import kotlin.jvm.internal.Reflection +import kotlin.reflect.KClass + +object SealedClassHelper { + + val gson: Gson = GsonBuilder().registerTypeAdapterFactory( + object : TypeAdapterFactory { + override fun create(gson: Gson, type: TypeToken): TypeAdapter { + val kClass = Reflection.getOrCreateKotlinClass(type.rawType) + return if (kClass.sealedSubclasses.any()) { + SealedClassTypeAdapter(kClass, gson) + } else + gson.getDelegateAdapter(this, type) + } + }).create() + + private class SealedClassTypeAdapter(private val kClass: KClass, val gson: Gson) : TypeAdapter() { + + override fun read(jsonReader: JsonReader): T? { + jsonReader.beginObject() + val nextName = jsonReader.nextName() + val innerClass = kClass.sealedSubclasses.firstOrNull { it.simpleName == nextName } + ?: throw Exception("$nextName is not a child of the sealed class ${kClass.qualifiedName}") + val x = gson.fromJson(jsonReader, innerClass.javaObjectType) + jsonReader.endObject() + // if there a static object, actually return that + @Suppress("UNCHECKED_CAST") + return innerClass.objectInstance as T? ?: x + } + + override fun write(out: JsonWriter, value: T) { + val jsonString = gson.toJson(value) + val name = value.javaClass.canonicalName + if (name != null) { + out.beginObject() + out.name(name.splitToSequence(".").last()).jsonValue(jsonString) + out.endObject() + } + } + } +} + +inline fun Gson.fromJson(json: String): T = fromJson(json, object : TypeToken() {}.type) diff --git a/core/src/main/java/info/nightscout/androidaps/utils/serialisation/ValueWithUnitSerialiser.kt b/core/src/main/java/info/nightscout/androidaps/utils/serialisation/ValueWithUnitSerialiser.kt new file mode 100644 index 0000000000..42db084ddc --- /dev/null +++ b/core/src/main/java/info/nightscout/androidaps/utils/serialisation/ValueWithUnitSerialiser.kt @@ -0,0 +1,14 @@ +package info.nightscout.androidaps.utils.serialisation + +import info.nightscout.androidaps.database.entities.ValueWithUnit + +object ValueWithUnitSerialiser { + + fun toSealedClassJson(list: List): String = list.map(::ValueWithUnitWrapper) + .let(SealedClassHelper.gson::toJson) + + fun fromJson(string: String): List = SealedClassHelper.gson + .fromJson>(string).map { it.wrapped } + + private class ValueWithUnitWrapper(val wrapped: ValueWithUnit) +} \ No newline at end of file diff --git a/core/src/main/java/info/nightscout/androidaps/utils/ui/UIRunnable.kt b/core/src/main/java/info/nightscout/androidaps/utils/ui/UIRunnable.kt index d3860ac53b..36f44f6693 100644 --- a/core/src/main/java/info/nightscout/androidaps/utils/ui/UIRunnable.kt +++ b/core/src/main/java/info/nightscout/androidaps/utils/ui/UIRunnable.kt @@ -1,6 +1,6 @@ package info.nightscout.androidaps.utils.ui -import info.nightscout.androidaps.utils.extensions.runOnUiThread +import info.nightscout.androidaps.extensions.runOnUiThread class UIRunnable (val runnable: Runnable) : Runnable { override fun run() { diff --git a/core/src/main/java/info/nightscout/androidaps/utils/ui/WeekdayPicker.kt b/core/src/main/java/info/nightscout/androidaps/utils/ui/WeekdayPicker.kt index e3352ec94d..e76dc1b2e1 100644 --- a/core/src/main/java/info/nightscout/androidaps/utils/ui/WeekdayPicker.kt +++ b/core/src/main/java/info/nightscout/androidaps/utils/ui/WeekdayPicker.kt @@ -7,7 +7,7 @@ import android.widget.Checkable import androidx.appcompat.widget.AppCompatCheckedTextView import androidx.constraintlayout.widget.ConstraintLayout import info.nightscout.androidaps.core.databinding.WeekdayPickerBinding -import info.nightscout.androidaps.utils.extensions.toVisibility +import info.nightscout.androidaps.extensions.toVisibility import java.util.* class WeekdayPicker @JvmOverloads constructor( diff --git a/core/src/main/java/info/nightscout/androidaps/utils/userEntry/UserEntryMapper.kt b/core/src/main/java/info/nightscout/androidaps/utils/userEntry/UserEntryMapper.kt new file mode 100644 index 0000000000..9bcd0ab632 --- /dev/null +++ b/core/src/main/java/info/nightscout/androidaps/utils/userEntry/UserEntryMapper.kt @@ -0,0 +1,150 @@ +package info.nightscout.androidaps.utils.userEntry + +import info.nightscout.androidaps.database.entities.UserEntry + +class UserEntryMapper { + enum class Action (val db: UserEntry.Action) { + BOLUS (UserEntry.Action.BOLUS), + SMB (UserEntry.Action.SMB), + BOLUS_ADVISOR (UserEntry.Action.BOLUS_ADVISOR), + EXTENDED_BOLUS (UserEntry.Action.EXTENDED_BOLUS), + SUPERBOLUS_TBR (UserEntry.Action.SUPERBOLUS_TBR), + CARBS (UserEntry.Action.CARBS), + EXTENDED_CARBS (UserEntry.Action.EXTENDED_CARBS), + TEMP_BASAL (UserEntry.Action.TEMP_BASAL), + TT (UserEntry.Action.TT), + NEW_PROFILE (UserEntry.Action.NEW_PROFILE), + CLONE_PROFILE (UserEntry.Action.CLONE_PROFILE), + STORE_PROFILE (UserEntry.Action.STORE_PROFILE), + PROFILE_SWITCH (UserEntry.Action.PROFILE_SWITCH), + PROFILE_SWITCH_CLONED (UserEntry.Action.PROFILE_SWITCH_CLONED), + CLOSED_LOOP_MODE (UserEntry.Action.CLOSED_LOOP_MODE), + LGS_LOOP_MODE (UserEntry.Action.LGS_LOOP_MODE), + OPEN_LOOP_MODE (UserEntry.Action.OPEN_LOOP_MODE), + LOOP_DISABLED (UserEntry.Action.LOOP_DISABLED), + LOOP_ENABLED (UserEntry.Action.LOOP_ENABLED), + RECONNECT (UserEntry.Action.RECONNECT), + DISCONNECT (UserEntry.Action.DISCONNECT), + RESUME (UserEntry.Action.RESUME), + SUSPEND (UserEntry.Action.SUSPEND), + HW_PUMP_ALLOWED (UserEntry.Action.HW_PUMP_ALLOWED), + CLEAR_PAIRING_KEYS (UserEntry.Action.CLEAR_PAIRING_KEYS), + ACCEPTS_TEMP_BASAL (UserEntry.Action.ACCEPTS_TEMP_BASAL), + CANCEL_TEMP_BASAL (UserEntry.Action.CANCEL_TEMP_BASAL), + CANCEL_EXTENDED_BOLUS (UserEntry.Action.CANCEL_EXTENDED_BOLUS), + CANCEL_TT (UserEntry.Action.CANCEL_TT), + CAREPORTAL (UserEntry.Action.CAREPORTAL), + SITE_CHANGE (UserEntry.Action.SITE_CHANGE), + RESERVOIR_CHANGE (UserEntry.Action.RESERVOIR_CHANGE), + CALIBRATION (UserEntry.Action.CALIBRATION), + PRIME_BOLUS (UserEntry.Action.PRIME_BOLUS), + TREATMENT (UserEntry.Action.TREATMENT), + CAREPORTAL_NS_REFRESH (UserEntry.Action.CAREPORTAL_NS_REFRESH), + PROFILE_SWITCH_NS_REFRESH (UserEntry.Action.PROFILE_SWITCH_NS_REFRESH), + TREATMENTS_NS_REFRESH (UserEntry.Action.TREATMENTS_NS_REFRESH), + TT_NS_REFRESH (UserEntry.Action.TT_NS_REFRESH), + AUTOMATION_REMOVED (UserEntry.Action.AUTOMATION_REMOVED), + BG_REMOVED (UserEntry.Action.BG_REMOVED), + CAREPORTAL_REMOVED (UserEntry.Action.CAREPORTAL_REMOVED), + EXTENDED_BOLUS_REMOVED (UserEntry.Action.EXTENDED_BOLUS_REMOVED), + FOOD_REMOVED (UserEntry.Action.FOOD_REMOVED), + PROFILE_REMOVED (UserEntry.Action.PROFILE_REMOVED), + PROFILE_SWITCH_REMOVED (UserEntry.Action.PROFILE_SWITCH_REMOVED), + RESTART_EVENTS_REMOVED (UserEntry.Action.RESTART_EVENTS_REMOVED), + TREATMENT_REMOVED (UserEntry.Action.TREATMENT_REMOVED), + BOLUS_REMOVED (UserEntry.Action.BOLUS_REMOVED), + CARBS_REMOVED (UserEntry.Action.CARBS_REMOVED), + TEMP_BASAL_REMOVED (UserEntry.Action.TEMP_BASAL_REMOVED), + TT_REMOVED (UserEntry.Action.TT_REMOVED), + NS_PAUSED (UserEntry.Action.NS_PAUSED), + NS_RESUME (UserEntry.Action.NS_RESUME), + NS_QUEUE_CLEARED (UserEntry.Action.NS_QUEUE_CLEARED), + NS_SETTINGS_COPIED (UserEntry.Action.NS_SETTINGS_COPIED), + ERROR_DIALOG_OK (UserEntry.Action.ERROR_DIALOG_OK), + ERROR_DIALOG_MUTE (UserEntry.Action.ERROR_DIALOG_MUTE), + ERROR_DIALOG_MUTE_5MIN (UserEntry.Action.ERROR_DIALOG_MUTE_5MIN), + OBJECTIVE_STARTED (UserEntry.Action.OBJECTIVE_STARTED), + OBJECTIVE_UNSTARTED (UserEntry.Action.OBJECTIVE_UNSTARTED), + OBJECTIVES_SKIPPED (UserEntry.Action.OBJECTIVES_SKIPPED), + STAT_RESET (UserEntry.Action.STAT_RESET), + DELETE_LOGS (UserEntry.Action.DELETE_LOGS), + DELETE_FUTURE_TREATMENTS (UserEntry.Action.DELETE_FUTURE_TREATMENTS), + EXPORT_SETTINGS (UserEntry.Action.EXPORT_SETTINGS), + IMPORT_SETTINGS (UserEntry.Action.IMPORT_SETTINGS), + RESET_DATABASES (UserEntry.Action.RESET_DATABASES), + EXPORT_DATABASES (UserEntry.Action.EXPORT_DATABASES), + IMPORT_DATABASES (UserEntry.Action.IMPORT_DATABASES), + OTP_EXPORT (UserEntry.Action.OTP_EXPORT), + OTP_RESET (UserEntry.Action.OTP_RESET), + STOP_SMS (UserEntry.Action.STOP_SMS), + FOOD (UserEntry.Action.FOOD), + EXPORT_CSV (UserEntry.Action.EXPORT_CSV), + START_AAPS (UserEntry.Action.START_AAPS), + EXIT_AAPS (UserEntry.Action.EXIT_AAPS), + UNKNOWN (UserEntry.Action.UNKNOWN) + ; + } + + enum class Sources (val db: UserEntry.Sources) { + TreatmentDialog (UserEntry.Sources.TreatmentDialog), + InsulinDialog (UserEntry.Sources.InsulinDialog), + CarbDialog (UserEntry.Sources.CarbDialog), + WizardDialog (UserEntry.Sources.WizardDialog), + QuickWizard (UserEntry.Sources.QuickWizard), + ExtendedBolusDialog (UserEntry.Sources.ExtendedBolusDialog), + TTDialog (UserEntry.Sources.TTDialog), + ProfileSwitchDialog (UserEntry.Sources.ProfileSwitchDialog), + LoopDialog (UserEntry.Sources.LoopDialog), + TempBasalDialog (UserEntry.Sources.TempBasalDialog), + CalibrationDialog (UserEntry.Sources.CalibrationDialog), + FillDialog (UserEntry.Sources.FillDialog), + BgCheck (UserEntry.Sources.BgCheck), + SensorInsert (UserEntry.Sources.SensorInsert), + BatteryChange (UserEntry.Sources.BatteryChange), + Note (UserEntry.Sources.Note), + Exercise (UserEntry.Sources.Exercise), + Question (UserEntry.Sources.Question), + Announcement (UserEntry.Sources.Announcement), + Actions (UserEntry.Sources.Actions), + Automation (UserEntry.Sources.Automation), + BG (UserEntry.Sources.BG), + Dexcom (UserEntry.Sources.Dexcom), + Eversense (UserEntry.Sources.Eversense), + Glimp (UserEntry.Sources.Glimp), + MM640g (UserEntry.Sources.MM640g), + NSClientSource (UserEntry.Sources.BG), + PocTech (UserEntry.Sources.PocTech), + Tomato (UserEntry.Sources.Tomato), + Xdrip (UserEntry.Sources.Xdrip), + LocalProfile (UserEntry.Sources.LocalProfile), + Loop (UserEntry.Sources.Loop), + Maintenance (UserEntry.Sources.Maintenance), + NSClient (UserEntry.Sources.NSClient), + NSProfile (UserEntry.Sources.NSProfile), + Objectives (UserEntry.Sources.Objectives), + Pump (UserEntry.Sources.Pump), + Dana (UserEntry.Sources.Dana), + DanaR (UserEntry.Sources.DanaR), + DanaRC (UserEntry.Sources.DanaRC), + DanaRv2 (UserEntry.Sources.DanaRv2), + DanaRS (UserEntry.Sources.DanaRS), + Insight (UserEntry.Sources.Insight), + Combo (UserEntry.Sources.Combo), + Medtronic (UserEntry.Sources.Medtronic), + Omnipod (UserEntry.Sources.Omnipod), + OmnipodEros (UserEntry.Sources.OmnipodEros), + OmnipodDash (UserEntry.Sources.OmnipodDash), + MDI (UserEntry.Sources.MDI), + VirtualPump (UserEntry.Sources.VirtualPump), + SMS (UserEntry.Sources.SMS), + Treatments (UserEntry.Sources.Treatments), + Wear (UserEntry.Sources.Wear), + Food (UserEntry.Sources.Food), + ConfigBuilder (UserEntry.Sources.ConfigBuilder), + Overview (UserEntry.Sources.Overview), + Stats (UserEntry.Sources.Stats), + Aaps (UserEntry.Sources.Aaps), + Unknown(UserEntry.Sources.Unknown) + ; + } +} \ No newline at end of file diff --git a/core/src/main/java/info/nightscout/androidaps/utils/userEntry/UserEntryPresentationHelper.kt b/core/src/main/java/info/nightscout/androidaps/utils/userEntry/UserEntryPresentationHelper.kt new file mode 100644 index 0000000000..b3a5049f9b --- /dev/null +++ b/core/src/main/java/info/nightscout/androidaps/utils/userEntry/UserEntryPresentationHelper.kt @@ -0,0 +1,226 @@ +package info.nightscout.androidaps.utils.userEntry + +import android.text.Spanned +import dagger.Reusable +import info.nightscout.androidaps.Constants +import info.nightscout.androidaps.core.R +import info.nightscout.androidaps.database.entities.UserEntry +import info.nightscout.androidaps.database.entities.UserEntry.Action +import info.nightscout.androidaps.database.entities.UserEntry.ColorGroup +import info.nightscout.androidaps.database.entities.UserEntry.Sources +import info.nightscout.androidaps.database.entities.ValueWithUnit +import info.nightscout.androidaps.interfaces.ProfileFunction +import info.nightscout.androidaps.utils.DateUtil +import info.nightscout.androidaps.utils.DecimalFormatter +import info.nightscout.androidaps.utils.HtmlHelper +import info.nightscout.androidaps.utils.Translator +import info.nightscout.androidaps.utils.resources.ResourceHelper +import javax.inject.Inject + +@Reusable +class UserEntryPresentationHelper @Inject constructor( + private val translator: Translator, + private val profileFunction: ProfileFunction, + private val resourceHelper: ResourceHelper, + private val dateUtil: DateUtil +) { + + fun colorId(colorGroup: ColorGroup): Int = when (colorGroup) { + ColorGroup.InsulinTreatment -> R.color.iob + ColorGroup.BasalTreatment -> R.color.basal + ColorGroup.CarbTreatment -> R.color.carbs + ColorGroup.TT -> R.color.tempTargetConfirmation + ColorGroup.Profile -> R.color.white + ColorGroup.Loop -> R.color.loopClosed + ColorGroup.Careportal -> R.color.high + ColorGroup.Pump -> R.color.loopDisconnected + ColorGroup.Aaps -> R.color.defaulttext + else -> R.color.defaulttext + } + + fun iconId(source: Sources): Int = when (source) { + Sources.TreatmentDialog -> R.drawable.icon_insulin_carbs + Sources.InsulinDialog -> R.drawable.ic_bolus + Sources.CarbDialog -> R.drawable.ic_cp_bolus_carbs + Sources.WizardDialog -> R.drawable.ic_calculator + Sources.QuickWizard -> R.drawable.ic_quick_wizard + Sources.ExtendedBolusDialog -> R.drawable.ic_actions_startextbolus + Sources.TTDialog -> R.drawable.ic_temptarget_high + Sources.ProfileSwitchDialog -> R.drawable.ic_actions_profileswitch + Sources.LoopDialog -> R.drawable.ic_loop_closed + Sources.TempBasalDialog -> R.drawable.ic_actions_starttempbasal + Sources.CalibrationDialog -> R.drawable.ic_calibration + Sources.FillDialog -> R.drawable.ic_cp_pump_canula + Sources.BgCheck -> R.drawable.ic_cp_bgcheck + Sources.SensorInsert -> R.drawable.ic_cp_cgm_insert + Sources.BatteryChange -> R.drawable.ic_cp_pump_battery + Sources.Note -> R.drawable.ic_cp_note + Sources.Exercise -> R.drawable.ic_cp_exercise + Sources.Question -> R.drawable.ic_cp_question + Sources.Announcement -> R.drawable.ic_cp_announcement + Sources.Actions -> R.drawable.ic_action + Sources.Automation -> R.drawable.ic_automation + Sources.BG -> R.drawable.ic_generic_cgm + Sources.Dexcom -> R.drawable.ic_dexcom_g6 + Sources.Eversense -> R.drawable.ic_eversense + Sources.Glimp -> R.drawable.ic_glimp + Sources.MM640g -> R.drawable.ic_generic_cgm + Sources.NSClientSource -> R.drawable.ic_nsclient_bg + Sources.PocTech -> R.drawable.ic_poctech + Sources.Tomato -> R.drawable.ic_sensor + Sources.Xdrip -> R.drawable.ic_blooddrop_48 + Sources.LocalProfile -> R.drawable.ic_local_profile + Sources.Loop -> R.drawable.ic_loop_closed_white + Sources.Maintenance -> R.drawable.ic_maintenance + Sources.NSClient -> R.drawable.ic_nightscout_syncs + Sources.NSProfile -> R.drawable.ic_nightscout_profile + Sources.Objectives -> R.drawable.ic_graduation + Sources.Pump -> R.drawable.ic_generic_icon + Sources.Dana -> R.drawable.ic_danars_128 + Sources.DanaR -> R.drawable.ic_danars_128 + Sources.DanaRC -> R.drawable.ic_danars_128 + Sources.DanaRv2 -> R.drawable.ic_danars_128 + Sources.DanaRS -> R.drawable.ic_danars_128 + Sources.Insight -> R.drawable.ic_insight_128 + Sources.Combo -> R.drawable.ic_combo_128 + Sources.Medtronic -> R.drawable.ic_veo_128 + Sources.Omnipod -> R.drawable.ic_pod_128 + Sources.OmnipodEros -> R.drawable.ic_pod_128 + Sources.OmnipodDash -> R.drawable.ic_pod_128 + Sources.MDI -> R.drawable.ic_ict + Sources.VirtualPump -> R.drawable.ic_virtual_pump + Sources.SMS -> R.drawable.ic_sms + Sources.Treatments -> R.drawable.ic_treatments + Sources.Wear -> R.drawable.ic_watch + Sources.Food -> R.drawable.ic_food + Sources.Stats -> R.drawable.ic_cp_stats + Sources.ConfigBuilder -> R.drawable.ic_cogs + Sources.Overview -> R.drawable.ic_notif_aaps + Sources.Aaps -> R.drawable.ic_notif_aaps + Sources.Unknown -> R.drawable.ic_generic_icon + } + + fun actionToColoredString(action: Action): Spanned = when (action) { + Action.TREATMENT -> HtmlHelper.fromHtml(coloredAction(Action.BOLUS) + " + " + coloredAction(Action.CARBS)) + else -> HtmlHelper.fromHtml(coloredAction(action)) + } + + private fun coloredAction(action: Action): String = "${translator.translate(action)}" + + fun listToPresentationString(list: List) = + list.joinToString(separator = " ", transform = this::toPresentationString) + + private fun toPresentationString(valueWithUnit: ValueWithUnit?): String = when (valueWithUnit) { + is ValueWithUnit.Gram -> "${valueWithUnit.value}${translator.translate(valueWithUnit)}" + is ValueWithUnit.Hour -> "${valueWithUnit.value}${translator.translate(valueWithUnit)}" + is ValueWithUnit.Minute -> "${valueWithUnit.value}${translator.translate(valueWithUnit)}" + is ValueWithUnit.Percent -> "${valueWithUnit.value}${translator.translate(valueWithUnit)}" + is ValueWithUnit.Insulin -> DecimalFormatter.to2Decimal(valueWithUnit.value) + translator.translate(valueWithUnit) + is ValueWithUnit.UnitPerHour -> DecimalFormatter.to2Decimal(valueWithUnit.value) + translator.translate(valueWithUnit) + is ValueWithUnit.SimpleInt -> valueWithUnit.value.toString() + is ValueWithUnit.SimpleString -> valueWithUnit.value + is ValueWithUnit.TherapyEventMeterType -> translator.translate(valueWithUnit.value) + is ValueWithUnit.TherapyEventTTReason -> translator.translate(valueWithUnit.value) + is ValueWithUnit.TherapyEventType -> translator.translate(valueWithUnit.value) + is ValueWithUnit.Timestamp -> dateUtil.dateAndTimeAndSecondsString(valueWithUnit.value) + + is ValueWithUnit.Mgdl -> { + if (profileFunction.getUnits() == Constants.MGDL) DecimalFormatter.to0Decimal(valueWithUnit.value) + translator.translate(valueWithUnit) + else DecimalFormatter.to1Decimal(valueWithUnit.value / Constants.MMOLL_TO_MGDL) + translator.translate(valueWithUnit) + } + + is ValueWithUnit.Mmoll -> { + if (profileFunction.getUnits() == Constants.MGDL) DecimalFormatter.to0Decimal(valueWithUnit.value) + translator.translate(valueWithUnit) + else DecimalFormatter.to1Decimal(valueWithUnit.value * Constants.MMOLL_TO_MGDL) + translator.translate(valueWithUnit) + } + + ValueWithUnit.UNKNOWN -> "" + null -> "" + } + + fun userEntriesToCsv(userEntries: List): String { + return getCsvHeader() + userEntries.joinToString("\n") { entry -> getCsvEntry(entry) } + } + + private fun getCsvHeader() = resourceHelper.gs(R.string.ue_csv_header, + csvString(R.string.ue_timestamp), + csvString(R.string.date), + csvString(R.string.ue_utc_offset), + csvString(R.string.ue_action), + csvString(R.string.eventtype), + csvString(R.string.ue_source), + csvString(R.string.careportal_note), + csvString(R.string.ue_formated_string), + csvString(R.string.event_time_label), + csvString(if (profileFunction.getUnits() == Constants.MGDL) R.string.mgdl else R.string.mmol), + csvString(R.string.shortgram), + csvString(R.string.insulin_unit_shortname), + csvString(R.string.profile_ins_units_per_hour), + csvString(R.string.shortpercent), + csvString(R.string.shorthour), + csvString(R.string.shortminute), + csvString(R.string.ue_none) + ) + "\n" + + private fun getCsvEntry(entry: UserEntry): String { + val fullvalueWithUnitList = ArrayList(entry.values) + var timestampRec = "" + entry.timestamp + var dateTimestampRev = dateUtil.dateAndTimeAndSecondsString(entry.timestamp) + var utcOffset = dateUtil.timeString(entry.utcOffset) + var action = csvString(entry.action) + var therapyEvent = "" + var source = translator.translate(entry.source) + var note = csvString(entry.note) + var stringResource = "" + var timestamp = "" + var bg = "" + var gram = "" + var insulin = "" + var unitPerHour = "" + var percent = "" + var hour = "" + var minute = "" + var other = "" + + for (valueWithUnit in fullvalueWithUnitList.filterNotNull()) { + when (valueWithUnit) { + is ValueWithUnit.Gram -> gram = valueWithUnit.value.toString() + is ValueWithUnit.Hour -> hour = valueWithUnit.value.toString() + is ValueWithUnit.Minute -> minute = valueWithUnit.value.toString() + is ValueWithUnit.Percent -> percent = valueWithUnit.value.toString() + is ValueWithUnit.Insulin -> insulin = DecimalFormatter.to2Decimal(valueWithUnit.value) + is ValueWithUnit.UnitPerHour -> unitPerHour = DecimalFormatter.to2Decimal(valueWithUnit.value) + is ValueWithUnit.SimpleInt -> other = other.addWithSeparator(valueWithUnit.value) + is ValueWithUnit.SimpleString -> other = other.addWithSeparator(valueWithUnit.value) + is ValueWithUnit.TherapyEventMeterType -> therapyEvent = therapyEvent.addWithSeparator(translator.translate(valueWithUnit.value)) + is ValueWithUnit.TherapyEventTTReason -> therapyEvent = therapyEvent.addWithSeparator(translator.translate(valueWithUnit.value)) + is ValueWithUnit.TherapyEventType -> therapyEvent = therapyEvent.addWithSeparator(translator.translate(valueWithUnit.value)) + is ValueWithUnit.Timestamp -> timestamp = dateUtil.dateAndTimeAndSecondsString(valueWithUnit.value) + + is ValueWithUnit.Mgdl -> { + bg = if (profileFunction.getUnits() == Constants.MGDL) DecimalFormatter.to0Decimal(valueWithUnit.value) + else DecimalFormatter.to1Decimal(valueWithUnit.value / Constants.MMOLL_TO_MGDL) + } + + is ValueWithUnit.Mmoll -> { + bg = if (profileFunction.getUnits() == Constants.MGDL) DecimalFormatter.to0Decimal(valueWithUnit.value) + else DecimalFormatter.to1Decimal(valueWithUnit.value * Constants.MMOLL_TO_MGDL) + } + + ValueWithUnit.UNKNOWN -> Unit + } + } + + therapyEvent = csvString(therapyEvent) + stringResource = csvString(stringResource) + other = csvString(other) + return "$timestampRec;$dateTimestampRev;$utcOffset;$action;$therapyEvent;$source;$note;$stringResource;$timestamp;$bg;$gram;$insulin;$unitPerHour;$percent;$hour;$minute;$other" + } + + private fun csvString(action: Action): String = "\"" + translator.translate(action).replace("\"", "\"\"").replace("\n"," / ") + "\"" + private fun csvString(id: Int): String = if (id != 0) "\"" + resourceHelper.gs(id).replace("\"", "\"\"").replace("\n"," / ") + "\"" else "" + private fun csvString(s: String): String = if (s != "") "\"" + s.replace("\"", "\"\"").replace("\n"," / ") + "\"" else "" + + private fun String.addWithSeparator(add: Any) = + this + (if (this.isBlank()) "" else " / ") + add.toString() +} \ No newline at end of file diff --git a/core/src/main/java/info/nightscout/androidaps/utils/userEntry/ValueWithUnitMapper.kt b/core/src/main/java/info/nightscout/androidaps/utils/userEntry/ValueWithUnitMapper.kt new file mode 100644 index 0000000000..88b8270df9 --- /dev/null +++ b/core/src/main/java/info/nightscout/androidaps/utils/userEntry/ValueWithUnitMapper.kt @@ -0,0 +1,92 @@ +package info.nightscout.androidaps.utils.userEntry + +import androidx.annotation.StringRes +import info.nightscout.androidaps.Constants +import info.nightscout.androidaps.database.entities.TemporaryTarget +import info.nightscout.androidaps.database.entities.TherapyEvent +import info.nightscout.androidaps.database.entities.ValueWithUnit + +sealed class ValueWithUnitMapper { //I use a sealed class because of StringResource that containts a listOf as second parameter + + object UNKNOWN : ValueWithUnitMapper() // formerly None used as fallback + + data class SimpleString(val value: String) : ValueWithUnitMapper() // formerly one usage of None + + data class SimpleInt(val value: Int) : ValueWithUnitMapper() // formerly one usage of None + + data class Mgdl(val value: Double) : ValueWithUnitMapper() + + data class Mmoll(val value: Double) : ValueWithUnitMapper() + + data class Timestamp(val value: Long) : ValueWithUnitMapper() + + data class Insulin(val value: Double) : ValueWithUnitMapper() + + data class UnitPerHour(val value: Double) : ValueWithUnitMapper() + + data class Gram(val value: Int) : ValueWithUnitMapper() + + data class Minute(val value: Int) : ValueWithUnitMapper() + + data class Hour(val value: Int) : ValueWithUnitMapper() + + data class Percent(val value: Int) : ValueWithUnitMapper() + + data class TherapyEventType(val value: TherapyEvent.Type) : ValueWithUnitMapper() + + data class TherapyEventMeterType(val value: TherapyEvent.MeterType) : ValueWithUnitMapper() + + data class TherapyEventTTReason(val value: TemporaryTarget.Reason) : ValueWithUnitMapper() + + fun db(): ValueWithUnit? { + return when(this) { + is Gram -> ValueWithUnit.Gram(this.value) + is Hour -> ValueWithUnit.Hour(this.value) + is Insulin -> ValueWithUnit.Insulin(this.value) + is Mgdl -> ValueWithUnit.Mgdl(this.value) + is Minute -> ValueWithUnit.Minute(this.value) + is Mmoll -> ValueWithUnit.Mmoll(this.value) + is Percent -> ValueWithUnit.Percent(this.value) + is SimpleInt -> ValueWithUnit.SimpleInt(this.value) + is SimpleString -> ValueWithUnit.SimpleString(this.value) + is TherapyEventMeterType -> ValueWithUnit.TherapyEventMeterType(this.value) + is TherapyEventTTReason -> ValueWithUnit.TherapyEventTTReason(this.value) + is TherapyEventType -> ValueWithUnit.TherapyEventType(this.value) + is Timestamp -> ValueWithUnit.Timestamp(this.value) + is UnitPerHour -> ValueWithUnit.UnitPerHour(this.value) + UNKNOWN -> null + } + } + + fun value(): Any? { + return when(this) { + is Gram -> this.value + is Hour -> this.value + is Insulin -> this.value + is Mgdl -> this.value + is Minute -> this.value + is Mmoll -> this.value + is Percent -> this.value + is SimpleInt -> this.value + is SimpleString -> this.value + is TherapyEventMeterType -> this.value + is TherapyEventTTReason -> this.value + is TherapyEventType -> this.value + is Timestamp -> this.value + is UnitPerHour -> this.value + UNKNOWN -> null + } + } + + companion object { + + const val MGDL = Constants.MGDL + const val MMOL = Constants.MMOL + + fun fromGlucoseUnit(value: Double, string: String): ValueWithUnitMapper? = when (string) { + MGDL, "mgdl" -> Mgdl(value) + MMOL, "mmol/l" -> Mmoll(value) + else -> null + } + } +} \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_action.xml b/core/src/main/res/drawable/ic_action.xml similarity index 100% rename from app/src/main/res/drawable/ic_action.xml rename to core/src/main/res/drawable/ic_action.xml diff --git a/app/src/main/res/drawable/ic_actions_startextbolus.xml b/core/src/main/res/drawable/ic_actions_startextbolus.xml similarity index 100% rename from app/src/main/res/drawable/ic_actions_startextbolus.xml rename to core/src/main/res/drawable/ic_actions_startextbolus.xml diff --git a/app/src/main/res/drawable/ic_actions_starttempbasal.xml b/core/src/main/res/drawable/ic_actions_starttempbasal.xml similarity index 100% rename from app/src/main/res/drawable/ic_actions_starttempbasal.xml rename to core/src/main/res/drawable/ic_actions_starttempbasal.xml diff --git a/automation/src/main/res/drawable/ic_automation.xml b/core/src/main/res/drawable/ic_automation.xml similarity index 100% rename from automation/src/main/res/drawable/ic_automation.xml rename to core/src/main/res/drawable/ic_automation.xml diff --git a/app/src/main/res/drawable/ic_calculator.xml b/core/src/main/res/drawable/ic_calculator.xml similarity index 100% rename from app/src/main/res/drawable/ic_calculator.xml rename to core/src/main/res/drawable/ic_calculator.xml diff --git a/app/src/main/res/drawable/ic_calibration.xml b/core/src/main/res/drawable/ic_calibration.xml similarity index 100% rename from app/src/main/res/drawable/ic_calibration.xml rename to core/src/main/res/drawable/ic_calibration.xml diff --git a/app/src/main/res/drawable/ic_cogs.xml b/core/src/main/res/drawable/ic_cogs.xml similarity index 100% rename from app/src/main/res/drawable/ic_cogs.xml rename to core/src/main/res/drawable/ic_cogs.xml diff --git a/combo/src/main/res/drawable/ic_combo_128.xml b/core/src/main/res/drawable/ic_combo_128.xml similarity index 100% rename from combo/src/main/res/drawable/ic_combo_128.xml rename to core/src/main/res/drawable/ic_combo_128.xml diff --git a/app/src/main/res/drawable/ic_cp_announcement.xml b/core/src/main/res/drawable/ic_cp_announcement.xml similarity index 100% rename from app/src/main/res/drawable/ic_cp_announcement.xml rename to core/src/main/res/drawable/ic_cp_announcement.xml diff --git a/app/src/main/res/drawable/ic_cp_cgm_insert.xml b/core/src/main/res/drawable/ic_cp_cgm_insert.xml similarity index 100% rename from app/src/main/res/drawable/ic_cp_cgm_insert.xml rename to core/src/main/res/drawable/ic_cp_cgm_insert.xml diff --git a/app/src/main/res/drawable/ic_cp_exercise.xml b/core/src/main/res/drawable/ic_cp_exercise.xml similarity index 100% rename from app/src/main/res/drawable/ic_cp_exercise.xml rename to core/src/main/res/drawable/ic_cp_exercise.xml diff --git a/app/src/main/res/drawable/ic_cp_note.xml b/core/src/main/res/drawable/ic_cp_note.xml similarity index 100% rename from app/src/main/res/drawable/ic_cp_note.xml rename to core/src/main/res/drawable/ic_cp_note.xml diff --git a/app/src/main/res/drawable/ic_cp_pump_battery.xml b/core/src/main/res/drawable/ic_cp_pump_battery.xml similarity index 100% rename from app/src/main/res/drawable/ic_cp_pump_battery.xml rename to core/src/main/res/drawable/ic_cp_pump_battery.xml diff --git a/app/src/main/res/drawable/ic_cp_pump_canula.xml b/core/src/main/res/drawable/ic_cp_pump_canula.xml similarity index 100% rename from app/src/main/res/drawable/ic_cp_pump_canula.xml rename to core/src/main/res/drawable/ic_cp_pump_canula.xml diff --git a/app/src/main/res/drawable/ic_cp_question.xml b/core/src/main/res/drawable/ic_cp_question.xml similarity index 100% rename from app/src/main/res/drawable/ic_cp_question.xml rename to core/src/main/res/drawable/ic_cp_question.xml diff --git a/app/src/main/res/drawable/ic_cp_stats.xml b/core/src/main/res/drawable/ic_cp_stats.xml similarity index 100% rename from app/src/main/res/drawable/ic_cp_stats.xml rename to core/src/main/res/drawable/ic_cp_stats.xml diff --git a/dana/src/main/res/drawable/ic_danars_128.xml b/core/src/main/res/drawable/ic_danars_128.xml similarity index 100% rename from dana/src/main/res/drawable/ic_danars_128.xml rename to core/src/main/res/drawable/ic_danars_128.xml diff --git a/app/src/main/res/drawable/ic_eversense.xml b/core/src/main/res/drawable/ic_eversense.xml similarity index 100% rename from app/src/main/res/drawable/ic_eversense.xml rename to core/src/main/res/drawable/ic_eversense.xml diff --git a/app/src/main/res/drawable/ic_food.xml b/core/src/main/res/drawable/ic_food.xml similarity index 100% rename from app/src/main/res/drawable/ic_food.xml rename to core/src/main/res/drawable/ic_food.xml diff --git a/app/src/main/res/drawable/ic_generic_cgm.xml b/core/src/main/res/drawable/ic_generic_cgm.xml similarity index 100% rename from app/src/main/res/drawable/ic_generic_cgm.xml rename to core/src/main/res/drawable/ic_generic_cgm.xml diff --git a/app/src/main/res/drawable/ic_generic_icon.xml b/core/src/main/res/drawable/ic_generic_icon.xml similarity index 100% rename from app/src/main/res/drawable/ic_generic_icon.xml rename to core/src/main/res/drawable/ic_generic_icon.xml diff --git a/app/src/main/res/drawable/ic_glimp.xml b/core/src/main/res/drawable/ic_glimp.xml similarity index 100% rename from app/src/main/res/drawable/ic_glimp.xml rename to core/src/main/res/drawable/ic_glimp.xml diff --git a/app/src/main/res/drawable/ic_graduation.xml b/core/src/main/res/drawable/ic_graduation.xml similarity index 100% rename from app/src/main/res/drawable/ic_graduation.xml rename to core/src/main/res/drawable/ic_graduation.xml diff --git a/app/src/main/res/drawable/ic_ict.xml b/core/src/main/res/drawable/ic_ict.xml similarity index 100% rename from app/src/main/res/drawable/ic_ict.xml rename to core/src/main/res/drawable/ic_ict.xml diff --git a/insight/src/main/res/drawable/ic_insight_128.xml b/core/src/main/res/drawable/ic_insight_128.xml similarity index 100% rename from insight/src/main/res/drawable/ic_insight_128.xml rename to core/src/main/res/drawable/ic_insight_128.xml diff --git a/app/src/main/res/drawable/ic_local_profile.xml b/core/src/main/res/drawable/ic_local_profile.xml similarity index 100% rename from app/src/main/res/drawable/ic_local_profile.xml rename to core/src/main/res/drawable/ic_local_profile.xml diff --git a/app/src/main/res/drawable/ic_loop_closed.xml b/core/src/main/res/drawable/ic_loop_closed.xml similarity index 100% rename from app/src/main/res/drawable/ic_loop_closed.xml rename to core/src/main/res/drawable/ic_loop_closed.xml diff --git a/app/src/main/res/drawable/ic_loop_closed_white.xml b/core/src/main/res/drawable/ic_loop_closed_white.xml similarity index 100% rename from app/src/main/res/drawable/ic_loop_closed_white.xml rename to core/src/main/res/drawable/ic_loop_closed_white.xml diff --git a/insight/src/main/res/drawable/ic_maintenance.xml b/core/src/main/res/drawable/ic_maintenance.xml similarity index 100% rename from insight/src/main/res/drawable/ic_maintenance.xml rename to core/src/main/res/drawable/ic_maintenance.xml diff --git a/app/src/main/res/drawable/ic_nightscout_profile.xml b/core/src/main/res/drawable/ic_nightscout_profile.xml similarity index 100% rename from app/src/main/res/drawable/ic_nightscout_profile.xml rename to core/src/main/res/drawable/ic_nightscout_profile.xml diff --git a/app/src/main/res/drawable/ic_nightscout_syncs.xml b/core/src/main/res/drawable/ic_nightscout_syncs.xml similarity index 100% rename from app/src/main/res/drawable/ic_nightscout_syncs.xml rename to core/src/main/res/drawable/ic_nightscout_syncs.xml diff --git a/app/src/main/res/drawable/ic_nsclient_bg.xml b/core/src/main/res/drawable/ic_nsclient_bg.xml similarity index 100% rename from app/src/main/res/drawable/ic_nsclient_bg.xml rename to core/src/main/res/drawable/ic_nsclient_bg.xml diff --git a/app/src/main/res/drawable/ic_poctech.xml b/core/src/main/res/drawable/ic_poctech.xml similarity index 100% rename from app/src/main/res/drawable/ic_poctech.xml rename to core/src/main/res/drawable/ic_poctech.xml diff --git a/omnipod-common/src/main/res/drawable/ic_pod_128.xml b/core/src/main/res/drawable/ic_pod_128.xml similarity index 100% rename from omnipod-common/src/main/res/drawable/ic_pod_128.xml rename to core/src/main/res/drawable/ic_pod_128.xml diff --git a/app/src/main/res/drawable/ic_quick_wizard.xml b/core/src/main/res/drawable/ic_quick_wizard.xml similarity index 100% rename from app/src/main/res/drawable/ic_quick_wizard.xml rename to core/src/main/res/drawable/ic_quick_wizard.xml diff --git a/app/src/main/res/drawable/ic_sms.xml b/core/src/main/res/drawable/ic_sms.xml similarity index 100% rename from app/src/main/res/drawable/ic_sms.xml rename to core/src/main/res/drawable/ic_sms.xml diff --git a/app/src/main/res/drawable/ic_treatments.xml b/core/src/main/res/drawable/ic_treatments.xml similarity index 100% rename from app/src/main/res/drawable/ic_treatments.xml rename to core/src/main/res/drawable/ic_treatments.xml diff --git a/medtronic/src/main/res/drawable/ic_veo_128.xml b/core/src/main/res/drawable/ic_veo_128.xml similarity index 100% rename from medtronic/src/main/res/drawable/ic_veo_128.xml rename to core/src/main/res/drawable/ic_veo_128.xml diff --git a/app/src/main/res/drawable/ic_virtual_pump.xml b/core/src/main/res/drawable/ic_virtual_pump.xml similarity index 100% rename from app/src/main/res/drawable/ic_virtual_pump.xml rename to core/src/main/res/drawable/ic_virtual_pump.xml diff --git a/app/src/main/res/drawable/ic_watch.xml b/core/src/main/res/drawable/ic_watch.xml similarity index 100% rename from app/src/main/res/drawable/ic_watch.xml rename to core/src/main/res/drawable/ic_watch.xml diff --git a/app/src/main/res/drawable/icon_insulin_carbs.xml b/core/src/main/res/drawable/icon_insulin_carbs.xml similarity index 100% rename from app/src/main/res/drawable/icon_insulin_carbs.xml rename to core/src/main/res/drawable/icon_insulin_carbs.xml diff --git a/core/src/main/res/values/strings.xml b/core/src/main/res/values/strings.xml index 7ccc01f2af..225303c081 100644 --- a/core/src/main/res/values/strings.xml +++ b/core/src/main/res/values/strings.xml @@ -8,7 +8,6 @@ absorption_maxtime openapsama_min_5m_carbimpact absorption_cutoff - danar_visualizeextendedaspercentage" danar_useextended eatingsoon_duration eatingsoon_target @@ -56,6 +55,9 @@ insight_local_settings data_choices_settings dexcom_settings + active_pump_change_timestamp + active_pump_type + active_pump_serial_number Refresh @@ -161,6 +163,7 @@ Notes Remove Add new + Data is coming from different pump. Change pump driver to reset pump state. Limiting max basal rate to %1$.2f U/h because of %2$s @@ -217,6 +220,7 @@ No profile selected + Start profile %1$d%% for %2$d min * Only discrete values no ranges are supported as granularity for basal/bolus in virtual pump. @@ -276,6 +280,10 @@ Wear Automation Custom + Pump + Loop + NS + Record Connection timed out @@ -401,7 +409,6 @@ BOLUS BOLUS ADVISOR - BOLUS RECORD EXTENDED BOLUS SUPERBOLUS TBR CARBS @@ -429,6 +436,8 @@ CANCEL EXTENDED BOLUS CANCEL TT CAREPORTAL + SITE CHANGE + RESERVOIR CHANGE CALIBRATION PRIME BOLUS TREATMENT @@ -439,7 +448,11 @@ AUTOMATION REMOVED BG REMOVED CAREPORTAL REMOVED + BOLUS REMOVED + CARBS REMOVED + TEMP BASAL REMOVED EXTENDED BOLUS REMOVED + FOOD FOOD REMOVED PROFILE REMOVED PROFILE SWITCH REMOVED @@ -466,30 +479,21 @@ IMPORT DATABASES OTP EXPORT OTP RESET - SMS BASAL - SMS BOLUS - SMS CAL - SMS CARBS - SMS EXTENDED BOLUS - SMS LOOP DISABLED - SMS LOOP ENABLED - SMS LOOP RESUME - SMS LOOP SUSPEND - SMS PROFILE - SMS PUMP CONNECT - SMS PUMP DISCONNECT - SMS SMS - SMS TT - TT DELETED FROM NS - CAREPORTAL DELETED FROM NS - CAREPORTAL FROM NS - TT FROM NS - TT CANCELED FROM NS + STOP SMS EXPORT USER ENTRIES + START AAPS + EXIT AAPS + PLUGIN ENABLED + PLUGIN DISABLED UNKNOWN - Formated string + Formated string + Source + UTC Offset + Action + Timestamp + No Unit Export User Entries to Excel (csv) - "Timestamp;Date;UTC Offset;Action;Note;Value;Unit" + "%1$s;%2$s;%3$s;%4$s;%5$s;%6$s;%7$s;%8$s;%9$s;%10$s;%11$s;%12$s;%13$s;%14$s;%15$s;%16$s;%17$s" %1$d day diff --git a/core/src/test/java/info/nightscout/androidaps/TestBaseWithProfile.kt b/core/src/test/java/info/nightscout/androidaps/TestBaseWithProfile.kt index e3e5c7391b..9ec854b49d 100644 --- a/core/src/test/java/info/nightscout/androidaps/TestBaseWithProfile.kt +++ b/core/src/test/java/info/nightscout/androidaps/TestBaseWithProfile.kt @@ -4,9 +4,8 @@ import dagger.android.AndroidInjector import dagger.android.HasAndroidInjector import info.nightscout.androidaps.data.Profile import info.nightscout.androidaps.db.ProfileSwitch -import info.nightscout.androidaps.db.Treatment -import info.nightscout.androidaps.interfaces.ActivePluginProvider -import info.nightscout.androidaps.interfaces.ConfigInterface +import info.nightscout.androidaps.interfaces.ActivePlugin +import info.nightscout.androidaps.interfaces.Config import info.nightscout.androidaps.interfaces.ProfileFunction import info.nightscout.androidaps.interfaces.ProfileStore import info.nightscout.androidaps.interfaces.TreatmentsInterface @@ -24,14 +23,14 @@ import org.powermock.core.classloader.annotations.PrepareForTest @PrepareForTest(FabricPrivacy::class) open class TestBaseWithProfile : TestBase() { - @Mock lateinit var activePluginProvider: ActivePluginProvider + @Mock lateinit var activePluginProvider: ActivePlugin @Mock lateinit var resourceHelper: ResourceHelper @Mock lateinit var treatmentsInterface: TreatmentsInterface @Mock lateinit var fabricPrivacy: FabricPrivacy @Mock lateinit var profileFunction: ProfileFunction @Mock lateinit var defaultValueHelper: DefaultValueHelper @Mock lateinit var dateUtil: DateUtil - @Mock lateinit var configInterface: ConfigInterface + @Mock lateinit var config: Config val rxBus = RxBusWrapper(aapsSchedulers) @@ -43,7 +42,8 @@ open class TestBaseWithProfile : TestBase() { it.resourceHelper = resourceHelper it.rxBus = rxBus it.fabricPrivacy = fabricPrivacy - it.configInterface = configInterface + it.config = config + it.dateUtil = dateUtil } if (it is ProfileSwitch) { it.treatmentsPlugin = treatmentsInterface @@ -52,12 +52,6 @@ open class TestBaseWithProfile : TestBase() { it.resourceHelper = resourceHelper it.dateUtil = dateUtil } - if (it is Treatment) { - it.activePlugin = activePluginProvider - it.profileFunction = profileFunction - it.defaultValueHelper = defaultValueHelper - it.resourceHelper = resourceHelper - } } } diff --git a/core/src/test/java/info/nightscout/androidaps/TestPumpPlugin.kt b/core/src/test/java/info/nightscout/androidaps/TestPumpPlugin.kt index 97727ab5af..0cb1ec2e78 100644 --- a/core/src/test/java/info/nightscout/androidaps/TestPumpPlugin.kt +++ b/core/src/test/java/info/nightscout/androidaps/TestPumpPlugin.kt @@ -5,14 +5,15 @@ import info.nightscout.androidaps.data.DetailedBolusInfo import info.nightscout.androidaps.data.Profile import info.nightscout.androidaps.data.PumpEnactResult import info.nightscout.androidaps.interfaces.PumpDescription -import info.nightscout.androidaps.interfaces.PumpInterface +import info.nightscout.androidaps.interfaces.Pump +import info.nightscout.androidaps.interfaces.PumpSync import info.nightscout.androidaps.plugins.common.ManufacturerType import info.nightscout.androidaps.plugins.pump.common.defs.PumpType import info.nightscout.androidaps.utils.TimeChangeType import org.json.JSONObject @Suppress("MemberVisibilityCanBePrivate") -class TestPumpPlugin(val injector: HasAndroidInjector) : PumpInterface { +class TestPumpPlugin(val injector: HasAndroidInjector) : Pump { var connected = false var isProfileSet = true @@ -50,14 +51,14 @@ class TestPumpPlugin(val injector: HasAndroidInjector) : PumpInterface { override val batteryLevel: Int = 0 override fun deliverTreatment(detailedBolusInfo: DetailedBolusInfo): PumpEnactResult = PumpEnactResult(injector).success(true) override fun stopBolusDelivering() {} - override fun setTempBasalAbsolute(absoluteRate: Double, durationInMinutes: Int, profile: Profile, enforceNew: Boolean): PumpEnactResult = PumpEnactResult(injector).success(true) - override fun setTempBasalPercent(percent: Int, durationInMinutes: Int, profile: Profile, enforceNew: Boolean): PumpEnactResult = PumpEnactResult(injector).success(true) + override fun setTempBasalAbsolute(absoluteRate: Double, durationInMinutes: Int, profile: Profile, enforceNew: Boolean, tbrType: PumpSync.TemporaryBasalType): PumpEnactResult = PumpEnactResult(injector).success(true) + override fun setTempBasalPercent(percent: Int, durationInMinutes: Int, profile: Profile, enforceNew: Boolean, tbrType: PumpSync.TemporaryBasalType): PumpEnactResult = PumpEnactResult(injector).success(true) override fun setExtendedBolus(insulin: Double, durationInMinutes: Int): PumpEnactResult = PumpEnactResult(injector).success(true) override fun cancelTempBasal(enforceNew: Boolean): PumpEnactResult = PumpEnactResult(injector).success(true) override fun cancelExtendedBolus(): PumpEnactResult = PumpEnactResult(injector).success(true) override fun getJSONStatus(profile: Profile, profileName: String, version: String): JSONObject = JSONObject() override fun manufacturer(): ManufacturerType = ManufacturerType.AndroidAPS - override fun model(): PumpType = PumpType.GenericAAPS + override fun model(): PumpType = PumpType.GENERIC_AAPS override fun serialNumber(): String = "1" override fun shortStatus(veryShort: Boolean): String = "" override val isFakingTempsByExtendedBoluses: Boolean = false diff --git a/core/src/test/java/info/nightscout/androidaps/data/DetailedBolusInfoTest.kt b/core/src/test/java/info/nightscout/androidaps/data/DetailedBolusInfoTest.kt index 6587bc880d..2e37734b64 100644 --- a/core/src/test/java/info/nightscout/androidaps/data/DetailedBolusInfoTest.kt +++ b/core/src/test/java/info/nightscout/androidaps/data/DetailedBolusInfoTest.kt @@ -1,13 +1,18 @@ package info.nightscout.androidaps.data +import android.content.Context +import info.nightscout.androidaps.TestBase +import info.nightscout.androidaps.database.entities.Bolus +import info.nightscout.androidaps.database.entities.BolusCalculatorResult +import info.nightscout.androidaps.database.entities.TherapyEvent import org.apache.commons.lang3.builder.EqualsBuilder import org.junit.Assert import org.junit.Test -import org.junit.runner.RunWith -import org.powermock.modules.junit4.PowerMockRunner +import org.mockito.Mock -@RunWith(PowerMockRunner::class) -class DetailedBolusInfoTest { +class DetailedBolusInfoTest : TestBase() { + + @Mock lateinit var context: Context @Test fun toStringShouldBeOverloaded() { val detailedBolusInfo = DetailedBolusInfo() @@ -16,8 +21,97 @@ class DetailedBolusInfoTest { @Test fun copyShouldCopyAllProperties() { val d1 = DetailedBolusInfo() - d1.deliverAt = 123 + d1.deliverAtTheLatest = 123 val d2 = d1.copy() Assert.assertEquals(true, EqualsBuilder.reflectionEquals(d2, d1)) } + + @Test + fun shouldAllowSerialization() { + val detailedBolusInfo = DetailedBolusInfo() + detailedBolusInfo.bolusCalculatorResult = createBolusCalculatorResult() + detailedBolusInfo.context = context + detailedBolusInfo.eventType = DetailedBolusInfo.EventType.BOLUS_WIZARD + val serialized = detailedBolusInfo.toJsonString() + val deserialized = DetailedBolusInfo.fromJsonString(serialized) + Assert.assertEquals(1L, deserialized.bolusCalculatorResult?.timestamp) + Assert.assertEquals(DetailedBolusInfo.EventType.BOLUS_WIZARD, deserialized.eventType) + // Context should be excluded + Assert.assertNull(deserialized.context) + } + + @Test + fun generateTherapyEventTest() { + val detailedBolusInfo = DetailedBolusInfo() + detailedBolusInfo.timestamp = 1000 + detailedBolusInfo.notes = "note" + detailedBolusInfo.mgdlGlucose = 180.0 + detailedBolusInfo.glucoseType = DetailedBolusInfo.MeterType.FINGER + + val therapyEvent = detailedBolusInfo.createTherapyEvent() + Assert.assertEquals(1000L, therapyEvent.timestamp) + Assert.assertEquals(TherapyEvent.Type.MEAL_BOLUS, therapyEvent.type) + Assert.assertEquals(TherapyEvent.GlucoseUnit.MGDL, therapyEvent.glucoseUnit) + Assert.assertEquals("note", therapyEvent.note) + Assert.assertEquals(180.0, therapyEvent.glucose) + Assert.assertEquals(TherapyEvent.MeterType.FINGER, therapyEvent.glucoseType) + } + + @Test + fun generateBolus() { + val detailedBolusInfo = DetailedBolusInfo() + detailedBolusInfo.timestamp = 1000 + detailedBolusInfo.bolusType = DetailedBolusInfo.BolusType.SMB + detailedBolusInfo.insulin = 7.0 + + val bolus = detailedBolusInfo.createBolus() + Assert.assertEquals(1000L, bolus?.timestamp) + Assert.assertEquals(Bolus.Type.SMB, bolus?.type) + Assert.assertEquals(7.0, bolus?.amount) + } + + @Test + fun generateCarbs() { + val detailedBolusInfo = DetailedBolusInfo() + detailedBolusInfo.timestamp = 1000 + detailedBolusInfo.carbs = 6.0 + + val carbs = detailedBolusInfo.createCarbs() + Assert.assertEquals(1000L, carbs?.timestamp) + Assert.assertEquals(6.0, carbs?.amount) + } + + private fun createBolusCalculatorResult(): BolusCalculatorResult = + BolusCalculatorResult( + timestamp = 1, + targetBGLow = 5.0, + targetBGHigh = 5.0, + isf = 5.0, + ic = 5.0, + bolusIOB = 1.0, + wasBolusIOBUsed = true, + basalIOB = 1.0, + wasBasalIOBUsed = true, + glucoseValue = 10.0, + wasGlucoseUsed = true, + glucoseDifference = 1.0, + glucoseInsulin = 1.0, + glucoseTrend = 1.0, + wasTrendUsed = true, + trendInsulin = 1.0, + cob = 10.0, + wasCOBUsed = true, + cobInsulin = 1.0, + carbs = 5.0, + wereCarbsUsed = true, + carbsInsulin = 1.0, + otherCorrection = 1.0, + wasSuperbolusUsed = true, + superbolusInsulin = 1.0, + wasTempTargetUsed = true, + totalInsulin = 15.0, + percentageCorrection = 50, + profileName = "profile", + note = "" + ) } \ No newline at end of file diff --git a/core/src/test/java/info/nightscout/androidaps/data/IobTotalTest.kt b/core/src/test/java/info/nightscout/androidaps/data/IobTotalTest.kt index ebcf20c4af..bfe97bc80a 100644 --- a/core/src/test/java/info/nightscout/androidaps/data/IobTotalTest.kt +++ b/core/src/test/java/info/nightscout/androidaps/data/IobTotalTest.kt @@ -1,16 +1,29 @@ package info.nightscout.androidaps.data +import android.content.Context import info.nightscout.androidaps.utils.DateUtil import org.junit.Assert +import org.junit.Before import org.junit.Test import org.junit.runner.RunWith +import org.mockito.Mock import org.powermock.modules.junit4.PowerMockRunner @Suppress("SpellCheckingInspection") @RunWith(PowerMockRunner::class) class IobTotalTest { - var now = DateUtil.now() + @Mock lateinit var context: Context + + lateinit var dateUtil: DateUtil + var now = 0L + + @Before + fun prepare() { + dateUtil = DateUtil(context) + now = dateUtil.now() + } + @Test fun copyTest() { val a = IobTotal(now) a.iob = 10.0 @@ -94,11 +107,11 @@ class IobTotalTest { a.netInsulin = 16.0 a.extendedBolusInsulin = 17.0 try { - val j = a.json() + val j = a.json(dateUtil) Assert.assertEquals(a.iob, j.getDouble("iob"), 0.0000001) Assert.assertEquals(a.basaliob, j.getDouble("basaliob"), 0.0000001) Assert.assertEquals(a.activity, j.getDouble("activity"), 0.0000001) - Assert.assertEquals(now.toFloat(), DateUtil.fromISODateString(j.getString("time")).time.toFloat(), 1000f) + Assert.assertEquals(now, dateUtil.fromISODateString(j.getString("time"))) } catch (e: Exception) { Assert.fail("Exception: " + e.message) } @@ -116,13 +129,13 @@ class IobTotalTest { a.extendedBolusInsulin = 17.0 a.iobWithZeroTemp = IobTotal(now) try { - val j = a.determineBasalJson() + val j = a.determineBasalJson(dateUtil) Assert.assertEquals(a.iob, j.getDouble("iob"), 0.0000001) Assert.assertEquals(a.basaliob, j.getDouble("basaliob"), 0.0000001) Assert.assertEquals(a.bolussnooze, j.getDouble("bolussnooze"), 0.0000001) Assert.assertEquals(a.activity, j.getDouble("activity"), 0.0000001) Assert.assertEquals(0, j.getLong("lastBolusTime")) - Assert.assertEquals(now.toFloat(), DateUtil.fromISODateString(j.getString("time")).time.toFloat(), 1000f) + Assert.assertEquals(now, dateUtil.fromISODateString(j.getString("time"))) Assert.assertNotNull(j.getJSONObject("iobWithZeroTemp")) } catch (e: Exception) { Assert.fail("Exception: " + e.message) diff --git a/core/src/test/java/info/nightscout/androidaps/data/MealDataTest.kt b/core/src/test/java/info/nightscout/androidaps/data/MealDataTest.kt index 4c82b528b2..07ecaffe97 100644 --- a/core/src/test/java/info/nightscout/androidaps/data/MealDataTest.kt +++ b/core/src/test/java/info/nightscout/androidaps/data/MealDataTest.kt @@ -10,6 +10,6 @@ class MealDataTest { @Test fun canCreateObject() { val md = MealData() - Assert.assertEquals(0.0, md.boluses, 0.01) + Assert.assertEquals(0.0, md.carbs, 0.01) } } \ No newline at end of file diff --git a/core/src/test/java/info/nightscout/androidaps/data/NonOverlappingIntervalsTest.kt b/core/src/test/java/info/nightscout/androidaps/data/NonOverlappingIntervalsTest.kt index 2fe370aa9c..2f0c580b83 100644 --- a/core/src/test/java/info/nightscout/androidaps/data/NonOverlappingIntervalsTest.kt +++ b/core/src/test/java/info/nightscout/androidaps/data/NonOverlappingIntervalsTest.kt @@ -4,7 +4,6 @@ import dagger.android.AndroidInjector import dagger.android.HasAndroidInjector import info.nightscout.androidaps.TestBase import info.nightscout.androidaps.db.TemporaryBasal -import info.nightscout.androidaps.utils.DateUtil import info.nightscout.androidaps.utils.T import org.junit.Assert import org.junit.Test @@ -14,7 +13,7 @@ import org.powermock.modules.junit4.PowerMockRunner @RunWith(PowerMockRunner::class) class NonOverlappingIntervalsTest : TestBase() { - private val startDate = DateUtil.now() + private val startDate = System.currentTimeMillis() var list = NonOverlappingIntervals() val injector = HasAndroidInjector { AndroidInjector {} } diff --git a/core/src/test/java/info/nightscout/androidaps/data/OverlappingIntervalsTest.kt b/core/src/test/java/info/nightscout/androidaps/data/OverlappingIntervalsTest.kt index 9973fb69dc..09b41eb0fb 100644 --- a/core/src/test/java/info/nightscout/androidaps/data/OverlappingIntervalsTest.kt +++ b/core/src/test/java/info/nightscout/androidaps/data/OverlappingIntervalsTest.kt @@ -1,6 +1,5 @@ package info.nightscout.androidaps.data -import info.nightscout.androidaps.utils.DateUtil import info.nightscout.androidaps.utils.T import org.junit.Assert import org.junit.Test @@ -11,7 +10,7 @@ import java.util.* @RunWith(PowerMockRunner::class) class OverlappingIntervalsTest { - private val startDate = DateUtil.now() + private val startDate = System.currentTimeMillis() private var list = OverlappingIntervals() @Test fun doTests() { // create one 10h interval and test value in and out diff --git a/core/src/test/java/info/nightscout/androidaps/data/ProfileIntervalsTest.kt b/core/src/test/java/info/nightscout/androidaps/data/ProfileIntervalsTest.kt index 422634c5cc..c1b1b25323 100644 --- a/core/src/test/java/info/nightscout/androidaps/data/ProfileIntervalsTest.kt +++ b/core/src/test/java/info/nightscout/androidaps/data/ProfileIntervalsTest.kt @@ -3,7 +3,6 @@ package info.nightscout.androidaps.data import info.nightscout.androidaps.TestBaseWithProfile import info.nightscout.androidaps.TestPumpPlugin import info.nightscout.androidaps.db.ProfileSwitch -import info.nightscout.androidaps.utils.DateUtil import info.nightscout.androidaps.utils.T import org.junit.Assert import org.junit.Before @@ -17,7 +16,7 @@ import java.util.* class ProfileIntervalsTest : TestBaseWithProfile() { lateinit var testPumpPlugin: TestPumpPlugin - private val startDate = DateUtil.now() + private val startDate = System.currentTimeMillis() var list = ProfileIntervals() @Before @@ -32,12 +31,12 @@ class ProfileIntervalsTest : TestBaseWithProfile() { list.add(ProfileSwitch(profileInjector).date(startDate).duration(T.hours(10).mins().toInt()).profileName("1").profile(validProfile)) // for older date first record should be returned only if has zero duration Assert.assertEquals(null, list.getValueToTime(startDate - T.secs(1).msecs())) - Assert.assertEquals("1", (list.getValueToTime(startDate) as ProfileSwitch?)!!.profileName) + Assert.assertEquals("1", (list.getValueToTime(startDate) as ProfileSwitch).profileName) Assert.assertEquals(null, list.getValueToTime(startDate + T.hours(10).msecs() + 1)) list.reset() list.add(ProfileSwitch(profileInjector).date(startDate).profileName("1").profile(validProfile)) Assert.assertEquals("1", (list.getValueToTime(startDate - T.secs(1).msecs()) as ProfileSwitch?)!!.profileName) - Assert.assertEquals("1", (list.getValueToTime(startDate) as ProfileSwitch?)!!.profileName) + Assert.assertEquals("1", (list.getValueToTime(startDate) as ProfileSwitch).profileName) Assert.assertEquals("1", (list.getValueToTime(startDate + T.hours(10).msecs() + 1) as ProfileSwitch?)!!.profileName) // switch to different profile after 5h diff --git a/core/src/test/java/info/nightscout/androidaps/data/ProfileTest.kt b/core/src/test/java/info/nightscout/androidaps/data/ProfileTest.kt index 38b85fef53..b5a0ecb3e1 100644 --- a/core/src/test/java/info/nightscout/androidaps/data/ProfileTest.kt +++ b/core/src/test/java/info/nightscout/androidaps/data/ProfileTest.kt @@ -105,7 +105,6 @@ class ProfileTest : TestBaseWithProfile() { //Test basal profile below limit p = Profile(profileInjector, JSONObject(belowLimitValidProfile), 100, 0) p.isValid("Test") - //Assert.assertEquals(true, ((AAPSMocker.MockedBus) MainApp.bus()).notificationSent); // Test profile w/o units p = Profile(profileInjector, JSONObject(noUnitsValidProfile), 100, 0) @@ -142,9 +141,7 @@ class ProfileTest : TestBaseWithProfile() { // Test hour alignment testPumpPlugin.pumpDescription.is30minBasalRatesCapable = false - //((AAPSMocker.MockedBus) MainApp.bus()).notificationSent = false; p = Profile(profileInjector, JSONObject(notAlignedBasalValidProfile), 100, 0) p.isValid("Test") - //Assert.assertEquals(true, ((AAPSMocker.MockedBus) MainApp.bus()).notificationSent); } } \ No newline at end of file diff --git a/core/src/test/java/info/nightscout/androidaps/interfaces/PumpDescriptionTest.kt b/core/src/test/java/info/nightscout/androidaps/interfaces/PumpDescriptionTest.kt index 96f7edd776..392c7f9791 100644 --- a/core/src/test/java/info/nightscout/androidaps/interfaces/PumpDescriptionTest.kt +++ b/core/src/test/java/info/nightscout/androidaps/interfaces/PumpDescriptionTest.kt @@ -6,30 +6,27 @@ import info.nightscout.androidaps.plugins.pump.common.defs.PumpType import org.junit.Assert import org.junit.Test -/** - * Created by andy on 5/13/18. - */ class PumpDescriptionTest { @Test fun setPumpDescription() { val pumpDescription = PumpDescription() - pumpDescription.setPumpDescription(PumpType.AccuChekCombo) - Assert.assertEquals(pumpDescription.bolusStep, PumpType.AccuChekCombo.bolusSize, 0.1) - Assert.assertEquals(pumpDescription.basalMinimumRate, PumpType.AccuChekCombo.baseBasalStep, 0.1) - Assert.assertEquals(pumpDescription.basalStep, PumpType.AccuChekCombo.baseBasalStep, 0.1) - Assert.assertEquals(pumpDescription.extendedBolusDurationStep, PumpType.AccuChekCombo.extendedBolusSettings.durationStep.toDouble(), 0.1) - Assert.assertEquals(pumpDescription.extendedBolusMaxDuration, PumpType.AccuChekCombo.extendedBolusSettings.maxDuration.toDouble(), 0.1) - Assert.assertEquals(pumpDescription.extendedBolusStep, PumpType.AccuChekCombo.extendedBolusSettings.step, 0.1) - Assert.assertEquals(pumpDescription.isExtendedBolusCapable, PumpType.AccuChekCombo.pumpCapability.hasCapability(PumpCapability.ExtendedBolus)) - Assert.assertEquals(pumpDescription.isBolusCapable, PumpType.AccuChekCombo.pumpCapability.hasCapability(PumpCapability.Bolus)) - Assert.assertEquals(pumpDescription.isRefillingCapable, PumpType.AccuChekCombo.pumpCapability.hasCapability(PumpCapability.Refill)) - Assert.assertEquals(pumpDescription.isSetBasalProfileCapable, PumpType.AccuChekCombo.pumpCapability.hasCapability(PumpCapability.BasalProfileSet)) - Assert.assertEquals(pumpDescription.isTempBasalCapable, PumpType.AccuChekCombo.pumpCapability.hasCapability(PumpCapability.TempBasal)) - Assert.assertEquals(pumpDescription.maxTempPercent.toDouble(), PumpType.AccuChekCombo.tbrSettings.maxDose, 0.1) - Assert.assertEquals(pumpDescription.tempPercentStep.toDouble(), PumpType.AccuChekCombo.tbrSettings.step, 0.1) - Assert.assertEquals(pumpDescription.tempBasalStyle, if (PumpType.AccuChekCombo.pumpTempBasalType == PumpTempBasalType.Percent) PumpDescription.PERCENT else PumpDescription.ABSOLUTE) - Assert.assertEquals(pumpDescription.tempDurationStep.toLong(), PumpType.AccuChekCombo.tbrSettings.durationStep.toLong()) - Assert.assertEquals(pumpDescription.tempDurationStep15mAllowed, PumpType.AccuChekCombo.specialBasalDurations.hasCapability(PumpCapability.BasalRate_Duration15minAllowed)) - Assert.assertEquals(pumpDescription.tempDurationStep30mAllowed, PumpType.AccuChekCombo.specialBasalDurations.hasCapability(PumpCapability.BasalRate_Duration30minAllowed)) + pumpDescription.setPumpDescription(PumpType.ACCU_CHEK_COMBO) + Assert.assertEquals(pumpDescription.bolusStep, PumpType.ACCU_CHEK_COMBO.bolusSize, 0.1) + Assert.assertEquals(pumpDescription.basalMinimumRate, PumpType.ACCU_CHEK_COMBO.baseBasalStep, 0.1) + Assert.assertEquals(pumpDescription.basalStep, PumpType.ACCU_CHEK_COMBO.baseBasalStep, 0.1) + Assert.assertEquals(pumpDescription.extendedBolusDurationStep, PumpType.ACCU_CHEK_COMBO.extendedBolusSettings?.durationStep?.toDouble()) + Assert.assertEquals(pumpDescription.extendedBolusMaxDuration, PumpType.ACCU_CHEK_COMBO.extendedBolusSettings?.maxDuration?.toDouble()) + Assert.assertEquals(pumpDescription.extendedBolusStep, PumpType.ACCU_CHEK_COMBO.extendedBolusSettings?.step) + Assert.assertEquals(pumpDescription.isExtendedBolusCapable, PumpType.ACCU_CHEK_COMBO.pumpCapability?.hasCapability(PumpCapability.ExtendedBolus)) + Assert.assertEquals(pumpDescription.isBolusCapable, PumpType.ACCU_CHEK_COMBO.pumpCapability?.hasCapability(PumpCapability.Bolus)) + Assert.assertEquals(pumpDescription.isRefillingCapable, PumpType.ACCU_CHEK_COMBO.pumpCapability?.hasCapability(PumpCapability.Refill)) + Assert.assertEquals(pumpDescription.isSetBasalProfileCapable, PumpType.ACCU_CHEK_COMBO.pumpCapability?.hasCapability(PumpCapability.BasalProfileSet)) + Assert.assertEquals(pumpDescription.isTempBasalCapable, PumpType.ACCU_CHEK_COMBO.pumpCapability?.hasCapability(PumpCapability.TempBasal)) + Assert.assertEquals(pumpDescription.maxTempPercent.toDouble(), PumpType.ACCU_CHEK_COMBO.tbrSettings?.maxDose) + Assert.assertEquals(pumpDescription.tempPercentStep.toDouble(), PumpType.ACCU_CHEK_COMBO.tbrSettings?.step) + Assert.assertEquals(pumpDescription.tempBasalStyle, if (PumpType.ACCU_CHEK_COMBO.pumpTempBasalType == PumpTempBasalType.Percent) PumpDescription.PERCENT else PumpDescription.ABSOLUTE) + Assert.assertEquals(pumpDescription.tempDurationStep.toLong(), PumpType.ACCU_CHEK_COMBO.tbrSettings?.durationStep?.toLong()) + Assert.assertEquals(pumpDescription.tempDurationStep15mAllowed, PumpType.ACCU_CHEK_COMBO.specialBasalDurations?.hasCapability(PumpCapability.BasalRate_Duration15minAllowed)) + Assert.assertEquals(pumpDescription.tempDurationStep30mAllowed, PumpType.ACCU_CHEK_COMBO.specialBasalDurations?.hasCapability(PumpCapability.BasalRate_Duration30minAllowed)) } } \ No newline at end of file diff --git a/core/src/test/java/info/nightscout/androidaps/plugins/aps/loop/APSResultTest.kt b/core/src/test/java/info/nightscout/androidaps/plugins/aps/loop/APSResultTest.kt index d591fd3e87..40a6cd3c20 100644 --- a/core/src/test/java/info/nightscout/androidaps/plugins/aps/loop/APSResultTest.kt +++ b/core/src/test/java/info/nightscout/androidaps/plugins/aps/loop/APSResultTest.kt @@ -4,8 +4,9 @@ import dagger.android.AndroidInjector import dagger.android.HasAndroidInjector import info.nightscout.androidaps.TestBaseWithProfile import info.nightscout.androidaps.TestPumpPlugin -import info.nightscout.androidaps.db.TemporaryBasal +import info.nightscout.androidaps.database.entities.TemporaryBasal import info.nightscout.androidaps.interfaces.Constraint +import info.nightscout.androidaps.interfaces.IobCobCalculator import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker import info.nightscout.androidaps.plugins.pump.common.defs.PumpType import info.nightscout.androidaps.utils.JsonHelper.safeGetDouble @@ -26,6 +27,7 @@ class APSResultTest : TestBaseWithProfile() { @Mock lateinit var constraintChecker: ConstraintChecker @Mock lateinit var sp: SP + @Mock lateinit var iobCobCalculator: IobCobCalculator private lateinit var testPumpPlugin: TestPumpPlugin private val injector = HasAndroidInjector { AndroidInjector { } } @@ -41,7 +43,7 @@ class APSResultTest : TestBaseWithProfile() { it.constraintChecker = constraintChecker it.sp = sp it.activePlugin = activePluginProvider - it.treatmentsPlugin = treatmentsInterface + it.iobCobCalculator = iobCobCalculator it.profileFunction = profileFunction it.resourceHelper = resourceHelper } @@ -49,12 +51,12 @@ class APSResultTest : TestBaseWithProfile() { // BASAL RATE IN TEST PROFILE IS 1U/h // **** PERCENT pump **** - testPumpPlugin.pumpDescription.setPumpDescription(PumpType.Cellnovo1) // % based + testPumpPlugin.pumpDescription.setPumpDescription(PumpType.CELLNOVO) // % based apsResult.usePercent(true) // closed loop mode return original request closedLoopEnabled.set(aapsLogger, true) - `when`(treatmentsInterface.getTempBasalFromHistory(ArgumentMatchers.anyLong())).thenReturn(null) + `when`(iobCobCalculator.getTempBasalIncludingConvertedExtended(ArgumentMatchers.anyLong())).thenReturn(null) apsResult.tempBasalRequested(false) Assert.assertEquals(false, apsResult.isChangeRequested) apsResult.tempBasalRequested(true).percent(200).duration(30) @@ -63,94 +65,94 @@ class APSResultTest : TestBaseWithProfile() { // open loop closedLoopEnabled.set(aapsLogger, false) // no change requested - `when`(treatmentsInterface.getTempBasalFromHistory(ArgumentMatchers.anyLong())).thenReturn(null) + `when`(iobCobCalculator.getTempBasalIncludingConvertedExtended(ArgumentMatchers.anyLong())).thenReturn(null) apsResult.tempBasalRequested(false) Assert.assertEquals(false, apsResult.isChangeRequested) // request 100% when no temp is running - `when`(treatmentsInterface.getTempBasalFromHistory(ArgumentMatchers.anyLong())).thenReturn(null) + `when`(iobCobCalculator.getTempBasalIncludingConvertedExtended(ArgumentMatchers.anyLong())).thenReturn(null) apsResult.tempBasalRequested(true).percent(100).duration(30) Assert.assertEquals(false, apsResult.isChangeRequested) // request equal temp - `when`(treatmentsInterface.getTempBasalFromHistory(ArgumentMatchers.anyLong())).thenReturn(TemporaryBasal(injector).percent(70).duration(30)) + `when`(iobCobCalculator.getTempBasalIncludingConvertedExtended(ArgumentMatchers.anyLong())).thenReturn(TemporaryBasal(timestamp = 0, rate = 70.0, duration = 30, isAbsolute = false, type = TemporaryBasal.Type.NORMAL)) apsResult.tempBasalRequested(true).percent(70).duration(30) Assert.assertEquals(false, apsResult.isChangeRequested) // request zero temp - `when`(treatmentsInterface.getTempBasalFromHistory(ArgumentMatchers.anyLong())).thenReturn(TemporaryBasal(injector).percent(10).duration(30)) + `when`(iobCobCalculator.getTempBasalIncludingConvertedExtended(ArgumentMatchers.anyLong())).thenReturn(TemporaryBasal(timestamp = 0, rate = 10.0, duration = 30, isAbsolute = false, type = TemporaryBasal.Type.NORMAL)) apsResult.tempBasalRequested(true).percent(0).duration(30) Assert.assertEquals(true, apsResult.isChangeRequested) // request high temp - `when`(treatmentsInterface.getTempBasalFromHistory(ArgumentMatchers.anyLong())).thenReturn(TemporaryBasal(injector).percent(190).duration(30)) + `when`(iobCobCalculator.getTempBasalIncludingConvertedExtended(ArgumentMatchers.anyLong())).thenReturn(TemporaryBasal(timestamp = 0, rate = 190.0, duration = 30, isAbsolute = false, type = TemporaryBasal.Type.NORMAL)) apsResult.tempBasalRequested(true).percent(200).duration(30) Assert.assertEquals(true, apsResult.isChangeRequested) // request slightly different temp - `when`(treatmentsInterface.getTempBasalFromHistory(ArgumentMatchers.anyLong())).thenReturn(TemporaryBasal(injector).percent(70).duration(30)) + `when`(iobCobCalculator.getTempBasalIncludingConvertedExtended(ArgumentMatchers.anyLong())).thenReturn(TemporaryBasal(timestamp = 0, rate = 70.0, duration = 30, isAbsolute = false, type = TemporaryBasal.Type.NORMAL)) apsResult.tempBasalRequested(true).percent(80).duration(30) Assert.assertEquals(false, apsResult.isChangeRequested) // request different temp - `when`(treatmentsInterface.getTempBasalFromHistory(ArgumentMatchers.anyLong())).thenReturn(TemporaryBasal(injector).percent(70).duration(30)) + `when`(iobCobCalculator.getTempBasalIncludingConvertedExtended(ArgumentMatchers.anyLong())).thenReturn(TemporaryBasal(timestamp = 0, rate = 70.0, duration = 30, isAbsolute = false, type = TemporaryBasal.Type.NORMAL)) apsResult.tempBasalRequested(true).percent(120).duration(30) Assert.assertEquals(true, apsResult.isChangeRequested) // it should work with absolute temps too // request different temp - `when`(treatmentsInterface.getTempBasalFromHistory(ArgumentMatchers.anyLong())).thenReturn(TemporaryBasal(injector).absolute(1.0).duration(30)) + `when`(iobCobCalculator.getTempBasalIncludingConvertedExtended(ArgumentMatchers.anyLong())).thenReturn(TemporaryBasal(timestamp = 0, rate = 1.0, duration = 30, isAbsolute = true, type = TemporaryBasal.Type.NORMAL)) apsResult.tempBasalRequested(true).percent(100).duration(30) Assert.assertEquals(false, apsResult.isChangeRequested) - `when`(treatmentsInterface.getTempBasalFromHistory(ArgumentMatchers.anyLong())).thenReturn(TemporaryBasal(injector).absolute(2.0).duration(30)) + `when`(iobCobCalculator.getTempBasalIncludingConvertedExtended(ArgumentMatchers.anyLong())).thenReturn(TemporaryBasal(timestamp = 0, rate = 2.0, duration = 30, isAbsolute = true, type = TemporaryBasal.Type.NORMAL)) apsResult.tempBasalRequested(true).percent(50).duration(30) Assert.assertEquals(true, apsResult.isChangeRequested) // **** ABSOLUTE pump **** - testPumpPlugin.pumpDescription.setPumpDescription(PumpType.Medtronic_515_715) // U/h based + testPumpPlugin.pumpDescription.setPumpDescription(PumpType.MEDTRONIC_515_715) // U/h based apsResult.usePercent(false) // open loop closedLoopEnabled.set(aapsLogger, false) // request 100% when no temp is running - `when`(treatmentsInterface.getTempBasalFromHistory(ArgumentMatchers.anyLong())).thenReturn(null) + `when`(iobCobCalculator.getTempBasalIncludingConvertedExtended(ArgumentMatchers.anyLong())).thenReturn(null) apsResult.tempBasalRequested(true).rate(1.0).duration(30) Assert.assertEquals(false, apsResult.isChangeRequested) // request equal temp - `when`(treatmentsInterface.getTempBasalFromHistory(ArgumentMatchers.anyLong())).thenReturn(TemporaryBasal(injector).absolute(2.0).duration(30)) + `when`(iobCobCalculator.getTempBasalIncludingConvertedExtended(ArgumentMatchers.anyLong())).thenReturn(TemporaryBasal(timestamp = 0, rate = 2.0, duration = 30, isAbsolute = true, type = TemporaryBasal.Type.NORMAL)) apsResult.tempBasalRequested(true).rate(2.0).duration(30) Assert.assertEquals(false, apsResult.isChangeRequested) - `when`(treatmentsInterface.getTempBasalFromHistory(ArgumentMatchers.anyLong())).thenReturn(TemporaryBasal(injector).percent(200).duration(30)) + `when`(iobCobCalculator.getTempBasalIncludingConvertedExtended(ArgumentMatchers.anyLong())).thenReturn(TemporaryBasal(timestamp = 0, rate = 200.0, duration = 30, isAbsolute = false, type = TemporaryBasal.Type.NORMAL)) apsResult.tempBasalRequested(true).rate(2.0).duration(30) Assert.assertEquals(false, apsResult.isChangeRequested) // request zero temp - `when`(treatmentsInterface.getTempBasalFromHistory(ArgumentMatchers.anyLong())).thenReturn(TemporaryBasal(injector).absolute(0.1).duration(30)) + `when`(iobCobCalculator.getTempBasalIncludingConvertedExtended(ArgumentMatchers.anyLong())).thenReturn(TemporaryBasal(timestamp = 0, rate = 0.1, duration = 30, isAbsolute = true, type = TemporaryBasal.Type.NORMAL)) apsResult.tempBasalRequested(true).rate(0.0).duration(30) Assert.assertEquals(true, apsResult.isChangeRequested) // request high temp - `when`(treatmentsInterface.getTempBasalFromHistory(ArgumentMatchers.anyLong())).thenReturn(TemporaryBasal(injector).absolute(34.9).duration(30)) + `when`(iobCobCalculator.getTempBasalIncludingConvertedExtended(ArgumentMatchers.anyLong())).thenReturn(TemporaryBasal(timestamp = 0, rate = 34.9, duration = 30, isAbsolute = true, type = TemporaryBasal.Type.NORMAL)) apsResult.tempBasalRequested(true).rate(35.0).duration(30) Assert.assertEquals(true, apsResult.isChangeRequested) // request slightly different temp - `when`(treatmentsInterface.getTempBasalFromHistory(ArgumentMatchers.anyLong())).thenReturn(TemporaryBasal(injector).absolute(1.1).duration(30)) + `when`(iobCobCalculator.getTempBasalIncludingConvertedExtended(ArgumentMatchers.anyLong())).thenReturn(TemporaryBasal(timestamp = 0, rate = 1.1, duration = 30, isAbsolute = true, type = TemporaryBasal.Type.NORMAL)) apsResult.tempBasalRequested(true).rate(1.2).duration(30) Assert.assertEquals(false, apsResult.isChangeRequested) // request different temp - `when`(treatmentsInterface.getTempBasalFromHistory(ArgumentMatchers.anyLong())).thenReturn(TemporaryBasal(injector).absolute(1.1).duration(30)) + `when`(iobCobCalculator.getTempBasalIncludingConvertedExtended(ArgumentMatchers.anyLong())).thenReturn(TemporaryBasal(timestamp = 0, rate = 1.1, duration = 30, isAbsolute = true, type = TemporaryBasal.Type.NORMAL)) apsResult.tempBasalRequested(true).rate(1.5).duration(30) Assert.assertEquals(true, apsResult.isChangeRequested) // it should work with percent temps too // request different temp - `when`(treatmentsInterface.getTempBasalFromHistory(ArgumentMatchers.anyLong())).thenReturn(TemporaryBasal(injector).percent(110).duration(30)) + `when`(iobCobCalculator.getTempBasalIncludingConvertedExtended(ArgumentMatchers.anyLong())).thenReturn(TemporaryBasal(timestamp = 0, rate = 110.0, duration = 30, isAbsolute = false, type = TemporaryBasal.Type.NORMAL)) apsResult.tempBasalRequested(true).rate(1.1).duration(30) Assert.assertEquals(false, apsResult.isChangeRequested) - `when`(treatmentsInterface.getTempBasalFromHistory(ArgumentMatchers.anyLong())).thenReturn(TemporaryBasal(injector).percent(200).duration(30)) + `when`(iobCobCalculator.getTempBasalIncludingConvertedExtended(ArgumentMatchers.anyLong())).thenReturn(TemporaryBasal(timestamp = 0, rate = 200.0, duration = 30, isAbsolute = false, type = TemporaryBasal.Type.NORMAL)) apsResult.tempBasalRequested(true).rate(0.5).duration(30) Assert.assertEquals(true, apsResult.isChangeRequested) } @@ -162,7 +164,7 @@ class APSResultTest : TestBaseWithProfile() { it.constraintChecker = constraintChecker it.sp = sp it.activePlugin = activePluginProvider - it.treatmentsPlugin = treatmentsInterface + it.iobCobCalculator = iobCobCalculator it.profileFunction = profileFunction it.resourceHelper = resourceHelper } @@ -179,7 +181,7 @@ class APSResultTest : TestBaseWithProfile() { it.constraintChecker = constraintChecker it.sp = sp it.activePlugin = activePluginProvider - it.treatmentsPlugin = treatmentsInterface + it.iobCobCalculator = iobCobCalculator it.profileFunction = profileFunction it.resourceHelper = resourceHelper } diff --git a/core/src/test/java/info/nightscout/androidaps/plugins/general/maintenance/formats/ClassicPrefsFormatTest.kt b/core/src/test/java/info/nightscout/androidaps/plugins/general/maintenance/formats/ClassicPrefsFormatTest.kt index 5f4386ee1a..ae55f7ede9 100644 --- a/core/src/test/java/info/nightscout/androidaps/plugins/general/maintenance/formats/ClassicPrefsFormatTest.kt +++ b/core/src/test/java/info/nightscout/androidaps/plugins/general/maintenance/formats/ClassicPrefsFormatTest.kt @@ -1,9 +1,7 @@ package info.nightscout.androidaps.plugins.general.maintenance.formats import info.nightscout.androidaps.TestBase -import info.nightscout.androidaps.interfaces.ProfileFunction -import info.nightscout.androidaps.utils.DateUtil -import info.nightscout.androidaps.utils.Translator +import info.nightscout.androidaps.utils.userEntry.UserEntryPresentationHelper import info.nightscout.androidaps.utils.resources.ResourceHelper import org.junit.Assert import org.junit.Test @@ -15,20 +13,18 @@ import org.powermock.modules.junit4.PowerMockRunner import java.io.File @RunWith(PowerMockRunner::class) -@PrepareForTest(File::class, Translator::class) +@PrepareForTest(File::class, UserEntryPresentationHelper::class) class ClassicPrefsFormatTest : TestBase() { @Mock lateinit var resourceHelper: ResourceHelper - @Mock lateinit var dateUtil: DateUtil - @Mock lateinit var translator: Translator - @Mock lateinit var profileFunction: ProfileFunction + @Mock lateinit var userEntryPresentationHelper: UserEntryPresentationHelper @Mock lateinit var file: MockedFile @Test fun preferenceLoadingTest() { val test = "key1::val1\nkeyB::valB" - val classicFormat = ClassicPrefsFormat(resourceHelper, dateUtil, translator, profileFunction, SingleStringStorage(test)) + val classicFormat = ClassicPrefsFormat(resourceHelper, userEntryPresentationHelper, SingleStringStorage(test)) val prefs = classicFormat.loadPreferences(getMockedFile(), "") Assert.assertEquals(prefs.values.size, 2) @@ -40,7 +36,7 @@ class ClassicPrefsFormatTest : TestBase() { @Test fun preferenceSavingTest() { val storage = SingleStringStorage("") - val classicFormat = ClassicPrefsFormat(resourceHelper, dateUtil, translator, profileFunction, storage) + val classicFormat = ClassicPrefsFormat(resourceHelper, userEntryPresentationHelper, storage) val prefs = Prefs( mapOf( "key1" to "A", diff --git a/core/src/test/java/info/nightscout/androidaps/plugins/iob/iobCalculator/GlucoseStatusTest.kt b/core/src/test/java/info/nightscout/androidaps/plugins/iob/iobCalculator/GlucoseStatusTest.kt index d6a5abbb8b..31319712a1 100644 --- a/core/src/test/java/info/nightscout/androidaps/plugins/iob/iobCalculator/GlucoseStatusTest.kt +++ b/core/src/test/java/info/nightscout/androidaps/plugins/iob/iobCalculator/GlucoseStatusTest.kt @@ -2,7 +2,8 @@ package info.nightscout.androidaps.plugins.iob.iobCalculator import info.nightscout.androidaps.TestBase import info.nightscout.androidaps.database.entities.GlucoseValue -import info.nightscout.androidaps.interfaces.IobCobCalculatorInterface +import info.nightscout.androidaps.interfaces.IobCobCalculator +import info.nightscout.androidaps.plugins.iob.iobCobCalculator.AutosensDataStore import info.nightscout.androidaps.plugins.iob.iobCobCalculator.GlucoseStatus import info.nightscout.androidaps.plugins.iob.iobCobCalculator.GlucoseStatusProvider import info.nightscout.androidaps.plugins.iob.iobCobCalculator.asRounded @@ -24,11 +25,17 @@ import java.util.* */ @Suppress("SpellCheckingInspection") @RunWith(PowerMockRunner::class) -@PrepareForTest(DateUtil::class) +@PrepareForTest(DateUtil::class, AutosensDataStore::class) class GlucoseStatusTest : TestBase() { @Mock lateinit var dateUtil: DateUtil - @Mock lateinit var iobCobCalculatorPlugin: IobCobCalculatorInterface + @Mock lateinit var iobCobCalculatorPlugin: IobCobCalculator + @Mock lateinit var autosensDataStore: AutosensDataStore + + @Before + fun prepare() { + `when`(iobCobCalculatorPlugin.ads).thenReturn(autosensDataStore) + } @Test fun toStringShouldBeOverloaded() { val glucoseStatus = GlucoseStatus(glucose = 0.0, noise = 0.0, delta = 0.0, shortAvgDelta = 0.0, longAvgDelta = 0.0, date = 0) @@ -41,8 +48,8 @@ class GlucoseStatusTest : TestBase() { } @Test fun calculateValidGlucoseStatus() { - PowerMockito.`when`(iobCobCalculatorPlugin.bgReadings).thenReturn(generateValidBgData()) - val glucoseStatus = GlucoseStatusProvider(aapsLogger, iobCobCalculatorPlugin).glucoseStatusData!! + PowerMockito.`when`(autosensDataStore.getBgReadingsDataTableCopy()).thenReturn(generateValidBgData()) + val glucoseStatus = GlucoseStatusProvider(aapsLogger, iobCobCalculatorPlugin, dateUtil).glucoseStatusData!! Assert.assertEquals(214.0, glucoseStatus.glucose, 0.001) Assert.assertEquals(-2.0, glucoseStatus.delta, 0.001) Assert.assertEquals(-2.5, glucoseStatus.shortAvgDelta, 0.001) // -2 -2.5 -3 deltas are relative to current value @@ -51,8 +58,8 @@ class GlucoseStatusTest : TestBase() { } @Test fun calculateMostRecentGlucoseStatus() { - PowerMockito.`when`(iobCobCalculatorPlugin.bgReadings).thenReturn(generateMostRecentBgData()) - val glucoseStatus: GlucoseStatus = GlucoseStatusProvider(aapsLogger, iobCobCalculatorPlugin).glucoseStatusData!! + PowerMockito.`when`(autosensDataStore.getBgReadingsDataTableCopy()).thenReturn(generateMostRecentBgData()) + val glucoseStatus: GlucoseStatus = GlucoseStatusProvider(aapsLogger, iobCobCalculatorPlugin, dateUtil).glucoseStatusData!! Assert.assertEquals(215.0, glucoseStatus.glucose, 0.001) // (214+216) / 2 Assert.assertEquals(-1.0, glucoseStatus.delta, 0.001) Assert.assertEquals(-1.0, glucoseStatus.shortAvgDelta, 0.001) @@ -61,8 +68,8 @@ class GlucoseStatusTest : TestBase() { } @Test fun oneRecordShouldProduceZeroDeltas() { - PowerMockito.`when`(iobCobCalculatorPlugin.bgReadings).thenReturn(generateOneCurrentRecordBgData()) - val glucoseStatus: GlucoseStatus = GlucoseStatusProvider(aapsLogger, iobCobCalculatorPlugin).glucoseStatusData!! + PowerMockito.`when`(autosensDataStore.getBgReadingsDataTableCopy()).thenReturn(generateOneCurrentRecordBgData()) + val glucoseStatus: GlucoseStatus = GlucoseStatusProvider(aapsLogger, iobCobCalculatorPlugin, dateUtil).glucoseStatusData!! Assert.assertEquals(214.0, glucoseStatus.glucose, 0.001) Assert.assertEquals(0.0, glucoseStatus.delta, 0.001) Assert.assertEquals(0.0, glucoseStatus.shortAvgDelta, 0.001) // -2 -2.5 -3 deltas are relative to current value @@ -71,20 +78,20 @@ class GlucoseStatusTest : TestBase() { } @Test fun insufficientDataShouldReturnNull() { - PowerMockito.`when`(iobCobCalculatorPlugin.bgReadings).thenReturn(generateInsufficientBgData()) - val glucoseStatus: GlucoseStatus? = GlucoseStatusProvider(aapsLogger, iobCobCalculatorPlugin).glucoseStatusData + PowerMockito.`when`(autosensDataStore.getBgReadingsDataTableCopy()).thenReturn(generateInsufficientBgData()) + val glucoseStatus: GlucoseStatus? = GlucoseStatusProvider(aapsLogger, iobCobCalculatorPlugin, dateUtil).glucoseStatusData Assert.assertEquals(null, glucoseStatus) } @Test fun oldDataShouldReturnNull() { - PowerMockito.`when`(iobCobCalculatorPlugin.bgReadings).thenReturn(generateOldBgData()) - val glucoseStatus: GlucoseStatus? = GlucoseStatusProvider(aapsLogger, iobCobCalculatorPlugin).glucoseStatusData + PowerMockito.`when`(autosensDataStore.getBgReadingsDataTableCopy()).thenReturn(generateOldBgData()) + val glucoseStatus: GlucoseStatus? = GlucoseStatusProvider(aapsLogger, iobCobCalculatorPlugin, dateUtil).glucoseStatusData Assert.assertEquals(null, glucoseStatus) } @Test fun returnOldDataIfAllowed() { - PowerMockito.`when`(iobCobCalculatorPlugin.bgReadings).thenReturn(generateOldBgData()) - val glucoseStatus: GlucoseStatus? = GlucoseStatusProvider(aapsLogger, iobCobCalculatorPlugin).getGlucoseStatusData(true) + PowerMockito.`when`(autosensDataStore.getBgReadingsDataTableCopy()).thenReturn(generateOldBgData()) + val glucoseStatus: GlucoseStatus? = GlucoseStatusProvider(aapsLogger, iobCobCalculatorPlugin, dateUtil).getGlucoseStatusData(true) Assert.assertNotEquals(null, glucoseStatus) } @@ -93,8 +100,8 @@ class GlucoseStatusTest : TestBase() { } @Test fun calculateGlucoseStatusForLibreTestBgData() { - PowerMockito.`when`(iobCobCalculatorPlugin.bgReadings).thenReturn(generateLibreTestData()) - val glucoseStatus: GlucoseStatus = GlucoseStatusProvider(aapsLogger, iobCobCalculatorPlugin).glucoseStatusData!! + PowerMockito.`when`(autosensDataStore.getBgReadingsDataTableCopy()).thenReturn(generateLibreTestData()) + val glucoseStatus: GlucoseStatus = GlucoseStatusProvider(aapsLogger, iobCobCalculatorPlugin, dateUtil).glucoseStatusData!! Assert.assertEquals(100.0, glucoseStatus.glucose, 0.001) // Assert.assertEquals(-10.0, glucoseStatus.delta, 0.001) Assert.assertEquals(-10.0, glucoseStatus.shortAvgDelta, 0.001) @@ -104,9 +111,8 @@ class GlucoseStatusTest : TestBase() { @Before fun initMocking() { - PowerMockito.mockStatic(DateUtil::class.java) - PowerMockito.`when`(DateUtil.now()).thenReturn(1514766900000L + T.mins(1).msecs()) - `when`(iobCobCalculatorPlugin.dataLock).thenReturn(Unit) + `when`(dateUtil.now()).thenReturn(1514766900000L + T.mins(1).msecs()) + `when`(iobCobCalculatorPlugin.ads).thenReturn(autosensDataStore) } // [{"mgdl":214,"mills":1521895773113,"device":"xDrip-DexcomG5","direction":"Flat","filtered":191040,"unfiltered":205024,"noise":1,"rssi":100},{"mgdl":219,"mills":1521896073352,"device":"xDrip-DexcomG5","direction":"Flat","filtered":200160,"unfiltered":209760,"noise":1,"rssi":100},{"mgdl":222,"mills":1521896372890,"device":"xDrip-DexcomG5","direction":"Flat","filtered":207360,"unfiltered":212512,"noise":1,"rssi":100},{"mgdl":220,"mills":1521896673062,"device":"xDrip-DexcomG5","direction":"Flat","filtered":211488,"unfiltered":210688,"noise":1,"rssi":100},{"mgdl":193,"mills":1521896972933,"device":"xDrip-DexcomG5","direction":"Flat","filtered":212384,"unfiltered":208960,"noise":1,"rssi":100},{"mgdl":181,"mills":1521897273336,"device":"xDrip-DexcomG5","direction":"SingleDown","filtered":210592,"unfiltered":204320,"noise":1,"rssi":100},{"mgdl":176,"mills":1521897572875,"device":"xDrip-DexcomG5","direction":"FortyFiveDown","filtered":206720,"unfiltered":197440,"noise":1,"rssi":100},{"mgdl":168,"mills":1521897872929,"device":"xDrip-DexcomG5","direction":"FortyFiveDown","filtered":201024,"unfiltered":187904,"noise":1,"rssi":100},{"mgdl":161,"mills":1521898172814,"device":"xDrip-DexcomG5","direction":"FortyFiveDown","filtered":193376,"unfiltered":178144,"noise":1,"rssi":100},{"mgdl":148,"mills":1521898472879,"device":"xDrip-DexcomG5","direction":"SingleDown","filtered":183264,"unfiltered":161216,"noise":1,"rssi":100},{"mgdl":139,"mills":1521898772862,"device":"xDrip-DexcomG5","direction":"FortyFiveDown","filtered":170784,"unfiltered":148928,"noise":1,"rssi":100},{"mgdl":132,"mills":1521899072896,"device":"xDrip-DexcomG5","direction":"FortyFiveDown","filtered":157248,"unfiltered":139552,"noise":1,"rssi":100},{"mgdl":125,"mills":1521899372834,"device":"xDrip-DexcomG5","direction":"FortyFiveDown","filtered":144416,"unfiltered":129616.00000000001,"noise":1,"rssi":100},{"mgdl":128,"mills":1521899973456,"device":"xDrip-DexcomG5","direction":"Flat","filtered":130240.00000000001,"unfiltered":133536,"noise":1,"rssi":100},{"mgdl":132,"mills":1521900573287,"device":"xDrip-DexcomG5","direction":"Flat","filtered":133504,"unfiltered":138720,"noise":1,"rssi":100},{"mgdl":127,"mills":1521900873711,"device":"xDrip-DexcomG5","direction":"Flat","filtered":136480,"unfiltered":132992,"noise":1,"rssi":100},{"mgdl":127,"mills":1521901180151,"device":"xDrip-DexcomG5","direction":"Flat","filtered":136896,"unfiltered":132128,"noise":1,"rssi":100},{"mgdl":125,"mills":1521901473582,"device":"xDrip-DexcomG5","direction":"Flat","filtered":134624,"unfiltered":129696,"noise":1,"rssi":100},{"mgdl":120,"mills":1521901773597,"device":"xDrip-DexcomG5","direction":"Flat","filtered":130704.00000000001,"unfiltered":123376,"noise":1,"rssi":100},{"mgdl":116,"mills":1521902075855,"device":"xDrip-DexcomG5","direction":"Flat","filtered":126272,"unfiltered":118448,"noise":1,"rssi":100}] diff --git a/app/src/test/java/info/nightscout/androidaps/plugins/iob/iobCobCalculator/IobCobCalculatorPluginTest.kt b/core/src/test/java/info/nightscout/androidaps/plugins/iob/iobCobCalculator/AutosensDataStoreTest.kt similarity index 50% rename from app/src/test/java/info/nightscout/androidaps/plugins/iob/iobCobCalculator/IobCobCalculatorPluginTest.kt rename to core/src/test/java/info/nightscout/androidaps/plugins/iob/iobCobCalculator/AutosensDataStoreTest.kt index 391e54f035..5fbafb3419 100644 --- a/app/src/test/java/info/nightscout/androidaps/plugins/iob/iobCobCalculator/IobCobCalculatorPluginTest.kt +++ b/core/src/test/java/info/nightscout/androidaps/plugins/iob/iobCobCalculator/AutosensDataStoreTest.kt @@ -1,58 +1,27 @@ package info.nightscout.androidaps.plugins.iob.iobCobCalculator -import dagger.android.AndroidInjector -import dagger.android.HasAndroidInjector +import android.content.Context import info.nightscout.androidaps.TestBase -import info.nightscout.androidaps.database.AppRepository import info.nightscout.androidaps.database.entities.GlucoseValue -import info.nightscout.androidaps.interfaces.ActivePluginProvider -import info.nightscout.androidaps.interfaces.ProfileFunction -import info.nightscout.androidaps.plugins.bus.RxBusWrapper -import info.nightscout.androidaps.plugins.sensitivity.SensitivityAAPSPlugin -import info.nightscout.androidaps.plugins.sensitivity.SensitivityOref1Plugin -import info.nightscout.androidaps.plugins.sensitivity.SensitivityWeightedAveragePlugin -import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin import info.nightscout.androidaps.utils.DateUtil -import info.nightscout.androidaps.utils.FabricPrivacy import info.nightscout.androidaps.utils.T -import info.nightscout.androidaps.utils.resources.ResourceHelper -import info.nightscout.androidaps.utils.sharedPreferences.SP import org.junit.Assert import org.junit.Before import org.junit.Test -import org.junit.runner.RunWith import org.mockito.Mock -import org.powermock.core.classloader.annotations.PrepareForTest -import org.powermock.modules.junit4.PowerMockRunner import java.util.* -@RunWith(PowerMockRunner::class) -@PrepareForTest(FabricPrivacy::class, AppRepository::class) -class IobCobCalculatorPluginTest : TestBase() { +class AutosensDataStoreTest : TestBase() { - @Mock lateinit var sp: SP - private val rxBus = RxBusWrapper(aapsSchedulers) - @Mock lateinit var resourceHelper: ResourceHelper - @Mock lateinit var profileFunction: ProfileFunction - @Mock lateinit var activePlugin: ActivePluginProvider - @Mock lateinit var treatmentsPlugin: TreatmentsPlugin - @Mock lateinit var sensitivityOref1Plugin: SensitivityOref1Plugin - @Mock lateinit var sensitivityAAPSPlugin: SensitivityAAPSPlugin - @Mock lateinit var sensitivityWeightedAveragePlugin: SensitivityWeightedAveragePlugin - @Mock lateinit var fabricPrivacy: FabricPrivacy - @Mock lateinit var dateUtil: DateUtil - @Mock lateinit var repository: AppRepository + @Mock lateinit var context: Context - lateinit var iobCobCalculatorPlugin: IobCobCalculatorPlugin + lateinit var dateUtil: DateUtil - val injector = HasAndroidInjector { - AndroidInjector { - } - } + private val autosensDataStore = AutosensDataStore() @Before fun mock() { - iobCobCalculatorPlugin = IobCobCalculatorPlugin(injector, aapsLogger, aapsSchedulers, rxBus, sp, resourceHelper, profileFunction, activePlugin, treatmentsPlugin, sensitivityOref1Plugin, sensitivityAAPSPlugin, sensitivityWeightedAveragePlugin, fabricPrivacy, dateUtil, repository) + dateUtil = DateUtil(context) } @Test @@ -65,8 +34,8 @@ class IobCobCalculatorPluginTest : TestBase() { bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = T.mins(15).msecs(), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT)) bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = T.mins(10).msecs(), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT)) bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = T.mins(5).msecs(), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT)) - iobCobCalculatorPlugin.bgReadings = bgReadingList - Assert.assertEquals(true, iobCobCalculatorPlugin.isAbout5minData) + autosensDataStore.bgReadings = bgReadingList + Assert.assertEquals(true, autosensDataStore.isAbout5minData(aapsLogger)) // too much shifted data should return false bgReadingList.clear() @@ -74,16 +43,16 @@ class IobCobCalculatorPluginTest : TestBase() { bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = T.mins(15).msecs(), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT)) bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = T.mins(9).msecs(), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT)) bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = T.mins(5).msecs(), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT)) - iobCobCalculatorPlugin.bgReadings = bgReadingList - Assert.assertEquals(false, iobCobCalculatorPlugin.isAbout5minData) + autosensDataStore.bgReadings = bgReadingList + Assert.assertEquals(false, autosensDataStore.isAbout5minData(aapsLogger)) // too much shifted and missing data should return false bgReadingList.clear() bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = T.mins(20).msecs(), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT)) bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = T.mins(9).msecs(), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT)) bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = T.mins(5).msecs(), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT)) - iobCobCalculatorPlugin.bgReadings = bgReadingList - Assert.assertEquals(false, iobCobCalculatorPlugin.isAbout5minData) + autosensDataStore.bgReadings = bgReadingList + Assert.assertEquals(false, autosensDataStore.isAbout5minData(aapsLogger)) // too much shifted and missing data should return false bgReadingList.clear() @@ -101,8 +70,8 @@ class IobCobCalculatorPluginTest : TestBase() { bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = T.mins(28).plus(T.secs(0)).msecs(), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT)) bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = T.mins(23).plus(T.secs(0)).msecs(), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT)) bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = T.mins(16).plus(T.secs(36)).msecs(), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT)) - iobCobCalculatorPlugin.bgReadings = bgReadingList - Assert.assertEquals(false, iobCobCalculatorPlugin.isAbout5minData) + autosensDataStore.bgReadings = bgReadingList + Assert.assertEquals(false, autosensDataStore.isAbout5minData(aapsLogger)) // slightly shifted data should return true bgReadingList.clear() @@ -110,20 +79,20 @@ class IobCobCalculatorPluginTest : TestBase() { bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = T.mins(15).msecs(), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT)) bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = T.mins(10).plus(T.secs(10)).msecs(), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT)) bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = T.mins(5).msecs(), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT)) - iobCobCalculatorPlugin.bgReadings = bgReadingList - Assert.assertEquals(true, iobCobCalculatorPlugin.isAbout5minData) + autosensDataStore.bgReadings = bgReadingList + Assert.assertEquals(true, autosensDataStore.isAbout5minData(aapsLogger)) // slightly shifted and missing data should return true bgReadingList.clear() bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = T.mins(20).msecs(), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT)) bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = T.mins(10).plus(T.secs(10)).msecs(), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT)) bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = T.mins(5).msecs(), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT)) - iobCobCalculatorPlugin.bgReadings = bgReadingList - Assert.assertEquals(true, iobCobCalculatorPlugin.isAbout5minData) + autosensDataStore.bgReadings = bgReadingList + Assert.assertEquals(true, autosensDataStore.isAbout5minData(aapsLogger)) } @Test - fun createBucketedData5minTest() { + fun createBucketedData5minTest1() { val bgReadingList: MutableList = ArrayList() // Super data should not be touched @@ -132,24 +101,24 @@ class IobCobCalculatorPluginTest : TestBase() { bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = T.mins(15).msecs(), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT)) bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = T.mins(10).msecs(), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT)) bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = T.mins(5).msecs(), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT)) - iobCobCalculatorPlugin.bgReadings = bgReadingList - Assert.assertEquals(true, iobCobCalculatorPlugin.isAbout5minData) - iobCobCalculatorPlugin.createBucketedData() - Assert.assertEquals(bgReadingList[0].timestamp, iobCobCalculatorPlugin.bucketedData!![0].timestamp) - Assert.assertEquals(bgReadingList[3].timestamp, iobCobCalculatorPlugin.bucketedData!![3].timestamp) - Assert.assertEquals(bgReadingList.size.toLong(), iobCobCalculatorPlugin.bucketedData!!.size.toLong()) + autosensDataStore.bgReadings = bgReadingList + Assert.assertEquals(true, autosensDataStore.isAbout5minData(aapsLogger)) + autosensDataStore.createBucketedData(aapsLogger, dateUtil) + Assert.assertEquals(bgReadingList[0].timestamp, autosensDataStore.bucketedData!![0].timestamp) + Assert.assertEquals(bgReadingList[3].timestamp, autosensDataStore.bucketedData!![3].timestamp) + Assert.assertEquals(bgReadingList.size.toLong(), autosensDataStore.bucketedData!!.size.toLong()) // Missing value should be replaced bgReadingList.clear() bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = T.mins(20).msecs(), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT)) bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = T.mins(10).plus(T.secs(10)).msecs(), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT)) bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = T.mins(5).msecs(), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT)) - iobCobCalculatorPlugin.bgReadings = bgReadingList - Assert.assertEquals(true, iobCobCalculatorPlugin.isAbout5minData) - iobCobCalculatorPlugin.createBucketedData() - Assert.assertEquals(bgReadingList[0].timestamp, iobCobCalculatorPlugin.bucketedData!![0].timestamp) - Assert.assertEquals(bgReadingList[2].timestamp, iobCobCalculatorPlugin.bucketedData!![3].timestamp) - Assert.assertEquals(bgReadingList.size + 1.toLong(), iobCobCalculatorPlugin.bucketedData!!.size.toLong()) + autosensDataStore.bgReadings = bgReadingList + Assert.assertEquals(true, autosensDataStore.isAbout5minData(aapsLogger)) + autosensDataStore.createBucketedData(aapsLogger, dateUtil) + Assert.assertEquals(bgReadingList[0].timestamp, autosensDataStore.bucketedData!![0].timestamp) + Assert.assertEquals(bgReadingList[2].timestamp, autosensDataStore.bucketedData!![3].timestamp) + Assert.assertEquals(bgReadingList.size + 1.toLong(), autosensDataStore.bucketedData!!.size.toLong()) // drift should be cleared bgReadingList.clear() @@ -158,135 +127,140 @@ class IobCobCalculatorPluginTest : TestBase() { bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = T.mins(10).msecs() + T.secs(10).msecs(), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT)) bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = T.mins(5).msecs() + T.secs(10).msecs(), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT)) bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = T.mins(0).msecs(), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT)) - iobCobCalculatorPlugin.bgReadings = bgReadingList - Assert.assertEquals(true, iobCobCalculatorPlugin.isAbout5minData) - iobCobCalculatorPlugin.createBucketedData() - Assert.assertEquals(T.mins(20).msecs(), iobCobCalculatorPlugin.bucketedData!![0].timestamp) - Assert.assertEquals(T.mins(15).msecs(), iobCobCalculatorPlugin.bucketedData!![1].timestamp) - Assert.assertEquals(T.mins(10).msecs(), iobCobCalculatorPlugin.bucketedData!![2].timestamp) - Assert.assertEquals(T.mins(5).msecs(), iobCobCalculatorPlugin.bucketedData!![3].timestamp) - Assert.assertEquals(bgReadingList.size.toLong(), iobCobCalculatorPlugin.bucketedData!!.size.toLong()) + autosensDataStore.bgReadings = bgReadingList + Assert.assertEquals(true, autosensDataStore.isAbout5minData(aapsLogger)) + autosensDataStore.createBucketedData(aapsLogger, dateUtil) + Assert.assertEquals(T.mins(20).msecs(), autosensDataStore.bucketedData!![0].timestamp) + Assert.assertEquals(T.mins(15).msecs(), autosensDataStore.bucketedData!![1].timestamp) + Assert.assertEquals(T.mins(10).msecs(), autosensDataStore.bucketedData!![2].timestamp) + Assert.assertEquals(T.mins(5).msecs(), autosensDataStore.bucketedData!![3].timestamp) + Assert.assertEquals(bgReadingList.size.toLong(), autosensDataStore.bucketedData!!.size.toLong()) // bucketed data should return null if not enough bg data bgReadingList.clear() bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = T.mins(30).msecs(), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT)) bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = T.mins(5).msecs(), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT)) - iobCobCalculatorPlugin.bgReadings = bgReadingList - Assert.assertEquals(true, iobCobCalculatorPlugin.isAbout5minData) - iobCobCalculatorPlugin.createBucketedData() - Assert.assertEquals(null, iobCobCalculatorPlugin.bucketedData) + autosensDataStore.bgReadings = bgReadingList + Assert.assertEquals(true, autosensDataStore.isAbout5minData(aapsLogger)) + autosensDataStore.createBucketedData(aapsLogger, dateUtil) + Assert.assertEquals(null, autosensDataStore.bucketedData) // data should be reconstructed bgReadingList.clear() bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = T.mins(50).msecs(), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT)) bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 90.0, timestamp = T.mins(45).msecs(), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT)) bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 40.0, timestamp = T.mins(20).msecs(), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT)) - iobCobCalculatorPlugin.bgReadings = bgReadingList - Assert.assertEquals(true, iobCobCalculatorPlugin.isAbout5minData) - iobCobCalculatorPlugin.createBucketedData() - Assert.assertEquals(T.mins(50).msecs(), iobCobCalculatorPlugin.bucketedData!![0].timestamp) - Assert.assertEquals(T.mins(20).msecs(), iobCobCalculatorPlugin.bucketedData!![6].timestamp) - Assert.assertEquals(7, iobCobCalculatorPlugin.bucketedData!!.size.toLong()) - Assert.assertEquals(100.0, iobCobCalculatorPlugin.bucketedData!![0].value, 1.0) - Assert.assertEquals(90.0, iobCobCalculatorPlugin.bucketedData!![1].value, 1.0) - Assert.assertEquals(50.0, iobCobCalculatorPlugin.bucketedData!![5].value, 1.0) - Assert.assertEquals(40.0, iobCobCalculatorPlugin.bucketedData!![6].value, 1.0) + autosensDataStore.bgReadings = bgReadingList + Assert.assertEquals(true, autosensDataStore.isAbout5minData(aapsLogger)) + autosensDataStore.createBucketedData(aapsLogger, dateUtil) + Assert.assertEquals(T.mins(50).msecs(), autosensDataStore.bucketedData!![0].timestamp) + Assert.assertEquals(T.mins(20).msecs(), autosensDataStore.bucketedData!![6].timestamp) + Assert.assertEquals(7, autosensDataStore.bucketedData!!.size.toLong()) + Assert.assertEquals(100.0, autosensDataStore.bucketedData!![0].value, 1.0) + Assert.assertEquals(90.0, autosensDataStore.bucketedData!![1].value, 1.0) + Assert.assertEquals(50.0, autosensDataStore.bucketedData!![5].value, 1.0) + Assert.assertEquals(40.0, autosensDataStore.bucketedData!![6].value, 1.0) // non 5min data should be reconstructed bgReadingList.clear() bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = T.mins(50).msecs(), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT)) bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 96.0, timestamp = T.mins(48).msecs(), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT)) bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 40.0, timestamp = T.mins(20).msecs(), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT)) - iobCobCalculatorPlugin.bgReadings = bgReadingList - Assert.assertEquals(false, iobCobCalculatorPlugin.isAbout5minData) - iobCobCalculatorPlugin.createBucketedData() - Assert.assertEquals(T.mins(50).msecs(), iobCobCalculatorPlugin.bucketedData!![0].timestamp) - Assert.assertEquals(T.mins(20).msecs(), iobCobCalculatorPlugin.bucketedData!![6].timestamp) - Assert.assertEquals(7, iobCobCalculatorPlugin.bucketedData!!.size.toLong()) - Assert.assertEquals(100.0, iobCobCalculatorPlugin.bucketedData!![0].value, 1.0) - Assert.assertEquals(90.0, iobCobCalculatorPlugin.bucketedData!![1].value, 1.0) - Assert.assertEquals(50.0, iobCobCalculatorPlugin.bucketedData!![5].value, 1.0) - Assert.assertEquals(40.0, iobCobCalculatorPlugin.bucketedData!![6].value, 1.0) + autosensDataStore.bgReadings = bgReadingList + Assert.assertEquals(false, autosensDataStore.isAbout5minData(aapsLogger)) + autosensDataStore.createBucketedData(aapsLogger, dateUtil) + Assert.assertEquals(T.mins(50).msecs(), autosensDataStore.bucketedData!![0].timestamp) + Assert.assertEquals(T.mins(20).msecs(), autosensDataStore.bucketedData!![6].timestamp) + Assert.assertEquals(7, autosensDataStore.bucketedData!!.size.toLong()) + Assert.assertEquals(100.0, autosensDataStore.bucketedData!![0].value, 1.0) + Assert.assertEquals(90.0, autosensDataStore.bucketedData!![1].value, 1.0) + Assert.assertEquals(50.0, autosensDataStore.bucketedData!![5].value, 1.0) + Assert.assertEquals(40.0, autosensDataStore.bucketedData!![6].value, 1.0) + } + + @Test + fun createBucketedData5minTest2() { + val bgReadingList: MutableList = ArrayList() //bucketed data should be null if no bg data available - iobCobCalculatorPlugin.bgReadings = ArrayList() - iobCobCalculatorPlugin.createBucketedData() - Assert.assertEquals(null, iobCobCalculatorPlugin.bucketedData) + autosensDataStore.bgReadings = ArrayList() + autosensDataStore.createBucketedData(aapsLogger, dateUtil) + Assert.assertEquals(null, autosensDataStore.bucketedData) // real data gap test bgReadingList.clear() - bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = DateUtil.fromISODateString("2018-09-05T13:34:55Z").time, sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT)) - bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = DateUtil.fromISODateString("2018-09-05T13:14:55Z").time, sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT)) - bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = DateUtil.fromISODateString("2018-09-05T13:09:55Z").time, sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT)) - bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = DateUtil.fromISODateString("2018-09-05T13:04:55Z").time, sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT)) - bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = DateUtil.fromISODateString("2018-09-05T12:59:55Z").time, sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT)) - bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = DateUtil.fromISODateString("2018-09-05T12:54:55Z").time, sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT)) - bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = DateUtil.fromISODateString("2018-09-05T12:49:55Z").time, sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT)) - bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = DateUtil.fromISODateString("2018-09-05T12:44:55Z").time, sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT)) - bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = DateUtil.fromISODateString("2018-09-05T12:39:55Z").time, sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT)) - bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = DateUtil.fromISODateString("2018-09-05T12:34:55Z").time, sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT)) - bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = DateUtil.fromISODateString("2018-09-05T12:29:56Z").time, sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT)) - bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = DateUtil.fromISODateString("2018-09-05T12:24:55Z").time, sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT)) - bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = DateUtil.fromISODateString("2018-09-05T12:19:56Z").time, sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT)) - bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = DateUtil.fromISODateString("2018-09-05T12:14:56Z").time, sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT)) - bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = DateUtil.fromISODateString("2018-09-05T12:09:56Z").time, sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT)) - bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = DateUtil.fromISODateString("2018-09-05T12:04:56Z").time, sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT)) - bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = DateUtil.fromISODateString("2018-09-05T11:59:55Z").time, sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT)) + bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = dateUtil.fromISODateString("2018-09-05T13:34:55Z"), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT)) + bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = dateUtil.fromISODateString("2018-09-05T13:14:55Z"), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT)) + bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = dateUtil.fromISODateString("2018-09-05T13:09:55Z"), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT)) + bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = dateUtil.fromISODateString("2018-09-05T13:04:55Z"), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT)) + bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = dateUtil.fromISODateString("2018-09-05T12:59:55Z"), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT)) + bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = dateUtil.fromISODateString("2018-09-05T12:54:55Z"), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT)) + bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = dateUtil.fromISODateString("2018-09-05T12:49:55Z"), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT)) + bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = dateUtil.fromISODateString("2018-09-05T12:44:55Z"), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT)) + bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = dateUtil.fromISODateString("2018-09-05T12:39:55Z"), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT)) + bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = dateUtil.fromISODateString("2018-09-05T12:34:55Z"), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT)) + bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = dateUtil.fromISODateString("2018-09-05T12:29:56Z"), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT)) + bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = dateUtil.fromISODateString("2018-09-05T12:24:55Z"), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT)) + bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = dateUtil.fromISODateString("2018-09-05T12:19:56Z"), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT)) + bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = dateUtil.fromISODateString("2018-09-05T12:14:56Z"), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT)) + bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = dateUtil.fromISODateString("2018-09-05T12:09:56Z"), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT)) + bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = dateUtil.fromISODateString("2018-09-05T12:04:56Z"), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT)) + bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = dateUtil.fromISODateString("2018-09-05T11:59:55Z"), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT)) - bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = DateUtil.fromISODateString("2018-09-05T04:29:57Z").time, sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT)) - bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = DateUtil.fromISODateString("2018-09-05T04:24:56Z").time, sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT)) - bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = DateUtil.fromISODateString("2018-09-05T04:19:57Z").time, sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT)) - bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = DateUtil.fromISODateString("2018-09-05T04:14:57Z").time, sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT)) - bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = DateUtil.fromISODateString("2018-09-05T04:10:03Z").time, sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT)) - bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = DateUtil.fromISODateString("2018-09-05T04:04:56Z").time, sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT)) - bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = DateUtil.fromISODateString("2018-09-05T03:59:56Z").time, sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT)) - bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = DateUtil.fromISODateString("2018-09-05T03:54:56Z").time, sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT)) - bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = DateUtil.fromISODateString("2018-09-05T03:50:03Z").time, sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT)) - bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = DateUtil.fromISODateString("2018-09-05T03:44:57Z").time, sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT)) - iobCobCalculatorPlugin.bgReadings = bgReadingList - iobCobCalculatorPlugin.referenceTime = -1 - Assert.assertEquals(true, iobCobCalculatorPlugin.isAbout5minData) - iobCobCalculatorPlugin.createBucketedData() - Assert.assertEquals(DateUtil.fromISODateString("2018-09-05T13:34:57Z").time, iobCobCalculatorPlugin.bucketedData!![0].timestamp) - Assert.assertEquals(DateUtil.fromISODateString("2018-09-05T03:44:57Z").time, iobCobCalculatorPlugin.bucketedData!![iobCobCalculatorPlugin.bucketedData!!.size - 1].timestamp) + bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = dateUtil.fromISODateString("2018-09-05T04:29:57Z"), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT)) + bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = dateUtil.fromISODateString("2018-09-05T04:24:56Z"), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT)) + bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = dateUtil.fromISODateString("2018-09-05T04:19:57Z"), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT)) + bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = dateUtil.fromISODateString("2018-09-05T04:14:57Z"), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT)) + bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = dateUtil.fromISODateString("2018-09-05T04:10:03Z"), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT)) + bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = dateUtil.fromISODateString("2018-09-05T04:04:56Z"), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT)) + bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = dateUtil.fromISODateString("2018-09-05T03:59:56Z"), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT)) + bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = dateUtil.fromISODateString("2018-09-05T03:54:56Z"), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT)) + bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = dateUtil.fromISODateString("2018-09-05T03:50:03Z"), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT)) + bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = dateUtil.fromISODateString("2018-09-05T03:44:57Z"), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT)) + autosensDataStore.bgReadings = bgReadingList + autosensDataStore.referenceTime = -1 + Assert.assertEquals(true, autosensDataStore.isAbout5minData(aapsLogger)) + autosensDataStore.createBucketedData(aapsLogger, dateUtil) + Assert.assertEquals(dateUtil.fromISODateString("2018-09-05T13:34:57Z"), autosensDataStore.bucketedData!![0].timestamp) + Assert.assertEquals(dateUtil.fromISODateString("2018-09-05T03:44:57Z"), autosensDataStore.bucketedData!![autosensDataStore.bucketedData!!.size - 1].timestamp) // 5min 4sec data bgReadingList.clear() - bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = DateUtil.fromISODateString("2018-10-05T06:33:40Z").time, sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT)) - bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = DateUtil.fromISODateString("2018-10-05T06:28:36Z").time, sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT)) - bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = DateUtil.fromISODateString("2018-10-05T06:23:32Z").time, sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT)) - bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = DateUtil.fromISODateString("2018-10-05T06:18:28Z").time, sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT)) - bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = DateUtil.fromISODateString("2018-10-05T06:13:24Z").time, sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT)) - bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = DateUtil.fromISODateString("2018-10-05T06:08:19Z").time, sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT)) - bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = DateUtil.fromISODateString("2018-10-05T06:03:16Z").time, sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT)) - bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = DateUtil.fromISODateString("2018-10-05T05:58:11Z").time, sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT)) - bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = DateUtil.fromISODateString("2018-10-05T05:53:07Z").time, sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT)) - bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = DateUtil.fromISODateString("2018-10-05T05:48:03Z").time, sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT)) - bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = DateUtil.fromISODateString("2018-10-05T05:42:58Z").time, sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT)) - bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = DateUtil.fromISODateString("2018-10-05T05:37:54Z").time, sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT)) - bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = DateUtil.fromISODateString("2018-10-05T05:32:51Z").time, sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT)) - bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = DateUtil.fromISODateString("2018-10-05T05:27:46Z").time, sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT)) - bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = DateUtil.fromISODateString("2018-10-05T05:22:42Z").time, sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT)) - bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = DateUtil.fromISODateString("2018-10-05T05:17:38Z").time, sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT)) - bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = DateUtil.fromISODateString("2018-10-05T05:12:33Z").time, sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT)) - bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = DateUtil.fromISODateString("2018-10-05T05:07:29Z").time, sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT)) - bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = DateUtil.fromISODateString("2018-10-05T05:02:26Z").time, sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT)) - bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = DateUtil.fromISODateString("2018-10-05T04:57:21Z").time, sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT)) - bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = DateUtil.fromISODateString("2018-10-05T04:52:17Z").time, sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT)) - iobCobCalculatorPlugin.bgReadings = bgReadingList - Assert.assertEquals(false, iobCobCalculatorPlugin.isAbout5minData) + bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = dateUtil.fromISODateString("2018-10-05T06:33:40Z"), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT)) + bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = dateUtil.fromISODateString("2018-10-05T06:28:36Z"), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT)) + bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = dateUtil.fromISODateString("2018-10-05T06:23:32Z"), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT)) + bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = dateUtil.fromISODateString("2018-10-05T06:18:28Z"), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT)) + bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = dateUtil.fromISODateString("2018-10-05T06:13:24Z"), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT)) + bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = dateUtil.fromISODateString("2018-10-05T06:08:19Z"), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT)) + bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = dateUtil.fromISODateString("2018-10-05T06:03:16Z"), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT)) + bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = dateUtil.fromISODateString("2018-10-05T05:58:11Z"), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT)) + bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = dateUtil.fromISODateString("2018-10-05T05:53:07Z"), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT)) + bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = dateUtil.fromISODateString("2018-10-05T05:48:03Z"), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT)) + bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = dateUtil.fromISODateString("2018-10-05T05:42:58Z"), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT)) + bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = dateUtil.fromISODateString("2018-10-05T05:37:54Z"), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT)) + bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = dateUtil.fromISODateString("2018-10-05T05:32:51Z"), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT)) + bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = dateUtil.fromISODateString("2018-10-05T05:27:46Z"), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT)) + bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = dateUtil.fromISODateString("2018-10-05T05:22:42Z"), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT)) + bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = dateUtil.fromISODateString("2018-10-05T05:17:38Z"), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT)) + bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = dateUtil.fromISODateString("2018-10-05T05:12:33Z"), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT)) + bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = dateUtil.fromISODateString("2018-10-05T05:07:29Z"), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT)) + bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = dateUtil.fromISODateString("2018-10-05T05:02:26Z"), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT)) + bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = dateUtil.fromISODateString("2018-10-05T04:57:21Z"), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT)) + bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = dateUtil.fromISODateString("2018-10-05T04:52:17Z"), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT)) + autosensDataStore.bgReadings = bgReadingList + Assert.assertEquals(false, autosensDataStore.isAbout5minData(aapsLogger)) } @Test fun bgReadingsTest() { val bgReadingList: List = ArrayList() - iobCobCalculatorPlugin.bgReadings = bgReadingList - Assert.assertEquals(bgReadingList, iobCobCalculatorPlugin.bgReadings) + autosensDataStore.bgReadings = bgReadingList + Assert.assertEquals(bgReadingList, autosensDataStore.bgReadings) } @Test fun roundUpTimeTest() { - Assert.assertEquals(T.mins(3).msecs(), IobCobCalculatorPlugin.roundUpTime(T.secs(155).msecs())) + Assert.assertEquals(T.mins(3).msecs(), autosensDataStore.roundUpTime(T.secs(155).msecs())) } @Test @@ -296,12 +270,12 @@ class IobCobCalculatorPluginTest : TestBase() { bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = T.mins(15).msecs(), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT)) bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = T.mins(10).msecs(), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT)) bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = T.mins(5).msecs(), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT)) - iobCobCalculatorPlugin.bgReadings = bgReadingList - Assert.assertEquals(T.mins(10).msecs(), iobCobCalculatorPlugin.findNewer(T.mins(8).msecs())!!.timestamp) - Assert.assertEquals(T.mins(5).msecs(), iobCobCalculatorPlugin.findNewer(T.mins(5).msecs())!!.timestamp) - Assert.assertEquals(T.mins(10).msecs(), iobCobCalculatorPlugin.findNewer(T.mins(10).msecs())!!.timestamp) - Assert.assertEquals(T.mins(20).msecs(), iobCobCalculatorPlugin.findNewer(T.mins(20).msecs())!!.timestamp) - Assert.assertEquals(null, iobCobCalculatorPlugin.findNewer(T.mins(22).msecs())) + autosensDataStore.bgReadings = bgReadingList + Assert.assertEquals(T.mins(10).msecs(), autosensDataStore.findNewer(T.mins(8).msecs())!!.timestamp) + Assert.assertEquals(T.mins(5).msecs(), autosensDataStore.findNewer(T.mins(5).msecs())!!.timestamp) + Assert.assertEquals(T.mins(10).msecs(), autosensDataStore.findNewer(T.mins(10).msecs())!!.timestamp) + Assert.assertEquals(T.mins(20).msecs(), autosensDataStore.findNewer(T.mins(20).msecs())!!.timestamp) + Assert.assertEquals(null, autosensDataStore.findNewer(T.mins(22).msecs())) } @Test @@ -311,20 +285,20 @@ class IobCobCalculatorPluginTest : TestBase() { bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = T.mins(15).msecs(), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT)) bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = T.mins(10).msecs(), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT)) bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = T.mins(5).msecs(), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT)) - iobCobCalculatorPlugin.bgReadings = bgReadingList - Assert.assertEquals(T.mins(5).msecs(), iobCobCalculatorPlugin.findOlder(T.mins(8).msecs())!!.timestamp) - Assert.assertEquals(T.mins(5).msecs(), iobCobCalculatorPlugin.findOlder(T.mins(5).msecs())!!.timestamp) - Assert.assertEquals(T.mins(10).msecs(), iobCobCalculatorPlugin.findOlder(T.mins(10).msecs())!!.timestamp) - Assert.assertEquals(T.mins(20).msecs(), iobCobCalculatorPlugin.findOlder(T.mins(20).msecs())!!.timestamp) - Assert.assertEquals(null, iobCobCalculatorPlugin.findOlder(T.mins(4).msecs())) + autosensDataStore.bgReadings = bgReadingList + Assert.assertEquals(T.mins(5).msecs(), autosensDataStore.findOlder(T.mins(8).msecs())!!.timestamp) + Assert.assertEquals(T.mins(5).msecs(), autosensDataStore.findOlder(T.mins(5).msecs())!!.timestamp) + Assert.assertEquals(T.mins(10).msecs(), autosensDataStore.findOlder(T.mins(10).msecs())!!.timestamp) + Assert.assertEquals(T.mins(20).msecs(), autosensDataStore.findOlder(T.mins(20).msecs())!!.timestamp) + Assert.assertEquals(null, autosensDataStore.findOlder(T.mins(4).msecs())) } @Test fun findPreviousTimeFromBucketedDataTest() { val bgReadingList: MutableList = ArrayList() - iobCobCalculatorPlugin.bgReadings = bgReadingList - iobCobCalculatorPlugin.createBucketedData() - Assert.assertEquals(null, iobCobCalculatorPlugin.findPreviousTimeFromBucketedData(1000)) + autosensDataStore.bgReadings = bgReadingList + autosensDataStore.createBucketedData(aapsLogger, dateUtil) + Assert.assertEquals(null, autosensDataStore.findPreviousTimeFromBucketedData(1000)) // Super data should not be touched bgReadingList.clear() @@ -332,11 +306,11 @@ class IobCobCalculatorPluginTest : TestBase() { bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = T.mins(15).msecs(), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT)) bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = T.mins(10).msecs(), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT)) bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = T.mins(5).msecs(), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT)) - iobCobCalculatorPlugin.bgReadings = bgReadingList - iobCobCalculatorPlugin.createBucketedData() - Assert.assertEquals(null, iobCobCalculatorPlugin.findPreviousTimeFromBucketedData(T.mins(4).msecs())) - Assert.assertEquals(T.mins(5).msecs(), iobCobCalculatorPlugin.findPreviousTimeFromBucketedData(T.mins(6).msecs())) - Assert.assertEquals(T.mins(20).msecs(), iobCobCalculatorPlugin.findPreviousTimeFromBucketedData(T.mins(20).msecs())) - Assert.assertEquals(T.mins(20).msecs(), iobCobCalculatorPlugin.findPreviousTimeFromBucketedData(T.mins(25).msecs())) + autosensDataStore.bgReadings = bgReadingList + autosensDataStore.createBucketedData(aapsLogger, dateUtil) + Assert.assertEquals(null, autosensDataStore.findPreviousTimeFromBucketedData(T.mins(4).msecs())) + Assert.assertEquals(T.mins(5).msecs(), autosensDataStore.findPreviousTimeFromBucketedData(T.mins(6).msecs())) + Assert.assertEquals(T.mins(20).msecs(), autosensDataStore.findPreviousTimeFromBucketedData(T.mins(20).msecs())) + Assert.assertEquals(T.mins(20).msecs(), autosensDataStore.findPreviousTimeFromBucketedData(T.mins(25).msecs())) } } \ No newline at end of file diff --git a/core/src/test/java/info/nightscout/androidaps/pump/bolusInfo/DetailedBolusInfoStorageTest.kt b/core/src/test/java/info/nightscout/androidaps/pump/bolusInfo/DetailedBolusInfoStorageTest.kt index eb09873b30..7e0eb236c1 100644 --- a/core/src/test/java/info/nightscout/androidaps/pump/bolusInfo/DetailedBolusInfoStorageTest.kt +++ b/core/src/test/java/info/nightscout/androidaps/pump/bolusInfo/DetailedBolusInfoStorageTest.kt @@ -7,10 +7,7 @@ import org.junit.Assert.assertEquals import org.junit.Assert.assertNull import org.junit.Before import org.junit.Test -import org.junit.runner.RunWith -import org.powermock.modules.junit4.PowerMockRunner -@RunWith(PowerMockRunner::class) class DetailedBolusInfoStorageTest : TestBase() { private val info1 = DetailedBolusInfo() @@ -18,13 +15,13 @@ class DetailedBolusInfoStorageTest : TestBase() { private val info3 = DetailedBolusInfo() private lateinit var detailedBolusInfoStorage: DetailedBolusInfoStorage - + init { - info1.date = 1000000 + info1.timestamp = 1000000 info1.insulin = 3.0 - info2.date = 1000001 + info2.timestamp = 1000001 info2.insulin = 4.0 - info3.date = 2000000 + info3.timestamp = 2000000 info3.insulin = 5.0 } diff --git a/core/src/test/java/info/nightscout/androidaps/pump/bolusInfo/TemporaryBasalStorageTest.kt b/core/src/test/java/info/nightscout/androidaps/pump/bolusInfo/TemporaryBasalStorageTest.kt new file mode 100644 index 0000000000..d54568e4ae --- /dev/null +++ b/core/src/test/java/info/nightscout/androidaps/pump/bolusInfo/TemporaryBasalStorageTest.kt @@ -0,0 +1,79 @@ +package info.nightscout.androidaps.pump.bolusInfo + +import info.nightscout.androidaps.TestBase +import info.nightscout.androidaps.interfaces.PumpSync +import info.nightscout.androidaps.plugins.pump.common.bolusInfo.TemporaryBasalStorage +import org.junit.Assert.assertEquals +import org.junit.Assert.assertNull +import org.junit.Before +import org.junit.Test + +class TemporaryBasalStorageTest : TestBase() { + + private val info1 = PumpSync.PumpState.TemporaryBasal(1000000, 1000, 3.0, false, PumpSync.TemporaryBasalType.NORMAL, 0L, 0L) + private val info2 = PumpSync.PumpState.TemporaryBasal(1000001, 1000, 4.0, false, PumpSync.TemporaryBasalType.NORMAL, 0L, 0L) + private val info3 = PumpSync.PumpState.TemporaryBasal(2000000, 1000, 5.0, false, PumpSync.TemporaryBasalType.NORMAL, 0L, 0L) + + private lateinit var temporaryBasalStorage: TemporaryBasalStorage + + @Before + fun prepare() { + temporaryBasalStorage = TemporaryBasalStorage(aapsLogger) + } + + private fun setUp() { + temporaryBasalStorage.store.clear() + temporaryBasalStorage.add(info1) + temporaryBasalStorage.add(info2) + temporaryBasalStorage.add(info3) + } + + @Test + fun add() { + temporaryBasalStorage.store.clear() + assertEquals(0, temporaryBasalStorage.store.size) + temporaryBasalStorage.add(info1) + assertEquals(1, temporaryBasalStorage.store.size) + } + + @Test + fun findTemporaryBasal() { + + // Look for exact bolus + setUp() + var d = temporaryBasalStorage.findTemporaryBasal(1000000, 4.0) + assertEquals(4.0, d!!.rate, 0.01) + assertEquals(2, temporaryBasalStorage.store.size) + // Look for exact bolus + setUp() + d = temporaryBasalStorage.findTemporaryBasal(1000000, 3.0) + assertEquals(3.0, d!!.rate, 0.01) + assertEquals(2, temporaryBasalStorage.store.size) + // With less rate (bolus not delivered completely). Should return first one matching date + setUp() + d = temporaryBasalStorage.findTemporaryBasal(1000500, 2.0) + assertEquals(3.0, d!!.rate, 0.01) + assertEquals(2, temporaryBasalStorage.store.size) + // With less rate (bolus not delivered completely). Should return first one matching date + setUp() + d = temporaryBasalStorage.findTemporaryBasal(1000500, 3.5) + assertEquals(4.0, d!!.rate, 0.01) + assertEquals(2, temporaryBasalStorage.store.size) + // With more rate should return null + setUp() + d = temporaryBasalStorage.findTemporaryBasal(1000500, 4.5) + assertNull(d) + assertEquals(3, temporaryBasalStorage.store.size) + // With more than one minute off should return null + setUp() + d = temporaryBasalStorage.findTemporaryBasal(1070000, 4.0) + assertNull(d) + assertEquals(3, temporaryBasalStorage.store.size) + // Use last, if bolus size is the same + setUp() + d = temporaryBasalStorage.findTemporaryBasal(1070000, 5.0) + assertEquals(5.0, d!!.rate, 0.01) + assertEquals(2, temporaryBasalStorage.store.size) + + } +} \ No newline at end of file diff --git a/core/src/test/java/info/nightscout/androidaps/utils/DateUtilTest.kt b/core/src/test/java/info/nightscout/androidaps/utils/DateUtilTest.kt index 41590e7b48..57119d66bd 100644 --- a/core/src/test/java/info/nightscout/androidaps/utils/DateUtilTest.kt +++ b/core/src/test/java/info/nightscout/androidaps/utils/DateUtilTest.kt @@ -20,43 +20,38 @@ class DateUtilTest : TestBase() { @Test fun fromISODateStringTest() { - Assert.assertEquals(1511124634417L, DateUtil.fromISODateString("2017-11-19T22:50:34.417+0200").time) - Assert.assertEquals(1511124634000L, DateUtil.fromISODateString("2017-11-19T22:50:34+0200").time) - Assert.assertEquals(1512317365000L, DateUtil.fromISODateString("2017-12-03T16:09:25.000Z").time) - Assert.assertEquals(1513902750000L, DateUtil.fromISODateString("2017-12-22T00:32:30Z").time) + Assert.assertEquals(1511124634417L, DateUtil(context).fromISODateString("2017-11-19T22:50:34.417+0200")) + Assert.assertEquals(1511124634000L, DateUtil(context).fromISODateString("2017-11-19T22:50:34+0200")) + Assert.assertEquals(1512317365000L, DateUtil(context).fromISODateString("2017-12-03T16:09:25.000Z")) + Assert.assertEquals(1513902750000L, DateUtil(context).fromISODateString("2017-12-22T00:32:30Z")) } @Test fun toISOStringTest() { - Assert.assertEquals("2017-12-22T00:32:30.000Z", DateUtil.toISOString(Date(1513902750000L))) - Assert.assertEquals("2017-12-22T00:32:30.000Z", DateUtil.toISOString(1513902750000L)) + Assert.assertEquals("2017-12-22T00:32:30.000Z", DateUtil(context).toISOString(1513902750000L)) } - @Test fun toDateTest() { - Assert.assertTrue(DateUtil.toDate((T.hours(1).secs() + T.mins(1).secs() + 1).toInt()).toString().contains("01:01:00")) + @Test fun secondsOfTheDayToMillisecondsTest() { + Assert.assertTrue(Date(DateUtil(context).secondsOfTheDayToMilliseconds((T.hours(1).secs() + T.mins(1).secs() + 1).toInt())).toString().contains("01:01:00")) } @Test fun toSecondsTest() { - Assert.assertEquals(3600, DateUtil.toSeconds("01:00").toLong()) - Assert.assertEquals(3600, DateUtil.toSeconds("01:00 a.m.").toLong()) - Assert.assertEquals(3600, DateUtil.toSeconds("01:00 AM").toLong()) + Assert.assertEquals(3600, DateUtil(context).toSeconds("01:00").toLong()) + Assert.assertEquals(3600, DateUtil(context).toSeconds("01:00 a.m.").toLong()) + Assert.assertEquals(3600, DateUtil(context).toSeconds("01:00 AM").toLong()) } @Test fun dateStringTest() { - Assert.assertTrue(DateUtil.dateString(Date(1513902750000L)).contains("22")) - Assert.assertTrue(DateUtil.dateString(1513902750000L).contains("22")) + Assert.assertTrue(DateUtil(context).dateString(1513902750000L).contains("22")) } @Test fun timeStringTest() { - Assert.assertTrue(DateUtil(context).timeString(Date(1513902750000L)).contains("32")) Assert.assertTrue(DateUtil(context).timeString(1513902750000L).contains("32")) } @Test fun dateAndTimeStringTest() { Assert.assertTrue(DateUtil(context).dateAndTimeString(1513902750000L).contains("22")) Assert.assertTrue(DateUtil(context).dateAndTimeString(1513902750000L).contains("32")) - Assert.assertTrue(DateUtil(context).dateAndTimeString(Date(1513902750000L)).contains("22")) - Assert.assertTrue(DateUtil(context).dateAndTimeString(Date(1513902750000L)).contains("32")) } @Test fun dateAndTimeRangeStringTest() { @@ -74,6 +69,6 @@ class DateUtilTest : TestBase() { */ @Test fun timeFrameStringTest() { `when`(resourceHelper.gs(R.string.shorthour)).thenReturn("h") - Assert.assertEquals("(1h 1')", DateUtil.timeFrameString(T.hours(1).msecs() + T.mins(1).msecs(), resourceHelper)) + Assert.assertEquals("(1h 1')", DateUtil(context).timeFrameString(T.hours(1).msecs() + T.mins(1).msecs(), resourceHelper)) } } \ No newline at end of file diff --git a/core/src/test/java/info/nightscout/androidaps/utils/MidnightTimeTest.java b/core/src/test/java/info/nightscout/androidaps/utils/MidnightTimeTest.java deleted file mode 100644 index 28a6b1cc31..0000000000 --- a/core/src/test/java/info/nightscout/androidaps/utils/MidnightTimeTest.java +++ /dev/null @@ -1,62 +0,0 @@ -package info.nightscout.androidaps.utils; - - -import org.junit.Assert; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.powermock.core.classloader.annotations.PrepareForTest; -import org.powermock.modules.junit4.PowerMockRunner; - -import java.util.Calendar; - -/** - * Created by mike on 20.11.2017. - */ -@RunWith(PowerMockRunner.class) -@PrepareForTest({Calendar.class}) -public class MidnightTimeTest { - - @Test - public void calc() { - // We get real midnight - long now = DateUtil.now(); - Assert.assertTrue(now >= MidnightTime.calc()); - Calendar c = Calendar.getInstance(); - c.setTimeInMillis(MidnightTime.calc()); - Assert.assertEquals(c.get(Calendar.HOUR_OF_DAY), 0); - Assert.assertEquals(c.get(Calendar.MINUTE), 0); - Assert.assertEquals(c.get(Calendar.SECOND), 0); - Assert.assertEquals(c.get(Calendar.MILLISECOND), 0); - } - - @Test - public void calc_time() { - // We get real midnight - long now = DateUtil.now(); - long midnight = MidnightTime.calc(now); - Assert.assertTrue(now >= midnight); - Calendar c = Calendar.getInstance(); - c.setTimeInMillis(MidnightTime.calc(now)); - Assert.assertEquals(c.get(Calendar.HOUR_OF_DAY), 0); - Assert.assertEquals(c.get(Calendar.MINUTE), 0); - Assert.assertEquals(c.get(Calendar.SECOND), 0); - Assert.assertEquals(c.get(Calendar.MILLISECOND), 0); - // Assure we get the same time from cache - Assert.assertEquals(midnight, MidnightTime.calc(now)); - } - - @Test - public void resetCache() { - long now = DateUtil.now(); - MidnightTime.calc(now); - MidnightTime.resetCache(); - Assert.assertEquals(0, MidnightTime.times.size()); - } - - @Test - public void log() { - long now = DateUtil.now(); - MidnightTime.calc(now); - Assert.assertTrue(MidnightTime.log().startsWith("Hits:")); - } -} diff --git a/core/src/test/java/info/nightscout/androidaps/utils/MidnightTimeTest.kt b/core/src/test/java/info/nightscout/androidaps/utils/MidnightTimeTest.kt new file mode 100644 index 0000000000..528dc1c094 --- /dev/null +++ b/core/src/test/java/info/nightscout/androidaps/utils/MidnightTimeTest.kt @@ -0,0 +1,48 @@ +package info.nightscout.androidaps.utils + +import org.junit.Assert +import org.junit.Test +import java.util.* + +class MidnightTimeTest { + + @Test fun calc() { + // We get real midnight + val now = System.currentTimeMillis() + Assert.assertTrue(now >= MidnightTime.calc()) + val c = Calendar.getInstance() + c.timeInMillis = MidnightTime.calc() + Assert.assertEquals(c[Calendar.HOUR_OF_DAY].toLong(), 0) + Assert.assertEquals(c[Calendar.MINUTE].toLong(), 0) + Assert.assertEquals(c[Calendar.SECOND].toLong(), 0) + Assert.assertEquals(c[Calendar.MILLISECOND].toLong(), 0) + } + + @Test fun calc_time() { + // We get real midnight + val now = System.currentTimeMillis() + val midnight = MidnightTime.calc(now) + Assert.assertTrue(now >= midnight) + val c = Calendar.getInstance() + c.timeInMillis = MidnightTime.calc(now) + Assert.assertEquals(c[Calendar.HOUR_OF_DAY].toLong(), 0) + Assert.assertEquals(c[Calendar.MINUTE].toLong(), 0) + Assert.assertEquals(c[Calendar.SECOND].toLong(), 0) + Assert.assertEquals(c[Calendar.MILLISECOND].toLong(), 0) + // Assure we get the same time from cache + Assert.assertEquals(midnight, MidnightTime.calc(now)) + } + + @Test fun resetCache() { + val now = System.currentTimeMillis() + MidnightTime.calc(now) + MidnightTime.resetCache() + Assert.assertEquals(0, MidnightTime.times.size().toLong()) + } + + @Test fun log() { + val now = System.currentTimeMillis() + MidnightTime.calc(now) + Assert.assertTrue(MidnightTime.log().startsWith("Hits:")) + } +} \ No newline at end of file diff --git a/core/src/test/java/info/nightscout/androidaps/utils/serialisation/ValueWithUnitSerialiserTest.kt b/core/src/test/java/info/nightscout/androidaps/utils/serialisation/ValueWithUnitSerialiserTest.kt new file mode 100644 index 0000000000..16123cf67b --- /dev/null +++ b/core/src/test/java/info/nightscout/androidaps/utils/serialisation/ValueWithUnitSerialiserTest.kt @@ -0,0 +1,36 @@ +package info.nightscout.androidaps.utils.serialisation + +import info.nightscout.androidaps.database.entities.ValueWithUnit +import org.junit.Assert +import org.junit.Test + +internal class ValueWithUnitSerialiserTest { + + @Test + fun testSerialisationDeserization() { + + val list = listOf( + ValueWithUnit.SimpleString("hello"), + ValueWithUnit.SimpleInt(5), + ValueWithUnit.UNKNOWN + ) + + val serialized = ValueWithUnitSerialiser.toSealedClassJson(list) + val deserialized = ValueWithUnitSerialiser.fromJson(serialized) + + Assert.assertEquals(3, list.size) + Assert.assertEquals(list, deserialized) + } + + @Test + fun testEmptyList() { + + val list = listOf() + + val serialized = ValueWithUnitSerialiser.toSealedClassJson(list) + val deserialized = ValueWithUnitSerialiser.fromJson(serialized) + + Assert.assertEquals(0, list.size) + Assert.assertEquals(list, deserialized) + } +} \ No newline at end of file diff --git a/dana/build.gradle b/dana/build.gradle index 55565f892b..8020051b31 100644 --- a/dana/build.gradle +++ b/dana/build.gradle @@ -17,5 +17,4 @@ android { dependencies { implementation project(':core') - implementation project(':database') } \ No newline at end of file diff --git a/dana/src/main/java/info/nightscout/androidaps/dana/DanaFragment.kt b/dana/src/main/java/info/nightscout/androidaps/dana/DanaFragment.kt index b0100f93c3..8277823fbe 100644 --- a/dana/src/main/java/info/nightscout/androidaps/dana/DanaFragment.kt +++ b/dana/src/main/java/info/nightscout/androidaps/dana/DanaFragment.kt @@ -10,15 +10,14 @@ import android.view.ViewGroup import dagger.android.support.DaggerFragment import info.nightscout.androidaps.activities.TDDStatsActivity import info.nightscout.androidaps.dana.databinding.DanarFragmentBinding -import info.nightscout.androidaps.database.entities.UserEntry.* import info.nightscout.androidaps.dialogs.ProfileViewerDialog import info.nightscout.androidaps.events.EventExtendedBolusChange import info.nightscout.androidaps.events.EventInitializationChanged import info.nightscout.androidaps.events.EventPumpStatusChanged import info.nightscout.androidaps.events.EventTempBasalChange -import info.nightscout.androidaps.interfaces.ActivePluginProvider +import info.nightscout.androidaps.interfaces.ActivePlugin import info.nightscout.androidaps.interfaces.CommandQueueProvider -import info.nightscout.androidaps.interfaces.PumpInterface +import info.nightscout.androidaps.interfaces.Pump import info.nightscout.androidaps.logging.AAPSLogger import info.nightscout.androidaps.logging.LTag import info.nightscout.androidaps.logging.UserEntryLogger @@ -28,9 +27,12 @@ import info.nightscout.androidaps.queue.events.EventQueueChanged import info.nightscout.androidaps.utils.DateUtil import info.nightscout.androidaps.utils.FabricPrivacy import info.nightscout.androidaps.utils.T +import info.nightscout.androidaps.utils.userEntry.UserEntryMapper.Action +import info.nightscout.androidaps.utils.userEntry.UserEntryMapper.Sources import info.nightscout.androidaps.utils.WarnColors import info.nightscout.androidaps.utils.alertDialogs.OKDialog -import info.nightscout.androidaps.utils.extensions.toVisibility +import info.nightscout.androidaps.extensions.toVisibility +import info.nightscout.androidaps.interfaces.Dana import info.nightscout.androidaps.utils.resources.ResourceHelper import info.nightscout.androidaps.utils.rx.AapsSchedulers import info.nightscout.androidaps.utils.sharedPreferences.SP @@ -44,7 +46,7 @@ class DanaFragment : DaggerFragment() { @Inject lateinit var aapsLogger: AAPSLogger @Inject lateinit var fabricPrivacy: FabricPrivacy @Inject lateinit var commandQueue: CommandQueueProvider - @Inject lateinit var activePlugin: ActivePluginProvider + @Inject lateinit var activePlugin: ActivePlugin @Inject lateinit var danaPump: DanaPump @Inject lateinit var resourceHelper: ResourceHelper @Inject lateinit var sp: SP @@ -89,7 +91,7 @@ class DanaFragment : DaggerFragment() { val profileName = danaPump.createConvertedProfile()?.getDefaultProfileName() ?: return@setOnClickListener val args = Bundle() - args.putLong("time", DateUtil.now()) + args.putLong("time", dateUtil.now()) args.putInt("mode", ProfileViewerDialog.Mode.CUSTOM_PROFILE.ordinal) args.putString("customProfile", profile.data.toString()) args.putString("customProfileUnits", profile.units) @@ -102,15 +104,15 @@ class DanaFragment : DaggerFragment() { binding.userOptions.setOnClickListener { startActivity(Intent(context, info.nightscout.androidaps.dana.activities.DanaUserOptionsActivity::class.java)) } binding.btconnection.setOnClickListener { aapsLogger.debug(LTag.PUMP, "Clicked connect to pump") - danaPump.lastConnection = 0 + danaPump.reset() commandQueue.readStatus("Clicked connect to pump", null) } - if (activePlugin.activePump.pumpDescription.pumpType == PumpType.DanaRS) + if (activePlugin.activePump.pumpDescription.pumpType == PumpType.DANA_RS) binding.btconnection.setOnLongClickListener { activity?.let { OKDialog.showConfirmation(it, resourceHelper.gs(R.string.resetpairing)) { - uel.log(Action.CLEAR_PAIRING_KEYS) - (activePlugin.activePump as DanaPumpInterface).clearPairing() + uel.log(Action.CLEAR_PAIRING_KEYS, Sources.Dana) + (activePlugin.activePump as Dana).clearPairing() } } true @@ -187,7 +189,7 @@ class DanaFragment : DaggerFragment() { fun updateGUI() { if (_binding == null) return val pump = danaPump - val plugin: PumpInterface = activePlugin.activePump + val plugin: Pump = activePlugin.activePump if (pump.lastConnection != 0L) { val agoMsec = System.currentTimeMillis() - pump.lastConnection val agoMin = (agoMsec.toDouble() / 60.0 / 1000.0).toInt() @@ -199,7 +201,7 @@ class DanaFragment : DaggerFragment() { val agoHours = agoMsec.toDouble() / 60.0 / 60.0 / 1000.0 if (agoHours < 6) // max 6h back - binding.lastbolus.text = dateUtil.timeString(pump.lastBolusTime) + " " + DateUtil.sinceString(pump.lastBolusTime, resourceHelper) + " " + resourceHelper.gs(R.string.formatinsulinunits, pump.lastBolusAmount) + binding.lastbolus.text = dateUtil.timeString(pump.lastBolusTime) + " " + dateUtil.sinceString(pump.lastBolusTime, resourceHelper) + " " + resourceHelper.gs(R.string.formatinsulinunits, pump.lastBolusAmount) else binding.lastbolus.text = "" } @@ -208,16 +210,8 @@ class DanaFragment : DaggerFragment() { warnColors.setColor(binding.dailyunits, pump.dailyTotalUnits, pump.maxDailyTotalUnits * 0.75, pump.maxDailyTotalUnits * 0.9) binding.basabasalrate.text = "( " + (pump.activeProfile + 1) + " ) " + resourceHelper.gs(R.string.pump_basebasalrate, plugin.baseBasalRate) // DanaRPlugin, DanaRKoreanPlugin - if (activePlugin.activePump.isFakingTempsByExtendedBoluses) { - binding.tempbasal.text = activePlugin.activeTreatments.getRealTempBasalFromHistory(System.currentTimeMillis())?.toStringFull() - ?: "" - } else { - // v2 plugin - binding.tempbasal.text = activePlugin.activeTreatments.getTempBasalFromHistory(System.currentTimeMillis())?.toStringFull() - ?: "" - } - binding.extendedbolus.text = activePlugin.activeTreatments.getExtendedBolusFromHistory(System.currentTimeMillis())?.toString() - ?: "" + binding.tempbasal.text = danaPump.temporaryBasalToString() + binding.extendedbolus.text = danaPump.extendedBolusToString() binding.reservoir.text = resourceHelper.gs(R.string.reservoirvalue, pump.reservoirRemainingUnits, 300) warnColors.setColorInverse(binding.reservoir, pump.reservoirRemainingUnits, 50.0, 20.0) binding.battery.text = "{fa-battery-" + pump.batteryRemaining / 25 + "}" diff --git a/dana/src/main/java/info/nightscout/androidaps/dana/DanaPump.kt b/dana/src/main/java/info/nightscout/androidaps/dana/DanaPump.kt index 2966a25807..09f961eb2a 100644 --- a/dana/src/main/java/info/nightscout/androidaps/dana/DanaPump.kt +++ b/dana/src/main/java/info/nightscout/androidaps/dana/DanaPump.kt @@ -3,10 +3,14 @@ package info.nightscout.androidaps.dana import dagger.android.HasAndroidInjector import info.nightscout.androidaps.Constants import info.nightscout.androidaps.data.Profile -import info.nightscout.androidaps.db.Treatment import info.nightscout.androidaps.interfaces.ProfileStore +import info.nightscout.androidaps.interfaces.PumpSync import info.nightscout.androidaps.logging.AAPSLogger import info.nightscout.androidaps.logging.LTag +import info.nightscout.androidaps.plugins.general.overview.events.EventOverviewBolusProgress +import info.nightscout.androidaps.plugins.pump.common.defs.PumpType +import info.nightscout.androidaps.utils.DateUtil +import info.nightscout.androidaps.utils.DecimalFormatter import info.nightscout.androidaps.utils.T import info.nightscout.androidaps.utils.sharedPreferences.SP import org.joda.time.DateTime @@ -18,14 +22,15 @@ import java.text.DecimalFormat import java.util.concurrent.TimeUnit import javax.inject.Inject import javax.inject.Singleton +import kotlin.math.max +import kotlin.math.min +import kotlin.math.roundToInt -/** - * Created by mike on 04.07.2016. - */ @Singleton class DanaPump @Inject constructor( private val aapsLogger: AAPSLogger, private val sp: SP, + private val dateUtil: DateUtil, private val injector: HasAndroidInjector ) { @@ -38,6 +43,7 @@ class DanaPump @Inject constructor( NOPRIME(0x10); companion object { + private val map = values().associateBy(ErrorState::code) operator fun get(value: Int) = map[value] } @@ -45,6 +51,8 @@ class DanaPump @Inject constructor( var lastConnection: Long = 0 var lastSettingsRead: Long = 0 + @JvmField var lastHistoryFetched: Long = 0 + @JvmField var historyDoneReceived: Boolean = false // true when last history message is received // Info var serialNumber = "" @@ -109,20 +117,105 @@ class DanaPump @Inject constructor( var lastBolusTime: Long = 0 var lastBolusAmount = 0.0 var currentBasal = 0.0 - var isTempBasalInProgress = false - var tempBasalPercent = 0 - var tempBasalRemainingMin = 0 - var tempBasalTotalSec = 0 + + /* + * TEMP BASALS + */ + var tempBasalStart: Long = 0 - var isDualBolusInProgress = false - var isExtendedInProgress = false - var extendedBolusMinutes = 0 - var extendedBolusAmount = 0.0 - var extendedBolusAbsoluteRate = 0.0 - var extendedBolusSoFarInMinutes = 0 + var tempBasalDuration: Long = 0 // in milliseconds + var tempBasalPercent = 0 + + var tempBasalTotalSec: Long + set(durationInSec) { + tempBasalDuration = T.secs(durationInSec).msecs() + } + get() = T.msecs(tempBasalDuration).mins() + var isTempBasalInProgress: Boolean + get() = tempBasalStart != 0L && dateUtil.now() in tempBasalStart..tempBasalStart + tempBasalDuration + set(isRunning) { + if (isRunning) throw IllegalArgumentException("Use to cancel TBR only") + else { + tempBasalStart = 0L + tempBasalDuration = 0L + tempBasalPercent = 0 + } + } + val tempBasalRemainingMin: Int + get() = max(T.msecs(tempBasalStart + tempBasalDuration - dateUtil.now()).mins().toInt(), 0) + + fun temporaryBasalToString(): String { + if (!isTempBasalInProgress) return "" + + val passedMin = ((min(dateUtil.now(), tempBasalStart + tempBasalDuration) - tempBasalStart) / 60.0 / 1000).roundToInt() + return tempBasalPercent.toString() + "% @" + + dateUtil.timeString(tempBasalStart) + + " " + passedMin + "/" + T.msecs(tempBasalDuration).mins() + "'" + } + + fun fromTemporaryBasal(tbr: PumpSync.PumpState.TemporaryBasal?) { + if (tbr == null) { + tempBasalStart = 0 + tempBasalDuration = 0 + tempBasalPercent = 0 + } else { + tempBasalStart = tbr.timestamp + tempBasalDuration = tbr.duration + tempBasalPercent = tbr.rate.toInt() + } + } + + /* + * EXTENDED BOLUSES + */ + var extendedBolusStart: Long = 0 - var extendedBolusRemainingMinutes = 0 - var extendedBolusDeliveredSoFar = 0.0 //RS only = 0.0 + var extendedBolusDuration: Long = 0 + var extendedBolusAmount = 0.0 + + var isExtendedInProgress: Boolean + get() = extendedBolusStart != 0L && dateUtil.now() in extendedBolusStart..extendedBolusStart + extendedBolusDuration + set(isRunning) { + if (isRunning) throw IllegalArgumentException("Use to cancel EB only") + else { + extendedBolusStart = 0L + extendedBolusDuration = 0L + extendedBolusAmount = 0.0 + } + } + val extendedBolusPassedMinutes: Int + get() = T.msecs(max(0, dateUtil.now() - extendedBolusStart)).mins().toInt() + val extendedBolusRemainingMinutes: Int + get() = max(T.msecs(extendedBolusStart + extendedBolusDuration - dateUtil.now()).mins().toInt(), 0) + private val extendedBolusDurationInMinutes: Int + get() = T.msecs(extendedBolusDuration).mins().toInt() + var extendedBolusAbsoluteRate: Double + get() = extendedBolusAmount * T.hours(1).msecs() / extendedBolusDuration + set(rate) { + extendedBolusAmount = rate * extendedBolusDuration / T.hours(1).msecs() + } + + fun extendedBolusToString(): String { + if (!isExtendedInProgress) return "" + + return "E " + DecimalFormatter.to2Decimal(extendedBolusAbsoluteRate) + "U/h @" + + dateUtil.timeString(extendedBolusStart) + + " " + extendedBolusPassedMinutes + "/" + extendedBolusDurationInMinutes + "'" + } + + fun fromExtendedBolus(eb: PumpSync.PumpState.ExtendedBolus?) { + if (eb == null) { + extendedBolusStart = 0 + extendedBolusDuration = 0 + extendedBolusAmount = 0.0 + } else { + extendedBolusStart = eb.timestamp + extendedBolusDuration = eb.duration + extendedBolusAmount = eb.amount + } + } + + var isDualBolusInProgress = false // Profile R,RSv1 var units = 0 @@ -180,8 +273,7 @@ class DanaPump @Inject constructor( } var bolusStartErrorCode: Int = 0 // last start bolus erroCode - var historyDoneReceived: Boolean = false // true when last history message is received - var bolusingTreatment: Treatment? = null // actually delivered treatment + var bolusingTreatment: EventOverviewBolusProgress.Treatment? = null // actually delivered treatment var bolusAmountToBeDelivered = 0.0 // amount to be delivered var bolusProgressLastTimeStamp: Long = 0 // timestamp of last bolus progress message var bolusStopped = false // bolus finished @@ -189,7 +281,7 @@ class DanaPump @Inject constructor( var bolusDone = false // success end var lastEventTimeLoaded: Long = 0 // timestamp of last received event - val lastKnownHistoryId: Int = 0 // hwver 7+, 1-2000 + // val lastKnownHistoryId: Int = 0 // hwver 7+, 1-2000 fun createConvertedProfile(): ProfileStore? { pumpProfiles?.let { @@ -280,15 +372,18 @@ class DanaPump @Inject constructor( aapsLogger.debug(LTag.PUMP, "DanaRPump reset") lastConnection = 0 lastSettingsRead = 0 + lastHistoryFetched = 0 } fun modelFriendlyName(): String = when (hwModel) { 0x01 -> "DanaR Korean" 0x03 -> - if (protocol == 0x00) "DanaR old" - else if (protocol == 0x02) "DanaR v2" - else "DanaR" // 0x01 and 0x03 known + when (protocol) { + 0x00 -> "DanaR old" + 0x02 -> "DanaR v2" + else -> "DanaR" // 0x01 and 0x03 known + } 0x05 -> if (protocol < 10) "DanaRS" else "DanaRS v3" @@ -297,7 +392,23 @@ class DanaPump @Inject constructor( else -> "Unknown Dana pump" } + fun pumpType(): PumpType = + when (hwModel) { + 0x01 -> PumpType.DANA_R_KOREAN + 0x03 -> + when (protocol) { + 0x00 -> PumpType.DANA_R + 0x02 -> PumpType.DANA_RV2 + else -> PumpType.DANA_R // 0x01 and 0x03 known + } + 0x05 -> PumpType.DANA_RS + 0x06 -> PumpType.DANA_RS_KOREAN + 0x07 -> PumpType.DANA_I + else -> PumpType.DANA_R + } + companion object { + const val UNITS_MGDL = 0 const val UNITS_MMOL = 1 const val DELIVERY_PRIME = 0x01 diff --git a/dana/src/main/java/info/nightscout/androidaps/dana/DanaPumpInterface.kt b/dana/src/main/java/info/nightscout/androidaps/dana/DanaPumpInterface.kt deleted file mode 100644 index 56bbede985..0000000000 --- a/dana/src/main/java/info/nightscout/androidaps/dana/DanaPumpInterface.kt +++ /dev/null @@ -1,5 +0,0 @@ -package info.nightscout.androidaps.dana - -interface DanaPumpInterface { - fun clearPairing() -} \ No newline at end of file diff --git a/dana/src/main/java/info/nightscout/androidaps/dana/activities/DanaHistoryActivity.kt b/dana/src/main/java/info/nightscout/androidaps/dana/activities/DanaHistoryActivity.kt index 29bb7789ca..76d491995c 100644 --- a/dana/src/main/java/info/nightscout/androidaps/dana/activities/DanaHistoryActivity.kt +++ b/dana/src/main/java/info/nightscout/androidaps/dana/activities/DanaHistoryActivity.kt @@ -18,7 +18,7 @@ import info.nightscout.androidaps.data.Profile import info.nightscout.androidaps.db.DanaRHistoryRecord import info.nightscout.androidaps.events.EventDanaRSyncStatus import info.nightscout.androidaps.events.EventPumpStatusChanged -import info.nightscout.androidaps.interfaces.ActivePluginProvider +import info.nightscout.androidaps.interfaces.ActivePlugin import info.nightscout.androidaps.interfaces.CommandQueueProvider import info.nightscout.androidaps.interfaces.DatabaseHelperInterface import info.nightscout.androidaps.interfaces.ProfileFunction @@ -42,7 +42,7 @@ class DanaHistoryActivity : NoSplashAppCompatActivity() { @Inject lateinit var aapsLogger: AAPSLogger @Inject lateinit var profileFunction: ProfileFunction @Inject lateinit var fabricPrivacy: FabricPrivacy - @Inject lateinit var activePlugin: ActivePluginProvider + @Inject lateinit var activePlugin: ActivePlugin @Inject lateinit var commandQueue: CommandQueueProvider @Inject lateinit var databaseHelper: DatabaseHelperInterface @Inject lateinit var dateUtil: DateUtil @@ -91,8 +91,8 @@ class DanaHistoryActivity : NoSplashAppCompatActivity() { binding.status.visibility = View.GONE val pump = activePlugin.activePump - val isKorean = pump.pumpDescription.pumpType == PumpType.DanaRKorean - val isRS = pump.pumpDescription.pumpType == PumpType.DanaRS + val isKorean = pump.pumpDescription.pumpType == PumpType.DANA_R_KOREAN + val isRS = pump.pumpDescription.pumpType == PumpType.DANA_RS // Types val typeList = ArrayList() @@ -185,7 +185,7 @@ class DanaHistoryActivity : NoSplashAppCompatActivity() { holder.dailyBasal.text = resourceHelper.gs(R.string.formatinsulinunits, record.recordDailyBasal) holder.dailyBolus.text = resourceHelper.gs(R.string.formatinsulinunits, record.recordDailyBolus) holder.dailyTotal.text = resourceHelper.gs(R.string.formatinsulinunits, record.recordDailyBolus + record.recordDailyBasal) - holder.time.text = DateUtil.dateString(record.recordDate) + holder.time.text = dateUtil.dateString(record.recordDate) holder.time.visibility = View.VISIBLE holder.value.visibility = View.GONE holder.stringValue.visibility = View.GONE diff --git a/dana/src/main/java/info/nightscout/androidaps/dana/activities/DanaUserOptionsActivity.kt b/dana/src/main/java/info/nightscout/androidaps/dana/activities/DanaUserOptionsActivity.kt index e6e8698e13..3936d22eb8 100644 --- a/dana/src/main/java/info/nightscout/androidaps/dana/activities/DanaUserOptionsActivity.kt +++ b/dana/src/main/java/info/nightscout/androidaps/dana/activities/DanaUserOptionsActivity.kt @@ -9,7 +9,7 @@ import info.nightscout.androidaps.dana.DanaPump import info.nightscout.androidaps.dana.R import info.nightscout.androidaps.dana.databinding.DanarUserOptionsActivityBinding import info.nightscout.androidaps.events.EventInitializationChanged -import info.nightscout.androidaps.interfaces.ActivePluginProvider +import info.nightscout.androidaps.interfaces.ActivePlugin import info.nightscout.androidaps.interfaces.CommandQueueProvider import info.nightscout.androidaps.logging.AAPSLogger import info.nightscout.androidaps.logging.LTag @@ -32,16 +32,16 @@ class DanaUserOptionsActivity : NoSplashAppCompatActivity() { @Inject lateinit var fabricPrivacy: FabricPrivacy @Inject lateinit var context: Context @Inject lateinit var danaPump: DanaPump - @Inject lateinit var activePlugin: ActivePluginProvider + @Inject lateinit var activePlugin: ActivePlugin @Inject lateinit var commandQueue: CommandQueueProvider @Inject lateinit var aapsSchedulers: AapsSchedulers private val disposable = CompositeDisposable() // This is for Dana pumps only - private fun isRS() = activePlugin.activePump.pumpDescription.pumpType == PumpType.DanaRS - private fun isDanaR() = activePlugin.activePump.pumpDescription.pumpType == PumpType.DanaR - private fun isDanaRv2() = activePlugin.activePump.pumpDescription.pumpType == PumpType.DanaRv2 + private fun isRS() = activePlugin.activePump.pumpDescription.pumpType == PumpType.DANA_RS + private fun isDanaR() = activePlugin.activePump.pumpDescription.pumpType == PumpType.DANA_R + private fun isDanaRv2() = activePlugin.activePump.pumpDescription.pumpType == PumpType.DANA_RV2 var minBacklight = 1 diff --git a/dana/src/main/res/values/strings.xml b/dana/src/main/res/values/strings.xml index c6ec142c94..131e23c744 100644 --- a/dana/src/main/res/values/strings.xml +++ b/dana/src/main/res/values/strings.xml @@ -120,7 +120,6 @@ Pump password (v1 only) Pump password Use extended boluses for >200%% - Visualize extended bolus as %% Bolus speed Selected pump Log reservoir change diff --git a/dana/src/test/java/info/nightscout/androidaps/TestBaseWithProfile.kt b/dana/src/test/java/info/nightscout/androidaps/TestBaseWithProfile.kt index e3e5c7391b..e3ca031cd5 100644 --- a/dana/src/test/java/info/nightscout/androidaps/TestBaseWithProfile.kt +++ b/dana/src/test/java/info/nightscout/androidaps/TestBaseWithProfile.kt @@ -4,9 +4,8 @@ import dagger.android.AndroidInjector import dagger.android.HasAndroidInjector import info.nightscout.androidaps.data.Profile import info.nightscout.androidaps.db.ProfileSwitch -import info.nightscout.androidaps.db.Treatment -import info.nightscout.androidaps.interfaces.ActivePluginProvider -import info.nightscout.androidaps.interfaces.ConfigInterface +import info.nightscout.androidaps.interfaces.ActivePlugin +import info.nightscout.androidaps.interfaces.Config import info.nightscout.androidaps.interfaces.ProfileFunction import info.nightscout.androidaps.interfaces.ProfileStore import info.nightscout.androidaps.interfaces.TreatmentsInterface @@ -24,14 +23,14 @@ import org.powermock.core.classloader.annotations.PrepareForTest @PrepareForTest(FabricPrivacy::class) open class TestBaseWithProfile : TestBase() { - @Mock lateinit var activePluginProvider: ActivePluginProvider + @Mock lateinit var activePluginProvider: ActivePlugin @Mock lateinit var resourceHelper: ResourceHelper @Mock lateinit var treatmentsInterface: TreatmentsInterface @Mock lateinit var fabricPrivacy: FabricPrivacy @Mock lateinit var profileFunction: ProfileFunction @Mock lateinit var defaultValueHelper: DefaultValueHelper @Mock lateinit var dateUtil: DateUtil - @Mock lateinit var configInterface: ConfigInterface + @Mock lateinit var config: Config val rxBus = RxBusWrapper(aapsSchedulers) @@ -43,7 +42,7 @@ open class TestBaseWithProfile : TestBase() { it.resourceHelper = resourceHelper it.rxBus = rxBus it.fabricPrivacy = fabricPrivacy - it.configInterface = configInterface + it.config = config } if (it is ProfileSwitch) { it.treatmentsPlugin = treatmentsInterface @@ -52,12 +51,6 @@ open class TestBaseWithProfile : TestBase() { it.resourceHelper = resourceHelper it.dateUtil = dateUtil } - if (it is Treatment) { - it.activePlugin = activePluginProvider - it.profileFunction = profileFunction - it.defaultValueHelper = defaultValueHelper - it.resourceHelper = resourceHelper - } } } diff --git a/dana/src/test/java/info/nightscout/androidaps/dana/DanaPumpTest.kt b/dana/src/test/java/info/nightscout/androidaps/dana/DanaPumpTest.kt index 69d35cc180..fe5e5e61df 100644 --- a/dana/src/test/java/info/nightscout/androidaps/dana/DanaPumpTest.kt +++ b/dana/src/test/java/info/nightscout/androidaps/dana/DanaPumpTest.kt @@ -18,7 +18,7 @@ class DanaPumpTest : TestBaseWithProfile() { @Before fun setup() { - sut = DanaPump(aapsLogger, sp, profileInjector) + sut = DanaPump(aapsLogger, sp, dateUtil, profileInjector) } @Test diff --git a/danar/src/main/java/info/nightscout/androidaps/danaRKorean/DanaRKoreanPlugin.java b/danar/src/main/java/info/nightscout/androidaps/danaRKorean/DanaRKoreanPlugin.java deleted file mode 100644 index 2dd51b0b69..0000000000 --- a/danar/src/main/java/info/nightscout/androidaps/danaRKorean/DanaRKoreanPlugin.java +++ /dev/null @@ -1,357 +0,0 @@ -package info.nightscout.androidaps.danaRKorean; - -import android.content.ComponentName; -import android.content.Context; -import android.content.Intent; -import android.content.ServiceConnection; -import android.os.IBinder; - -import androidx.annotation.NonNull; - -import javax.inject.Inject; -import javax.inject.Singleton; - -import dagger.android.HasAndroidInjector; -import info.nightscout.androidaps.dana.DanaPump; -import info.nightscout.androidaps.danaRKorean.services.DanaRKoreanExecutionService; -import info.nightscout.androidaps.danar.AbstractDanaRPlugin; -import info.nightscout.androidaps.danar.R; -import info.nightscout.androidaps.data.DetailedBolusInfo; -import info.nightscout.androidaps.data.Profile; -import info.nightscout.androidaps.data.PumpEnactResult; -import info.nightscout.androidaps.db.ExtendedBolus; -import info.nightscout.androidaps.db.TemporaryBasal; -import info.nightscout.androidaps.db.Treatment; -import info.nightscout.androidaps.events.EventAppExit; -import info.nightscout.androidaps.events.EventPreferenceChange; -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.logging.AAPSLogger; -import info.nightscout.androidaps.logging.LTag; -import info.nightscout.androidaps.plugins.bus.RxBusWrapper; -import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker; -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.resources.ResourceHelper; -import info.nightscout.androidaps.utils.rx.AapsSchedulers; -import info.nightscout.androidaps.utils.sharedPreferences.SP; -import io.reactivex.disposables.CompositeDisposable; - -@Singleton -public class DanaRKoreanPlugin extends AbstractDanaRPlugin { - private final CompositeDisposable disposable = new CompositeDisposable(); - - private final AAPSLogger aapsLogger; - private final Context context; - private final ResourceHelper resourceHelper; - private final ConstraintChecker constraintChecker; - private final FabricPrivacy fabricPrivacy; - - @Inject - public DanaRKoreanPlugin( - HasAndroidInjector injector, - AAPSLogger aapsLogger, - AapsSchedulers aapsSchedulers, - RxBusWrapper rxBus, - DanaPump danaPump, - Context context, - ResourceHelper resourceHelper, - ConstraintChecker constraintChecker, - ActivePluginProvider activePlugin, - SP sp, - CommandQueueProvider commandQueue, - DateUtil dateUtil, - FabricPrivacy fabricPrivacy - ) { - super(injector, danaPump, resourceHelper, constraintChecker, aapsLogger, aapsSchedulers, commandQueue, rxBus, activePlugin, sp, dateUtil); - this.aapsLogger = aapsLogger; - this.context = context; - this.resourceHelper = resourceHelper; - this.constraintChecker = constraintChecker; - this.fabricPrivacy = fabricPrivacy; - getPluginDescription().description(R.string.description_pump_dana_r_korean); - - useExtendedBoluses = sp.getBoolean(R.string.key_danar_useextended, false); - pumpDescription.setPumpDescription(PumpType.DanaRKorean); - } - - @Override - protected void onStart() { - Intent intent = new Intent(context, DanaRKoreanExecutionService.class); - context.bindService(intent, mConnection, Context.BIND_AUTO_CREATE); - disposable.add(rxBus - .toObservable(EventPreferenceChange.class) - .observeOn(aapsSchedulers.getIo()) - .subscribe(event -> { - if (isEnabled(PluginType.PUMP)) { - boolean previousValue = useExtendedBoluses; - useExtendedBoluses = sp.getBoolean(R.string.key_danar_useextended, false); - - if (useExtendedBoluses != previousValue && activePlugin.getActiveTreatments().isInHistoryExtendedBolusInProgress()) { - sExecutionService.extendedBolusStop(); - } - } - }, fabricPrivacy::logException) - ); - disposable.add(rxBus - .toObservable(EventAppExit.class) - .observeOn(aapsSchedulers.getIo()) - .subscribe(event -> context.unbindService(mConnection), fabricPrivacy::logException) - ); - super.onStart(); - } - - @Override - protected void onStop() { - context.unbindService(mConnection); - disposable.clear(); - super.onStop(); - } - - private final ServiceConnection mConnection = new ServiceConnection() { - - public void onServiceDisconnected(ComponentName name) { - aapsLogger.debug(LTag.PUMP, "Service is disconnected"); - sExecutionService = null; - } - - public void onServiceConnected(ComponentName name, IBinder service) { - aapsLogger.debug(LTag.PUMP, "Service is connected"); - DanaRKoreanExecutionService.LocalBinder mLocalBinder = (DanaRKoreanExecutionService.LocalBinder) service; - sExecutionService = mLocalBinder.getServiceInstance(); - } - }; - - // Plugin base interface - @NonNull - @Override - public String getName() { - return resourceHelper.gs(R.string.danarkoreanpump); - } - - @Override - public int getPreferencesId() { - return R.xml.pref_danarkorean; - } - - // Pump interface - @Override - public boolean isFakingTempsByExtendedBoluses() { - return useExtendedBoluses; - } - - @Override - public boolean isInitialized() { - return danaPump.getLastConnection() > 0 && danaPump.getMaxBasal() > 0 && !danaPump.isConfigUD() && !danaPump.isEasyModeEnabled() && danaPump.isExtendedBolusEnabled() && danaPump.isPasswordOK(); - } - - @Override - public boolean isHandshakeInProgress() { - return sExecutionService != null && sExecutionService.isHandshakeInProgress(); - } - - @Override - public void finishHandshaking() { - sExecutionService.finishHandshaking(); - } - - @NonNull @Override - public PumpEnactResult deliverTreatment(DetailedBolusInfo detailedBolusInfo) { - detailedBolusInfo.insulin = constraintChecker.applyBolusConstraints(new Constraint<>(detailedBolusInfo.insulin)).value(); - if (detailedBolusInfo.insulin > 0 || detailedBolusInfo.carbs > 0) { - Treatment t = new Treatment(); - t.isSMB = detailedBolusInfo.isSMB; - boolean connectionOK = false; - if (detailedBolusInfo.insulin > 0 || detailedBolusInfo.carbs > 0) - connectionOK = sExecutionService.bolus(detailedBolusInfo.insulin, (int) detailedBolusInfo.carbs, detailedBolusInfo.carbTime, t); - PumpEnactResult result = new PumpEnactResult(getInjector()); - result.success(connectionOK && Math.abs(detailedBolusInfo.insulin - t.insulin) < pumpDescription.getBolusStep()) - .bolusDelivered(t.insulin) - .carbsDelivered(detailedBolusInfo.carbs); - if (!result.getSuccess()) - result.comment(resourceHelper.gs(R.string.boluserrorcode, detailedBolusInfo.insulin, t.insulin, danaPump.getBolusStartErrorCode())); - else - result.comment(R.string.ok); - aapsLogger.debug(LTag.PUMP, "deliverTreatment: OK. Asked: " + detailedBolusInfo.insulin + " Delivered: " + result.getBolusDelivered()); - detailedBolusInfo.insulin = t.insulin; - detailedBolusInfo.date = System.currentTimeMillis(); - activePlugin.getActiveTreatments().addToHistoryTreatment(detailedBolusInfo, false); - return result; - } else { - PumpEnactResult result = new PumpEnactResult(getInjector()); - result.success(false).bolusDelivered(0d).carbsDelivered(0d).comment(R.string.invalidinput); - aapsLogger.error("deliverTreatment: Invalid input"); - return result; - } - } - - // This is called from APS - @NonNull @Override - public PumpEnactResult setTempBasalAbsolute(double absoluteRate, int durationInMinutes, @NonNull Profile profile, boolean enforceNew) { - // Recheck pump status if older than 30 min - //This should not be needed while using queue because connection should be done before calling this - PumpEnactResult result = new PumpEnactResult(getInjector()); - - absoluteRate = constraintChecker.applyBasalConstraints(new Constraint<>(absoluteRate), profile).value(); - - final boolean doTempOff = getBaseBasalRate() - absoluteRate == 0d && absoluteRate >= 0.10d; - final boolean doLowTemp = absoluteRate < getBaseBasalRate() || absoluteRate < 0.10d; - final boolean doHighTemp = absoluteRate > getBaseBasalRate() && !useExtendedBoluses; - final boolean doExtendedTemp = absoluteRate > getBaseBasalRate() && useExtendedBoluses; - - long now = System.currentTimeMillis(); - TemporaryBasal activeTemp = activePlugin.getActiveTreatments().getRealTempBasalFromHistory(now); - ExtendedBolus activeExtended = activePlugin.getActiveTreatments().getExtendedBolusFromHistory(now); - - if (doTempOff) { - // If extended in progress - if (activeExtended != null && useExtendedBoluses) { - aapsLogger.debug(LTag.PUMP, "setTempBasalAbsolute: Stopping extended bolus (doTempOff)"); - return cancelExtendedBolus(); - } - // If temp in progress - if (activeTemp != null) { - aapsLogger.debug(LTag.PUMP, "setTempBasalAbsolute: Stopping temp basal (doTempOff)"); - return cancelRealTempBasal(); - } - result.success(true).enacted(false).percent(100).isPercent(true).isTempCancel(true); - aapsLogger.debug(LTag.PUMP, "setTempBasalAbsolute: doTempOff OK"); - return result; - } - - if (doLowTemp || doHighTemp) { - int percentRate = Double.valueOf(absoluteRate / getBaseBasalRate() * 100).intValue(); - // Any basal less than 0.10u/h will be dumped once per hour, not every 4 minutes. So if it's less than .10u/h, set a zero temp. - if (absoluteRate < 0.10d) percentRate = 0; - if (percentRate < 100) percentRate = Round.ceilTo((double) percentRate, 10d).intValue(); - else percentRate = Round.floorTo((double) percentRate, 10d).intValue(); - if (percentRate > getPumpDescription().getMaxTempPercent()) { - percentRate = getPumpDescription().getMaxTempPercent(); - } - aapsLogger.debug(LTag.PUMP, "setTempBasalAbsolute: Calculated percent rate: " + percentRate); - - // If extended in progress - if (activeExtended != null && useExtendedBoluses) { - aapsLogger.debug(LTag.PUMP, "setTempBasalAbsolute: Stopping extended bolus (doLowTemp || doHighTemp)"); - result = cancelExtendedBolus(); - if (!result.getSuccess()) { - aapsLogger.error("setTempBasalAbsolute: Failed to stop previous extended bolus (doLowTemp || doHighTemp)"); - return result; - } - } - // Check if some temp is already in progress - if (activeTemp != null) { - // Correct basal already set ? - aapsLogger.debug(LTag.PUMP, "setTempBasalAbsolute: currently running: " + activeTemp.toString()); - if (activeTemp.percentRate == percentRate && activeTemp.getPlannedRemainingMinutes() > 4) { - if (enforceNew) { - cancelTempBasal(true); - } else { - result.success(true).percent(percentRate).enacted(false).duration(activeTemp.getPlannedRemainingMinutes()).isPercent(true).isTempCancel(false); - aapsLogger.debug(LTag.PUMP, "setTempBasalAbsolute: Correct temp basal already set (doLowTemp || doHighTemp)"); - return result; - } - } - } - // Convert duration from minutes to hours - aapsLogger.debug(LTag.PUMP, "setTempBasalAbsolute: Setting temp basal " + percentRate + "% for " + durationInMinutes + " minutes (doLowTemp || doHighTemp)"); - return setTempBasalPercent(percentRate, durationInMinutes, profile, false); - } - if (doExtendedTemp) { - // Check if some temp is already in progress - if (activeTemp != null) { - aapsLogger.debug(LTag.PUMP, "setTempBasalAbsolute: Stopping temp basal (doExtendedTemp)"); - result = cancelRealTempBasal(); - // Check for proper result - if (!result.getSuccess()) { - aapsLogger.error("setTempBasalAbsolute: Failed to stop previous temp basal (doExtendedTemp)"); - return result; - } - } - - // Calculate # of halfHours from minutes - int durationInHalfHours = Math.max(durationInMinutes / 30, 1); - // We keep current basal running so need to sub current basal - double extendedRateToSet = absoluteRate - getBaseBasalRate(); - extendedRateToSet = constraintChecker.applyBasalConstraints(new Constraint<>(extendedRateToSet), profile).value(); - // needs to be rounded to 0.1 - extendedRateToSet = Round.roundTo(extendedRateToSet, pumpDescription.getExtendedBolusStep() * 2); // *2 because of half hours - - // What is current rate of extended bolusing in u/h? - aapsLogger.debug(LTag.PUMP, "setTempBasalAbsolute: Extended bolus in progress: " + (activeExtended != null) + " rate: " + danaPump.getExtendedBolusAbsoluteRate() + "U/h duration remaining: " + danaPump.getExtendedBolusRemainingMinutes() + "min"); - aapsLogger.debug(LTag.PUMP, "setTempBasalAbsolute: Rate to set: " + extendedRateToSet + "U/h"); - - // Compare with extended rate in progress - if (activeExtended != null && Math.abs(danaPump.getExtendedBolusAbsoluteRate() - extendedRateToSet) < getPumpDescription().getExtendedBolusStep()) { - // correct extended already set - result.success(true).absolute(danaPump.getExtendedBolusAbsoluteRate()).enacted(false).duration(danaPump.getExtendedBolusRemainingMinutes()).isPercent(false).isTempCancel(false); - aapsLogger.debug(LTag.PUMP, "setTempBasalAbsolute: Correct extended already set"); - return result; - } - - // Now set new extended, no need to to stop previous (if running) because it's replaced - double extendedAmount = extendedRateToSet / 2 * durationInHalfHours; - aapsLogger.debug(LTag.PUMP, "setTempBasalAbsolute: Setting extended: " + extendedAmount + "U half hours: " + durationInHalfHours); - result = setExtendedBolus(extendedAmount, durationInMinutes); - if (!result.getSuccess()) { - aapsLogger.error("setTempBasalAbsolute: Failed to set extended bolus"); - return result; - } - aapsLogger.debug(LTag.PUMP, "setTempBasalAbsolute: Extended bolus set ok"); - result.absolute(result.getAbsolute() + getBaseBasalRate()); - return result; - } - // We should never end here - aapsLogger.error("setTempBasalAbsolute: Internal error"); - result.success(false).comment("Internal error"); - return result; - } - - @NonNull @Override - public PumpEnactResult cancelTempBasal(boolean force) { - if (activePlugin.getActiveTreatments().isInHistoryRealTempBasalInProgress()) - return cancelRealTempBasal(); - if (activePlugin.getActiveTreatments().isInHistoryExtendedBolusInProgress() && useExtendedBoluses) { - return cancelExtendedBolus(); - } - PumpEnactResult result = new PumpEnactResult(getInjector()); - result.success(true).enacted(false).comment(R.string.ok).isTempCancel(true); - return result; - } - - @NonNull @Override - public PumpType model() { - return PumpType.DanaRKorean; - } - - private PumpEnactResult cancelRealTempBasal() { - PumpEnactResult result = new PumpEnactResult(getInjector()); - TemporaryBasal runningTB = activePlugin.getActiveTreatments().getTempBasalFromHistory(System.currentTimeMillis()); - if (runningTB != null) { - sExecutionService.tempBasalStop(); - result.enacted(true).isTempCancel(true); - } - if (!danaPump.isTempBasalInProgress()) { - result.success(true).isTempCancel(true).comment(R.string.ok); - aapsLogger.debug(LTag.PUMP, "cancelRealTempBasal: OK"); - } else { - result.success(false).comment(R.string.danar_valuenotsetproperly).isTempCancel(true); - aapsLogger.error("cancelRealTempBasal: Failed to cancel temp basal"); - } - return result; - } - - @NonNull @Override - public PumpEnactResult loadEvents() { - return new PumpEnactResult(getInjector()); // no history, not needed - } - - @NonNull @Override - public PumpEnactResult setUserOptions() { - return new PumpEnactResult(getInjector()); - } -} diff --git a/danar/src/main/java/info/nightscout/androidaps/danaRKorean/DanaRKoreanPlugin.kt b/danar/src/main/java/info/nightscout/androidaps/danaRKorean/DanaRKoreanPlugin.kt new file mode 100644 index 0000000000..0f9669df39 --- /dev/null +++ b/danar/src/main/java/info/nightscout/androidaps/danaRKorean/DanaRKoreanPlugin.kt @@ -0,0 +1,304 @@ +package info.nightscout.androidaps.danaRKorean + +import android.content.ComponentName +import android.content.Context +import android.content.Intent +import android.content.ServiceConnection +import android.os.IBinder +import dagger.android.HasAndroidInjector +import info.nightscout.androidaps.dana.DanaPump +import info.nightscout.androidaps.danaRKorean.services.DanaRKoreanExecutionService +import info.nightscout.androidaps.danar.AbstractDanaRPlugin +import info.nightscout.androidaps.danar.R +import info.nightscout.androidaps.data.DetailedBolusInfo +import info.nightscout.androidaps.data.Profile +import info.nightscout.androidaps.data.PumpEnactResult +import info.nightscout.androidaps.events.EventAppExit +import info.nightscout.androidaps.events.EventPreferenceChange +import info.nightscout.androidaps.interfaces.ActivePlugin +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.interfaces.PumpSync.TemporaryBasalType +import info.nightscout.androidaps.logging.AAPSLogger +import info.nightscout.androidaps.logging.LTag +import info.nightscout.androidaps.plugins.bus.RxBusWrapper +import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker +import info.nightscout.androidaps.plugins.general.overview.events.EventOverviewBolusProgress +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.resources.ResourceHelper +import info.nightscout.androidaps.utils.rx.AapsSchedulers +import info.nightscout.androidaps.utils.sharedPreferences.SP +import io.reactivex.rxkotlin.plusAssign +import javax.inject.Inject +import javax.inject.Singleton +import kotlin.math.abs +import kotlin.math.max + +@Singleton +class DanaRKoreanPlugin @Inject constructor( + injector: HasAndroidInjector, + aapsLogger: AAPSLogger, + aapsSchedulers: AapsSchedulers, + rxBus: RxBusWrapper, + private val context: Context, + resourceHelper: ResourceHelper, + constraintChecker: ConstraintChecker, + activePlugin: ActivePlugin, + sp: SP, + commandQueue: CommandQueueProvider, + danaPump: DanaPump, + dateUtil: DateUtil, + private val fabricPrivacy: FabricPrivacy, + pumpSync: PumpSync +) : AbstractDanaRPlugin(injector, danaPump, resourceHelper, constraintChecker, aapsLogger, aapsSchedulers, commandQueue, rxBus, activePlugin, sp, dateUtil, pumpSync) { + + init { + pluginDescription.description(R.string.description_pump_dana_r_korean) + useExtendedBoluses = sp.getBoolean(R.string.key_danar_useextended, false) + pumpDescription.setPumpDescription(PumpType.DANA_R_KOREAN) + } + + override fun onStart() { + context.bindService(Intent(context, DanaRKoreanExecutionService::class.java), mConnection, Context.BIND_AUTO_CREATE) + disposable += rxBus + .toObservable(EventPreferenceChange::class.java) + .observeOn(aapsSchedulers.io) + .subscribe({ + if (isEnabled(PluginType.PUMP)) { + val previousValue = useExtendedBoluses + useExtendedBoluses = sp.getBoolean(R.string.key_danar_useextended, false) + if (useExtendedBoluses != previousValue && pumpSync.expectedPumpState().extendedBolus != null) { + sExecutionService.extendedBolusStop() + } + } + }, fabricPrivacy::logException) + disposable += rxBus + .toObservable(EventAppExit::class.java) + .observeOn(aapsSchedulers.io) + .subscribe({ context.unbindService(mConnection) }, fabricPrivacy::logException) + super.onStart() + } + + override fun onStop() { + context.unbindService(mConnection) + disposable.clear() + super.onStop() + } + + private val mConnection: ServiceConnection = object : ServiceConnection { + override fun onServiceDisconnected(name: ComponentName) { + aapsLogger.debug(LTag.PUMP, "Service is disconnected") + sExecutionService = null + } + + override fun onServiceConnected(name: ComponentName, service: IBinder) { + aapsLogger.debug(LTag.PUMP, "Service is connected") + val mLocalBinder = service as DanaRKoreanExecutionService.LocalBinder + sExecutionService = mLocalBinder.serviceInstance + } + } + + // Plugin base interface + override val name: String + get() = resourceHelper.gs(R.string.danarkoreanpump) + override val preferencesId: Int + get() = R.xml.pref_danarkorean + + // Pump interface + override val isFakingTempsByExtendedBoluses: Boolean + get() = useExtendedBoluses + + override fun isInitialized(): Boolean = + danaPump.lastConnection > 0 && danaPump.maxBasal > 0 && !danaPump.isConfigUD && !danaPump.isEasyModeEnabled && danaPump.isExtendedBolusEnabled && danaPump.isPasswordOK + + override fun isHandshakeInProgress(): Boolean = + sExecutionService != null && sExecutionService.isHandshakeInProgress + + override fun finishHandshaking() { + sExecutionService.finishHandshaking() + } + + override fun deliverTreatment(detailedBolusInfo: DetailedBolusInfo): PumpEnactResult { + detailedBolusInfo.insulin = constraintChecker.applyBolusConstraints(Constraint(detailedBolusInfo.insulin)).value() + if (detailedBolusInfo.carbs > 0) throw IllegalArgumentException() + return if (detailedBolusInfo.insulin > 0) { + val t = EventOverviewBolusProgress.Treatment(0.0, 0, detailedBolusInfo.bolusType == DetailedBolusInfo.BolusType.SMB) + var connectionOK = false + if (detailedBolusInfo.insulin > 0) + connectionOK = sExecutionService.bolus(detailedBolusInfo.insulin, detailedBolusInfo.carbs.toInt(), detailedBolusInfo.carbTime.toLong(), t) + val result = PumpEnactResult(injector) + result.success(connectionOK && abs(detailedBolusInfo.insulin - t.insulin) < pumpDescription.bolusStep) + .bolusDelivered(t.insulin) + if (!result.success) result.comment(resourceHelper.gs(R.string.boluserrorcode, detailedBolusInfo.insulin, t.insulin, danaPump.bolusStartErrorCode)) else result.comment(R.string.ok) + aapsLogger.debug(LTag.PUMP, "deliverTreatment: OK. Asked: " + detailedBolusInfo.insulin + " Delivered: " + result.bolusDelivered) + detailedBolusInfo.insulin = t.insulin + detailedBolusInfo.timestamp = dateUtil.now() + if (detailedBolusInfo.insulin > 0) pumpSync.syncBolusWithPumpId( + detailedBolusInfo.timestamp, + detailedBolusInfo.insulin, + detailedBolusInfo.bolusType, + dateUtil.now(), + PumpType.DANA_R_KOREAN, + serialNumber() + ) + result + } else { + val result = PumpEnactResult(injector) + result.success(false).bolusDelivered(0.0).carbsDelivered(0.0).comment(R.string.invalidinput) + aapsLogger.error("deliverTreatment: Invalid input") + result + } + } + + // This is called from APS + override fun setTempBasalAbsolute(absoluteRate: Double, durationInMinutes: Int, profile: Profile, enforceNew: Boolean, tbrType: TemporaryBasalType): PumpEnactResult { + // Recheck pump status if older than 30 min + //This should not be needed while using queue because connection should be done before calling this + var result = PumpEnactResult(injector) + val absoluteRateAfterConstraint = constraintChecker.applyBasalConstraints(Constraint(absoluteRate), profile).value() + val doTempOff = baseBasalRate - absoluteRateAfterConstraint == 0.0 && absoluteRateAfterConstraint >= 0.10 + val doLowTemp = absoluteRateAfterConstraint < baseBasalRate || absoluteRateAfterConstraint < 0.10 + val doHighTemp = absoluteRateAfterConstraint > baseBasalRate && !useExtendedBoluses + val doExtendedTemp = absoluteRateAfterConstraint > baseBasalRate && useExtendedBoluses + if (doTempOff) { + // If extended in progress + if (danaPump.isExtendedInProgress && useExtendedBoluses) { + aapsLogger.debug(LTag.PUMP, "setTempBasalAbsolute: Stopping extended bolus (doTempOff)") + return cancelExtendedBolus() + } + // If temp in progress + if (danaPump.isTempBasalInProgress) { + aapsLogger.debug(LTag.PUMP, "setTempBasalAbsolute: Stopping temp basal (doTempOff)") + return cancelRealTempBasal() + } + result.success(true).enacted(false).percent(100).isPercent(true).isTempCancel(true) + aapsLogger.debug(LTag.PUMP, "setTempBasalAbsolute: doTempOff OK") + return result + } + if (doLowTemp || doHighTemp) { + var percentRate: Int = java.lang.Double.valueOf(absoluteRateAfterConstraint / baseBasalRate * 100).toInt() + // Any basal less than 0.10u/h will be dumped once per hour, not every 4 minutes. So if it's less than .10u/h, set a zero temp. + if (absoluteRateAfterConstraint < 0.10) percentRate = 0 + percentRate = if (percentRate < 100) Round.ceilTo(percentRate.toDouble(), 10.0).toInt() else Round.floorTo(percentRate.toDouble(), 10.0).toInt() + if (percentRate > pumpDescription.maxTempPercent) { + percentRate = pumpDescription.maxTempPercent + } + aapsLogger.debug(LTag.PUMP, "setTempBasalAbsolute: Calculated percent rate: $percentRate") + + // If extended in progress + if (danaPump.isExtendedInProgress && useExtendedBoluses) { + aapsLogger.debug(LTag.PUMP, "setTempBasalAbsolute: Stopping extended bolus (doLowTemp || doHighTemp)") + result = cancelExtendedBolus() + if (!result.success) { + aapsLogger.error("setTempBasalAbsolute: Failed to stop previous extended bolus (doLowTemp || doHighTemp)") + return result + } + } + // Check if some temp is already in progress + if (danaPump.isTempBasalInProgress) { + // Correct basal already set ? + aapsLogger.debug(LTag.PUMP, "setTempBasalAbsolute: currently running: " + danaPump.temporaryBasalToString()) + if (danaPump.tempBasalPercent == percentRate && danaPump.tempBasalRemainingMin > 4) { + if (enforceNew) { + cancelTempBasal(true) + } else { + result.success(true).percent(percentRate).enacted(false).duration(danaPump.tempBasalRemainingMin).isPercent(true).isTempCancel(false) + aapsLogger.debug(LTag.PUMP, "setTempBasalAbsolute: Correct temp basal already set (doLowTemp || doHighTemp)") + return result + } + } + } + // Convert duration from minutes to hours + aapsLogger.debug(LTag.PUMP, "setTempBasalAbsolute: Setting temp basal $percentRate% for $durationInMinutes minutes (doLowTemp || doHighTemp)") + return setTempBasalPercent(percentRate, durationInMinutes, profile, false, tbrType) + } + if (doExtendedTemp) { + // Check if some temp is already in progress + if (danaPump.isTempBasalInProgress) { + aapsLogger.debug(LTag.PUMP, "setTempBasalAbsolute: Stopping temp basal (doExtendedTemp)") + result = cancelRealTempBasal() + // Check for proper result + if (!result.success) { + aapsLogger.error("setTempBasalAbsolute: Failed to stop previous temp basal (doExtendedTemp)") + return result + } + } + + // Calculate # of halfHours from minutes + val durationInHalfHours = max(durationInMinutes / 30, 1) + // We keep current basal running so need to sub current basal + var extendedRateToSet: Double = absoluteRateAfterConstraint - baseBasalRate + extendedRateToSet = constraintChecker.applyBasalConstraints(Constraint(extendedRateToSet), profile).value() + // needs to be rounded to 0.1 + extendedRateToSet = Round.roundTo(extendedRateToSet, pumpDescription.extendedBolusStep * 2) // *2 because of half hours + + // What is current rate of extended bolusing in u/h? + aapsLogger.debug(LTag.PUMP, "setTempBasalAbsolute: Extended bolus in progress: " + danaPump.isExtendedInProgress + " rate: " + danaPump.extendedBolusAbsoluteRate + "U/h duration remaining: " + danaPump.extendedBolusRemainingMinutes + "min") + aapsLogger.debug(LTag.PUMP, "setTempBasalAbsolute: Rate to set: " + extendedRateToSet + "U/h") + + // Compare with extended rate in progress + if (danaPump.isExtendedInProgress && abs(danaPump.extendedBolusAbsoluteRate - extendedRateToSet) < pumpDescription.extendedBolusStep) { + // correct extended already set + result.success(true).absolute(danaPump.extendedBolusAbsoluteRate).enacted(false).duration(danaPump.extendedBolusRemainingMinutes).isPercent(false).isTempCancel(false) + aapsLogger.debug(LTag.PUMP, "setTempBasalAbsolute: Correct extended already set") + return result + } + + // Now set new extended, no need to to stop previous (if running) because it's replaced + val extendedAmount = extendedRateToSet / 2 * durationInHalfHours + aapsLogger.debug(LTag.PUMP, "setTempBasalAbsolute: Setting extended: " + extendedAmount + "U half hours: " + durationInHalfHours) + result = setExtendedBolus(extendedAmount, durationInMinutes) + if (!result.success) { + aapsLogger.error("setTempBasalAbsolute: Failed to set extended bolus") + return result + } + aapsLogger.debug(LTag.PUMP, "setTempBasalAbsolute: Extended bolus set ok") + result.absolute(result.absolute + baseBasalRate) + return result + } + // We should never end here + aapsLogger.error("setTempBasalAbsolute: Internal error") + result.success(false).comment("Internal error") + return result + } + + override fun cancelTempBasal(enforceNew: Boolean): PumpEnactResult { + if (danaPump.isTempBasalInProgress) return cancelRealTempBasal() + if (danaPump.isExtendedInProgress && useExtendedBoluses) { + return cancelExtendedBolus() + } + val result = PumpEnactResult(injector) + result.success(true).enacted(false).comment(R.string.ok).isTempCancel(true) + return result + } + + override fun model(): PumpType = PumpType.DANA_R_KOREAN + + private fun cancelRealTempBasal(): PumpEnactResult { + val result = PumpEnactResult(injector) + if (danaPump.isTempBasalInProgress) { + sExecutionService.tempBasalStop() + if (!danaPump.isTempBasalInProgress) { + pumpSync.syncStopTemporaryBasalWithPumpId( + dateUtil.now(), + dateUtil.now(), + pumpDescription.pumpType, + serialNumber() + ) + result.success(true).enacted(true).isTempCancel(true) + } else result.success(false).enacted(false).isTempCancel(true) + } else { + result.success(true).isTempCancel(true).comment(R.string.ok) + aapsLogger.debug(LTag.PUMP, "cancelRealTempBasal: OK") + } + return result + } + + override fun loadEvents(): PumpEnactResult = PumpEnactResult(injector) // no history, not needed + override fun setUserOptions(): PumpEnactResult = PumpEnactResult(injector) +} \ No newline at end of file diff --git a/danar/src/main/java/info/nightscout/androidaps/danaRKorean/comm/MsgInitConnStatusTime_k.kt b/danar/src/main/java/info/nightscout/androidaps/danaRKorean/comm/MsgInitConnStatusTime_k.kt index c884364b03..26c602a237 100644 --- a/danar/src/main/java/info/nightscout/androidaps/danaRKorean/comm/MsgInitConnStatusTime_k.kt +++ b/danar/src/main/java/info/nightscout/androidaps/danaRKorean/comm/MsgInitConnStatusTime_k.kt @@ -29,6 +29,7 @@ class MsgInitConnStatusTime_k( danaRPlugin.setPluginEnabled(PluginType.PUMP, true) danaRPlugin.setFragmentVisible(PluginType.PUMP, true) danaPump.reset() // mark not initialized + pumpSync.connectNewPump() //If profile coming from pump, switch it as well configBuilder.storeSettings("ChangingKoreanDanaDriver") rxBus.send(EventRebuildTabs()) diff --git a/danar/src/main/java/info/nightscout/androidaps/danaRKorean/comm/MsgStatus_k.kt b/danar/src/main/java/info/nightscout/androidaps/danaRKorean/comm/MsgStatus_k.kt index 0f0815bd93..0138c65ee3 100644 --- a/danar/src/main/java/info/nightscout/androidaps/danaRKorean/comm/MsgStatus_k.kt +++ b/danar/src/main/java/info/nightscout/androidaps/danaRKorean/comm/MsgStatus_k.kt @@ -15,9 +15,9 @@ class MsgStatus_k( override fun handleMessage(bytes: ByteArray) { danaPump.dailyTotalUnits = intFromBuff(bytes, 0, 3) / 750.0 - danaPump.isExtendedInProgress = intFromBuff(bytes, 3, 1) == 1 - danaPump.extendedBolusMinutes = intFromBuff(bytes, 4, 2) - danaPump.extendedBolusAmount = intFromBuff(bytes, 6, 2) / 100.0 + val isExtendedInProgress = intFromBuff(bytes, 3, 1) == 1 + val extendedBolusMinutes = intFromBuff(bytes, 4, 2) + val extendedBolusAmount = intFromBuff(bytes, 6, 2) / 100.0 //val lastBolusAmount = intFromBuff(bytes, 13, 2) / 100.0 //if (lastBolusAmount != 0d) { // pump.lastBolusTime = dateTimeFromBuff(bytes, 8); @@ -25,9 +25,9 @@ class MsgStatus_k( //} danaPump.iob = intFromBuff(bytes, 15, 2) / 100.0 aapsLogger.debug(LTag.PUMPCOMM, "Daily total: " + danaPump.dailyTotalUnits) - aapsLogger.debug(LTag.PUMPCOMM, "Is extended bolus running: " + danaPump.isExtendedInProgress) - aapsLogger.debug(LTag.PUMPCOMM, "Extended bolus min: " + danaPump.extendedBolusMinutes) - aapsLogger.debug(LTag.PUMPCOMM, "Extended bolus amount: " + danaPump.extendedBolusAmount) + aapsLogger.debug(LTag.PUMPCOMM, "Is extended bolus running: $isExtendedInProgress") + aapsLogger.debug(LTag.PUMPCOMM, "Extended bolus min: $extendedBolusMinutes") + aapsLogger.debug(LTag.PUMPCOMM, "Extended bolus amount: $extendedBolusAmount") //aapsLogger.debug(LTag.PUMPCOMM, "Last bolus time: " + pump.lastBolusTime); //aapsLogger.debug(LTag.PUMPCOMM, "Last bolus amount: " + pump.lastBolusAmount); aapsLogger.debug(LTag.PUMPCOMM, "IOB: " + danaPump.iob) diff --git a/danar/src/main/java/info/nightscout/androidaps/danaRKorean/services/DanaRKoreanExecutionService.java b/danar/src/main/java/info/nightscout/androidaps/danaRKorean/services/DanaRKoreanExecutionService.java index 2b4004386f..a4a5555c81 100644 --- a/danar/src/main/java/info/nightscout/androidaps/danaRKorean/services/DanaRKoreanExecutionService.java +++ b/danar/src/main/java/info/nightscout/androidaps/danaRKorean/services/DanaRKoreanExecutionService.java @@ -38,21 +38,22 @@ import info.nightscout.androidaps.danar.comm.MsgStatusTempBasal; import info.nightscout.androidaps.danar.services.AbstractDanaRExecutionService; import info.nightscout.androidaps.data.Profile; import info.nightscout.androidaps.data.PumpEnactResult; -import info.nightscout.androidaps.db.Treatment; import info.nightscout.androidaps.dialogs.BolusProgressDialog; import info.nightscout.androidaps.events.EventInitializationChanged; import info.nightscout.androidaps.events.EventProfileNeedsUpdate; import info.nightscout.androidaps.events.EventPumpStatusChanged; -import info.nightscout.androidaps.interfaces.ActivePluginProvider; +import info.nightscout.androidaps.interfaces.ActivePlugin; import info.nightscout.androidaps.interfaces.CommandQueueProvider; import info.nightscout.androidaps.interfaces.ProfileFunction; +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; import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker; -import info.nightscout.androidaps.plugins.general.nsclient.NSUpload; import info.nightscout.androidaps.plugins.general.overview.events.EventNewNotification; +import info.nightscout.androidaps.plugins.general.overview.events.EventOverviewBolusProgress; import info.nightscout.androidaps.plugins.general.overview.notifications.Notification; +import info.nightscout.androidaps.plugins.pump.common.defs.PumpType; import info.nightscout.androidaps.queue.commands.Command; import info.nightscout.androidaps.utils.DateUtil; import info.nightscout.androidaps.utils.T; @@ -68,9 +69,9 @@ public class DanaRKoreanExecutionService extends AbstractDanaRExecutionService { @Inject DanaRKoreanPlugin danaRKoreanPlugin; @Inject CommandQueueProvider commandQueue; @Inject MessageHashTableRKorean messageHashTableRKorean; - @Inject ActivePluginProvider activePlugin; + @Inject ActivePlugin activePlugin; @Inject ProfileFunction profileFunction; - @Inject NSUpload nsUpload; + @Inject PumpSync pumpSync; @Inject DateUtil dateUtil; public DanaRKoreanExecutionService() { @@ -171,7 +172,7 @@ public class DanaRKoreanExecutionService extends AbstractDanaRExecutionService { rxBus.send(new EventPumpStatusChanged(resourceHelper.gs(R.string.gettingpumptime))); mSerialIOThread.sendMessage(new MsgSettingPumpTime(injector)); if (danaPump.getPumpTime() == 0) { - // initial handshake was not successfull + // initial handshake was not successful // deinitialize pump danaPump.reset(); rxBus.send(new EventDanaRNewStatus()); @@ -182,8 +183,8 @@ public class DanaRKoreanExecutionService extends AbstractDanaRExecutionService { aapsLogger.debug(LTag.PUMP, "Pump time difference: " + timeDiff + " seconds"); if (Math.abs(timeDiff) > 10) { waitForWholeMinute(); // Dana can set only whole minute - // add 10sec to be sure we are over minute (will be cutted off anyway) - mSerialIOThread.sendMessage(new MsgSetTime(injector, DateUtil.now() + T.secs(10).msecs())); + // add 10sec to be sure we are over minute (will be cut off anyway) + mSerialIOThread.sendMessage(new MsgSetTime(injector, dateUtil.now() + T.secs(10).msecs())); mSerialIOThread.sendMessage(new MsgSettingPumpTime(injector)); timeDiff = (danaPump.getPumpTime() - System.currentTimeMillis()) / 1000L; aapsLogger.debug(LTag.PUMP, "Pump time difference: " + timeDiff + " seconds"); @@ -199,10 +200,12 @@ public class DanaRKoreanExecutionService extends AbstractDanaRExecutionService { if (System.currentTimeMillis() > lastApproachingDailyLimit + 30 * 60 * 1000) { Notification reportFail = new Notification(Notification.APPROACHING_DAILY_LIMIT, resourceHelper.gs(R.string.approachingdailylimit), Notification.URGENT); rxBus.send(new EventNewNotification(reportFail)); - nsUpload.uploadError(resourceHelper.gs(R.string.approachingdailylimit) + ": " + danaPump.getDailyTotalUnits() + "/" + danaPump.getMaxDailyTotalUnits() + "U"); + pumpSync.insertAnnouncement(resourceHelper.gs(R.string.approachingdailylimit) + ": " + danaPump.getDailyTotalUnits() + "/" + danaPump.getMaxDailyTotalUnits() + "U", null, PumpType.DANA_R_KOREAN, danaRKoreanPlugin.serialNumber()); lastApproachingDailyLimit = System.currentTimeMillis(); } } + + doSanityCheck(); } catch (Exception e) { aapsLogger.error("Unhandled exception", e); } @@ -254,7 +257,7 @@ public class DanaRKoreanExecutionService extends AbstractDanaRExecutionService { return null; } - public boolean bolus(double amount, int carbs, long carbtime, final Treatment t) { + public boolean bolus(double amount, int carbs, long carbtime, final EventOverviewBolusProgress.Treatment t) { if (!isConnected()) return false; if (BolusProgressDialog.stopPressed) return false; 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 6cc7f6bf43..34309dd182 100644 --- a/danar/src/main/java/info/nightscout/androidaps/danaRv2/DanaRv2Plugin.java +++ b/danar/src/main/java/info/nightscout/androidaps/danaRv2/DanaRv2Plugin.java @@ -19,17 +19,18 @@ import info.nightscout.androidaps.danar.R; import info.nightscout.androidaps.data.DetailedBolusInfo; import info.nightscout.androidaps.data.Profile; import info.nightscout.androidaps.data.PumpEnactResult; -import info.nightscout.androidaps.db.TemporaryBasal; -import info.nightscout.androidaps.db.Treatment; import info.nightscout.androidaps.events.EventAppExit; -import info.nightscout.androidaps.interfaces.ActivePluginProvider; +import info.nightscout.androidaps.interfaces.ActivePlugin; 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; import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker; +import info.nightscout.androidaps.plugins.general.overview.events.EventOverviewBolusProgress; import info.nightscout.androidaps.plugins.pump.common.bolusInfo.DetailedBolusInfoStorage; +import info.nightscout.androidaps.plugins.pump.common.bolusInfo.TemporaryBasalStorage; import info.nightscout.androidaps.plugins.pump.common.defs.PumpType; import info.nightscout.androidaps.utils.DateUtil; import info.nightscout.androidaps.utils.FabricPrivacy; @@ -49,10 +50,10 @@ public class DanaRv2Plugin extends AbstractDanaRPlugin { private final ResourceHelper resourceHelper; private final ConstraintChecker constraintChecker; private final DetailedBolusInfoStorage detailedBolusInfoStorage; + private final TemporaryBasalStorage temporaryBasalStorage; private final FabricPrivacy fabricPrivacy; public long lastEventTimeLoaded = 0; - public boolean eventsLoadingDone = false; @Inject public DanaRv2Plugin( @@ -61,27 +62,30 @@ public class DanaRv2Plugin extends AbstractDanaRPlugin { AapsSchedulers aapsSchedulers, RxBusWrapper rxBus, Context context, - DanaPump danaPump, ResourceHelper resourceHelper, ConstraintChecker constraintChecker, - ActivePluginProvider activePlugin, + ActivePlugin activePlugin, SP sp, CommandQueueProvider commandQueue, + DanaPump danaPump, DetailedBolusInfoStorage detailedBolusInfoStorage, + TemporaryBasalStorage temporaryBasalStorage, 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; this.constraintChecker = constraintChecker; this.detailedBolusInfoStorage = detailedBolusInfoStorage; + this.temporaryBasalStorage = temporaryBasalStorage; this.fabricPrivacy = fabricPrivacy; getPluginDescription().description(R.string.description_pump_dana_r_v2); useExtendedBoluses = false; - pumpDescription.setPumpDescription(PumpType.DanaRv2); + pumpDescription.setPumpDescription(PumpType.DANA_RV2); } @Override @@ -171,7 +175,7 @@ public class DanaRv2Plugin extends AbstractDanaRPlugin { speed = 60; break; } - detailedBolusInfo.date = DateUtil.now() + (long) (speed * detailedBolusInfo.insulin * 1000); + detailedBolusInfo.timestamp = dateUtil.now() + (long) (speed * detailedBolusInfo.insulin * 1000); // clean carbs to prevent counting them as twice because they will picked up as another record // I don't think it's necessary to copy DetailedBolusInfo right now for carbs records double carbs = detailedBolusInfo.carbs; @@ -182,11 +186,10 @@ public class DanaRv2Plugin extends AbstractDanaRPlugin { detailedBolusInfoStorage.add(detailedBolusInfo); // will be picked up on reading history - Treatment t = new Treatment(); - t.isSMB = detailedBolusInfo.isSMB; + EventOverviewBolusProgress.Treatment t = new EventOverviewBolusProgress.Treatment(0, 0, detailedBolusInfo.getBolusType() == DetailedBolusInfo.BolusType.SMB); boolean connectionOK = false; if (detailedBolusInfo.insulin > 0 || carbs > 0) - connectionOK = sExecutionService.bolus(detailedBolusInfo.insulin, (int) carbs, DateUtil.now() + T.mins(carbTime).msecs(), t); + connectionOK = sExecutionService.bolus(detailedBolusInfo.insulin, (int) carbs, dateUtil.now() + T.mins(carbTime).msecs(), t); PumpEnactResult result = new PumpEnactResult(getInjector()); result.success(connectionOK && Math.abs(detailedBolusInfo.insulin - t.insulin) < pumpDescription.getBolusStep()) .bolusDelivered(t.insulin) @@ -217,7 +220,7 @@ public class DanaRv2Plugin extends AbstractDanaRPlugin { // This is called from APS @NonNull @Override - public PumpEnactResult setTempBasalAbsolute(double absoluteRate, int durationInMinutes, @NonNull Profile profile, boolean enforceNew) { + public PumpEnactResult setTempBasalAbsolute(double absoluteRate, int durationInMinutes, @NonNull Profile profile, boolean enforceNew, @NonNull PumpSync.TemporaryBasalType tbrType) { PumpEnactResult result = new PumpEnactResult(getInjector()); @@ -229,7 +232,7 @@ public class DanaRv2Plugin extends AbstractDanaRPlugin { if (doTempOff) { // If temp in progress - if (activePlugin.getActiveTreatments().isTempBasalInProgress()) { + if (danaPump.isTempBasalInProgress()) { aapsLogger.debug(LTag.PUMP, "setTempBasalAbsolute: Stopping temp basal (doTempOff)"); return cancelTempBasal(false); } @@ -247,21 +250,21 @@ public class DanaRv2Plugin extends AbstractDanaRPlugin { if (percentRate > 500) // Special high temp 500/15min percentRate = 500; // Check if some temp is already in progress - TemporaryBasal activeTemp = activePlugin.getActiveTreatments().getTempBasalFromHistory(System.currentTimeMillis()); - if (activeTemp != null) { + if (danaPump.isTempBasalInProgress()) { // Correct basal already set ? - if (activeTemp.percentRate == percentRate && activeTemp.getPlannedRemainingMinutes() > 4) { + if (danaPump.getTempBasalPercent() == percentRate && danaPump.getTempBasalRemainingMin() > 4) { if (!enforceNew) { - result.success(true).percent(percentRate).enacted(false).duration(activeTemp.getPlannedRemainingMinutes()).isPercent(true).isTempCancel(false); + result.success(true).percent(percentRate).enacted(false).duration(danaPump.getTempBasalRemainingMin()).isPercent(true).isTempCancel(false); aapsLogger.debug(LTag.PUMP, "setTempBasalAbsolute: Correct temp basal already set (doLowTemp || doHighTemp)"); return result; } } } + temporaryBasalStorage.add(new PumpSync.PumpState.TemporaryBasal(dateUtil.now(), T.mins(durationInMinutes).msecs(), percentRate, false, tbrType, 0L, 0L)); // Convert duration from minutes to hours aapsLogger.debug(LTag.PUMP, "setTempBasalAbsolute: Setting temp basal " + percentRate + "% for " + durationInMinutes + " minutes (doLowTemp || doHighTemp)"); if (percentRate == 0 && durationInMinutes > 30) { - result = setTempBasalPercent(percentRate, durationInMinutes, profile, enforceNew); + result = setTempBasalPercent(percentRate, durationInMinutes, profile, enforceNew, tbrType); } else { // use special APS temp basal call ... 100+/15min .... 100-/30min result = setHighTempBasalPercent(percentRate, durationInMinutes); @@ -280,7 +283,7 @@ public class DanaRv2Plugin extends AbstractDanaRPlugin { } @NonNull @Override - public PumpEnactResult setTempBasalPercent(int percent, int durationInMinutes, @NonNull Profile profile, boolean enforceNew) { + public PumpEnactResult setTempBasalPercent(int percent, int durationInMinutes, @NonNull Profile profile, boolean enforceNew, @NonNull PumpSync.TemporaryBasalType tbrType) { DanaPump pump = danaPump; PumpEnactResult result = new PumpEnactResult(getInjector()); percent = constraintChecker.applyBasalPercentConstraints(new Constraint<>(percent), profile).value(); @@ -291,13 +294,12 @@ public class DanaRv2Plugin extends AbstractDanaRPlugin { } if (percent > getPumpDescription().getMaxTempPercent()) percent = getPumpDescription().getMaxTempPercent(); - long now = System.currentTimeMillis(); - TemporaryBasal activeTemp = activePlugin.getActiveTreatments().getRealTempBasalFromHistory(now); - if (activeTemp != null && activeTemp.percentRate == percent && activeTemp.getPlannedRemainingMinutes() > 4 && !enforceNew) { + if (danaPump.isTempBasalInProgress() && danaPump.getTempBasalPercent() == percent && danaPump.getTempBasalRemainingMin() > 4 && !enforceNew) { result.enacted(false).success(true).isTempCancel(false).comment(R.string.ok).duration(pump.getTempBasalRemainingMin()).percent(pump.getTempBasalPercent()).isPercent(true); aapsLogger.debug(LTag.PUMP, "setTempBasalPercent: Correct value already set"); return result; } + temporaryBasalStorage.add(new PumpSync.PumpState.TemporaryBasal(dateUtil.now(), T.mins(durationInMinutes).msecs(), percent, false, tbrType, 0L, 0L)); boolean connectionOK; if (durationInMinutes == 15 || durationInMinutes == 30) { connectionOK = sExecutionService.tempBasalShortDuration(percent, durationInMinutes); @@ -332,24 +334,71 @@ public class DanaRv2Plugin extends AbstractDanaRPlugin { @NonNull @Override public PumpEnactResult cancelTempBasal(boolean force) { PumpEnactResult result = new PumpEnactResult(getInjector()); - TemporaryBasal runningTB = activePlugin.getActiveTreatments().getTempBasalFromHistory(System.currentTimeMillis()); - if (runningTB != null) { + if (danaPump.isTempBasalInProgress()) { sExecutionService.tempBasalStop(); result.enacted(true).isTempCancel(true); - } - if (!danaPump.isTempBasalInProgress()) { + } else { result.success(true).isTempCancel(true).comment(R.string.ok); aapsLogger.debug(LTag.PUMP, "cancelRealTempBasal: OK"); - } else { - result.success(false).comment(R.string.danar_valuenotsetproperly).isTempCancel(true); - aapsLogger.error("cancelRealTempBasal: Failed to cancel temp basal"); + } + return result; + } + + @NonNull @Override + public PumpEnactResult setExtendedBolus(double insulin, int durationInMinutes) { + DanaPump pump = danaPump; + insulin = constraintChecker.applyExtendedBolusConstraints(new Constraint<>(insulin)).value(); + // needs to be rounded + int durationInHalfHours = Math.max(durationInMinutes / 30, 1); + insulin = Round.roundTo(insulin, getPumpDescription().getExtendedBolusStep()); + + PumpEnactResult result = new PumpEnactResult(getInjector()); + if (danaPump.isExtendedInProgress() && Math.abs(danaPump.getExtendedBolusAmount() - insulin) < pumpDescription.getExtendedBolusStep()) { + result.enacted(false) + .success(true) + .comment(R.string.ok) + .duration(pump.getExtendedBolusRemainingMinutes()) + .absolute(pump.getExtendedBolusAbsoluteRate()) + .isPercent(false) + .isTempCancel(false); + getAapsLogger().debug(LTag.PUMP, "setExtendedBolus: Correct extended bolus already set. Current: " + pump.getExtendedBolusAmount() + " Asked: " + insulin); + return result; + } + boolean connectionOK = sExecutionService.extendedBolus(insulin, durationInHalfHours); + if (connectionOK && pump.isExtendedInProgress() && Math.abs(pump.getExtendedBolusAmount() - insulin) < getPumpDescription().getExtendedBolusStep()) { + result.enacted(true) + .success(true) + .comment(R.string.ok) + .isTempCancel(false) + .duration(pump.getExtendedBolusRemainingMinutes()) + .absolute(pump.getExtendedBolusAbsoluteRate()) + .isPercent(false); + if (!sp.getBoolean("danar_useextended", false)) + result.bolusDelivered(pump.getExtendedBolusAmount()); + getAapsLogger().debug(LTag.PUMP, "setExtendedBolus: OK"); + return result; + } + result.enacted(false).success(false).comment(R.string.danar_valuenotsetproperly); + getAapsLogger().error("setExtendedBolus: Failed to extended bolus"); + return result; + } + + @NonNull @Override + public PumpEnactResult cancelExtendedBolus() { + PumpEnactResult result = new PumpEnactResult(getInjector()); + if (danaPump.isExtendedInProgress()) { + sExecutionService.extendedBolusStop(); + result.enacted(true).success(!danaPump.isExtendedInProgress()).isTempCancel(true); + } else { + result.success(true).enacted(false).comment(R.string.ok); + getAapsLogger().debug(LTag.PUMP, "cancelExtendedBolus: OK"); } return result; } @NonNull @Override public PumpType model() { - return PumpType.DanaRv2; + return PumpType.DANA_RV2; } @NonNull @Override diff --git a/danar/src/main/java/info/nightscout/androidaps/danaRv2/comm/MessageHashTableRv2.kt b/danar/src/main/java/info/nightscout/androidaps/danaRv2/comm/MessageHashTableRv2.kt index 89764534d6..05ca40da1d 100644 --- a/danar/src/main/java/info/nightscout/androidaps/danaRv2/comm/MessageHashTableRv2.kt +++ b/danar/src/main/java/info/nightscout/androidaps/danaRv2/comm/MessageHashTableRv2.kt @@ -19,8 +19,8 @@ class MessageHashTableRv2 @Inject constructor( put(MsgBolusStartWithSpeed(injector, 0.0, 0)) // 0x0104 CMD_MEALINS_START_DATA_SPEED put(MsgBolusProgress(injector)) // 0x0202 CMD_PUMP_THIS_REMAINDER_MEAL_INS put(MsgStatusProfile(injector)) // 0x0204 CMD_PUMP_CALCULATION_SETTING - put(MsgStatusTempBasal_v2(injector)) // 0x0205 CMD_PUMP_EXERCISE_MODE - put(MsgStatusBolusExtended_v2(injector)) // 0x0207 CMD_PUMP_EXPANS_INS_I + put(MsgStatusTempBasal(injector)) // 0x0205 CMD_PUMP_EXERCISE_MODE + put(MsgStatusBolusExtended(injector)) // 0x0207 CMD_PUMP_EXPANS_INS_I put(MsgStatusBasic(injector)) // 0x020A CMD_PUMP_INITVIEW_I put(MsgStatus(injector)) // 0x020B CMD_PUMP_STATUS put(MsgInitConnStatusTime(injector)) // 0x0301 CMD_PUMPINIT_TIME_INFO diff --git a/danar/src/main/java/info/nightscout/androidaps/danaRv2/comm/MsgCheckValue_v2.kt b/danar/src/main/java/info/nightscout/androidaps/danaRv2/comm/MsgCheckValue_v2.kt index 184acdec55..500cbc8808 100644 --- a/danar/src/main/java/info/nightscout/androidaps/danaRv2/comm/MsgCheckValue_v2.kt +++ b/danar/src/main/java/info/nightscout/androidaps/danaRv2/comm/MsgCheckValue_v2.kt @@ -27,7 +27,6 @@ class MsgCheckValue_v2( danaPump.protocol = intFromBuff(bytes, 1, 1) danaPump.productCode = intFromBuff(bytes, 2, 1) if (danaPump.hwModel != DanaPump.EXPORT_MODEL) { - danaPump.reset() val notification = Notification(Notification.WRONG_DRIVER, resourceHelper.gs(R.string.pumpdrivercorrected), Notification.NORMAL) rxBus.send(EventNewNotification(notification)) danaRPlugin.disconnect("Wrong Model") @@ -37,6 +36,7 @@ class MsgCheckValue_v2( danaRPlugin.setPluginEnabled(PluginType.PUMP, false) danaRPlugin.setFragmentVisible(PluginType.PUMP, false) danaPump.reset() // mark not initialized + pumpSync.connectNewPump() //If profile coming from pump, switch it as well configBuilder.storeSettings("ChangingDanaRv2Driver") rxBus.send(EventRebuildTabs()) @@ -44,7 +44,6 @@ class MsgCheckValue_v2( return } if (danaPump.protocol != 2) { - danaPump.reset() val notification = Notification(Notification.WRONG_DRIVER, resourceHelper.gs(R.string.pumpdrivercorrected), Notification.NORMAL) rxBus.send(EventNewNotification(notification)) danaRKoreanPlugin.disconnect("Wrong Model") @@ -53,6 +52,8 @@ class MsgCheckValue_v2( danaRv2Plugin.setFragmentVisible(PluginType.PUMP, false) danaRPlugin.setPluginEnabled(PluginType.PUMP, true) danaRPlugin.setFragmentVisible(PluginType.PUMP, true) + danaPump.reset() // mark not initialized + pumpSync.connectNewPump() //If profile coming from pump, switch it as well configBuilder.storeSettings("ChangingDanaRv2Driver") rxBus.send(EventRebuildTabs()) 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 ae2c29e8be..0cd213a56a 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,23 +3,25 @@ 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 import info.nightscout.androidaps.events.EventPumpStatusChanged import info.nightscout.androidaps.logging.LTag -import info.nightscout.androidaps.utils.DateUtil +import info.nightscout.androidaps.plugins.pump.common.defs.PumpType +import info.nightscout.androidaps.utils.T import java.util.* class MsgHistoryEvents_v2 constructor( - private val injector: HasAndroidInjector, + injector: HasAndroidInjector, var from: Long = 0 ) : MessageBase(injector) { + companion object { + + var messageBuffer = arrayListOf() // for reversing order of incoming messages + } + init { SetCommand(0xE003) - if (from > DateUtil.now()) { + if (from > dateUtil.now()) { aapsLogger.error("Asked to load from the future") from = 0 } @@ -34,95 +36,133 @@ class MsgHistoryEvents_v2 constructor( gfrom.timeInMillis = from AddParamDate(gfrom) } - danaRv2Plugin.eventsLoadingDone = false - aapsLogger.debug(LTag.PUMPBTCOMM, "New message") + aapsLogger.debug(LTag.PUMPCOMM, "Loading event history from: " + dateUtil.dateAndTimeString(from)) + danaPump.historyDoneReceived = false + messageBuffer = arrayListOf() } - override fun handleMessage(bytes: ByteArray) { + override fun handleMessage(data: ByteArray) { + val recordCode = intFromBuff(data, 0, 1).toByte() + // Last record + if (recordCode == 0xFF.toByte()) { + aapsLogger.debug(LTag.PUMPCOMM, "Last record received") + + val array: Array = messageBuffer.toTypedArray() + val sorted = array.sortedArrayWith { s1: ByteArray, s2: ByteArray -> (dateTime(s1) - dateTime(s2)).toInt() } + for (message in sorted) processMessage(message) + danaPump.historyDoneReceived = true + } else messageBuffer.add(data) + } + + fun dateTime(data: ByteArray): Long = + dateTimeSecFromBuff(data, 1) // 6 bytes + + fun processMessage(bytes: ByteArray) { val recordCode = intFromBuff(bytes, 0, 1).toByte() // Last record if (recordCode == 0xFF.toByte()) { - danaRv2Plugin.eventsLoadingDone = true return } - danaRv2Plugin.eventsLoadingDone = false val datetime = dateTimeSecFromBuff(bytes, 1) // 6 bytes val param1 = intFromBuff(bytes, 7, 2) val param2 = intFromBuff(bytes, 9, 2) - val temporaryBasal = TemporaryBasal(injector) - .date(datetime) - .source(Source.PUMP) - .pumpId(datetime) - val extendedBolus = ExtendedBolus(injector) - .date(datetime) - .source(Source.PUMP) - .pumpId(datetime) val status: String when (recordCode.toInt()) { info.nightscout.androidaps.dana.DanaPump.TEMPSTART -> { aapsLogger.debug(LTag.PUMPBTCOMM, "EVENT TEMPSTART (" + recordCode + ") " + dateUtil.dateAndTimeString(datetime) + " (" + datetime + ")" + " Ratio: " + param1 + "% Duration: " + param2 + "min") - temporaryBasal.percentRate = param1 - temporaryBasal.durationInMinutes = param2 - activePlugin.activeTreatments.addToHistoryTempBasal(temporaryBasal) + val temporaryBasalInfo = temporaryBasalStorage.findTemporaryBasal(datetime, param1.toDouble()) + pumpSync.syncTemporaryBasalWithPumpId( + timestamp = datetime, + rate = param1.toDouble(), + duration = T.mins(param2.toLong()).msecs(), + isAbsolute = false, + type = temporaryBasalInfo?.type, + pumpId = datetime, + pumpType = PumpType.DANA_RV2, + pumpSerial = danaPump.serialNumber) status = "TEMPSTART " + dateUtil.timeString(datetime) } info.nightscout.androidaps.dana.DanaPump.TEMPSTOP -> { aapsLogger.debug(LTag.PUMPBTCOMM, "EVENT TEMPSTOP (" + recordCode + ") " + dateUtil.dateAndTimeString(datetime)) - activePlugin.activeTreatments.addToHistoryTempBasal(temporaryBasal) + pumpSync.syncStopTemporaryBasalWithPumpId( + timestamp = datetime, + endPumpId = datetime, + pumpType = PumpType.DANA_RV2, + pumpSerial = danaPump.serialNumber) status = "TEMPSTOP " + dateUtil.timeString(datetime) } info.nightscout.androidaps.dana.DanaPump.EXTENDEDSTART -> { - aapsLogger.debug(LTag.PUMPBTCOMM, "EVENT EXTENDEDSTART (" + recordCode + ") " + dateUtil.dateAndTimeString(datetime) + " (" + datetime + ")" + " Amount: " + param1 / 100.0 + "U Duration: " + param2 + "min") - extendedBolus.insulin = param1 / 100.0 - extendedBolus.durationInMinutes = param2 - activePlugin.activeTreatments.addToHistoryExtendedBolus(extendedBolus) + val newRecord = pumpSync.syncExtendedBolusWithPumpId( + timestamp = datetime, + amount = param1 / 100.0, + duration = T.mins(param2.toLong()).msecs(), + isEmulatingTB = false, + pumpId = datetime, + pumpType = PumpType.DANA_RV2, + pumpSerial = danaPump.serialNumber) + aapsLogger.debug(LTag.PUMPBTCOMM, (if (newRecord) "**NEW** " else "") + "EVENT EXTENDEDSTART (" + recordCode + ") " + dateUtil.dateAndTimeString(datetime) + " (" + datetime + ")" + " Amount: " + param1 / 100.0 + "U Duration: " + param2 + "min") status = "EXTENDEDSTART " + dateUtil.timeString(datetime) } info.nightscout.androidaps.dana.DanaPump.EXTENDEDSTOP -> { - aapsLogger.debug(LTag.PUMPBTCOMM, "EVENT EXTENDEDSTOP (" + recordCode + ") " + dateUtil.dateAndTimeString(datetime) + " (" + datetime + ")" + " Delivered: " + param1 / 100.0 + "U RealDuration: " + param2 + "min") - activePlugin.activeTreatments.addToHistoryExtendedBolus(extendedBolus) + val newRecord = pumpSync.syncStopExtendedBolusWithPumpId( + timestamp = datetime, + endPumpId = datetime, + pumpType = PumpType.DANA_RV2, + pumpSerial = danaPump.serialNumber) + aapsLogger.debug(LTag.PUMPBTCOMM, (if (newRecord) "**NEW** " else "") + "EVENT EXTENDEDSTOP (" + recordCode + ") " + dateUtil.dateAndTimeString(datetime) + " (" + datetime + ")" + " Delivered: " + param1 / 100.0 + "U RealDuration: " + param2 + "min") status = "EXTENDEDSTOP " + dateUtil.timeString(datetime) } info.nightscout.androidaps.dana.DanaPump.BOLUS -> { val detailedBolusInfo = detailedBolusInfoStorage.findDetailedBolusInfo(datetime, param1 / 100.0) - ?: DetailedBolusInfo() - detailedBolusInfo.date = datetime - detailedBolusInfo.source = Source.PUMP - detailedBolusInfo.pumpId = 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.date = datetime - detailedBolusInfo.source = Source.PUMP - detailedBolusInfo.pumpId = 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) } info.nightscout.androidaps.dana.DanaPump.DUALEXTENDEDSTART -> { - aapsLogger.debug(LTag.PUMPBTCOMM, "EVENT DUALEXTENDEDSTART (" + recordCode + ") " + dateUtil.dateAndTimeString(datetime) + " (" + datetime + ")" + " Amount: " + param1 / 100.0 + "U Duration: " + param2 + "min") - extendedBolus.insulin = param1 / 100.0 - extendedBolus.durationInMinutes = param2 - activePlugin.activeTreatments.addToHistoryExtendedBolus(extendedBolus) + val newRecord = pumpSync.syncExtendedBolusWithPumpId( + timestamp = datetime, + amount = param1 / 100.0, + duration = T.mins(param2.toLong()).msecs(), + isEmulatingTB = false, + pumpId = datetime, + pumpType = PumpType.DANA_RV2, + pumpSerial = danaPump.serialNumber) + aapsLogger.debug(LTag.PUMPBTCOMM, (if (newRecord) "**NEW** " else "") + "EVENT DUALEXTENDEDSTART (" + recordCode + ") " + dateUtil.dateAndTimeString(datetime) + " (" + datetime + ")" + " Amount: " + param1 / 100.0 + "U Duration: " + param2 + "min") status = "DUALEXTENDEDSTART " + dateUtil.timeString(datetime) } info.nightscout.androidaps.dana.DanaPump.DUALEXTENDEDSTOP -> { - aapsLogger.debug(LTag.PUMPBTCOMM, "EVENT DUALEXTENDEDSTOP (" + recordCode + ") " + dateUtil.dateAndTimeString(datetime) + " (" + datetime + ")" + " Delivered: " + param1 / 100.0 + "U RealDuration: " + param2 + "min") - activePlugin.activeTreatments.addToHistoryExtendedBolus(extendedBolus) + val newRecord = pumpSync.syncStopExtendedBolusWithPumpId( + timestamp = datetime, + endPumpId = datetime, + pumpType = PumpType.DANA_RV2, + pumpSerial = danaPump.serialNumber) + aapsLogger.debug(LTag.PUMPBTCOMM, (if (newRecord) "**NEW** " else "") + "EVENT DUALEXTENDEDSTOP (" + recordCode + ") " + dateUtil.dateAndTimeString(datetime) + " (" + datetime + ")" + " Delivered: " + param1 / 100.0 + "U RealDuration: " + param2 + "min") status = "DUALEXTENDEDSTOP " + dateUtil.timeString(datetime) } @@ -152,12 +192,12 @@ class MsgHistoryEvents_v2 constructor( } info.nightscout.androidaps.dana.DanaPump.CARBS -> { - val emptyCarbsInfo = DetailedBolusInfo() - emptyCarbsInfo.carbs = param1.toDouble() - emptyCarbsInfo.date = datetime - emptyCarbsInfo.source = Source.PUMP - emptyCarbsInfo.pumpId = 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) } @@ -167,7 +207,7 @@ class MsgHistoryEvents_v2 constructor( status = "UNKNOWN " + dateUtil.timeString(datetime) } } - if (datetime > danaRv2Plugin.lastEventTimeLoaded) danaRv2Plugin.lastEventTimeLoaded = datetime + if (datetime > danaPump.lastEventTimeLoaded) danaPump.lastEventTimeLoaded = datetime rxBus.send(EventPumpStatusChanged(resourceHelper.gs(R.string.processinghistory) + ": " + status)) } } \ No newline at end of file diff --git a/danar/src/main/java/info/nightscout/androidaps/danaRv2/comm/MsgStatusBolusExtended_v2.kt b/danar/src/main/java/info/nightscout/androidaps/danaRv2/comm/MsgStatusBolusExtended_v2.kt deleted file mode 100644 index f0afbabcb2..0000000000 --- a/danar/src/main/java/info/nightscout/androidaps/danaRv2/comm/MsgStatusBolusExtended_v2.kt +++ /dev/null @@ -1,49 +0,0 @@ -package info.nightscout.androidaps.danaRv2.comm - -import dagger.android.HasAndroidInjector -import info.nightscout.androidaps.danar.comm.MessageBase -import info.nightscout.androidaps.logging.LTag -import kotlin.math.ceil - -class MsgStatusBolusExtended_v2( - injector: HasAndroidInjector -) : MessageBase(injector) { - - init { - SetCommand(0x0207) - aapsLogger.debug(LTag.PUMPCOMM, "New message") - } - - override fun handleMessage(bytes: ByteArray) { - val isExtendedInProgress = intFromBuff(bytes, 0, 1) == 1 - val extendedBolusHalfHours = intFromBuff(bytes, 1, 1) - val extendedBolusMinutes = extendedBolusHalfHours * 30 - val extendedBolusAmount = intFromBuff(bytes, 2, 2) / 100.0 - val extendedBolusSoFarInSecs = intFromBuff(bytes, 4, 3) - // This is available only on korean, but not needed now -// int extendedBolusDeliveryPulse = intFromBuff(bytes, 7, 2); -// int isEasyUIUserSleep = intFromBuff(bytes, 9, 1); - val extendedBolusSoFarInMinutes = extendedBolusSoFarInSecs / 60 - val extendedBolusAbsoluteRate = if (isExtendedInProgress) extendedBolusAmount / extendedBolusMinutes * 60 else 0.0 - val extendedBolusStart = if (isExtendedInProgress) getDateFromSecAgo(extendedBolusSoFarInSecs) else 0 - val extendedBolusRemainingMinutes = extendedBolusMinutes - extendedBolusSoFarInMinutes - danaPump.isExtendedInProgress = isExtendedInProgress - danaPump.extendedBolusMinutes = extendedBolusMinutes - danaPump.extendedBolusAmount = extendedBolusAmount - danaPump.extendedBolusSoFarInMinutes = extendedBolusSoFarInMinutes - danaPump.extendedBolusAbsoluteRate = extendedBolusAbsoluteRate - danaPump.extendedBolusStart = extendedBolusStart - danaPump.extendedBolusRemainingMinutes = extendedBolusRemainingMinutes - aapsLogger.debug(LTag.PUMPCOMM, "Is extended bolus running: $isExtendedInProgress") - aapsLogger.debug(LTag.PUMPCOMM, "Extended bolus min: $extendedBolusMinutes") - aapsLogger.debug(LTag.PUMPCOMM, "Extended bolus amount: $extendedBolusAmount") - aapsLogger.debug(LTag.PUMPCOMM, "Extended bolus so far in minutes: $extendedBolusSoFarInMinutes") - aapsLogger.debug(LTag.PUMPCOMM, "Extended bolus absolute rate: $extendedBolusAbsoluteRate") - aapsLogger.debug(LTag.PUMPCOMM, "Extended bolus start: $extendedBolusStart") - aapsLogger.debug(LTag.PUMPCOMM, "Extended bolus remaining minutes: $extendedBolusRemainingMinutes") - } - - private fun getDateFromSecAgo(tempBasalAgoSecs: Int): Long { - return (ceil(System.currentTimeMillis() / 1000.0) - tempBasalAgoSecs).toLong() * 1000 - } -} \ No newline at end of file diff --git a/danar/src/main/java/info/nightscout/androidaps/danaRv2/comm/MsgStatusTempBasal_v2.kt b/danar/src/main/java/info/nightscout/androidaps/danaRv2/comm/MsgStatusTempBasal_v2.kt deleted file mode 100644 index 53f2c81e1d..0000000000 --- a/danar/src/main/java/info/nightscout/androidaps/danaRv2/comm/MsgStatusTempBasal_v2.kt +++ /dev/null @@ -1,42 +0,0 @@ -package info.nightscout.androidaps.danaRv2.comm - -import dagger.android.HasAndroidInjector -import info.nightscout.androidaps.danar.comm.MessageBase -import info.nightscout.androidaps.logging.LTag -import kotlin.math.ceil - -class MsgStatusTempBasal_v2( - injector: HasAndroidInjector -) : MessageBase(injector) { - - init { - SetCommand(0x0205) - aapsLogger.debug(LTag.PUMPCOMM, "New message") - } - - override fun handleMessage(bytes: ByteArray) { - val isTempBasalInProgress = intFromBuff(bytes, 0, 1) and 0x01 == 0x01 - val isAPSTempBasalInProgress = intFromBuff(bytes, 0, 1) and 0x02 == 0x02 - var tempBasalPercent = intFromBuff(bytes, 1, 1) - if (tempBasalPercent > 200) tempBasalPercent = (tempBasalPercent - 200) * 10 - val tempBasalTotalSec: Int = if (intFromBuff(bytes, 2, 1) == 150) 15 * 60 else if (intFromBuff(bytes, 2, 1) == 160) 30 * 60 else intFromBuff(bytes, 2, 1) * 60 * 60 - val tempBasalRunningSeconds = intFromBuff(bytes, 3, 3) - val tempBasalRemainingMin = (tempBasalTotalSec - tempBasalRunningSeconds) / 60 - val tempBasalStart = if (isTempBasalInProgress) getDateFromTempBasalSecAgo(tempBasalRunningSeconds) else 0 - danaPump.isTempBasalInProgress = isTempBasalInProgress - danaPump.tempBasalPercent = tempBasalPercent - danaPump.tempBasalRemainingMin = tempBasalRemainingMin - danaPump.tempBasalTotalSec = tempBasalTotalSec - danaPump.tempBasalStart = tempBasalStart - aapsLogger.debug(LTag.PUMPCOMM, "Is temp basal running: $isTempBasalInProgress") - aapsLogger.debug(LTag.PUMPCOMM, "Is APS temp basal running: $isAPSTempBasalInProgress") - aapsLogger.debug(LTag.PUMPCOMM, "Current temp basal percent: $tempBasalPercent") - aapsLogger.debug(LTag.PUMPCOMM, "Current temp basal remaining min: $tempBasalRemainingMin") - aapsLogger.debug(LTag.PUMPCOMM, "Current temp basal total sec: $tempBasalTotalSec") - aapsLogger.debug(LTag.PUMPCOMM, "Current temp basal start: " + dateUtil.dateAndTimeString(tempBasalStart)) - } - - private fun getDateFromTempBasalSecAgo(tempBasalAgoSecs: Int): Long { - return (ceil(System.currentTimeMillis() / 1000.0) - tempBasalAgoSecs).toLong() * 1000 - } -} \ No newline at end of file diff --git a/danar/src/main/java/info/nightscout/androidaps/danaRv2/services/DanaRv2ExecutionService.java b/danar/src/main/java/info/nightscout/androidaps/danaRv2/services/DanaRv2ExecutionService.java index 2cfb3501cb..cb393a5ed9 100644 --- a/danar/src/main/java/info/nightscout/androidaps/danaRv2/services/DanaRv2ExecutionService.java +++ b/danar/src/main/java/info/nightscout/androidaps/danaRv2/services/DanaRv2ExecutionService.java @@ -20,9 +20,6 @@ import info.nightscout.androidaps.danaRv2.comm.MsgCheckValue_v2; import info.nightscout.androidaps.danaRv2.comm.MsgHistoryEvents_v2; import info.nightscout.androidaps.danaRv2.comm.MsgSetAPSTempBasalStart_v2; import info.nightscout.androidaps.danaRv2.comm.MsgSetHistoryEntry_v2; -import info.nightscout.androidaps.danaRv2.comm.MsgStatusBolusExtended_v2; -import info.nightscout.androidaps.danaRv2.comm.MsgStatusTempBasal_v2; -import info.nightscout.androidaps.danar.DanaRPlugin; import info.nightscout.androidaps.danar.R; import info.nightscout.androidaps.danar.SerialIOThread; import info.nightscout.androidaps.danar.comm.MessageBase; @@ -49,28 +46,27 @@ import info.nightscout.androidaps.danar.comm.MsgSettingShippingInfo; import info.nightscout.androidaps.danar.comm.MsgSettingUserOptions; import info.nightscout.androidaps.danar.comm.MsgStatus; import info.nightscout.androidaps.danar.comm.MsgStatusBasic; +import info.nightscout.androidaps.danar.comm.MsgStatusBolusExtended; +import info.nightscout.androidaps.danar.comm.MsgStatusTempBasal; import info.nightscout.androidaps.danar.services.AbstractDanaRExecutionService; import info.nightscout.androidaps.data.Profile; import info.nightscout.androidaps.data.PumpEnactResult; -import info.nightscout.androidaps.db.Treatment; import info.nightscout.androidaps.dialogs.BolusProgressDialog; import info.nightscout.androidaps.events.EventInitializationChanged; import info.nightscout.androidaps.events.EventProfileNeedsUpdate; import info.nightscout.androidaps.events.EventPumpStatusChanged; -import info.nightscout.androidaps.interfaces.ActivePluginProvider; +import info.nightscout.androidaps.interfaces.ActivePlugin; import info.nightscout.androidaps.interfaces.CommandQueueProvider; -import info.nightscout.androidaps.interfaces.ConfigBuilderInterface; import info.nightscout.androidaps.interfaces.ProfileFunction; -import info.nightscout.androidaps.interfaces.PumpInterface; +import info.nightscout.androidaps.interfaces.Pump; +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; -import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker; -import info.nightscout.androidaps.plugins.general.nsclient.NSUpload; import info.nightscout.androidaps.plugins.general.overview.events.EventNewNotification; import info.nightscout.androidaps.plugins.general.overview.events.EventOverviewBolusProgress; import info.nightscout.androidaps.plugins.general.overview.notifications.Notification; -import info.nightscout.androidaps.plugins.pump.common.bolusInfo.DetailedBolusInfoStorage; +import info.nightscout.androidaps.plugins.pump.common.defs.PumpType; import info.nightscout.androidaps.queue.Callback; import info.nightscout.androidaps.queue.commands.Command; import info.nightscout.androidaps.utils.DateUtil; @@ -83,25 +79,18 @@ public class DanaRv2ExecutionService extends AbstractDanaRExecutionService { @Inject AAPSLogger aapsLogger; @Inject RxBusWrapper rxBus; @Inject ResourceHelper resourceHelper; - @Inject ConstraintChecker constraintChecker; @Inject DanaPump danaPump; - @Inject DanaRPlugin danaRPlugin; @Inject DanaRKoreanPlugin danaRKoreanPlugin; @Inject DanaRv2Plugin danaRv2Plugin; - @Inject ActivePluginProvider activePlugin; - @Inject ConfigBuilderInterface configBuilderPlugin; + @Inject ActivePlugin activePlugin; @Inject CommandQueueProvider commandQueue; @Inject Context context; @Inject MessageHashTableRv2 messageHashTableRv2; - @Inject DetailedBolusInfoStorage detailedBolusInfoStorage; - @Inject ActivePluginProvider activePluginProvider; @Inject ProfileFunction profileFunction; - @Inject NSUpload nsUpload; + @Inject PumpSync pumpSync; @Inject SP sp; @Inject DateUtil dateUtil; - private long lastHistoryFetched = 0; - public DanaRv2ExecutionService() { } @@ -157,8 +146,8 @@ public class DanaRv2ExecutionService extends AbstractDanaRExecutionService { rxBus.send(new EventPumpStatusChanged(resourceHelper.gs(R.string.gettingpumpstatus))); MsgStatus statusMsg = new MsgStatus(injector); MsgStatusBasic statusBasicMsg = new MsgStatusBasic(injector); - MsgStatusTempBasal_v2 tempStatusMsg = new MsgStatusTempBasal_v2(injector); - MsgStatusBolusExtended_v2 exStatusMsg = new MsgStatusBolusExtended_v2(injector); + MsgStatusTempBasal tempStatusMsg = new MsgStatusTempBasal(injector); + MsgStatusBolusExtended exStatusMsg = new MsgStatusBolusExtended(injector); MsgCheckValue_v2 checkValue = new MsgCheckValue_v2(injector); if (danaPump.isNewPump()) { @@ -179,7 +168,7 @@ public class DanaRv2ExecutionService extends AbstractDanaRExecutionService { danaPump.setLastConnection(System.currentTimeMillis()); Profile profile = profileFunction.getProfile(); - PumpInterface pump = activePlugin.getActivePump(); + Pump pump = activePlugin.getActivePump(); if (profile != null && Math.abs(danaPump.getCurrentBasal() - profile.getBasal()) >= pump.getPumpDescription().getBasalStep()) { rxBus.send(new EventPumpStatusChanged(resourceHelper.gs(R.string.gettingpumpsettings))); mSerialIOThread.sendMessage(new MsgSettingBasal(injector)); @@ -191,8 +180,8 @@ public class DanaRv2ExecutionService extends AbstractDanaRExecutionService { rxBus.send(new EventPumpStatusChanged(resourceHelper.gs(R.string.gettingpumptime))); mSerialIOThread.sendMessage(new MsgSettingPumpTime(injector)); if (danaPump.getPumpTime() == 0) { - // initial handshake was not successfull - // deinitialize pump + // initial handshake was not successful + // de-initialize pump danaPump.reset(); rxBus.send(new EventDanaRNewStatus()); rxBus.send(new EventInitializationChanged()); @@ -214,7 +203,7 @@ public class DanaRv2ExecutionService extends AbstractDanaRExecutionService { } else { waitForWholeMinute(); // Dana can set only whole minute // add 10sec to be sure we are over minute (will be cutted off anyway) - mSerialIOThread.sendMessage(new MsgSetTime(injector, DateUtil.now() + T.secs(10).msecs())); + mSerialIOThread.sendMessage(new MsgSetTime(injector, dateUtil.now() + T.secs(10).msecs())); mSerialIOThread.sendMessage(new MsgSettingPumpTime(injector)); timeDiff = (danaPump.getPumpTime() - System.currentTimeMillis()) / 1000L; aapsLogger.debug(LTag.PUMP, "Pump time difference: " + timeDiff + " seconds"); @@ -248,7 +237,7 @@ public class DanaRv2ExecutionService extends AbstractDanaRExecutionService { if (System.currentTimeMillis() > lastApproachingDailyLimit + 30 * 60 * 1000) { Notification reportFail = new Notification(Notification.APPROACHING_DAILY_LIMIT, resourceHelper.gs(R.string.approachingdailylimit), Notification.URGENT); rxBus.send(new EventNewNotification(reportFail)); - nsUpload.uploadError(resourceHelper.gs(R.string.approachingdailylimit) + ": " + danaPump.getDailyTotalUnits() + "/" + danaPump.getMaxDailyTotalUnits() + "U"); + pumpSync.insertAnnouncement(resourceHelper.gs(R.string.approachingdailylimit) + ": " + danaPump.getDailyTotalUnits() + "/" + danaPump.getMaxDailyTotalUnits() + "U", null, PumpType.DANA_R_KOREAN, danaRKoreanPlugin.serialNumber()); lastApproachingDailyLimit = System.currentTimeMillis(); } } @@ -266,7 +255,7 @@ public class DanaRv2ExecutionService extends AbstractDanaRExecutionService { } rxBus.send(new EventPumpStatusChanged(resourceHelper.gs(R.string.settingtempbasal))); mSerialIOThread.sendMessage(new MsgSetTempBasalStart(injector, percent, durationInHours)); - mSerialIOThread.sendMessage(new MsgStatusTempBasal_v2(injector)); + mSerialIOThread.sendMessage(new MsgStatusTempBasal(injector)); loadEvents(); rxBus.send(new EventPumpStatusChanged(EventPumpStatusChanged.Status.DISCONNECTING)); return true; @@ -281,7 +270,7 @@ public class DanaRv2ExecutionService extends AbstractDanaRExecutionService { } rxBus.send(new EventPumpStatusChanged(resourceHelper.gs(R.string.settingtempbasal))); mSerialIOThread.sendMessage(new MsgSetAPSTempBasalStart_v2(injector, percent, durationInMinutes == 15, durationInMinutes == 30)); - mSerialIOThread.sendMessage(new MsgStatusTempBasal_v2(injector)); + mSerialIOThread.sendMessage(new MsgStatusTempBasal(injector)); loadEvents(); rxBus.send(new EventPumpStatusChanged(EventPumpStatusChanged.Status.DISCONNECTING)); return true; @@ -301,7 +290,7 @@ public class DanaRv2ExecutionService extends AbstractDanaRExecutionService { } rxBus.send(new EventPumpStatusChanged(resourceHelper.gs(R.string.settingtempbasal))); mSerialIOThread.sendMessage(new MsgSetAPSTempBasalStart_v2(injector, percent, durationInMinutes == 15, durationInMinutes == 30)); - mSerialIOThread.sendMessage(new MsgStatusTempBasal_v2(injector)); + mSerialIOThread.sendMessage(new MsgStatusTempBasal(injector)); loadEvents(); rxBus.send(new EventPumpStatusChanged(EventPumpStatusChanged.Status.DISCONNECTING)); return true; @@ -311,7 +300,7 @@ public class DanaRv2ExecutionService extends AbstractDanaRExecutionService { if (!isConnected()) return false; rxBus.send(new EventPumpStatusChanged(resourceHelper.gs(R.string.stoppingtempbasal))); mSerialIOThread.sendMessage(new MsgSetTempBasalStop(injector)); - mSerialIOThread.sendMessage(new MsgStatusTempBasal_v2(injector)); + mSerialIOThread.sendMessage(new MsgStatusTempBasal(injector)); loadEvents(); rxBus.send(new EventPumpStatusChanged(EventPumpStatusChanged.Status.DISCONNECTING)); return true; @@ -321,7 +310,7 @@ public class DanaRv2ExecutionService extends AbstractDanaRExecutionService { if (!isConnected()) return false; rxBus.send(new EventPumpStatusChanged(resourceHelper.gs(R.string.settingextendedbolus))); mSerialIOThread.sendMessage(new MsgSetExtendedBolusStart(injector, insulin, (byte) (durationInHalfHours & 0xFF))); - mSerialIOThread.sendMessage(new MsgStatusBolusExtended_v2(injector)); + mSerialIOThread.sendMessage(new MsgStatusBolusExtended(injector)); loadEvents(); rxBus.send(new EventPumpStatusChanged(EventPumpStatusChanged.Status.DISCONNECTING)); return true; @@ -331,13 +320,13 @@ public class DanaRv2ExecutionService extends AbstractDanaRExecutionService { if (!isConnected()) return false; rxBus.send(new EventPumpStatusChanged(resourceHelper.gs(R.string.stoppingextendedbolus))); mSerialIOThread.sendMessage(new MsgSetExtendedBolusStop(injector)); - mSerialIOThread.sendMessage(new MsgStatusBolusExtended_v2(injector)); + mSerialIOThread.sendMessage(new MsgStatusBolusExtended(injector)); loadEvents(); rxBus.send(new EventPumpStatusChanged(EventPumpStatusChanged.Status.DISCONNECTING)); return true; } - public boolean bolus(final double amount, int carbs, long carbtime, final Treatment t) { + public boolean bolus(final double amount, int carbs, long carbtime, final EventOverviewBolusProgress.Treatment t) { if (!isConnected()) return false; if (BolusProgressDialog.stopPressed) return false; @@ -358,7 +347,7 @@ public class DanaRv2ExecutionService extends AbstractDanaRExecutionService { mSerialIOThread.sendMessage(msg); MsgSetHistoryEntry_v2 msgSetHistoryEntry_v2 = new MsgSetHistoryEntry_v2(injector, DanaPump.CARBS, carbtime, carbs, 0); mSerialIOThread.sendMessage(msgSetHistoryEntry_v2); - lastHistoryFetched = Math.min(lastHistoryFetched, carbtime - T.mins(1).msecs()); + danaPump.lastHistoryFetched = Math.min(danaPump.lastHistoryFetched, carbtime - T.mins(1).msecs()); } final long bolusStart = System.currentTimeMillis(); @@ -427,7 +416,7 @@ public class DanaRv2ExecutionService extends AbstractDanaRExecutionService { mSerialIOThread.sendMessage(msg); MsgSetHistoryEntry_v2 msgSetHistoryEntry_v2 = new MsgSetHistoryEntry_v2(injector, DanaPump.CARBS, time, amount, 0); mSerialIOThread.sendMessage(msgSetHistoryEntry_v2); - lastHistoryFetched = Math.min(lastHistoryFetched, time - T.mins(1).msecs()); + danaPump.lastHistoryFetched = Math.min(danaPump.lastHistoryFetched, time - T.mins(1).msecs()); return true; } @@ -442,18 +431,18 @@ public class DanaRv2ExecutionService extends AbstractDanaRExecutionService { if (!isConnected()) return new PumpEnactResult(injector).success(false); SystemClock.sleep(300); - MsgHistoryEvents_v2 msg = new MsgHistoryEvents_v2(injector, lastHistoryFetched); - aapsLogger.debug(LTag.PUMP, "Loading event history from: " + dateUtil.dateAndTimeString(lastHistoryFetched)); + MsgHistoryEvents_v2 msg = new MsgHistoryEvents_v2(injector, danaPump.lastHistoryFetched); + aapsLogger.debug(LTag.PUMP, "Loading event history from: " + dateUtil.dateAndTimeString(danaPump.lastHistoryFetched)); mSerialIOThread.sendMessage(msg); - while (!danaRv2Plugin.eventsLoadingDone && mRfcommSocket.isConnected()) { + while (!danaPump.historyDoneReceived && mRfcommSocket.isConnected()) { SystemClock.sleep(100); } SystemClock.sleep(200); if (danaRv2Plugin.lastEventTimeLoaded != 0) - lastHistoryFetched = danaRv2Plugin.lastEventTimeLoaded - T.mins(1).msecs(); + danaPump.lastHistoryFetched = danaRv2Plugin.lastEventTimeLoaded - T.mins(1).msecs(); else - lastHistoryFetched = 0; + danaPump.lastHistoryFetched = 0; danaPump.setLastConnection(System.currentTimeMillis()); return new PumpEnactResult(injector).success(true); } 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..270a4cbe1b 100644 --- a/danar/src/main/java/info/nightscout/androidaps/danar/AbstractDanaRPlugin.java +++ b/danar/src/main/java/info/nightscout/androidaps/danar/AbstractDanaRPlugin.java @@ -5,30 +5,27 @@ import androidx.annotation.NonNull; import org.json.JSONException; import org.json.JSONObject; -import java.util.Date; - import dagger.android.HasAndroidInjector; import info.nightscout.androidaps.dana.DanaFragment; import info.nightscout.androidaps.dana.DanaPump; -import info.nightscout.androidaps.dana.DanaPumpInterface; import info.nightscout.androidaps.dana.comm.RecordTypes; import info.nightscout.androidaps.danar.services.AbstractDanaRExecutionService; import info.nightscout.androidaps.data.Profile; import info.nightscout.androidaps.data.PumpEnactResult; -import info.nightscout.androidaps.db.ExtendedBolus; -import info.nightscout.androidaps.db.TemporaryBasal; import info.nightscout.androidaps.events.EventConfigBuilderChange; import info.nightscout.androidaps.events.EventPreferenceChange; -import info.nightscout.androidaps.interfaces.ActivePluginProvider; +import info.nightscout.androidaps.extensions.PumpStateExtensionKt; +import info.nightscout.androidaps.interfaces.ActivePlugin; import info.nightscout.androidaps.interfaces.CommandQueueProvider; import info.nightscout.androidaps.interfaces.Constraint; -import info.nightscout.androidaps.interfaces.ConstraintsInterface; -import info.nightscout.androidaps.interfaces.DanaRInterface; +import info.nightscout.androidaps.interfaces.Constraints; +import info.nightscout.androidaps.interfaces.Dana; import info.nightscout.androidaps.interfaces.PluginDescription; import info.nightscout.androidaps.interfaces.PluginType; import info.nightscout.androidaps.interfaces.PumpDescription; -import info.nightscout.androidaps.interfaces.PumpInterface; +import info.nightscout.androidaps.interfaces.Pump; 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; @@ -49,7 +46,7 @@ import io.reactivex.disposables.CompositeDisposable; * Created by mike on 28.01.2018. */ -public abstract class AbstractDanaRPlugin extends PumpPluginBase implements PumpInterface, DanaRInterface, ConstraintsInterface, DanaPumpInterface { +public abstract class AbstractDanaRPlugin extends PumpPluginBase implements Pump, Dana, Constraints { protected AbstractDanaRExecutionService sExecutionService; protected CompositeDisposable disposable = new CompositeDisposable(); @@ -60,10 +57,11 @@ public abstract class AbstractDanaRPlugin extends PumpPluginBase implements Pump protected DanaPump danaPump; protected ConstraintChecker constraintChecker; protected RxBusWrapper rxBus; - protected ActivePluginProvider activePlugin; + protected ActivePlugin activePlugin; protected SP sp; protected DateUtil dateUtil; protected AapsSchedulers aapsSchedulers; + protected PumpSync pumpSync; protected AbstractDanaRPlugin( HasAndroidInjector injector, @@ -74,9 +72,10 @@ public abstract class AbstractDanaRPlugin extends PumpPluginBase implements Pump AapsSchedulers aapsSchedulers, CommandQueueProvider commandQueue, RxBusWrapper rxBus, - ActivePluginProvider activePlugin, + ActivePlugin activePlugin, SP sp, - DateUtil dateUtil + DateUtil dateUtil, + PumpSync pumpSync ) { super(new PluginDescription() .mainType(PluginType.PUMP) @@ -95,6 +94,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() { @@ -110,6 +110,7 @@ public abstract class AbstractDanaRPlugin extends PumpPluginBase implements Pump .subscribe(event -> { if (event.isChanged(getResourceHelper(), R.string.key_danar_bt_name)) { danaPump.reset(); + pumpSync.connectNewPump(); getCommandQueue().readStatus("DeviceChanged", null); } }) @@ -214,8 +215,7 @@ public abstract class AbstractDanaRPlugin extends PumpPluginBase implements Pump } @NonNull @Override - public PumpEnactResult setTempBasalPercent(int percent, int durationInMinutes, @NonNull Profile profile, boolean enforceNew) { - DanaPump pump = danaPump; + public PumpEnactResult setTempBasalPercent(int percent, int durationInMinutes, @NonNull Profile profile, boolean enforceNew, @NonNull PumpSync.TemporaryBasalType tbrType) { PumpEnactResult result = new PumpEnactResult(getInjector()); percent = constraintChecker.applyBasalPercentConstraints(new Constraint<>(percent), profile).value(); if (percent < 0) { @@ -225,28 +225,36 @@ public abstract class AbstractDanaRPlugin extends PumpPluginBase implements Pump } if (percent > getPumpDescription().getMaxTempPercent()) percent = getPumpDescription().getMaxTempPercent(); - long now = System.currentTimeMillis(); - TemporaryBasal activeTemp = activePlugin.getActiveTreatments().getRealTempBasalFromHistory(now); - if (activeTemp != null && activeTemp.percentRate == percent && activeTemp.getPlannedRemainingMinutes() > 4 && !enforceNew) { + if (danaPump.isTempBasalInProgress() && danaPump.getTempBasalPercent() == percent && danaPump.getTempBasalRemainingMin() > 4 && !enforceNew) { result.enacted(false).success(true).isTempCancel(false) .comment(R.string.ok) - .duration(pump.getTempBasalRemainingMin()) - .percent(pump.getTempBasalPercent()) + .duration(danaPump.getTempBasalRemainingMin()) + .percent(danaPump.getTempBasalPercent()) .isPercent(true); getAapsLogger().debug(LTag.PUMP, "setTempBasalPercent: Correct value already set"); return result; } int durationInHours = Math.max(durationInMinutes / 60, 1); boolean connectionOK = sExecutionService.tempBasal(percent, durationInHours); - if (connectionOK && pump.isTempBasalInProgress() && pump.getTempBasalPercent() == percent) { + if (connectionOK && danaPump.isTempBasalInProgress() && danaPump.getTempBasalPercent() == percent) { result.enacted(true) .success(true) .comment(R.string.ok) .isTempCancel(false) - .duration(pump.getTempBasalRemainingMin()) - .percent(pump.getTempBasalPercent()) + .duration((int) danaPump.getTempBasalDuration()) + .percent(danaPump.getTempBasalPercent()) .isPercent(true); getAapsLogger().debug(LTag.PUMP, "setTempBasalPercent: OK"); + pumpSync.syncTemporaryBasalWithPumpId( + danaPump.getTempBasalStart(), + danaPump.getTempBasalPercent(), + danaPump.getTempBasalDuration(), + false, + tbrType, + danaPump.getTempBasalStart(), + getPumpDescription().getPumpType(), + serialNumber() + ); return result; } result.enacted(false).success(false).comment(R.string.tempbasaldeliveryerror); @@ -256,58 +264,78 @@ public abstract class AbstractDanaRPlugin extends PumpPluginBase implements Pump @NonNull @Override public PumpEnactResult setExtendedBolus(double insulin, int durationInMinutes) { - DanaPump pump = danaPump; insulin = constraintChecker.applyExtendedBolusConstraints(new Constraint<>(insulin)).value(); // needs to be rounded int durationInHalfHours = Math.max(durationInMinutes / 30, 1); insulin = Round.roundTo(insulin, getPumpDescription().getExtendedBolusStep()); PumpEnactResult result = new PumpEnactResult(getInjector()); - ExtendedBolus runningEB = activePlugin.getActiveTreatments().getExtendedBolusFromHistory(System.currentTimeMillis()); - if (runningEB != null && Math.abs(runningEB.insulin - insulin) < getPumpDescription().getExtendedBolusStep()) { + if (danaPump.isExtendedInProgress() && Math.abs(danaPump.getExtendedBolusAmount() - insulin) < getPumpDescription().getExtendedBolusStep()) { result.enacted(false) .success(true) .comment(R.string.ok) - .duration(pump.getExtendedBolusRemainingMinutes()) - .absolute(pump.getExtendedBolusAbsoluteRate()) + .duration(danaPump.getExtendedBolusRemainingMinutes()) + .absolute(danaPump.getExtendedBolusAbsoluteRate()) .isPercent(false) .isTempCancel(false); - getAapsLogger().debug(LTag.PUMP, "setExtendedBolus: Correct extended bolus already set. Current: " + pump.getExtendedBolusAmount() + " Asked: " + insulin); + getAapsLogger().debug(LTag.PUMP, "setExtendedBolus: Correct extended bolus already set. Current: " + danaPump.getExtendedBolusAmount() + " Asked: " + insulin); return result; } + if (danaPump.isExtendedInProgress()) { + cancelExtendedBolus(); + if (danaPump.isExtendedInProgress()) { + result.enacted(false).success(false); + getAapsLogger().debug(LTag.PUMP, "cancelExtendedBolus failed. aborting setExtendedBolus"); + return result; + } + } boolean connectionOK = sExecutionService.extendedBolus(insulin, durationInHalfHours); - if (connectionOK && pump.isExtendedInProgress() && Math.abs(pump.getExtendedBolusAmount() - insulin) < getPumpDescription().getExtendedBolusStep()) { + if (connectionOK && danaPump.isExtendedInProgress() && Math.abs(danaPump.getExtendedBolusAmount() - insulin) < getPumpDescription().getExtendedBolusStep()) { result.enacted(true) .success(true) .comment(R.string.ok) .isTempCancel(false) - .duration(pump.getExtendedBolusRemainingMinutes()) - .absolute(pump.getExtendedBolusAbsoluteRate()) + .duration(danaPump.getExtendedBolusRemainingMinutes()) + .absolute(danaPump.getExtendedBolusAbsoluteRate()) .isPercent(false); if (!sp.getBoolean("danar_useextended", false)) - result.bolusDelivered(pump.getExtendedBolusAmount()); + result.bolusDelivered(danaPump.getExtendedBolusAmount()); + pumpSync.syncExtendedBolusWithPumpId( + danaPump.getExtendedBolusStart(), + danaPump.getExtendedBolusAmount(), + danaPump.getExtendedBolusDuration(), + sp.getBoolean("danar_useextended", false), + danaPump.getExtendedBolusStart(), + getPumpDescription().getPumpType(), + serialNumber() + ); getAapsLogger().debug(LTag.PUMP, "setExtendedBolus: OK"); return result; } result.enacted(false).success(false).comment(R.string.danar_valuenotsetproperly); getAapsLogger().error("setExtendedBolus: Failed to extended bolus"); + getAapsLogger().error("inProgress: " + danaPump.isExtendedInProgress() + " start: " + danaPump.getExtendedBolusStart() + " amount: " + danaPump.getExtendedBolusAmount() + " duration: " + danaPump.getExtendedBolusDuration()); return result; } @NonNull @Override public PumpEnactResult cancelExtendedBolus() { PumpEnactResult result = new PumpEnactResult(getInjector()); - ExtendedBolus runningEB = activePlugin.getActiveTreatments().getExtendedBolusFromHistory(System.currentTimeMillis()); - if (runningEB != null) { + if (danaPump.isExtendedInProgress()) { sExecutionService.extendedBolusStop(); - result.enacted(true).isTempCancel(true); - } - if (!danaPump.isExtendedInProgress()) { - result.success(true).comment(R.string.ok); - getAapsLogger().debug(LTag.PUMP, "cancelExtendedBolus: OK"); + if (!danaPump.isExtendedInProgress()) { + result.success(true).enacted(true).isTempCancel(true); + pumpSync.syncStopExtendedBolusWithPumpId( + dateUtil.now(), + dateUtil.now(), + getPumpDescription().getPumpType(), + serialNumber() + ); + } else + result.success(false).enacted(false).isTempCancel(true); } else { - result.success(false).comment(R.string.danar_valuenotsetproperly); - getAapsLogger().error("cancelExtendedBolus: Failed to cancel extended bolus"); + result.success(true).comment(R.string.ok).isTempCancel(true); + getAapsLogger().debug(LTag.PUMP, "cancelExtendedBolus: OK"); } return result; } @@ -364,23 +392,22 @@ public abstract class AbstractDanaRPlugin extends PumpPluginBase implements Pump try { battery.put("percent", pump.getBatteryRemaining()); status.put("status", pump.getPumpSuspended() ? "suspended" : "normal"); - status.put("timestamp", DateUtil.toISOString(pump.getLastConnection())); + status.put("timestamp", dateUtil.toISOString(pump.getLastConnection())); extended.put("Version", version); if (pump.getLastBolusTime() != 0) { extended.put("LastBolus", dateUtil.dateAndTimeString(pump.getLastBolusTime())); extended.put("LastBolusAmount", pump.getLastBolusAmount()); } - TemporaryBasal tb = activePlugin.getActiveTreatments().getRealTempBasalFromHistory(now); - if (tb != null) { - extended.put("TempBasalAbsoluteRate", tb.tempBasalConvertedToAbsolute(now, profile)); - extended.put("TempBasalStart", dateUtil.dateAndTimeString(tb.date)); - extended.put("TempBasalRemaining", tb.getPlannedRemainingMinutes()); + PumpSync.PumpState pumpState = pumpSync.expectedPumpState(); + if (pumpState.getTemporaryBasal() != null) { + extended.put("TempBasalAbsoluteRate", PumpStateExtensionKt.convertedToAbsolute(pumpState.getTemporaryBasal(), now, profile)); + extended.put("TempBasalStart", dateUtil.dateAndTimeString(pumpState.getTemporaryBasal().getTimestamp())); + extended.put("TempBasalRemaining", PumpStateExtensionKt.getPlannedRemainingMinutes(pumpState.getTemporaryBasal())); } - ExtendedBolus eb = activePlugin.getActiveTreatments().getExtendedBolusFromHistory(now); - if (eb != null) { - extended.put("ExtendedBolusAbsoluteRate", eb.absoluteRate()); - extended.put("ExtendedBolusStart", dateUtil.dateAndTimeString(eb.date)); - extended.put("ExtendedBolusRemaining", eb.getPlannedRemainingMinutes()); + if (pumpState.getExtendedBolus() != null) { + extended.put("ExtendedBolusAbsoluteRate", pumpState.getExtendedBolus().getRate()); + extended.put("ExtendedBolusStart", dateUtil.dateAndTimeString(pumpState.getExtendedBolus().getTimestamp())); + extended.put("ExtendedBolusRemaining", PumpStateExtensionKt.getPlannedRemainingMinutes(pumpState.getExtendedBolus())); } extended.put("BaseBasalRate", getBaseBasalRate()); try { @@ -392,7 +419,7 @@ public abstract class AbstractDanaRPlugin extends PumpPluginBase implements Pump pumpJson.put("status", status); pumpJson.put("extended", extended); pumpJson.put("reservoir", (int) pump.getReservoirRemainingUnits()); - pumpJson.put("clock", DateUtil.toISOString(new Date())); + pumpJson.put("clock", dateUtil.toISOString(dateUtil.now())); } catch (JSONException e) { getAapsLogger().error("Unhandled exception", e); } @@ -459,29 +486,27 @@ public abstract class AbstractDanaRPlugin extends PumpPluginBase implements Pump // Reply for sms communicator @NonNull public String shortStatus(boolean veryShort) { - DanaPump pump = danaPump; String ret = ""; - if (pump.getLastConnection() != 0) { - long agoMilliseconds = System.currentTimeMillis() - pump.getLastConnection(); + if (danaPump.getLastConnection() != 0) { + long agoMilliseconds = System.currentTimeMillis() - danaPump.getLastConnection(); int agoMin = (int) (agoMilliseconds / 60d / 1000d); ret += "LastConn: " + agoMin + " min ago\n"; } - if (pump.getLastBolusTime() != 0) { - ret += "LastBolus: " + DecimalFormatter.INSTANCE.to2Decimal(pump.getLastBolusAmount()) + "U @" + android.text.format.DateFormat.format("HH:mm", pump.getLastBolusTime()) + "\n"; + if (danaPump.getLastBolusTime() != 0) { + ret += "LastBolus: " + DecimalFormatter.INSTANCE.to2Decimal(danaPump.getLastBolusAmount()) + "U @" + android.text.format.DateFormat.format("HH:mm", danaPump.getLastBolusTime()) + "\n"; } - TemporaryBasal activeTemp = activePlugin.getActiveTreatments().getRealTempBasalFromHistory(System.currentTimeMillis()); - if (activeTemp != null) { - ret += "Temp: " + activeTemp.toStringFull() + "\n"; + PumpSync.PumpState pumpState = pumpSync.expectedPumpState(); + if (pumpState.getTemporaryBasal() != null) { + ret += "Temp: " + PumpStateExtensionKt.toStringFull(pumpState.getTemporaryBasal(), dateUtil) + "\n"; } - ExtendedBolus activeExtendedBolus = activePlugin.getActiveTreatments().getExtendedBolusFromHistory(System.currentTimeMillis()); - if (activeExtendedBolus != null) { - ret += "Extended: " + activeExtendedBolus.toString() + "\n"; + if (pumpState.getExtendedBolus() != null) { + ret += "Extended: " + PumpStateExtensionKt.toStringFull(pumpState.getExtendedBolus(), dateUtil) + "\n"; } if (!veryShort) { - ret += "TDD: " + DecimalFormatter.INSTANCE.to0Decimal(pump.getDailyTotalUnits()) + " / " + pump.getMaxDailyTotalUnits() + " U\n"; + ret += "TDD: " + DecimalFormatter.INSTANCE.to0Decimal(danaPump.getDailyTotalUnits()) + " / " + danaPump.getMaxDailyTotalUnits() + " U\n"; } - ret += "Reserv: " + DecimalFormatter.INSTANCE.to0Decimal(pump.getReservoirRemainingUnits()) + "U\n"; - ret += "Batt: " + pump.getBatteryRemaining() + "\n"; + ret += "Reserv: " + DecimalFormatter.INSTANCE.to0Decimal(danaPump.getReservoirRemainingUnits()) + "U\n"; + ret += "Batt: " + danaPump.getBatteryRemaining() + "\n"; return ret; } // TODO: daily total constraint 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 221316292c..6aaa1f2bf2 100644 --- a/danar/src/main/java/info/nightscout/androidaps/danar/DanaRPlugin.java +++ b/danar/src/main/java/info/nightscout/androidaps/danar/DanaRPlugin.java @@ -17,23 +17,23 @@ import info.nightscout.androidaps.danar.services.DanaRExecutionService; import info.nightscout.androidaps.data.DetailedBolusInfo; import info.nightscout.androidaps.data.Profile; import info.nightscout.androidaps.data.PumpEnactResult; -import info.nightscout.androidaps.db.ExtendedBolus; -import info.nightscout.androidaps.db.TemporaryBasal; -import info.nightscout.androidaps.db.Treatment; import info.nightscout.androidaps.events.EventAppExit; import info.nightscout.androidaps.events.EventPreferenceChange; -import info.nightscout.androidaps.interfaces.ActivePluginProvider; +import info.nightscout.androidaps.interfaces.ActivePlugin; 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; import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker; +import info.nightscout.androidaps.plugins.general.overview.events.EventOverviewBolusProgress; 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; @@ -58,14 +58,15 @@ public class DanaRPlugin extends AbstractDanaRPlugin { Context context, ResourceHelper resourceHelper, ConstraintChecker constraintChecker, - ActivePluginProvider activePlugin, + ActivePlugin activePlugin, SP sp, 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; @@ -73,7 +74,7 @@ public class DanaRPlugin extends AbstractDanaRPlugin { this.fabricPrivacy = fabricPrivacy; useExtendedBoluses = sp.getBoolean(R.string.key_danar_useextended, false); - pumpDescription.setPumpDescription(PumpType.DanaR); + pumpDescription.setPumpDescription(PumpType.DANA_R); } @Override @@ -88,7 +89,7 @@ public class DanaRPlugin extends AbstractDanaRPlugin { boolean previousValue = useExtendedBoluses; useExtendedBoluses = sp.getBoolean(R.string.key_danar_useextended, false); - if (useExtendedBoluses != previousValue && activePlugin.getActiveTreatments().isInHistoryExtendedBolusInProgress()) { + if (useExtendedBoluses != previousValue && pumpSync.expectedPumpState().getExtendedBolus() != null) { sExecutionService.extendedBolusStop(); } } @@ -161,8 +162,7 @@ public class DanaRPlugin extends AbstractDanaRPlugin { public PumpEnactResult deliverTreatment(DetailedBolusInfo detailedBolusInfo) { detailedBolusInfo.insulin = constraintChecker.applyBolusConstraints(new Constraint<>(detailedBolusInfo.insulin)).value(); if (detailedBolusInfo.insulin > 0 || detailedBolusInfo.carbs > 0) { - Treatment t = new Treatment(); - t.isSMB = detailedBolusInfo.isSMB; + EventOverviewBolusProgress.Treatment t = new EventOverviewBolusProgress.Treatment(0, 0, detailedBolusInfo.getBolusType() == DetailedBolusInfo.BolusType.SMB); boolean connectionOK = false; if (detailedBolusInfo.insulin > 0 || detailedBolusInfo.carbs > 0) connectionOK = sExecutionService.bolus(detailedBolusInfo.insulin, (int) detailedBolusInfo.carbs, detailedBolusInfo.carbTime, t); @@ -176,8 +176,22 @@ public class DanaRPlugin extends AbstractDanaRPlugin { result.comment(R.string.ok); aapsLogger.debug(LTag.PUMP, "deliverTreatment: OK. Asked: " + detailedBolusInfo.insulin + " Delivered: " + result.getBolusDelivered()); detailedBolusInfo.insulin = t.insulin; - detailedBolusInfo.date = System.currentTimeMillis(); - activePlugin.getActiveTreatments().addToHistoryTreatment(detailedBolusInfo, false); + detailedBolusInfo.timestamp = System.currentTimeMillis(); + 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()); @@ -189,7 +203,7 @@ public class DanaRPlugin extends AbstractDanaRPlugin { // This is called from APS @NonNull @Override - public PumpEnactResult setTempBasalAbsolute(double absoluteRate, int durationInMinutes, @NonNull Profile profile, boolean enforceNew) { + public PumpEnactResult setTempBasalAbsolute(double absoluteRate, int durationInMinutes, @NonNull Profile profile, boolean enforceNew, @NonNull PumpSync.TemporaryBasalType tbrType) { // Recheck pump status if older than 30 min //This should not be needed while using queue because connection should be done before calling this PumpEnactResult result = new PumpEnactResult(getInjector()); @@ -201,18 +215,14 @@ public class DanaRPlugin extends AbstractDanaRPlugin { final boolean doHighTemp = absoluteRate > getBaseBasalRate() && !useExtendedBoluses; final boolean doExtendedTemp = absoluteRate > getBaseBasalRate() && useExtendedBoluses; - long now = System.currentTimeMillis(); - TemporaryBasal activeTemp = activePlugin.getActiveTreatments().getRealTempBasalFromHistory(now); - ExtendedBolus activeExtended = activePlugin.getActiveTreatments().getExtendedBolusFromHistory(now); - if (doTempOff) { // If extended in progress - if (activeExtended != null && useExtendedBoluses) { + if (danaPump.isExtendedInProgress() && useExtendedBoluses) { aapsLogger.debug(LTag.PUMP, "setTempBasalAbsolute: Stopping extended bolus (doTempOff)"); return cancelExtendedBolus(); } // If temp in progress - if (activeTemp != null) { + if (danaPump.isTempBasalInProgress()) { aapsLogger.debug(LTag.PUMP, "setTempBasalAbsolute: Stopping temp basal (doTempOff)"); return cancelRealTempBasal(); } @@ -233,7 +243,7 @@ public class DanaRPlugin extends AbstractDanaRPlugin { aapsLogger.debug(LTag.PUMP, "setTempBasalAbsolute: Calculated percent rate: " + percentRate); // If extended in progress - if (activeExtended != null && useExtendedBoluses) { + if (danaPump.isExtendedInProgress() && useExtendedBoluses) { aapsLogger.debug(LTag.PUMP, "setTempBasalAbsolute: Stopping extended bolus (doLowTemp || doHighTemp)"); result = cancelExtendedBolus(); if (!result.getSuccess()) { @@ -242,14 +252,14 @@ public class DanaRPlugin extends AbstractDanaRPlugin { } } // Check if some temp is already in progress - if (activeTemp != null) { + if (danaPump.isTempBasalInProgress()) { // Correct basal already set ? - aapsLogger.debug(LTag.PUMP, "setTempBasalAbsolute: currently running: " + activeTemp.toString()); - if (activeTemp.percentRate == percentRate && activeTemp.getPlannedRemainingMinutes() > 4) { + aapsLogger.debug(LTag.PUMP, "setTempBasalAbsolute: currently running: " + danaPump.temporaryBasalToString()); + if (danaPump.getTempBasalPercent() == percentRate && danaPump.getTempBasalRemainingMin() > 4) { if (enforceNew) { cancelTempBasal(true); } else { - result.success(true).percent(percentRate).enacted(false).duration(activeTemp.getPlannedRemainingMinutes()).isPercent(true).isTempCancel(false); + result.success(true).percent(percentRate).enacted(false).duration(danaPump.getTempBasalRemainingMin()).isPercent(true).isTempCancel(false); aapsLogger.debug(LTag.PUMP, "setTempBasalAbsolute: Correct temp basal already set (doLowTemp || doHighTemp)"); return result; } @@ -257,11 +267,11 @@ public class DanaRPlugin extends AbstractDanaRPlugin { } // Convert duration from minutes to hours aapsLogger.debug(LTag.PUMP, "setTempBasalAbsolute: Setting temp basal " + percentRate + "% for " + durationInMinutes + " minutes (doLowTemp || doHighTemp)"); - return setTempBasalPercent(percentRate, durationInMinutes, profile, false); + return setTempBasalPercent(percentRate, durationInMinutes, profile, false, tbrType); } if (doExtendedTemp) { // Check if some temp is already in progress - if (activeTemp != null) { + if (danaPump.isTempBasalInProgress()) { aapsLogger.debug(LTag.PUMP, "setTempBasalAbsolute: Stopping temp basal (doExtendedTemp)"); result = cancelRealTempBasal(); // Check for proper result @@ -280,11 +290,11 @@ public class DanaRPlugin extends AbstractDanaRPlugin { extendedRateToSet = Round.roundTo(extendedRateToSet, pumpDescription.getExtendedBolusStep() * 2); // *2 because of half hours // What is current rate of extended bolusing in u/h? - aapsLogger.debug(LTag.PUMP, "setTempBasalAbsolute: Extended bolus in progress: " + (activeExtended != null) + " rate: " + danaPump.getExtendedBolusAbsoluteRate() + "U/h duration remaining: " + danaPump.getExtendedBolusRemainingMinutes() + "min"); + aapsLogger.debug(LTag.PUMP, "setTempBasalAbsolute: Extended bolus in progress: " + (danaPump.isExtendedInProgress()) + " rate: " + danaPump.getExtendedBolusAbsoluteRate() + "U/h duration remaining: " + danaPump.getExtendedBolusRemainingMinutes() + "min"); aapsLogger.debug(LTag.PUMP, "setTempBasalAbsolute: Rate to set: " + extendedRateToSet + "U/h"); // Compare with extended rate in progress - if (activeExtended != null && Math.abs(danaPump.getExtendedBolusAbsoluteRate() - extendedRateToSet) < getPumpDescription().getExtendedBolusStep()) { + if (danaPump.isExtendedInProgress() && Math.abs(danaPump.getExtendedBolusAbsoluteRate() - extendedRateToSet) < getPumpDescription().getExtendedBolusStep()) { // correct extended already set result.success(true).absolute(danaPump.getExtendedBolusAbsoluteRate()).enacted(false).duration(danaPump.getExtendedBolusRemainingMinutes()).isPercent(false).isTempCancel(false); aapsLogger.debug(LTag.PUMP, "setTempBasalAbsolute: Correct extended already set"); @@ -311,9 +321,9 @@ public class DanaRPlugin extends AbstractDanaRPlugin { @NonNull @Override public PumpEnactResult cancelTempBasal(boolean force) { - if (activePlugin.getActiveTreatments().isInHistoryRealTempBasalInProgress()) + if (danaPump.isTempBasalInProgress()) return cancelRealTempBasal(); - if (activePlugin.getActiveTreatments().isInHistoryExtendedBolusInProgress() && useExtendedBoluses) { + if (danaPump.isExtendedInProgress() && useExtendedBoluses) { return cancelExtendedBolus(); } PumpEnactResult result = new PumpEnactResult(getInjector()); @@ -323,22 +333,26 @@ public class DanaRPlugin extends AbstractDanaRPlugin { @NonNull @Override public PumpType model() { - return PumpType.DanaR; + return PumpType.DANA_R; } private PumpEnactResult cancelRealTempBasal() { PumpEnactResult result = new PumpEnactResult(getInjector()); - TemporaryBasal runningTB = activePlugin.getActiveTreatments().getTempBasalFromHistory(System.currentTimeMillis()); - if (runningTB != null) { + if (danaPump.isTempBasalInProgress()) { sExecutionService.tempBasalStop(); - result.enacted(true).isTempCancel(true); - } - if (!danaPump.isTempBasalInProgress()) { + if (!danaPump.isTempBasalInProgress()) { + pumpSync.syncStopTemporaryBasalWithPumpId( + dateUtil.now(), + dateUtil.now(), + getPumpDescription().getPumpType(), + serialNumber() + ); + result.success(true).enacted(true).isTempCancel(true); + } else + result.success(false).enacted(false).isTempCancel(true); + } else { result.success(true).isTempCancel(true).comment(R.string.ok); aapsLogger.debug(LTag.PUMP, "cancelRealTempBasal: OK"); - } else { - result.success(false).comment(R.string.danar_valuenotsetproperly).isTempCancel(true); - aapsLogger.error("cancelRealTempBasal: Failed to cancel temp basal"); } return result; } diff --git a/danar/src/main/java/info/nightscout/androidaps/danar/comm/MessageBase.java b/danar/src/main/java/info/nightscout/androidaps/danar/comm/MessageBase.java index 9f918a416c..7ac298d494 100644 --- a/danar/src/main/java/info/nightscout/androidaps/danar/comm/MessageBase.java +++ b/danar/src/main/java/info/nightscout/androidaps/danar/comm/MessageBase.java @@ -17,16 +17,17 @@ import info.nightscout.androidaps.dana.DanaPump; import info.nightscout.androidaps.danaRKorean.DanaRKoreanPlugin; import info.nightscout.androidaps.danaRv2.DanaRv2Plugin; import info.nightscout.androidaps.danar.DanaRPlugin; -import info.nightscout.androidaps.interfaces.ActivePluginProvider; +import info.nightscout.androidaps.interfaces.ActivePlugin; import info.nightscout.androidaps.interfaces.CommandQueueProvider; -import info.nightscout.androidaps.interfaces.ConfigBuilderInterface; +import info.nightscout.androidaps.interfaces.ConfigBuilder; import info.nightscout.androidaps.interfaces.DatabaseHelperInterface; +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; import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker; -import info.nightscout.androidaps.plugins.general.nsclient.NSUpload; import info.nightscout.androidaps.plugins.pump.common.bolusInfo.DetailedBolusInfoStorage; +import info.nightscout.androidaps.plugins.pump.common.bolusInfo.TemporaryBasalStorage; import info.nightscout.androidaps.utils.CRC; import info.nightscout.androidaps.utils.DateUtil; import info.nightscout.androidaps.utils.resources.ResourceHelper; @@ -46,12 +47,13 @@ public class MessageBase { @Inject public DanaRv2Plugin danaRv2Plugin; @Inject public RxBusWrapper rxBus; @Inject public ResourceHelper resourceHelper; - @Inject public ActivePluginProvider activePlugin; - @Inject public ConfigBuilderInterface configBuilder; + @Inject public ActivePlugin activePlugin; + @Inject public ConfigBuilder configBuilder; @Inject public CommandQueueProvider commandQueue; @Inject public DetailedBolusInfoStorage detailedBolusInfoStorage; + @Inject public TemporaryBasalStorage temporaryBasalStorage; @Inject public ConstraintChecker constraintChecker; - @Inject public NSUpload nsUpload; + @Inject public PumpSync pumpSync; @Inject public DatabaseHelperInterface databaseHelper; HasAndroidInjector injector; @@ -63,7 +65,7 @@ public class MessageBase { public MessageBase(HasAndroidInjector injector) { injector.androidInjector().inject(this); - this. injector = injector; + this.injector = injector; } public void SetCommand(int cmd) { diff --git a/danar/src/main/java/info/nightscout/androidaps/danar/comm/MsgError.kt b/danar/src/main/java/info/nightscout/androidaps/danar/comm/MsgError.kt index 4791424d8e..af635686a0 100644 --- a/danar/src/main/java/info/nightscout/androidaps/danar/comm/MsgError.kt +++ b/danar/src/main/java/info/nightscout/androidaps/danar/comm/MsgError.kt @@ -34,6 +34,6 @@ class MsgError( failed = false } aapsLogger.debug(LTag.PUMPCOMM, "Error detected: $errorString") - nsUpload.uploadError(errorString) + pumpSync.insertAnnouncement(errorString, null, danaPump.pumpType(), danaPump.serialNumber) } } \ No newline at end of file diff --git a/danar/src/main/java/info/nightscout/androidaps/danar/comm/MsgInitConnStatusBasic.kt b/danar/src/main/java/info/nightscout/androidaps/danar/comm/MsgInitConnStatusBasic.kt index c0b3864df1..82ab4f12ea 100644 --- a/danar/src/main/java/info/nightscout/androidaps/danar/comm/MsgInitConnStatusBasic.kt +++ b/danar/src/main/java/info/nightscout/androidaps/danar/comm/MsgInitConnStatusBasic.kt @@ -23,9 +23,9 @@ class MsgInitConnStatusBasic( danaPump.reservoirRemainingUnits = intFromBuff(bytes, 7, 3) / 750.0 danaPump.bolusBlocked = intFromBuff(bytes, 10, 1) == 1 danaPump.currentBasal = intFromBuff(bytes, 11, 2) / 100.0 - danaPump.tempBasalPercent = intFromBuff(bytes, 13, 1) - danaPump.isExtendedInProgress = intFromBuff(bytes, 14, 1) == 1 - danaPump.isTempBasalInProgress = intFromBuff(bytes, 15, 1) == 1 + val tempBasalPercent = intFromBuff(bytes, 13, 1) + val isExtendedInProgress = intFromBuff(bytes, 14, 1) == 1 + //val isTempBasalInProgress = intFromBuff(bytes, 15, 1) == 1 val statusBasalUDOption = intFromBuff(bytes, 16, 1) danaPump.isDualBolusInProgress = intFromBuff(bytes, 17, 1) == 1 val extendedBolusRate = intFromBuff(bytes, 18, 2) / 100.0 @@ -46,8 +46,8 @@ class MsgInitConnStatusBasic( aapsLogger.debug(LTag.PUMPCOMM, "Reservoir remaining units: " + danaPump.reservoirRemainingUnits) aapsLogger.debug(LTag.PUMPCOMM, "Bolus blocked: " + danaPump.bolusBlocked) aapsLogger.debug(LTag.PUMPCOMM, "Current basal: " + danaPump.currentBasal) - aapsLogger.debug(LTag.PUMPCOMM, "Current temp basal percent: " + danaPump.tempBasalPercent) - aapsLogger.debug(LTag.PUMPCOMM, "Is extended bolus running: " + danaPump.isExtendedInProgress) + aapsLogger.debug(LTag.PUMPCOMM, "Current temp basal percent: $tempBasalPercent") + aapsLogger.debug(LTag.PUMPCOMM, "Is extended bolus running: $isExtendedInProgress") aapsLogger.debug(LTag.PUMPCOMM, "statusBasalUDOption: $statusBasalUDOption") aapsLogger.debug(LTag.PUMPCOMM, "Is dual bolus running: " + danaPump.isDualBolusInProgress) aapsLogger.debug(LTag.PUMPCOMM, "Extended bolus rate: $extendedBolusRate") diff --git a/danar/src/main/java/info/nightscout/androidaps/danar/comm/MsgInitConnStatusTime.kt b/danar/src/main/java/info/nightscout/androidaps/danar/comm/MsgInitConnStatusTime.kt index 090d4ee443..8afdbfa611 100644 --- a/danar/src/main/java/info/nightscout/androidaps/danar/comm/MsgInitConnStatusTime.kt +++ b/danar/src/main/java/info/nightscout/androidaps/danar/comm/MsgInitConnStatusTime.kt @@ -28,6 +28,7 @@ class MsgInitConnStatusTime( danaRPlugin.setPluginEnabled(PluginType.PUMP, false) danaRPlugin.setFragmentVisible(PluginType.PUMP, false) danaPump.reset() // mark not initialized + pumpSync.connectNewPump() //If profile coming from pump, switch it as well configBuilder.storeSettings("ChangingDanaDriver") rxBus.send(EventRebuildTabs()) diff --git a/danar/src/main/java/info/nightscout/androidaps/danar/comm/MsgSetExtendedBolusStop.kt b/danar/src/main/java/info/nightscout/androidaps/danar/comm/MsgSetExtendedBolusStop.kt index 422fef6875..1e6c825f0d 100644 --- a/danar/src/main/java/info/nightscout/androidaps/danar/comm/MsgSetExtendedBolusStop.kt +++ b/danar/src/main/java/info/nightscout/androidaps/danar/comm/MsgSetExtendedBolusStop.kt @@ -19,7 +19,7 @@ class MsgSetExtendedBolusStop( aapsLogger.debug(LTag.PUMPBTCOMM, "Set extended bolus stop result: $result FAILED!!!") } else { failed = false - aapsLogger.debug(LTag.PUMPBTCOMM, "Set extended bolus stop result: $result") + aapsLogger.debug(LTag.PUMPBTCOMM, "Set extended bolus stop result: $result OK") } } } \ No newline at end of file diff --git a/danar/src/main/java/info/nightscout/androidaps/danar/comm/MsgStatus.kt b/danar/src/main/java/info/nightscout/androidaps/danar/comm/MsgStatus.kt index 92100e07b1..5e17e5d501 100644 --- a/danar/src/main/java/info/nightscout/androidaps/danar/comm/MsgStatus.kt +++ b/danar/src/main/java/info/nightscout/androidaps/danar/comm/MsgStatus.kt @@ -14,9 +14,9 @@ class MsgStatus( override fun handleMessage(bytes: ByteArray) { danaPump.dailyTotalUnits = intFromBuff(bytes, 0, 3) / 750.0 - danaPump.isExtendedInProgress = intFromBuff(bytes, 3, 1) == 1 - danaPump.extendedBolusMinutes = intFromBuff(bytes, 4, 2) - danaPump.extendedBolusAmount = intFromBuff(bytes, 6, 2) / 100.0 + val isExtendedInProgress = intFromBuff(bytes, 3, 1) == 1 + val extendedBolusMinutes = intFromBuff(bytes, 4, 2) + val extendedBolusAmount = intFromBuff(bytes, 6, 2) / 100.0 val lastBolusAmount = intFromBuff(bytes, 13, 2) / 100.0 if (lastBolusAmount != 0.0) { danaPump.lastBolusTime = dateTimeFromBuff(bytes, 8) @@ -24,9 +24,9 @@ class MsgStatus( } danaPump.iob = intFromBuff(bytes, 15, 2) / 100.0 aapsLogger.debug(LTag.PUMPCOMM, "Daily total: " + danaPump.dailyTotalUnits) - aapsLogger.debug(LTag.PUMPCOMM, "Is extended bolus running: " + danaPump.isExtendedInProgress) - aapsLogger.debug(LTag.PUMPCOMM, "Extended bolus min: " + danaPump.extendedBolusMinutes) - aapsLogger.debug(LTag.PUMPCOMM, "Extended bolus amount: " + danaPump.extendedBolusAmount) + aapsLogger.debug(LTag.PUMPCOMM, "Is extended bolus running: $isExtendedInProgress") + aapsLogger.debug(LTag.PUMPCOMM, "Extended bolus min: $extendedBolusMinutes") + aapsLogger.debug(LTag.PUMPCOMM, "Extended bolus amount: $extendedBolusAmount") aapsLogger.debug(LTag.PUMPCOMM, "Last bolus time: " + danaPump.lastBolusTime) aapsLogger.debug(LTag.PUMPCOMM, "Last bolus amount: " + danaPump.lastBolusAmount) aapsLogger.debug(LTag.PUMPCOMM, "IOB: " + danaPump.iob) diff --git a/danar/src/main/java/info/nightscout/androidaps/danar/comm/MsgStatusBolusExtended.kt b/danar/src/main/java/info/nightscout/androidaps/danar/comm/MsgStatusBolusExtended.kt index 2daf290d93..6795b472ef 100644 --- a/danar/src/main/java/info/nightscout/androidaps/danar/comm/MsgStatusBolusExtended.kt +++ b/danar/src/main/java/info/nightscout/androidaps/danar/comm/MsgStatusBolusExtended.kt @@ -1,10 +1,10 @@ package info.nightscout.androidaps.danar.comm import dagger.android.HasAndroidInjector -import info.nightscout.androidaps.db.ExtendedBolus -import info.nightscout.androidaps.db.Source import info.nightscout.androidaps.logging.LTag -import kotlin.math.ceil +import info.nightscout.androidaps.utils.T +import kotlin.math.abs +import kotlin.math.floor class MsgStatusBolusExtended( injector: HasAndroidInjector @@ -18,7 +18,7 @@ class MsgStatusBolusExtended( override fun handleMessage(bytes: ByteArray) { val isExtendedInProgress = intFromBuff(bytes, 0, 1) == 1 val extendedBolusHalfHours = intFromBuff(bytes, 1, 1) - val extendedBolusMinutes = extendedBolusHalfHours * 30 + val extendedBolusMinutes = extendedBolusHalfHours * 30L val extendedBolusAmount = intFromBuff(bytes, 2, 2) / 100.0 val extendedBolusSoFarInSecs = intFromBuff(bytes, 4, 3) // This is available only on korean, but not needed now @@ -28,14 +28,17 @@ class MsgStatusBolusExtended( val extendedBolusAbsoluteRate = if (isExtendedInProgress) extendedBolusAmount / extendedBolusMinutes * 60 else 0.0 val extendedBolusStart = if (isExtendedInProgress) getDateFromSecAgo(extendedBolusSoFarInSecs) else 0 val extendedBolusRemainingMinutes = extendedBolusMinutes - extendedBolusSoFarInMinutes - danaPump.isExtendedInProgress = isExtendedInProgress - danaPump.extendedBolusMinutes = extendedBolusMinutes - danaPump.extendedBolusAmount = extendedBolusAmount - danaPump.extendedBolusSoFarInMinutes = extendedBolusSoFarInMinutes - danaPump.extendedBolusAbsoluteRate = extendedBolusAbsoluteRate - danaPump.extendedBolusStart = extendedBolusStart - danaPump.extendedBolusRemainingMinutes = extendedBolusRemainingMinutes - updateExtendedBolusInDB() + if (isExtendedInProgress && !isWithin3Sec(extendedBolusStart)) { + danaPump.extendedBolusDuration = T.mins(extendedBolusMinutes).msecs() + danaPump.extendedBolusAmount = extendedBolusAmount + danaPump.extendedBolusStart = extendedBolusStart + aapsLogger.debug(LTag.PUMPCOMM, "New extended bolus detected") + } else if (!isExtendedInProgress) { + aapsLogger.debug(LTag.PUMPCOMM, "Extended bolus stopped. Previous state: ${danaPump.isExtendedInProgress}") + danaPump.isExtendedInProgress = false + } else { + aapsLogger.debug(LTag.PUMPCOMM, "No change in extended bolus. Current state: ${danaPump.isExtendedInProgress}") + } aapsLogger.debug(LTag.PUMPCOMM, "Is extended bolus running: $isExtendedInProgress") aapsLogger.debug(LTag.PUMPCOMM, "Extended bolus min: $extendedBolusMinutes") aapsLogger.debug(LTag.PUMPCOMM, "Extended bolus amount: $extendedBolusAmount") @@ -46,41 +49,9 @@ class MsgStatusBolusExtended( } private fun getDateFromSecAgo(tempBasalAgoSecs: Int): Long { - return (ceil(System.currentTimeMillis() / 1000.0) - tempBasalAgoSecs).toLong() * 1000 + return (floor(System.currentTimeMillis() / 1000.0) - tempBasalAgoSecs).toLong() * 1000 } - private fun updateExtendedBolusInDB() { - val now = System.currentTimeMillis() - val extendedBolus = activePlugin.activeTreatments.getExtendedBolusFromHistory(System.currentTimeMillis()) - if (extendedBolus != null) { - if (danaPump.isExtendedInProgress) { - if (extendedBolus.absoluteRate() != danaPump.extendedBolusAbsoluteRate) { // Close current extended - val exStop = ExtendedBolus(injector, danaPump.extendedBolusStart - 1000) - exStop.source = Source.USER - activePlugin.activeTreatments.addToHistoryExtendedBolus(exStop) - // Create new - val newExtended = ExtendedBolus(injector) - .date(danaPump.extendedBolusStart) - .insulin(danaPump.extendedBolusAmount) - .durationInMinutes(danaPump.extendedBolusMinutes) - .source(Source.USER) - activePlugin.activeTreatments.addToHistoryExtendedBolus(newExtended) - } - } else { - // Close current temp basal - val exStop = ExtendedBolus(injector, now) - .source(Source.USER) - activePlugin.activeTreatments.addToHistoryExtendedBolus(exStop) - } - } else { - if (danaPump.isExtendedInProgress) { // Create new - val newExtended = ExtendedBolus(injector) - .date(danaPump.extendedBolusStart) - .insulin(danaPump.extendedBolusAmount) - .durationInMinutes(danaPump.extendedBolusMinutes) - .source(Source.USER) - activePlugin.activeTreatments.addToHistoryExtendedBolus(newExtended) - } - } - } + // because there is no fixed timestamp of start allow update of tbr only if tbr start differs more + private fun isWithin3Sec(newStart: Long) = abs(newStart - danaPump.tempBasalStart) < 3000 } \ No newline at end of file diff --git a/danar/src/main/java/info/nightscout/androidaps/danar/comm/MsgStatusTempBasal.kt b/danar/src/main/java/info/nightscout/androidaps/danar/comm/MsgStatusTempBasal.kt index c354da3bb0..6196357bce 100644 --- a/danar/src/main/java/info/nightscout/androidaps/danar/comm/MsgStatusTempBasal.kt +++ b/danar/src/main/java/info/nightscout/androidaps/danar/comm/MsgStatusTempBasal.kt @@ -1,10 +1,10 @@ package info.nightscout.androidaps.danar.comm import dagger.android.HasAndroidInjector -import info.nightscout.androidaps.db.Source -import info.nightscout.androidaps.db.TemporaryBasal import info.nightscout.androidaps.logging.LTag -import kotlin.math.ceil +import info.nightscout.androidaps.utils.T +import kotlin.math.abs +import kotlin.math.floor class MsgStatusTempBasal( injector: HasAndroidInjector @@ -15,62 +15,42 @@ class MsgStatusTempBasal( aapsLogger.debug(LTag.PUMPCOMM, "New message") } + var isTempBasalInProgress = false + override fun handleMessage(bytes: ByteArray) { - val isTempBasalInProgress = intFromBuff(bytes, 0, 1) and 0x01 == 0x01 + isTempBasalInProgress = intFromBuff(bytes, 0, 1) and 0x01 == 0x01 val isAPSTempBasalInProgress = intFromBuff(bytes, 0, 1) and 0x02 == 0x02 var tempBasalPercent = intFromBuff(bytes, 1, 1) if (tempBasalPercent > 200) tempBasalPercent = (tempBasalPercent - 200) * 10 - val tempBasalTotalSec: Int = if (intFromBuff(bytes, 2, 1) == 150) 15 * 60 else if (intFromBuff(bytes, 2, 1) == 160) 30 * 60 else intFromBuff(bytes, 2, 1) * 60 * 60 + var tempBasalTotalMin = intFromBuff(bytes, 2, 1) * 60 + tempBasalTotalMin = if (tempBasalTotalMin == 150) 15 else if (tempBasalTotalMin == 160) 30 else tempBasalTotalMin + val tempBasalTotalSec = tempBasalTotalMin * 60 val tempBasalRunningSeconds = intFromBuff(bytes, 3, 3) val tempBasalRemainingMin = (tempBasalTotalSec - tempBasalRunningSeconds) / 60 - val tempBasalStart = if (isTempBasalInProgress) getDateFromTempBasalSecAgo(tempBasalRunningSeconds) else 0 - danaPump.isTempBasalInProgress = isTempBasalInProgress - danaPump.tempBasalPercent = tempBasalPercent - danaPump.tempBasalRemainingMin = tempBasalRemainingMin - danaPump.tempBasalTotalSec = tempBasalTotalSec - danaPump.tempBasalStart = tempBasalStart - updateTempBasalInDB() + val tempBasalStart = if (isTempBasalInProgress) getDateFromSecAgo(tempBasalRunningSeconds) else 0 + if (isTempBasalInProgress && !isWithin3Sec(tempBasalStart)) { + danaPump.tempBasalStart = tempBasalStart + danaPump.tempBasalPercent = tempBasalPercent + danaPump.tempBasalDuration = T.mins(tempBasalTotalMin.toLong()).msecs() + aapsLogger.debug(LTag.PUMPCOMM, "New temp basal detected") + } else if (!isTempBasalInProgress) { + aapsLogger.debug(LTag.PUMPCOMM, "Temp basal stopped. Previous state: ${danaPump.isTempBasalInProgress}") + danaPump.isTempBasalInProgress = false + } else { + aapsLogger.debug(LTag.PUMPCOMM, "No change in temp basal. Current state: ${danaPump.isTempBasalInProgress}") + } aapsLogger.debug(LTag.PUMPCOMM, "Is temp basal running: $isTempBasalInProgress") aapsLogger.debug(LTag.PUMPCOMM, "Is APS temp basal running: $isAPSTempBasalInProgress") aapsLogger.debug(LTag.PUMPCOMM, "Current temp basal percent: $tempBasalPercent") aapsLogger.debug(LTag.PUMPCOMM, "Current temp basal remaining min: $tempBasalRemainingMin") - aapsLogger.debug(LTag.PUMPCOMM, "Current temp basal total sec: $tempBasalTotalSec") - aapsLogger.debug(LTag.PUMPCOMM, "Current temp basal start: $tempBasalStart") + aapsLogger.debug(LTag.PUMPCOMM, "Current temp basal total min: $tempBasalTotalMin") + aapsLogger.debug(LTag.PUMPCOMM, "Current temp basal start: " + dateUtil.dateAndTimeString(tempBasalStart)) } - private fun getDateFromTempBasalSecAgo(tempBasalAgoSecs: Int): Long { - return (ceil(System.currentTimeMillis() / 1000.0) - tempBasalAgoSecs).toLong() * 1000 + private fun getDateFromSecAgo(tempBasalAgoSecs: Int): Long { + return (floor(dateUtil.now() / 1000.0) - tempBasalAgoSecs).toLong() * 1000 } - private fun updateTempBasalInDB() { - val now = System.currentTimeMillis() - if (activePlugin.activeTreatments.isInHistoryRealTempBasalInProgress) { - val tempBasal = activePlugin.activeTreatments.getRealTempBasalFromHistory(System.currentTimeMillis()) - if (danaPump.isTempBasalInProgress) { - if (tempBasal.percentRate != danaPump.tempBasalPercent) { // Close current temp basal - val tempStop = TemporaryBasal(injector).date(danaPump.tempBasalStart - 1000).source(Source.USER) - activePlugin.activeTreatments.addToHistoryTempBasal(tempStop) - // Create new - val newTempBasal = TemporaryBasal(injector) - .date(danaPump.tempBasalStart) - .percent(danaPump.tempBasalPercent) - .duration(danaPump.tempBasalTotalSec / 60) - .source(Source.USER) - activePlugin.activeTreatments.addToHistoryTempBasal(newTempBasal) - } - } else { // Close current temp basal - val tempStop = TemporaryBasal(injector).date(now).source(Source.USER) - activePlugin.activeTreatments.addToHistoryTempBasal(tempStop) - } - } else { - if (danaPump.isTempBasalInProgress) { // Create new - val newTempBasal = TemporaryBasal(injector) - .date(danaPump.tempBasalStart) - .percent(danaPump.tempBasalPercent) - .duration(danaPump.tempBasalTotalSec / 60) - .source(Source.USER) - activePlugin.activeTreatments.addToHistoryTempBasal(newTempBasal) - } - } - } + // because there is no fixed timestamp of start allow update of tbr only if tbr start differs more + private fun isWithin3Sec(newStart: Long) = abs(newStart - danaPump.tempBasalStart) < 3000 } \ No newline at end of file diff --git a/danar/src/main/java/info/nightscout/androidaps/danar/di/DanaRCommModule.kt b/danar/src/main/java/info/nightscout/androidaps/danar/di/DanaRCommModule.kt index f9c9b58f8d..6c157f6efb 100644 --- a/danar/src/main/java/info/nightscout/androidaps/danar/di/DanaRCommModule.kt +++ b/danar/src/main/java/info/nightscout/androidaps/danar/di/DanaRCommModule.kt @@ -3,7 +3,11 @@ package info.nightscout.androidaps.danar.di import dagger.Module import dagger.android.ContributesAndroidInjector import info.nightscout.androidaps.danaRKorean.comm.* -import info.nightscout.androidaps.danaRv2.comm.* +import info.nightscout.androidaps.danaRv2.comm.MsgCheckValue_v2 +import info.nightscout.androidaps.danaRv2.comm.MsgHistoryEvents_v2 +import info.nightscout.androidaps.danaRv2.comm.MsgSetAPSTempBasalStart_v2 +import info.nightscout.androidaps.danaRv2.comm.MsgSetHistoryEntry_v2 +import info.nightscout.androidaps.danaRv2.comm.MsgStatusAPS_v2 import info.nightscout.androidaps.danar.comm.* @Module @@ -69,8 +73,6 @@ abstract class DanaRCommModule { @ContributesAndroidInjector abstract fun contributesMsgSetAPSTempBasalStart_v2(): MsgSetAPSTempBasalStart_v2 @ContributesAndroidInjector abstract fun contributesMsgSetHistoryEntry_v2(): MsgSetHistoryEntry_v2 @ContributesAndroidInjector abstract fun contributesMsgStatusAPS_v2(): MsgStatusAPS_v2 - @ContributesAndroidInjector abstract fun contributesMsgStatusBolusExtended_v2(): MsgStatusBolusExtended_v2 - @ContributesAndroidInjector abstract fun contributesMsgStatusTempBasal_v2(): MsgStatusTempBasal_v2 @ContributesAndroidInjector abstract fun contributesMsgCheckValue_k(): MsgCheckValue_k @ContributesAndroidInjector abstract fun contributesMsgInitConnStatusBasic_k(): MsgInitConnStatusBasic_k diff --git a/danar/src/main/java/info/nightscout/androidaps/danar/services/AbstractDanaRExecutionService.java b/danar/src/main/java/info/nightscout/androidaps/danar/services/AbstractDanaRExecutionService.java index 920ffe617c..51e81ab5e7 100644 --- a/danar/src/main/java/info/nightscout/androidaps/danar/services/AbstractDanaRExecutionService.java +++ b/danar/src/main/java/info/nightscout/androidaps/danar/services/AbstractDanaRExecutionService.java @@ -35,14 +35,18 @@ import info.nightscout.androidaps.danar.comm.MsgPCCommStart; import info.nightscout.androidaps.danar.comm.MsgPCCommStop; import info.nightscout.androidaps.data.Profile; import info.nightscout.androidaps.data.PumpEnactResult; -import info.nightscout.androidaps.db.Treatment; import info.nightscout.androidaps.events.EventAppExit; import info.nightscout.androidaps.events.EventBTChange; import info.nightscout.androidaps.events.EventPumpStatusChanged; +import info.nightscout.androidaps.interfaces.ActivePlugin; import info.nightscout.androidaps.interfaces.DatabaseHelperInterface; +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; +import info.nightscout.androidaps.plugins.general.overview.events.EventNewNotification; +import info.nightscout.androidaps.plugins.general.overview.events.EventOverviewBolusProgress; +import info.nightscout.androidaps.plugins.general.overview.notifications.Notification; import info.nightscout.androidaps.utils.DateUtil; import info.nightscout.androidaps.utils.FabricPrivacy; import info.nightscout.androidaps.utils.ToastUtils; @@ -67,6 +71,8 @@ public abstract class AbstractDanaRExecutionService extends DaggerService { @Inject DateUtil dateUtil; @Inject DatabaseHelperInterface databaseHelper; @Inject AapsSchedulers aapsSchedulers; + @Inject PumpSync pumpSync; + @Inject ActivePlugin activePlugin; private final CompositeDisposable disposable = new CompositeDisposable(); @@ -95,7 +101,7 @@ public abstract class AbstractDanaRExecutionService extends DaggerService { public abstract PumpEnactResult loadEvents(); - public abstract boolean bolus(double amount, int carbs, long carbtime, final Treatment t); + public abstract boolean bolus(double amount, int carbs, long carbtime, final EventOverviewBolusProgress.Treatment t); public abstract boolean highTempBasal(int percent, int durationInMinutes); // Rv2 only @@ -258,11 +264,11 @@ public abstract class AbstractDanaRExecutionService extends DaggerService { msg = new MsgHistorySuspend(injector); break; } - danaPump.setHistoryDoneReceived(false); + danaPump.historyDoneReceived = false; mSerialIOThread.sendMessage(new MsgPCCommStart(injector)); SystemClock.sleep(400); mSerialIOThread.sendMessage(msg); - while (!danaPump.getHistoryDoneReceived() && mRfcommSocket.isConnected()) { + while (!danaPump.historyDoneReceived && mRfcommSocket.isConnected()) { SystemClock.sleep(100); } SystemClock.sleep(200); @@ -273,7 +279,7 @@ public abstract class AbstractDanaRExecutionService extends DaggerService { protected void waitForWholeMinute() { while (true) { - long time = DateUtil.now(); + long time = dateUtil.now(); long timeToWholeMinute = (60000 - time % 60000); if (timeToWholeMinute > 59800 || timeToWholeMinute < 3000) break; @@ -281,4 +287,102 @@ public abstract class AbstractDanaRExecutionService extends DaggerService { SystemClock.sleep(Math.min(timeToWholeMinute, 100)); } } + + protected void doSanityCheck() { + PumpSync.PumpState pumpState = pumpSync.expectedPumpState(); + + // Temporary basal + if (pumpState.getTemporaryBasal() != null) { + if (danaPump.isTempBasalInProgress()) { + if (pumpState.getTemporaryBasal().getRate() != danaPump.getTempBasalPercent() + || Math.abs(pumpState.getTemporaryBasal().getTimestamp() - danaPump.getTempBasalStart()) > 10000 + ) { // Close current temp basal + Notification notification = new Notification(Notification.UNSUPPORTED_ACTION_IN_PUMP, resourceHelper.gs(R.string.unsupported_action_in_pump), Notification.URGENT); + rxBus.send(new EventNewNotification(notification)); + aapsLogger.error(LTag.PUMP, "Different temporary basal found running AAPS: " + (pumpState.getTemporaryBasal() + " DanaPump " + danaPump.temporaryBasalToString())); + pumpSync.syncTemporaryBasalWithPumpId( + danaPump.getTempBasalStart(), + danaPump.getTempBasalPercent(), danaPump.getTempBasalDuration(), + false, + PumpSync.TemporaryBasalType.NORMAL, + danaPump.getTempBasalStart(), + activePlugin.getActivePump().model(), + activePlugin.getActivePump().serialNumber() + ); + } + } else { + pumpSync.syncStopTemporaryBasalWithPumpId( + dateUtil.now(), + dateUtil.now(), + activePlugin.getActivePump().model(), + activePlugin.getActivePump().serialNumber() + ); + Notification notification = new Notification(Notification.UNSUPPORTED_ACTION_IN_PUMP, resourceHelper.gs(R.string.unsupported_action_in_pump), Notification.URGENT); + rxBus.send(new EventNewNotification(notification)); + aapsLogger.error(LTag.PUMP, "Temporary basal should not be running. Sending stop to AAPS"); + } + } else { + if (danaPump.isTempBasalInProgress()) { // Create new + pumpSync.syncTemporaryBasalWithPumpId( + danaPump.getTempBasalStart(), + danaPump.getTempBasalPercent(), danaPump.getTempBasalDuration(), + false, + PumpSync.TemporaryBasalType.NORMAL, + danaPump.getTempBasalStart(), + activePlugin.getActivePump().model(), + activePlugin.getActivePump().serialNumber() + ); + Notification notification = new Notification(Notification.UNSUPPORTED_ACTION_IN_PUMP, resourceHelper.gs(R.string.unsupported_action_in_pump), Notification.URGENT); + rxBus.send(new EventNewNotification(notification)); + aapsLogger.error(LTag.PUMP, "Temporary basal should be running: DanaPump " + danaPump.temporaryBasalToString()); + } + } + // Extended bolus + if (pumpState.getExtendedBolus() != null) { + if (danaPump.isExtendedInProgress()) { + if (pumpState.getExtendedBolus().getRate() != danaPump.getExtendedBolusAbsoluteRate() + || Math.abs(pumpState.getExtendedBolus().getTimestamp() - danaPump.getExtendedBolusStart()) > 10000 + ) { // Close current extended + Notification notification = new Notification(Notification.UNSUPPORTED_ACTION_IN_PUMP, resourceHelper.gs(R.string.unsupported_action_in_pump), Notification.URGENT); + rxBus.send(new EventNewNotification(notification)); + aapsLogger.error(LTag.PUMP, "Different extended bolus found running AAPS: " + (pumpState.getExtendedBolus() + " DanaPump " + danaPump.extendedBolusToString())); + pumpSync.syncExtendedBolusWithPumpId( + danaPump.getExtendedBolusStart(), + danaPump.getExtendedBolusAmount(), + danaPump.getExtendedBolusDuration(), + activePlugin.getActivePump().isFakingTempsByExtendedBoluses(), + danaPump.getTempBasalStart(), + activePlugin.getActivePump().model(), + activePlugin.getActivePump().serialNumber() + ); + } + } else { + pumpSync.syncStopExtendedBolusWithPumpId( + dateUtil.now(), + dateUtil.now(), + activePlugin.getActivePump().model(), + activePlugin.getActivePump().serialNumber() + ); + Notification notification = new Notification(Notification.UNSUPPORTED_ACTION_IN_PUMP, resourceHelper.gs(R.string.unsupported_action_in_pump), Notification.URGENT); + rxBus.send(new EventNewNotification(notification)); + aapsLogger.error(LTag.PUMP, "Extended bolus should not be running. Sending stop to AAPS"); + } + } else { + if (danaPump.isExtendedInProgress()) { // Create new + Notification notification = new Notification(Notification.UNSUPPORTED_ACTION_IN_PUMP, resourceHelper.gs(R.string.unsupported_action_in_pump), Notification.URGENT); + rxBus.send(new EventNewNotification(notification)); + aapsLogger.error(LTag.PUMP, "Extended bolus should not be running: DanaPump " + danaPump.extendedBolusToString()); + pumpSync.syncExtendedBolusWithPumpId( + danaPump.getExtendedBolusStart(), + danaPump.getExtendedBolusAmount(), + danaPump.getExtendedBolusDuration(), + activePlugin.getActivePump().isFakingTempsByExtendedBoluses(), + danaPump.getTempBasalStart(), + activePlugin.getActivePump().model(), + activePlugin.getActivePump().serialNumber() + ); + } + } + + } } diff --git a/danar/src/main/java/info/nightscout/androidaps/danar/services/DanaRExecutionService.java b/danar/src/main/java/info/nightscout/androidaps/danar/services/DanaRExecutionService.java index 9b3fcd079d..bd12d27e2d 100644 --- a/danar/src/main/java/info/nightscout/androidaps/danar/services/DanaRExecutionService.java +++ b/danar/src/main/java/info/nightscout/androidaps/danar/services/DanaRExecutionService.java @@ -45,25 +45,22 @@ import info.nightscout.androidaps.danar.comm.MsgStatusBolusExtended; import info.nightscout.androidaps.danar.comm.MsgStatusTempBasal; import info.nightscout.androidaps.data.Profile; import info.nightscout.androidaps.data.PumpEnactResult; -import info.nightscout.androidaps.db.Treatment; import info.nightscout.androidaps.dialogs.BolusProgressDialog; import info.nightscout.androidaps.events.EventInitializationChanged; import info.nightscout.androidaps.events.EventProfileNeedsUpdate; import info.nightscout.androidaps.events.EventPumpStatusChanged; -import info.nightscout.androidaps.interfaces.ActivePluginProvider; import info.nightscout.androidaps.interfaces.CommandQueueProvider; import info.nightscout.androidaps.interfaces.ProfileFunction; +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; -import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker; -import info.nightscout.androidaps.plugins.general.nsclient.NSUpload; import info.nightscout.androidaps.plugins.general.overview.events.EventNewNotification; import info.nightscout.androidaps.plugins.general.overview.events.EventOverviewBolusProgress; import info.nightscout.androidaps.plugins.general.overview.notifications.Notification; +import info.nightscout.androidaps.plugins.pump.common.defs.PumpType; import info.nightscout.androidaps.queue.Callback; import info.nightscout.androidaps.queue.commands.Command; -import info.nightscout.androidaps.utils.DateUtil; import info.nightscout.androidaps.utils.resources.ResourceHelper; import info.nightscout.androidaps.utils.sharedPreferences.SP; @@ -71,15 +68,13 @@ public class DanaRExecutionService extends AbstractDanaRExecutionService { @Inject AAPSLogger aapsLogger; @Inject RxBusWrapper rxBus; @Inject ResourceHelper resourceHelper; - @Inject ConstraintChecker constraintChecker; @Inject DanaPump danaPump; @Inject DanaRPlugin danaRPlugin; @Inject DanaRKoreanPlugin danaRKoreanPlugin; @Inject CommandQueueProvider commandQueue; @Inject MessageHashTableR messageHashTableR; - @Inject ActivePluginProvider activePlugin; @Inject ProfileFunction profileFunction; - @Inject NSUpload nsUpload; + @Inject PumpSync pumpSync; @Inject SP sp; @Inject HasAndroidInjector injector; @@ -195,7 +190,7 @@ public class DanaRExecutionService extends AbstractDanaRExecutionService { long timeDiff = (danaPump.getPumpTime() - System.currentTimeMillis()) / 1000L; aapsLogger.debug(LTag.PUMP, "Pump time difference: " + timeDiff + " seconds"); if (Math.abs(timeDiff) > 10) { - mSerialIOThread.sendMessage(new MsgSetTime(injector, DateUtil.now())); + mSerialIOThread.sendMessage(new MsgSetTime(injector, dateUtil.now())); mSerialIOThread.sendMessage(new MsgSettingPumpTime(injector)); timeDiff = (danaPump.getPumpTime() - System.currentTimeMillis()) / 1000L; aapsLogger.debug(LTag.PUMP, "Pump time difference: " + timeDiff + " seconds"); @@ -211,10 +206,12 @@ public class DanaRExecutionService extends AbstractDanaRExecutionService { if (System.currentTimeMillis() > lastApproachingDailyLimit + 30 * 60 * 1000) { Notification reportFail = new Notification(Notification.APPROACHING_DAILY_LIMIT, resourceHelper.gs(R.string.approachingdailylimit), Notification.URGENT); rxBus.send(new EventNewNotification(reportFail)); - nsUpload.uploadError(resourceHelper.gs(R.string.approachingdailylimit) + ": " + danaPump.getDailyTotalUnits() + "/" + danaPump.getMaxDailyTotalUnits() + "U"); + pumpSync.insertAnnouncement(resourceHelper.gs(R.string.approachingdailylimit) + ": " + danaPump.getDailyTotalUnits() + "/" + danaPump.getMaxDailyTotalUnits() + "U", null, PumpType.DANA_R_KOREAN, danaRKoreanPlugin.serialNumber()); lastApproachingDailyLimit = System.currentTimeMillis(); } } + + doSanityCheck(); } catch (Exception e) { aapsLogger.error("Unhandled exception", e); } @@ -266,7 +263,7 @@ public class DanaRExecutionService extends AbstractDanaRExecutionService { return null; } - public boolean bolus(double amount, int carbs, long carbtime, final Treatment t) { + public boolean bolus(double amount, int carbs, long carbtime, final EventOverviewBolusProgress.Treatment t) { if (!isConnected()) return false; if (BolusProgressDialog.stopPressed) return false; diff --git a/danar/src/main/res/values/strings.xml b/danar/src/main/res/values/strings.xml index 0383441326..0a916d48c9 100644 --- a/danar/src/main/res/values/strings.xml +++ b/danar/src/main/res/values/strings.xml @@ -1,4 +1,5 @@ danar_pump_settings + Unsupported action in pump. Use AndroidAPS UI only! \ No newline at end of file diff --git a/danar/src/main/res/xml/pref_danar.xml b/danar/src/main/res/xml/pref_danar.xml index 475c49531d..c7d45b8f12 100644 --- a/danar/src/main/res/xml/pref_danar.xml +++ b/danar/src/main/res/xml/pref_danar.xml @@ -33,12 +33,6 @@ android:key="@string/key_danar_useextended" android:title="@string/danar_useextended_title" /> - - \ No newline at end of file diff --git a/danar/src/main/res/xml/pref_danarkorean.xml b/danar/src/main/res/xml/pref_danarkorean.xml index 3e2944a2a3..96479baf58 100644 --- a/danar/src/main/res/xml/pref_danarkorean.xml +++ b/danar/src/main/res/xml/pref_danarkorean.xml @@ -26,12 +26,6 @@ android:key="@string/key_danar_useextended" android:title="@string/danar_useextended_title" /> - - \ No newline at end of file diff --git a/danar/src/test/java/info/nightscout/androidaps/TestBaseWithProfile.kt b/danar/src/test/java/info/nightscout/androidaps/TestBaseWithProfile.kt index e3e5c7391b..e3ca031cd5 100644 --- a/danar/src/test/java/info/nightscout/androidaps/TestBaseWithProfile.kt +++ b/danar/src/test/java/info/nightscout/androidaps/TestBaseWithProfile.kt @@ -4,9 +4,8 @@ import dagger.android.AndroidInjector import dagger.android.HasAndroidInjector import info.nightscout.androidaps.data.Profile import info.nightscout.androidaps.db.ProfileSwitch -import info.nightscout.androidaps.db.Treatment -import info.nightscout.androidaps.interfaces.ActivePluginProvider -import info.nightscout.androidaps.interfaces.ConfigInterface +import info.nightscout.androidaps.interfaces.ActivePlugin +import info.nightscout.androidaps.interfaces.Config import info.nightscout.androidaps.interfaces.ProfileFunction import info.nightscout.androidaps.interfaces.ProfileStore import info.nightscout.androidaps.interfaces.TreatmentsInterface @@ -24,14 +23,14 @@ import org.powermock.core.classloader.annotations.PrepareForTest @PrepareForTest(FabricPrivacy::class) open class TestBaseWithProfile : TestBase() { - @Mock lateinit var activePluginProvider: ActivePluginProvider + @Mock lateinit var activePluginProvider: ActivePlugin @Mock lateinit var resourceHelper: ResourceHelper @Mock lateinit var treatmentsInterface: TreatmentsInterface @Mock lateinit var fabricPrivacy: FabricPrivacy @Mock lateinit var profileFunction: ProfileFunction @Mock lateinit var defaultValueHelper: DefaultValueHelper @Mock lateinit var dateUtil: DateUtil - @Mock lateinit var configInterface: ConfigInterface + @Mock lateinit var config: Config val rxBus = RxBusWrapper(aapsSchedulers) @@ -43,7 +42,7 @@ open class TestBaseWithProfile : TestBase() { it.resourceHelper = resourceHelper it.rxBus = rxBus it.fabricPrivacy = fabricPrivacy - it.configInterface = configInterface + it.config = config } if (it is ProfileSwitch) { it.treatmentsPlugin = treatmentsInterface @@ -52,12 +51,6 @@ open class TestBaseWithProfile : TestBase() { it.resourceHelper = resourceHelper it.dateUtil = dateUtil } - if (it is Treatment) { - it.activePlugin = activePluginProvider - it.profileFunction = profileFunction - it.defaultValueHelper = defaultValueHelper - it.resourceHelper = resourceHelper - } } } diff --git a/danar/src/test/java/info/nightscout/androidaps/TestPumpPlugin.kt b/danar/src/test/java/info/nightscout/androidaps/TestPumpPlugin.kt index 97727ab5af..0cb1ec2e78 100644 --- a/danar/src/test/java/info/nightscout/androidaps/TestPumpPlugin.kt +++ b/danar/src/test/java/info/nightscout/androidaps/TestPumpPlugin.kt @@ -5,14 +5,15 @@ import info.nightscout.androidaps.data.DetailedBolusInfo import info.nightscout.androidaps.data.Profile import info.nightscout.androidaps.data.PumpEnactResult import info.nightscout.androidaps.interfaces.PumpDescription -import info.nightscout.androidaps.interfaces.PumpInterface +import info.nightscout.androidaps.interfaces.Pump +import info.nightscout.androidaps.interfaces.PumpSync import info.nightscout.androidaps.plugins.common.ManufacturerType import info.nightscout.androidaps.plugins.pump.common.defs.PumpType import info.nightscout.androidaps.utils.TimeChangeType import org.json.JSONObject @Suppress("MemberVisibilityCanBePrivate") -class TestPumpPlugin(val injector: HasAndroidInjector) : PumpInterface { +class TestPumpPlugin(val injector: HasAndroidInjector) : Pump { var connected = false var isProfileSet = true @@ -50,14 +51,14 @@ class TestPumpPlugin(val injector: HasAndroidInjector) : PumpInterface { override val batteryLevel: Int = 0 override fun deliverTreatment(detailedBolusInfo: DetailedBolusInfo): PumpEnactResult = PumpEnactResult(injector).success(true) override fun stopBolusDelivering() {} - override fun setTempBasalAbsolute(absoluteRate: Double, durationInMinutes: Int, profile: Profile, enforceNew: Boolean): PumpEnactResult = PumpEnactResult(injector).success(true) - override fun setTempBasalPercent(percent: Int, durationInMinutes: Int, profile: Profile, enforceNew: Boolean): PumpEnactResult = PumpEnactResult(injector).success(true) + override fun setTempBasalAbsolute(absoluteRate: Double, durationInMinutes: Int, profile: Profile, enforceNew: Boolean, tbrType: PumpSync.TemporaryBasalType): PumpEnactResult = PumpEnactResult(injector).success(true) + override fun setTempBasalPercent(percent: Int, durationInMinutes: Int, profile: Profile, enforceNew: Boolean, tbrType: PumpSync.TemporaryBasalType): PumpEnactResult = PumpEnactResult(injector).success(true) override fun setExtendedBolus(insulin: Double, durationInMinutes: Int): PumpEnactResult = PumpEnactResult(injector).success(true) override fun cancelTempBasal(enforceNew: Boolean): PumpEnactResult = PumpEnactResult(injector).success(true) override fun cancelExtendedBolus(): PumpEnactResult = PumpEnactResult(injector).success(true) override fun getJSONStatus(profile: Profile, profileName: String, version: String): JSONObject = JSONObject() override fun manufacturer(): ManufacturerType = ManufacturerType.AndroidAPS - override fun model(): PumpType = PumpType.GenericAAPS + override fun model(): PumpType = PumpType.GENERIC_AAPS override fun serialNumber(): String = "1" override fun shortStatus(veryShort: Boolean): String = "" override val isFakingTempsByExtendedBoluses: Boolean = false diff --git a/danar/src/test/java/info/nightscout/androidaps/plugins/pump/danaR/DanaRPluginTest.kt b/danar/src/test/java/info/nightscout/androidaps/plugins/pump/danaR/DanaRPluginTest.kt index 834c549718..6bbadd14e9 100644 --- a/danar/src/test/java/info/nightscout/androidaps/plugins/pump/danaR/DanaRPluginTest.kt +++ b/danar/src/test/java/info/nightscout/androidaps/plugins/pump/danaR/DanaRPluginTest.kt @@ -11,6 +11,7 @@ import info.nightscout.androidaps.danar.R 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.plugins.configBuilder.ConstraintChecker import info.nightscout.androidaps.utils.sharedPreferences.SP import org.junit.Assert @@ -30,6 +31,7 @@ class DanaRPluginTest : TestBaseWithProfile() { @Mock lateinit var constraintChecker: ConstraintChecker @Mock lateinit var sp: SP @Mock lateinit var commandQueue: CommandQueueProvider + @Mock lateinit var pumpSync: PumpSync lateinit var danaPump: DanaPump @@ -45,8 +47,8 @@ class DanaRPluginTest : TestBaseWithProfile() { `when`(resourceHelper.gs(R.string.pumplimit)).thenReturn("pump limit") `when`(resourceHelper.gs(R.string.limitingbasalratio)).thenReturn("Limiting max basal rate to %1\$.2f U/h because of %2\$s") `when`(resourceHelper.gs(R.string.limitingpercentrate)).thenReturn("Limiting max percent rate to %1\$d%% because of %2\$s") - danaPump = DanaPump(aapsLogger, sp, injector) - danaRPlugin = DanaRPlugin(injector, aapsLogger, aapsSchedulers, rxBus, context, resourceHelper, constraintChecker, activePluginProvider, sp, commandQueue, danaPump, dateUtil, fabricPrivacy) + danaPump = DanaPump(aapsLogger, sp, dateUtil, injector) + danaRPlugin = DanaRPlugin(injector, aapsLogger, aapsSchedulers, rxBus, context, resourceHelper, constraintChecker, activePluginProvider, sp, commandQueue, danaPump, dateUtil, fabricPrivacy, pumpSync) } @Test @Throws(Exception::class) diff --git a/danar/src/test/java/info/nightscout/androidaps/plugins/pump/danaR/comm/DanaRTestBase.kt b/danar/src/test/java/info/nightscout/androidaps/plugins/pump/danaR/comm/DanaRTestBase.kt index 9680740208..6eb138470a 100644 --- a/danar/src/test/java/info/nightscout/androidaps/plugins/pump/danaR/comm/DanaRTestBase.kt +++ b/danar/src/test/java/info/nightscout/androidaps/plugins/pump/danaR/comm/DanaRTestBase.kt @@ -9,11 +9,9 @@ import info.nightscout.androidaps.danaRKorean.DanaRKoreanPlugin import info.nightscout.androidaps.danaRv2.DanaRv2Plugin import info.nightscout.androidaps.danar.DanaRPlugin import info.nightscout.androidaps.danar.comm.MessageBase -import info.nightscout.androidaps.db.TemporaryBasal import info.nightscout.androidaps.interfaces.* import info.nightscout.androidaps.plugins.bus.RxBusWrapper import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker -import info.nightscout.androidaps.plugins.general.nsclient.NSUpload import info.nightscout.androidaps.plugins.pump.common.bolusInfo.DetailedBolusInfoStorage import info.nightscout.androidaps.utils.DateUtil import info.nightscout.androidaps.utils.resources.ResourceHelper @@ -31,28 +29,26 @@ open class DanaRTestBase : TestBase() { @Mock lateinit var sp: SP @Mock lateinit var profileFunction: ProfileFunction - @Mock lateinit var activePluginProvider: ActivePluginProvider + @Mock lateinit var activePlugin: ActivePlugin @Mock lateinit var dateUtil: DateUtil @Mock lateinit var databaseHelper: DatabaseHelperInterface - @Mock lateinit var treatmentsInterface: TreatmentsInterface @Mock lateinit var danaRPlugin: DanaRPlugin @Mock lateinit var danaRKoreanPlugin: DanaRKoreanPlugin @Mock lateinit var danaRv2Plugin: DanaRv2Plugin @Mock lateinit var resourceHelper: ResourceHelper - @Mock lateinit var configBuilder: ConfigBuilderInterface + @Mock lateinit var configBuilder: ConfigBuilder @Mock lateinit var commandQueue: CommandQueueProvider @Mock lateinit var detailedBolusInfoStorage: DetailedBolusInfoStorage @Mock lateinit var constraintChecker: ConstraintChecker - @Mock lateinit var nsUpload: NSUpload + @Mock lateinit var pumpSync: PumpSync - lateinit var testPumpPlugin: TestPumpPlugin + private lateinit var testPumpPlugin: TestPumpPlugin @Before fun setup() { - danaPump = DanaPump(aapsLogger, sp, injector) + danaPump = DanaPump(aapsLogger, sp, dateUtil, injector) testPumpPlugin = TestPumpPlugin(injector) - `when`(activePluginProvider.activeTreatments).thenReturn(treatmentsInterface) - `when`(activePluginProvider.activePump).thenReturn(testPumpPlugin) + `when`(activePlugin.activePump).thenReturn(testPumpPlugin) doNothing().`when`(danaRKoreanPlugin).setPluginEnabled(anyObject(), anyBoolean()) doNothing().`when`(danaRPlugin).setPluginEnabled(anyObject(), anyBoolean()) `when`(resourceHelper.gs(ArgumentMatchers.anyInt())).thenReturn("") @@ -69,19 +65,13 @@ open class DanaRTestBase : TestBase() { it.danaRv2Plugin = danaRv2Plugin it.rxBus = RxBusWrapper(aapsSchedulers) it.resourceHelper = resourceHelper - it.activePlugin = activePluginProvider + it.activePlugin = activePlugin it.configBuilder = configBuilder it.detailedBolusInfoStorage = detailedBolusInfoStorage it.constraintChecker = constraintChecker - it.nsUpload = nsUpload it.databaseHelper = databaseHelper it.commandQueue = commandQueue - } - if (it is TemporaryBasal) { - it.aapsLogger = aapsLogger - it.activePlugin = activePluginProvider - it.profileFunction = profileFunction - it.sp = sp + it.pumpSync = pumpSync } } } diff --git a/danar/src/test/java/info/nightscout/androidaps/plugins/pump/danaR/comm/MsgBolusProgressTest.kt b/danar/src/test/java/info/nightscout/androidaps/plugins/pump/danaR/comm/MsgBolusProgressTest.kt index d21a8f7939..a7c470008b 100644 --- a/danar/src/test/java/info/nightscout/androidaps/plugins/pump/danaR/comm/MsgBolusProgressTest.kt +++ b/danar/src/test/java/info/nightscout/androidaps/plugins/pump/danaR/comm/MsgBolusProgressTest.kt @@ -1,10 +1,8 @@ package info.nightscout.androidaps.plugins.pump.danaR.comm -import dagger.android.AndroidInjector -import dagger.android.HasAndroidInjector import info.nightscout.androidaps.danar.R import info.nightscout.androidaps.danar.comm.MsgBolusProgress -import info.nightscout.androidaps.db.Treatment +import info.nightscout.androidaps.plugins.general.overview.events.EventOverviewBolusProgress import org.junit.Assert import org.junit.Test import org.junit.runner.RunWith @@ -17,7 +15,7 @@ class MsgBolusProgressTest : DanaRTestBase() { @Test fun runTest() { `when`(resourceHelper.gs(ArgumentMatchers.eq(R.string.bolusdelivering), ArgumentMatchers.anyDouble())).thenReturn("Delivering %1\$.2fU") - danaPump.bolusingTreatment = Treatment(HasAndroidInjector { AndroidInjector { } }) + danaPump.bolusingTreatment = EventOverviewBolusProgress.Treatment(0.0, 0, true) danaPump.bolusAmountToBeDelivered = 3.0 val packet = MsgBolusProgress(injector) diff --git a/danar/src/test/java/info/nightscout/androidaps/plugins/pump/danaR/comm/MsgBolusStopTest.kt b/danar/src/test/java/info/nightscout/androidaps/plugins/pump/danaR/comm/MsgBolusStopTest.kt index d3bc63f092..46b901ec60 100644 --- a/danar/src/test/java/info/nightscout/androidaps/plugins/pump/danaR/comm/MsgBolusStopTest.kt +++ b/danar/src/test/java/info/nightscout/androidaps/plugins/pump/danaR/comm/MsgBolusStopTest.kt @@ -1,10 +1,8 @@ package info.nightscout.androidaps.plugins.pump.danaR.comm -import dagger.android.AndroidInjector -import dagger.android.HasAndroidInjector import info.nightscout.androidaps.danar.R import info.nightscout.androidaps.danar.comm.MsgBolusStop -import info.nightscout.androidaps.db.Treatment +import info.nightscout.androidaps.plugins.general.overview.events.EventOverviewBolusProgress import org.junit.Assert import org.junit.Test import org.junit.runner.RunWith @@ -16,7 +14,7 @@ class MsgBolusStopTest : DanaRTestBase() { @Test fun runTest() { `when`(resourceHelper.gs(R.string.overview_bolusprogress_delivered)).thenReturn("Delivered") - danaPump.bolusingTreatment = Treatment(HasAndroidInjector { AndroidInjector { } }) + danaPump.bolusingTreatment = EventOverviewBolusProgress.Treatment(0.0, 0, true) val packet = MsgBolusStop(injector) // test message decoding diff --git a/danar/src/test/java/info/nightscout/androidaps/plugins/pump/danaR/comm/MsgStatusBolusExtendedTest.kt b/danar/src/test/java/info/nightscout/androidaps/plugins/pump/danaR/comm/MsgStatusBolusExtendedTest.kt index 4621f34029..fb2687ff6a 100644 --- a/danar/src/test/java/info/nightscout/androidaps/plugins/pump/danaR/comm/MsgStatusBolusExtendedTest.kt +++ b/danar/src/test/java/info/nightscout/androidaps/plugins/pump/danaR/comm/MsgStatusBolusExtendedTest.kt @@ -1,10 +1,10 @@ package info.nightscout.androidaps.plugins.pump.danaR.comm import info.nightscout.androidaps.danar.comm.MsgStatusBolusExtended +import info.nightscout.androidaps.utils.T import org.junit.Assert import org.junit.Test import org.junit.runner.RunWith -import org.mockito.Mockito.`when` import org.powermock.modules.junit4.PowerMockRunner @RunWith(PowerMockRunner::class) @@ -12,12 +12,12 @@ class MsgStatusBolusExtendedTest : DanaRTestBase() { @Test fun runTest() { - `when`(activePluginProvider.activeTreatments).thenReturn(treatmentsInterface) val packet = MsgStatusBolusExtended(injector) // test message decoding val array = ByteArray(100) putByteToArray(array, 0, 1) + putByteToArray(array, 1, 1) packet.handleMessage(array) - Assert.assertEquals(true, danaPump.isExtendedInProgress) + Assert.assertEquals(T.mins(30).msecs(), danaPump.extendedBolusDuration) } } \ No newline at end of file diff --git a/danar/src/test/java/info/nightscout/androidaps/plugins/pump/danaR/comm/MsgStatusTempBasalTest.kt b/danar/src/test/java/info/nightscout/androidaps/plugins/pump/danaR/comm/MsgStatusTempBasalTest.kt index 5bcbe1db9f..f2a63b72ac 100644 --- a/danar/src/test/java/info/nightscout/androidaps/plugins/pump/danaR/comm/MsgStatusTempBasalTest.kt +++ b/danar/src/test/java/info/nightscout/androidaps/plugins/pump/danaR/comm/MsgStatusTempBasalTest.kt @@ -12,11 +12,10 @@ class MsgStatusTempBasalTest : DanaRTestBase() { @Test fun runTest() { val packet = MsgStatusTempBasal(injector) // test message decoding - // test message decoding packet.handleMessage(createArray(34, 1.toByte())) - Assert.assertEquals(true, danaPump.isTempBasalInProgress) + Assert.assertEquals(true, packet.isTempBasalInProgress) // passing an bigger number packet.handleMessage(createArray(34, 2.toByte())) - Assert.assertEquals(false, danaPump.isTempBasalInProgress) + Assert.assertEquals(false, packet.isTempBasalInProgress) } } \ No newline at end of file diff --git a/danar/src/test/java/info/nightscout/androidaps/plugins/pump/danaRKorean/DanaRKoreanPluginTest.kt b/danar/src/test/java/info/nightscout/androidaps/plugins/pump/danaRKorean/DanaRKoreanPluginTest.kt index f948cf7a10..e1762ddc6d 100644 --- a/danar/src/test/java/info/nightscout/androidaps/plugins/pump/danaRKorean/DanaRKoreanPluginTest.kt +++ b/danar/src/test/java/info/nightscout/androidaps/plugins/pump/danaRKorean/DanaRKoreanPluginTest.kt @@ -11,6 +11,7 @@ import info.nightscout.androidaps.danar.R 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.plugins.configBuilder.ConstraintChecker import info.nightscout.androidaps.utils.sharedPreferences.SP import org.junit.Assert @@ -30,6 +31,7 @@ class DanaRKoreanPluginTest : TestBaseWithProfile() { @Mock lateinit var constraintChecker: ConstraintChecker @Mock lateinit var sp: SP @Mock lateinit var commandQueue: CommandQueueProvider + @Mock lateinit var pumpSync: PumpSync lateinit var danaPump: DanaPump @@ -45,8 +47,8 @@ class DanaRKoreanPluginTest : TestBaseWithProfile() { `when`(resourceHelper.gs(R.string.pumplimit)).thenReturn("pump limit") `when`(resourceHelper.gs(R.string.limitingbasalratio)).thenReturn("Limiting max basal rate to %1\$.2f U/h because of %2\$s") `when`(resourceHelper.gs(R.string.limitingpercentrate)).thenReturn("Limiting max percent rate to %1\$d%% because of %2\$s") - danaPump = DanaPump(aapsLogger, sp, injector) - danaRPlugin = DanaRKoreanPlugin(injector, aapsLogger, aapsSchedulers, rxBus, danaPump, context, resourceHelper, constraintChecker, activePluginProvider, sp, commandQueue, dateUtil, fabricPrivacy) + danaPump = DanaPump(aapsLogger, sp, dateUtil, injector) + danaRPlugin = DanaRKoreanPlugin(injector, aapsLogger, aapsSchedulers, rxBus, context, resourceHelper, constraintChecker, activePluginProvider, sp, commandQueue, danaPump, dateUtil, fabricPrivacy, pumpSync) } @Test @Throws(Exception::class) diff --git a/danar/src/test/java/info/nightscout/androidaps/plugins/pump/danaRv2/DanaRv2PluginTest.kt b/danar/src/test/java/info/nightscout/androidaps/plugins/pump/danaRv2/DanaRv2PluginTest.kt index 2e0cee2135..bbdaececa1 100644 --- a/danar/src/test/java/info/nightscout/androidaps/plugins/pump/danaRv2/DanaRv2PluginTest.kt +++ b/danar/src/test/java/info/nightscout/androidaps/plugins/pump/danaRv2/DanaRv2PluginTest.kt @@ -11,8 +11,11 @@ import info.nightscout.androidaps.danar.R 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.plugins.configBuilder.ConstraintChecker import info.nightscout.androidaps.plugins.pump.common.bolusInfo.DetailedBolusInfoStorage +import info.nightscout.androidaps.plugins.pump.common.bolusInfo.TemporaryBasalStorage +import info.nightscout.androidaps.utils.sharedPreferences.SP import org.junit.Before import org.junit.Test import org.junit.runner.RunWith @@ -22,14 +25,16 @@ import org.powermock.core.classloader.annotations.PrepareForTest import org.powermock.modules.junit4.PowerMockRunner @RunWith(PowerMockRunner::class) -@PrepareForTest(ConstraintChecker::class, DetailedBolusInfoStorage::class) +@PrepareForTest(ConstraintChecker::class, DetailedBolusInfoStorage::class, TemporaryBasalStorage::class) class DanaRv2PluginTest : TestBaseWithProfile() { @Mock lateinit var context: Context @Mock lateinit var constraintChecker: ConstraintChecker - @Mock lateinit var sp: info.nightscout.androidaps.utils.sharedPreferences.SP + @Mock lateinit var sp: SP @Mock lateinit var commandQueue: CommandQueueProvider @Mock lateinit var detailedBolusInfoStorage: DetailedBolusInfoStorage + @Mock lateinit var temporaryBasalStorage: TemporaryBasalStorage + @Mock lateinit var pumpSync: PumpSync lateinit var danaPump: DanaPump @@ -45,8 +50,8 @@ class DanaRv2PluginTest : TestBaseWithProfile() { `when`(resourceHelper.gs(R.string.pumplimit)).thenReturn("pump limit") `when`(resourceHelper.gs(R.string.limitingbasalratio)).thenReturn("Limiting max basal rate to %1\$.2f U/h because of %2\$s") `when`(resourceHelper.gs(R.string.limitingpercentrate)).thenReturn("Limiting max percent rate to %1\$d%% because of %2\$s") - danaPump = DanaPump(aapsLogger, sp, injector) - danaRv2Plugin = DanaRv2Plugin(injector, aapsLogger, aapsSchedulers, rxBus, context, danaPump, resourceHelper, constraintChecker, activePluginProvider, sp, commandQueue, detailedBolusInfoStorage, dateUtil, fabricPrivacy) + danaPump = DanaPump(aapsLogger, sp, dateUtil, injector) + danaRv2Plugin = DanaRv2Plugin(injector, aapsLogger, aapsSchedulers, rxBus, context, resourceHelper, constraintChecker, activePluginProvider, sp, commandQueue, danaPump,detailedBolusInfoStorage, temporaryBasalStorage, dateUtil, fabricPrivacy, pumpSync) } @Test diff --git a/danar/src/test/java/info/nightscout/androidaps/plugins/pump/danaRv2/comm/MsgHistoryEventsRv2Test.kt b/danar/src/test/java/info/nightscout/androidaps/plugins/pump/danaRv2/comm/MsgHistoryEventsRv2Test.kt index 89a1e4f0a1..e76e29fa6e 100644 --- a/danar/src/test/java/info/nightscout/androidaps/plugins/pump/danaRv2/comm/MsgHistoryEventsRv2Test.kt +++ b/danar/src/test/java/info/nightscout/androidaps/plugins/pump/danaRv2/comm/MsgHistoryEventsRv2Test.kt @@ -19,12 +19,12 @@ class MsgHistoryEventsRv2Test : DanaRTestBase() { // test message decoding val array = createArray(100, 2) - putByteToArray(array, 0, 0xFF.toByte()) - packet.handleMessage(array) - Assert.assertEquals(true, danaRv2Plugin.eventsLoadingDone) - // passing an bigger number putByteToArray(array, 0, 0x01.toByte()) packet.handleMessage(array) - Assert.assertEquals(false, danaRv2Plugin.eventsLoadingDone) + Assert.assertEquals(false, danaPump.historyDoneReceived) + + putByteToArray(array, 0, 0xFF.toByte()) + packet.handleMessage(array) + Assert.assertEquals(true, danaPump.historyDoneReceived) } } \ No newline at end of file diff --git a/danar/src/test/java/info/nightscout/androidaps/plugins/pump/danaRv2/comm/MsgStatusBolusExtendedRv2Test.kt b/danar/src/test/java/info/nightscout/androidaps/plugins/pump/danaRv2/comm/MsgStatusBolusExtendedRv2Test.kt deleted file mode 100644 index 98b42c07cb..0000000000 --- a/danar/src/test/java/info/nightscout/androidaps/plugins/pump/danaRv2/comm/MsgStatusBolusExtendedRv2Test.kt +++ /dev/null @@ -1,20 +0,0 @@ -package info.nightscout.androidaps.plugins.pump.danaRv2.comm - -import info.nightscout.androidaps.danaRv2.comm.MsgStatusBolusExtended_v2 -import info.nightscout.androidaps.plugins.pump.danaR.comm.DanaRTestBase -import org.junit.Assert -import org.junit.Test -import org.junit.runner.RunWith -import org.powermock.modules.junit4.PowerMockRunner - -@RunWith(PowerMockRunner::class) -class MsgStatusBolusExtendedRv2Test : DanaRTestBase() { - - @Test - fun runTest() { - val packet = MsgStatusBolusExtended_v2(injector) - // test message decoding - packet.handleMessage(createArray(34, 7.toByte())) - Assert.assertEquals(packet.intFromBuff(createArray(10, 7.toByte()), 2, 2).toDouble() / 100.0, danaPump.extendedBolusAmount, 0.0) - } -} \ No newline at end of file diff --git a/danar/src/test/java/info/nightscout/androidaps/plugins/pump/danaRv2/comm/MsgStatusTempBasalRv2Test.kt b/danar/src/test/java/info/nightscout/androidaps/plugins/pump/danaRv2/comm/MsgStatusTempBasalRv2Test.kt deleted file mode 100644 index 31050bf109..0000000000 --- a/danar/src/test/java/info/nightscout/androidaps/plugins/pump/danaRv2/comm/MsgStatusTempBasalRv2Test.kt +++ /dev/null @@ -1,22 +0,0 @@ -package info.nightscout.androidaps.plugins.pump.danaRv2.comm - -import info.nightscout.androidaps.danaRv2.comm.MsgStatusTempBasal_v2 -import info.nightscout.androidaps.plugins.pump.danaR.comm.DanaRTestBase -import org.junit.Assert -import org.junit.Test -import org.junit.runner.RunWith -import org.powermock.modules.junit4.PowerMockRunner - -@RunWith(PowerMockRunner::class) -class MsgStatusTempBasalRv2Test : DanaRTestBase() { - - @Test fun runTest() { - val packet = MsgStatusTempBasal_v2(injector) - // test message decoding - packet.handleMessage(createArray(34, 1.toByte())) - Assert.assertEquals(true, danaPump.isTempBasalInProgress) - // passing an bigger number - packet.handleMessage(createArray(34, 2.toByte())) - Assert.assertEquals(false, danaPump.isTempBasalInProgress) - } -} \ No newline at end of file diff --git a/danars/build.gradle b/danars/build.gradle index f1437136ca..9ac3aa3f9a 100644 --- a/danars/build.gradle +++ b/danars/build.gradle @@ -23,5 +23,4 @@ android { dependencies { implementation project(':core') implementation project(':dana') - implementation project(':database') } \ No newline at end of file diff --git a/danars/src/main/java/info/nightscout/androidaps/danars/DanaRSPlugin.kt b/danars/src/main/java/info/nightscout/androidaps/danars/DanaRSPlugin.kt index ca1002db8e..0693b76912 100644 --- a/danars/src/main/java/info/nightscout/androidaps/danars/DanaRSPlugin.kt +++ b/danars/src/main/java/info/nightscout/androidaps/danars/DanaRSPlugin.kt @@ -9,13 +9,11 @@ import android.text.format.DateFormat import androidx.preference.Preference import dagger.android.HasAndroidInjector import info.nightscout.androidaps.dana.DanaPump -import info.nightscout.androidaps.dana.DanaPumpInterface import info.nightscout.androidaps.danars.events.EventDanaRSDeviceChange import info.nightscout.androidaps.danars.services.DanaRSService import info.nightscout.androidaps.data.DetailedBolusInfo import info.nightscout.androidaps.data.Profile import info.nightscout.androidaps.data.PumpEnactResult -import info.nightscout.androidaps.db.Treatment import info.nightscout.androidaps.events.EventAppExit import info.nightscout.androidaps.events.EventConfigBuilderChange import info.nightscout.androidaps.interfaces.* @@ -26,10 +24,15 @@ import info.nightscout.androidaps.plugins.common.ManufacturerType import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker import info.nightscout.androidaps.plugins.general.overview.events.EventDismissNotification import info.nightscout.androidaps.plugins.general.overview.events.EventNewNotification +import info.nightscout.androidaps.plugins.general.overview.events.EventOverviewBolusProgress import info.nightscout.androidaps.plugins.general.overview.notifications.Notification import info.nightscout.androidaps.plugins.pump.common.bolusInfo.DetailedBolusInfoStorage +import info.nightscout.androidaps.plugins.pump.common.bolusInfo.TemporaryBasalStorage import info.nightscout.androidaps.plugins.pump.common.defs.PumpType import info.nightscout.androidaps.utils.* +import info.nightscout.androidaps.utils.T.Companion.mins +import info.nightscout.androidaps.extensions.convertedToAbsolute +import info.nightscout.androidaps.extensions.plannedRemainingMinutes import info.nightscout.androidaps.utils.resources.ResourceHelper import info.nightscout.androidaps.utils.rx.AapsSchedulers import info.nightscout.androidaps.utils.sharedPreferences.SP @@ -51,11 +54,12 @@ class DanaRSPlugin @Inject constructor( resourceHelper: ResourceHelper, private val constraintChecker: ConstraintChecker, private val profileFunction: ProfileFunction, - private val activePluginProvider: ActivePluginProvider, private val sp: SP, commandQueue: CommandQueueProvider, private val danaPump: DanaPump, + private val pumpSync: PumpSync, private val detailedBolusInfoStorage: DetailedBolusInfoStorage, + private val temporaryBasalStorage: TemporaryBasalStorage, private val fabricPrivacy: FabricPrivacy, private val dateUtil: DateUtil ) : PumpPluginBase(PluginDescription() @@ -67,13 +71,13 @@ class DanaRSPlugin @Inject constructor( .preferencesId(R.xml.pref_danars) .description(R.string.description_pump_dana_rs), injector, aapsLogger, resourceHelper, commandQueue -), PumpInterface, DanaRInterface, ConstraintsInterface, DanaPumpInterface { +), Pump, Dana, Constraints { private val disposable = CompositeDisposable() private var danaRSService: DanaRSService? = null private var mDeviceAddress = "" var mDeviceName = "" - override val pumpDescription = PumpDescription(PumpType.DanaRS) + override val pumpDescription = PumpDescription(PumpType.DANA_RS) override fun updatePreferenceSummary(pref: Preference) { super.updatePreferenceSummary(pref) @@ -130,6 +134,7 @@ class DanaRSPlugin @Inject constructor( mDeviceAddress = sp.getString(R.string.key_danars_address, "") mDeviceName = sp.getString(R.string.key_danars_name, "") danaPump.reset() + pumpSync.connectNewPump() commandQueue.readStatus("DeviceChanged", null) } @@ -269,7 +274,7 @@ class DanaRSPlugin @Inject constructor( } // RS stores end time for bolus, we need to adjust time // default delivery speed is 12 sec/U - detailedBolusInfo.date = DateUtil.now() + (speed * detailedBolusInfo.insulin * 1000).toLong() + detailedBolusInfo.timestamp = dateUtil.now() + (speed * detailedBolusInfo.insulin * 1000).toLong() // clean carbs to prevent counting them as twice because they will picked up as another record // I don't think it's necessary to copy DetailedBolusInfo right now for carbs records val carbs = detailedBolusInfo.carbs @@ -278,10 +283,9 @@ class DanaRSPlugin @Inject constructor( if (carbTime == 0) carbTime-- // better set 1 min back to prevents clash with insulin detailedBolusInfo.carbTime = 0 detailedBolusInfoStorage.add(detailedBolusInfo) // will be picked up on reading history - val t = Treatment() - t.isSMB = detailedBolusInfo.isSMB + val t = EventOverviewBolusProgress.Treatment(0.0, 0, detailedBolusInfo.bolusType == DetailedBolusInfo.BolusType.SMB) var connectionOK = false - if (detailedBolusInfo.insulin > 0 || carbs > 0) connectionOK = danaRSService?.bolus(detailedBolusInfo.insulin, carbs.toInt(), DateUtil.now() + T.mins(carbTime.toLong()).msecs(), t) + if (detailedBolusInfo.insulin > 0 || carbs > 0) connectionOK = danaRSService?.bolus(detailedBolusInfo.insulin, carbs.toInt(), dateUtil.now() + T.mins(carbTime.toLong()).msecs(), t) ?: false val result = PumpEnactResult(injector) result.success = connectionOK && abs(detailedBolusInfo.insulin - t.insulin) < pumpDescription.bolusStep @@ -316,7 +320,7 @@ class DanaRSPlugin @Inject constructor( // This is called from APS @Synchronized - override fun setTempBasalAbsolute(absoluteRate: Double, durationInMinutes: Int, profile: Profile, enforceNew: Boolean): PumpEnactResult { + override fun setTempBasalAbsolute(absoluteRate: Double, durationInMinutes: Int, profile: Profile, enforceNew: Boolean, tbrType: PumpSync.TemporaryBasalType): PumpEnactResult { var result = PumpEnactResult(injector) val absoluteAfterConstrain = constraintChecker.applyBasalConstraints(Constraint(absoluteRate), profile).value() val doTempOff = baseBasalRate - absoluteAfterConstrain == 0.0 @@ -324,7 +328,7 @@ class DanaRSPlugin @Inject constructor( val doHighTemp = absoluteAfterConstrain > baseBasalRate if (doTempOff) { // If temp in progress - if (activePluginProvider.activeTreatments.isTempBasalInProgress) { + if (danaPump.isTempBasalInProgress) { aapsLogger.debug(LTag.PUMP, "setTempBasalAbsolute: Stopping temp basal (doTempOff)") return cancelTempBasal(false) } @@ -348,16 +352,15 @@ class DanaRSPlugin @Inject constructor( if (percentRate > 500) // Special high temp 500/15min percentRate = 500 // Check if some temp is already in progress - val activeTemp = activePluginProvider.activeTreatments.getTempBasalFromHistory(System.currentTimeMillis()) - if (activeTemp != null) { - aapsLogger.debug(LTag.PUMP, "setTempBasalAbsolute: currently running: $activeTemp") + if (danaPump.isTempBasalInProgress) { + aapsLogger.debug(LTag.PUMP, "setTempBasalAbsolute: currently running") // Correct basal already set ? - if (activeTemp.percentRate == percentRate && activeTemp.plannedRemainingMinutes > 4) { + if (danaPump.tempBasalPercent == percentRate && danaPump.tempBasalRemainingMin > 4) { if (!enforceNew) { result.success = true result.percent = percentRate result.enacted = false - result.duration = activeTemp.plannedRemainingMinutes + result.duration = danaPump.tempBasalRemainingMin result.isPercent = true result.isTempCancel = false aapsLogger.debug(LTag.PUMP, "setTempBasalAbsolute: Correct temp basal already set (doLowTemp || doHighTemp)") @@ -365,10 +368,11 @@ class DanaRSPlugin @Inject constructor( } } } + temporaryBasalStorage.add(PumpSync.PumpState.TemporaryBasal(dateUtil.now(), mins(durationInMinutes.toLong()).msecs(), percentRate.toDouble(), false, tbrType, 0L, 0L)) // Convert duration from minutes to hours aapsLogger.debug(LTag.PUMP, "setTempBasalAbsolute: Setting temp basal $percentRate% for $durationInMinutes minutes (doLowTemp || doHighTemp)") result = if (percentRate == 0 && durationInMinutes > 30) { - setTempBasalPercent(percentRate, durationInMinutes, profile, enforceNew) + setTempBasalPercent(percentRate, durationInMinutes, profile, enforceNew, tbrType) } else { // use special APS temp basal call ... 100+/15min .... 100-/30min setHighTempBasalPercent(percentRate) @@ -388,7 +392,7 @@ class DanaRSPlugin @Inject constructor( } @Synchronized - override fun setTempBasalPercent(percent: Int, durationInMinutes: Int, profile: Profile, enforceNew: Boolean): PumpEnactResult { + override fun setTempBasalPercent(percent: Int, durationInMinutes: Int, profile: Profile, enforceNew: Boolean, tbrType: PumpSync.TemporaryBasalType): PumpEnactResult { val result = PumpEnactResult(injector) var percentAfterConstraint = constraintChecker.applyBasalPercentConstraints(Constraint(percent), profile).value() if (percentAfterConstraint < 0) { @@ -400,9 +404,7 @@ class DanaRSPlugin @Inject constructor( return result } if (percentAfterConstraint > pumpDescription.maxTempPercent) percentAfterConstraint = pumpDescription.maxTempPercent - val now = System.currentTimeMillis() - val activeTemp = activePluginProvider.activeTreatments.getTempBasalFromHistory(now) - if (activeTemp != null && activeTemp.percentRate == percentAfterConstraint && activeTemp.plannedRemainingMinutes > 4 && !enforceNew) { + if (danaPump.isTempBasalInProgress && danaPump.tempBasalPercent == percentAfterConstraint && danaPump.tempBasalRemainingMin > 4 && !enforceNew) { result.enacted = false result.success = true result.isTempCancel = false @@ -413,6 +415,7 @@ class DanaRSPlugin @Inject constructor( aapsLogger.debug(LTag.PUMP, "setTempBasalPercent: Correct value already set") return result } + temporaryBasalStorage.add(PumpSync.PumpState.TemporaryBasal(dateUtil.now(), mins(durationInMinutes.toLong()).msecs(), percent.toDouble(), false, tbrType, 0L, 0L)) val connectionOK: Boolean = if (durationInMinutes == 15 || durationInMinutes == 30) { danaRSService?.tempBasalShortDuration(percentAfterConstraint, durationInMinutes) ?: false @@ -466,8 +469,7 @@ class DanaRSPlugin @Inject constructor( val durationInHalfHours = max(durationInMinutes / 30, 1) insulinAfterConstraint = Round.roundTo(insulinAfterConstraint, pumpDescription.extendedBolusStep) val result = PumpEnactResult(injector) - val runningEB = activePluginProvider.activeTreatments.getExtendedBolusFromHistory(System.currentTimeMillis()) - if (runningEB != null && abs(runningEB.insulin - insulinAfterConstraint) < pumpDescription.extendedBolusStep) { + if (danaPump.isExtendedInProgress && abs(danaPump.extendedBolusAmount - insulinAfterConstraint) < pumpDescription.extendedBolusStep) { result.enacted = false result.success = true result.comment = resourceHelper.gs(R.string.ok) @@ -480,7 +482,7 @@ class DanaRSPlugin @Inject constructor( } val connectionOK = danaRSService?.extendedBolus(insulinAfterConstraint, durationInHalfHours) ?: false - if (connectionOK && danaPump.isExtendedInProgress && abs(danaPump.extendedBolusAbsoluteRate - insulinAfterConstraint) < pumpDescription.extendedBolusStep) { + if (connectionOK && danaPump.isExtendedInProgress && abs(danaPump.extendedBolusAmount - insulinAfterConstraint) < pumpDescription.extendedBolusStep) { result.enacted = true result.success = true result.comment = resourceHelper.gs(R.string.ok) @@ -502,46 +504,34 @@ class DanaRSPlugin @Inject constructor( @Synchronized override fun cancelTempBasal(enforceNew: Boolean): PumpEnactResult { val result = PumpEnactResult(injector) - val runningTB = activePluginProvider.activeTreatments.getTempBasalFromHistory(System.currentTimeMillis()) - if (runningTB != null) { + if (danaPump.isTempBasalInProgress) { danaRSService?.tempBasalStop() + result.success = !danaPump.isTempBasalInProgress result.enacted = true result.isTempCancel = true - } - return if (!danaPump.isTempBasalInProgress) { + } else { result.success = true + result.enacted = false result.isTempCancel = true result.comment = resourceHelper.gs(R.string.ok) aapsLogger.debug(LTag.PUMP, "cancelRealTempBasal: OK") - result - } else { - result.success = false - result.comment = resourceHelper.gs(R.string.danar_valuenotsetproperly) - result.isTempCancel = true - aapsLogger.error("cancelRealTempBasal: Failed to cancel temp basal") - result } + return result } @Synchronized override fun cancelExtendedBolus(): PumpEnactResult { val result = PumpEnactResult(injector) - val runningEB = activePluginProvider.activeTreatments.getExtendedBolusFromHistory(System.currentTimeMillis()) - if (runningEB != null) { + if (danaPump.isExtendedInProgress) { danaRSService?.extendedBolusStop() + result.success = !danaPump.isExtendedInProgress result.enacted = true - result.isTempCancel = true - } - return if (!danaPump.isExtendedInProgress) { + } else { result.success = true + result.enacted = false result.comment = resourceHelper.gs(R.string.ok) aapsLogger.debug(LTag.PUMP, "cancelExtendedBolus: OK") - result - } else { - result.success = false - result.comment = resourceHelper.gs(R.string.danar_valuenotsetproperly) - aapsLogger.error("cancelExtendedBolus: Failed to cancel extended bolus") - result } + return result } override fun getJSONStatus(profile: Profile, profileName: String, version: String): JSONObject { @@ -556,22 +546,22 @@ class DanaRSPlugin @Inject constructor( try { battery.put("percent", danaPump.batteryRemaining) status.put("status", if (danaPump.pumpSuspended) "suspended" else "normal") - status.put("timestamp", DateUtil.toISOString(danaPump.lastConnection)) + status.put("timestamp", dateUtil.toISOString(danaPump.lastConnection)) extended.put("Version", version) if (danaPump.lastBolusTime != 0L) { extended.put("LastBolus", dateUtil.dateAndTimeString(danaPump.lastBolusTime)) extended.put("LastBolusAmount", danaPump.lastBolusAmount) } - val tb = activePluginProvider.activeTreatments.getTempBasalFromHistory(now) + val tb = pumpSync.expectedPumpState().temporaryBasal if (tb != null) { - extended.put("TempBasalAbsoluteRate", tb.tempBasalConvertedToAbsolute(now, profile)) - extended.put("TempBasalStart", dateUtil.dateAndTimeString(tb.date)) + extended.put("TempBasalAbsoluteRate", tb.convertedToAbsolute(now, profile)) + extended.put("TempBasalStart", dateUtil.dateAndTimeString(tb.timestamp)) extended.put("TempBasalRemaining", tb.plannedRemainingMinutes) } - val eb = activePluginProvider.activeTreatments.getExtendedBolusFromHistory(now) + val eb = pumpSync.expectedPumpState().extendedBolus if (eb != null) { - extended.put("ExtendedBolusAbsoluteRate", eb.absoluteRate()) - extended.put("ExtendedBolusStart", dateUtil.dateAndTimeString(eb.date)) + extended.put("ExtendedBolusAbsoluteRate", eb.rate) + extended.put("ExtendedBolusStart", dateUtil.dateAndTimeString(eb.timestamp)) extended.put("ExtendedBolusRemaining", eb.plannedRemainingMinutes) } extended.put("BaseBasalRate", baseBasalRate) @@ -584,7 +574,7 @@ class DanaRSPlugin @Inject constructor( pumpJson.put("status", status) pumpJson.put("extended", extended) pumpJson.put("reservoir", danaPump.reservoirRemainingUnits.toInt()) - pumpJson.put("clock", DateUtil.toISOString(now)) + pumpJson.put("clock", dateUtil.toISOString(now)) } catch (e: JSONException) { aapsLogger.error("Unhandled exception", e) } @@ -596,7 +586,7 @@ class DanaRSPlugin @Inject constructor( } override fun model(): PumpType { - return PumpType.DanaRS + return PumpType.DANA_RS } override fun serialNumber(): String { @@ -614,13 +604,11 @@ class DanaRSPlugin @Inject constructor( if (danaPump.lastBolusTime != 0L) ret += "LastBolus: ${DecimalFormatter.to2Decimal(danaPump.lastBolusAmount)}U @${DateFormat.format("HH:mm", danaPump.lastBolusTime)}" - val activeTemp = activePluginProvider.activeTreatments.getRealTempBasalFromHistory(System.currentTimeMillis()) - if (activeTemp != null) - ret += "Temp: ${activeTemp.toStringFull()}" + if (danaPump.isTempBasalInProgress) + ret += "Temp: ${danaPump.temporaryBasalToString()}" - val activeExtendedBolus = activePluginProvider.activeTreatments.getExtendedBolusFromHistory(System.currentTimeMillis()) - if (activeExtendedBolus != null) - ret += "Extended: $activeExtendedBolus\n" + if (danaPump.isExtendedInProgress) + ret += "Extended: ${danaPump.extendedBolusToString()}\n" if (!veryShort) { ret += "TDD: ${DecimalFormatter.to0Decimal(danaPump.dailyTotalUnits)} / ${danaPump.maxDailyTotalUnits} U" diff --git a/danars/src/main/java/info/nightscout/androidaps/danars/activities/EnterPinActivity.kt b/danars/src/main/java/info/nightscout/androidaps/danars/activities/EnterPinActivity.kt index 41c952e6c5..7161850604 100644 --- a/danars/src/main/java/info/nightscout/androidaps/danars/activities/EnterPinActivity.kt +++ b/danars/src/main/java/info/nightscout/androidaps/danars/activities/EnterPinActivity.kt @@ -11,7 +11,7 @@ import info.nightscout.androidaps.events.EventPumpStatusChanged import info.nightscout.androidaps.plugins.bus.RxBusWrapper import info.nightscout.androidaps.utils.FabricPrivacy import info.nightscout.androidaps.utils.alertDialogs.OKDialog -import info.nightscout.androidaps.utils.extensions.hexStringToByteArray +import info.nightscout.androidaps.extensions.hexStringToByteArray import info.nightscout.androidaps.utils.rx.AapsSchedulers import info.nightscout.androidaps.utils.sharedPreferences.SP import info.nightscout.androidaps.utils.textValidator.DefaultEditTextValidator diff --git a/danars/src/main/java/info/nightscout/androidaps/danars/comm/DanaRS_Packet_APS_History_Events.kt b/danars/src/main/java/info/nightscout/androidaps/danars/comm/DanaRS_Packet_APS_History_Events.kt index f5c834a41b..5e6b49a66a 100644 --- a/danars/src/main/java/info/nightscout/androidaps/danars/comm/DanaRS_Packet_APS_History_Events.kt +++ b/danars/src/main/java/info/nightscout/androidaps/danars/comm/DanaRS_Packet_APS_History_Events.kt @@ -5,23 +5,16 @@ import info.nightscout.androidaps.dana.DanaPump import info.nightscout.androidaps.danars.R import info.nightscout.androidaps.danars.encryption.BleEncryption import info.nightscout.androidaps.data.DetailedBolusInfo -import info.nightscout.androidaps.database.AppRepository -import info.nightscout.androidaps.database.entities.TherapyEvent -import info.nightscout.androidaps.database.transactions.InsertTherapyEventIfNewTransaction -import info.nightscout.androidaps.db.ExtendedBolus -import info.nightscout.androidaps.db.Source -import info.nightscout.androidaps.db.TemporaryBasal import info.nightscout.androidaps.events.EventPumpStatusChanged -import info.nightscout.androidaps.interfaces.ActivePluginProvider +import info.nightscout.androidaps.interfaces.PumpSync import info.nightscout.androidaps.logging.LTag import info.nightscout.androidaps.plugins.bus.RxBusWrapper -import info.nightscout.androidaps.plugins.general.nsclient.NSUpload import info.nightscout.androidaps.plugins.pump.common.bolusInfo.DetailedBolusInfoStorage -import info.nightscout.androidaps.utils.DateUtil +import info.nightscout.androidaps.plugins.pump.common.bolusInfo.TemporaryBasalStorage +import info.nightscout.androidaps.plugins.pump.common.defs.PumpType +import info.nightscout.androidaps.utils.T import info.nightscout.androidaps.utils.resources.ResourceHelper import info.nightscout.androidaps.utils.sharedPreferences.SP -import io.reactivex.disposables.CompositeDisposable -import io.reactivex.rxkotlin.plusAssign import org.joda.time.DateTime import org.joda.time.DateTimeZone import javax.inject.Inject @@ -33,23 +26,26 @@ open class DanaRS_Packet_APS_History_Events( @Inject lateinit var rxBus: RxBusWrapper @Inject lateinit var resourceHelper: ResourceHelper - @Inject lateinit var activePlugin: ActivePluginProvider @Inject lateinit var danaPump: DanaPump @Inject lateinit var detailedBolusInfoStorage: DetailedBolusInfoStorage + @Inject lateinit var temporaryBasalStorage: TemporaryBasalStorage @Inject lateinit var sp: SP - @Inject lateinit var nsUpload: NSUpload - @Inject lateinit var repository: AppRepository + @Inject lateinit var pumpSync: PumpSync - private val disposable = CompositeDisposable() + companion object { + + var messageBuffer = arrayListOf() // for reversing order of incoming messages + } init { opCode = BleEncryption.DANAR_PACKET__OPCODE__APS_HISTORY_EVENTS - if (from > DateUtil.now()) { + if (from > dateUtil.now()) { aapsLogger.debug(LTag.PUMPCOMM, "Asked to load from the future") from = 0 } aapsLogger.debug(LTag.PUMPCOMM, "Loading event history from: " + dateUtil.dateAndTimeString(from)) danaPump.historyDoneReceived = false + messageBuffer = arrayListOf() } override fun getRequestParams(): ByteArray { @@ -76,11 +72,43 @@ open class DanaRS_Packet_APS_History_Events( } override fun handleMessage(data: ByteArray) { + val recordCode = intFromBuff(data, 0, 1).toByte() + // Last record + if (recordCode == 0xFF.toByte()) { + aapsLogger.debug(LTag.PUMPCOMM, "Last record received") + + val array: Array = messageBuffer.toTypedArray() + val sorted = array.sortedArrayWith { s1: ByteArray, s2: ByteArray -> (dateTime(s1) - dateTime(s2)).toInt() } + for (index in sorted.indices) { + val message = sorted[index] + // workaround for RS history bug + // sometimes TB is marked as canceled immediately + // but on pump is running + // at least on Model: 05 Protocol: 10 Code: 10 + if (index > 0 && recordCode(message) == DanaPump.TEMPSTOP) { + val previous = sorted[index-1] + if (recordCode(previous) == DanaPump.TEMPSTART && dateTime(message) == dateTime(previous)) { + aapsLogger.debug(LTag.PUMPCOMM, "SKIPPING EVENT TEMPSTOP (" + recordCode(message) + ") " + dateUtil.dateAndTimeString(dateTime(message)) + " (" + dateTime(message) + ")") + continue + } + } + processMessage(message) + } + danaPump.historyDoneReceived = true + } else messageBuffer.add(data) + } + + fun dateTime(data: ByteArray): Long = + if (!danaPump.usingUTC) dateTimeSecFromBuff(data, 1) // 6 bytes + else intFromBuffMsbLsb(data, 3, 4) * 1000L + + fun recordCode(data: ByteArray): Int = + intFromBuff(data, 0, 1).toInt() + + fun processMessage(data: ByteArray) { var recordCode = intFromBuff(data, 0, 1).toByte() // Last record if (recordCode == 0xFF.toByte()) { - danaPump.historyDoneReceived = true - aapsLogger.debug(LTag.PUMPCOMM, "Last record received") return } val datetime: Long @@ -97,73 +125,102 @@ open class DanaRS_Packet_APS_History_Events( id = intFromBuffMsbLsb(data, 0, 2) // range only 1-2000 pumpId = datetime shl 16 + id } - val temporaryBasal = TemporaryBasal(injector).date(datetime).source(Source.PUMP).pumpId(pumpId) - val extendedBolus = ExtendedBolus(injector).date(datetime).source(Source.PUMP).pumpId(pumpId) val status: String when (recordCode.toInt()) { DanaPump.TEMPSTART -> { - aapsLogger.debug(LTag.PUMPCOMM, "[" + id + "] " + "EVENT TEMPSTART (" + recordCode + ") " + dateUtil.dateAndTimeString(datetime) + " (" + datetime + ")" + " Ratio: " + param1 + "% Duration: " + param2 + "min") - temporaryBasal.percentRate = param1 - temporaryBasal.durationInMinutes = param2 - activePlugin.activeTreatments.addToHistoryTempBasal(temporaryBasal) + val temporaryBasalInfo = temporaryBasalStorage.findTemporaryBasal(datetime, param1.toDouble()) + val newRecord = pumpSync.syncTemporaryBasalWithPumpId( + timestamp = datetime, + rate = param1.toDouble(), + duration = T.mins(param2.toLong()).msecs(), + isAbsolute = false, + type = temporaryBasalInfo?.type, + pumpId = pumpId, + pumpType = PumpType.DANA_RS, + pumpSerial = danaPump.serialNumber) + aapsLogger.debug(LTag.PUMPCOMM, "[" + id + "] " + (if (newRecord) "**NEW** " else "") + "EVENT TEMPSTART (" + recordCode + ") " + dateUtil.dateAndTimeString(datetime) + " (" + datetime + ")" + " Ratio: " + param1 + "% Duration: " + param2 + "min") status = "TEMPSTART " + dateUtil.timeString(datetime) } DanaPump.TEMPSTOP -> { - aapsLogger.debug(LTag.PUMPCOMM, "[" + id + "] " + "EVENT TEMPSTOP (" + recordCode + ") " + dateUtil.dateAndTimeString(datetime)) - activePlugin.activeTreatments.addToHistoryTempBasal(temporaryBasal) + val newRecord = pumpSync.syncStopTemporaryBasalWithPumpId( + timestamp = datetime, + endPumpId = pumpId, + pumpType = PumpType.DANA_RS, + pumpSerial = danaPump.serialNumber) + aapsLogger.debug(LTag.PUMPCOMM, "[" + id + "] " + (if (newRecord) "**NEW** " else "") + "EVENT TEMPSTOP (" + recordCode + ") " + dateUtil.dateAndTimeString(datetime) + " (" + datetime + ")") status = "TEMPSTOP " + dateUtil.timeString(datetime) } DanaPump.EXTENDEDSTART -> { - aapsLogger.debug(LTag.PUMPCOMM, "[" + id + "] " + "EVENT EXTENDEDSTART (" + recordCode + ") " + dateUtil.dateAndTimeString(datetime) + " (" + datetime + ")" + " Amount: " + param1 / 100.0 + "U Duration: " + param2 + "min") - extendedBolus.insulin = param1 / 100.0 - extendedBolus.durationInMinutes = param2 - activePlugin.activeTreatments.addToHistoryExtendedBolus(extendedBolus) + val newRecord = pumpSync.syncExtendedBolusWithPumpId( + timestamp = datetime, + amount = param1 / 100.0, + duration = T.mins(param2.toLong()).msecs(), + isEmulatingTB = false, + pumpId = pumpId, + pumpType = PumpType.DANA_RS, + pumpSerial = danaPump.serialNumber) + aapsLogger.debug(LTag.PUMPCOMM, "[" + id + "] " + (if (newRecord) "**NEW** " else "") + "EVENT EXTENDEDSTART (" + recordCode + ") " + dateUtil.dateAndTimeString(datetime) + " (" + datetime + ")" + " Amount: " + param1 / 100.0 + "U Duration: " + param2 + "min") status = "EXTENDEDSTART " + dateUtil.timeString(datetime) } DanaPump.EXTENDEDSTOP -> { - aapsLogger.debug(LTag.PUMPCOMM, "[" + id + "] " + "EVENT EXTENDEDSTOP (" + recordCode + ") " + dateUtil.dateAndTimeString(datetime) + " (" + datetime + ")" + " Delivered: " + param1 / 100.0 + "U RealDuration: " + param2 + "min") - activePlugin.activeTreatments.addToHistoryExtendedBolus(extendedBolus) + val newRecord = pumpSync.syncStopExtendedBolusWithPumpId( + timestamp = datetime, + endPumpId = pumpId, + pumpType = PumpType.DANA_RS, + pumpSerial = danaPump.serialNumber) + aapsLogger.debug(LTag.PUMPCOMM, "[" + id + "] " + (if (newRecord) "**NEW** " else "") + "EVENT EXTENDEDSTOP (" + recordCode + ") " + dateUtil.dateAndTimeString(datetime) + " (" + datetime + ")" + " Delivered: " + param1 / 100.0 + "U RealDuration: " + param2 + "min") status = "EXTENDEDSTOP " + dateUtil.timeString(datetime) } DanaPump.BOLUS -> { val detailedBolusInfo = detailedBolusInfoStorage.findDetailedBolusInfo(datetime, param1 / 100.0) - ?: DetailedBolusInfo() - detailedBolusInfo.date = datetime - detailedBolusInfo.source = Source.PUMP - detailedBolusInfo.pumpId = datetime - detailedBolusInfo.insulin = param1 / 100.0 - val newRecord = activePlugin.activeTreatments.addToHistoryTreatment(detailedBolusInfo, false) - aapsLogger.debug(LTag.PUMPCOMM, "[" + id + "] " + (if (newRecord) "**NEW** " else "") + "EVENT BOLUS (" + recordCode + ") " + dateUtil.dateAndTimeString(datetime) + " (" + datetime + ")" + " Bolus: " + param1 / 100.0 + "U Duration: " + param2 + "min") + val newRecord = pumpSync.syncBolusWithPumpId( + timestamp = datetime, + amount = param1 / 100.0, + type = detailedBolusInfo?.bolusType, + pumpId = pumpId, + pumpType = PumpType.DANA_RS, + pumpSerial = danaPump.serialNumber) + aapsLogger.debug(LTag.PUMPCOMM, "[" + id + "] " + (if (newRecord) "**NEW** " else "") + "EVENT BOLUS (" + recordCode + ") " + dateUtil.dateAndTimeString(datetime) + " (" + datetime + ")" + " Bolus: " + param1 / 100.0 + "U ") status = "BOLUS " + dateUtil.timeString(datetime) } DanaPump.DUALBOLUS -> { val detailedBolusInfo = detailedBolusInfoStorage.findDetailedBolusInfo(datetime, param1 / 100.0) - ?: DetailedBolusInfo() - detailedBolusInfo.date = datetime - detailedBolusInfo.source = Source.PUMP - detailedBolusInfo.pumpId = 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 = pumpId, + pumpType = PumpType.DANA_RS, + pumpSerial = danaPump.serialNumber) aapsLogger.debug(LTag.PUMPCOMM, "[" + id + "] " + (if (newRecord) "**NEW** " else "") + "EVENT DUALBOLUS (" + recordCode + ") " + dateUtil.dateAndTimeString(datetime) + " (" + datetime + ")" + " Bolus: " + param1 / 100.0 + "U Duration: " + param2 + "min") status = "DUALBOLUS " + dateUtil.timeString(datetime) } DanaPump.DUALEXTENDEDSTART -> { - aapsLogger.debug(LTag.PUMPCOMM, "[" + id + "] " + "EVENT DUALEXTENDEDSTART (" + recordCode + ") " + dateUtil.dateAndTimeString(datetime) + " (" + datetime + ")" + " Amount: " + param1 / 100.0 + "U Duration: " + param2 + "min") - extendedBolus.insulin = param1 / 100.0 - extendedBolus.durationInMinutes = param2 - activePlugin.activeTreatments.addToHistoryExtendedBolus(extendedBolus) + val newRecord = pumpSync.syncExtendedBolusWithPumpId( + timestamp = datetime, + amount = param1 / 100.0, + duration = T.mins(param2.toLong()).msecs(), + isEmulatingTB = false, + pumpId = pumpId, + pumpType = PumpType.DANA_RS, + pumpSerial = danaPump.serialNumber) + aapsLogger.debug(LTag.PUMPCOMM, "[" + id + "] " + (if (newRecord) "**NEW** " else "") + "EVENT DUALEXTENDEDSTART (" + recordCode + ") " + dateUtil.dateAndTimeString(datetime) + " (" + datetime + ")" + " Amount: " + param1 / 100.0 + "U Duration: " + param2 + "min") status = "DUALEXTENDEDSTART " + dateUtil.timeString(datetime) } DanaPump.DUALEXTENDEDSTOP -> { - aapsLogger.debug(LTag.PUMPCOMM, "[" + id + "] " + "EVENT DUALEXTENDEDSTOP (" + recordCode + ") " + dateUtil.dateAndTimeString(datetime) + " (" + datetime + ")" + " Delivered: " + param1 / 100.0 + "U RealDuration: " + param2 + "min") - activePlugin.activeTreatments.addToHistoryExtendedBolus(extendedBolus) + val newRecord = pumpSync.syncStopExtendedBolusWithPumpId( + timestamp = datetime, + endPumpId = pumpId, + pumpType = PumpType.DANA_RS, + pumpSerial = danaPump.serialNumber) + aapsLogger.debug(LTag.PUMPCOMM, "[" + id + "] " + (if (newRecord) "**NEW** " else "") + "EVENT DUALEXTENDEDSTOP (" + recordCode + ") " + dateUtil.dateAndTimeString(datetime) + " (" + datetime + ")" + " Delivered: " + param1 / 100.0 + "U RealDuration: " + param2 + "min") status = "DUALEXTENDEDSTOP " + dateUtil.timeString(datetime) } @@ -178,18 +235,16 @@ open class DanaRS_Packet_APS_History_Events( } DanaPump.REFILL -> { - aapsLogger.debug(LTag.PUMPCOMM, "[" + id + "] " + "EVENT REFILL (" + recordCode + ") " + dateUtil.dateAndTimeString(datetime) + " (" + datetime + ")" + " Amount: " + param1 / 100.0 + "U") - if (sp.getBoolean(R.string.key_rs_loginsulinchange, true)) - disposable += repository.runTransactionForResult(InsertTherapyEventIfNewTransaction( + if (sp.getBoolean(R.string.key_rs_loginsulinchange, true)) { + val newRecord = pumpSync.insertTherapyEventIfNewWithTimestamp( timestamp = datetime, - type = TherapyEvent.Type.INSULIN_CHANGE, - note = resourceHelper.gs(R.string.danarspump), - glucoseUnit = TherapyEvent.GlucoseUnit.MGDL - )).subscribe({ result -> - result.inserted.forEach { nsUpload.uploadEvent(it) } - }, { - aapsLogger.error(LTag.BGSOURCE, "Error while saving therapy event", it) - }) + type = DetailedBolusInfo.EventType.INSULIN_CHANGE, + pumpId = pumpId, + pumpType = danaPump.pumpType(), + pumpSerial = danaPump.serialNumber + ) + aapsLogger.debug(LTag.PUMPCOMM, "[" + id + "] " + (if (newRecord) "**NEW** " else "") + "EVENT REFILL (" + recordCode + ") " + dateUtil.dateAndTimeString(datetime) + " (" + datetime + ")" + " Amount: " + param1 / 100.0 + "U") + } status = "REFILL " + dateUtil.timeString(datetime) } @@ -204,29 +259,27 @@ open class DanaRS_Packet_APS_History_Events( } DanaPump.CARBS -> { - val emptyCarbsInfo = DetailedBolusInfo() - emptyCarbsInfo.carbs = param1.toDouble() - emptyCarbsInfo.date = datetime - emptyCarbsInfo.source = Source.PUMP - emptyCarbsInfo.pumpId = datetime - val newRecord = activePlugin.activeTreatments.addToHistoryTreatment(emptyCarbsInfo, false) + val newRecord = pumpSync.syncCarbsWithTimestamp( + timestamp = datetime, + amount = param1.toDouble(), + pumpId = pumpId, + pumpType = PumpType.DANA_RS, + pumpSerial = danaPump.serialNumber) aapsLogger.debug(LTag.PUMPCOMM, "[" + id + "] " + (if (newRecord) "**NEW** " else "") + "EVENT CARBS (" + recordCode + ") " + dateUtil.dateAndTimeString(datetime) + " (" + datetime + ")" + " Carbs: " + param1 + "g") status = "CARBS " + dateUtil.timeString(datetime) } DanaPump.PRIMECANNULA -> { - aapsLogger.debug(LTag.PUMPCOMM, "[" + id + "] " + "EVENT PRIMECANNULA(" + recordCode + ") " + dateUtil.dateAndTimeString(datetime) + " (" + datetime + ")" + " Amount: " + param1 / 100.0 + "U") - if (sp.getBoolean(R.string.key_rs_logcanulachange, true)) - disposable += repository.runTransactionForResult(InsertTherapyEventIfNewTransaction( + if (sp.getBoolean(R.string.key_rs_logcanulachange, true)) { + val newRecord = pumpSync.insertTherapyEventIfNewWithTimestamp( timestamp = datetime, - type = TherapyEvent.Type.CANNULA_CHANGE, - note = resourceHelper.gs(R.string.danarspump), - glucoseUnit = TherapyEvent.GlucoseUnit.MGDL - )).subscribe({ result -> - result.inserted.forEach { nsUpload.uploadEvent(it) } - }, { - aapsLogger.error(LTag.BGSOURCE, "Error while saving therapy event", it) - }) + type = DetailedBolusInfo.EventType.CANNULA_CHANGE, + pumpId = pumpId, + pumpType = danaPump.pumpType(), + pumpSerial = danaPump.serialNumber + ) + aapsLogger.debug(LTag.PUMPCOMM, "[" + id + "] " + (if (newRecord) "**NEW** " else "") + "EVENT PRIMECANNULA(" + recordCode + ") " + dateUtil.dateAndTimeString(datetime) + " (" + datetime + ")" + " Amount: " + param1 / 100.0 + "U") + } status = "PRIMECANNULA " + dateUtil.timeString(datetime) } diff --git a/danars/src/main/java/info/nightscout/androidaps/danars/comm/DanaRS_Packet_Basal_Get_Temporary_Basal_State.kt b/danars/src/main/java/info/nightscout/androidaps/danars/comm/DanaRS_Packet_Basal_Get_Temporary_Basal_State.kt index 1471af5478..f8f475f759 100644 --- a/danars/src/main/java/info/nightscout/androidaps/danars/comm/DanaRS_Packet_Basal_Get_Temporary_Basal_State.kt +++ b/danars/src/main/java/info/nightscout/androidaps/danars/comm/DanaRS_Packet_Basal_Get_Temporary_Basal_State.kt @@ -5,6 +5,7 @@ import info.nightscout.androidaps.logging.LTag import info.nightscout.androidaps.dana.DanaPump import info.nightscout.androidaps.danars.encryption.BleEncryption import javax.inject.Inject +import kotlin.math.abs import kotlin.math.ceil class DanaRS_Packet_Basal_Get_Temporary_Basal_State( @@ -18,24 +19,29 @@ class DanaRS_Packet_Basal_Get_Temporary_Basal_State( aapsLogger.debug(LTag.PUMPCOMM, "Requesting temporary basal status") } + var isTempBasalInProgress: Boolean = false + var tempBasalTotalSec: Int = 0 + var tempBasalPercent: Int = 0 + override fun handleMessage(data: ByteArray) { val error = byteArrayToInt(getBytes(data, DATA_START, 1)) - danaPump.isTempBasalInProgress = byteArrayToInt(getBytes(data, DATA_START + 1, 1)) == 0x01 + isTempBasalInProgress = byteArrayToInt(getBytes(data, DATA_START + 1, 1)) == 0x01 val isAPSTempBasalInProgress = byteArrayToInt(getBytes(data, DATA_START + 1, 1)) == 0x02 - danaPump.tempBasalPercent = byteArrayToInt(getBytes(data, DATA_START + 2, 1)) - if (danaPump.tempBasalPercent > 200) danaPump.tempBasalPercent = (danaPump.tempBasalPercent - 200) * 10 + tempBasalPercent = byteArrayToInt(getBytes(data, DATA_START + 2, 1)) + if (tempBasalPercent > 200) tempBasalPercent = (tempBasalPercent - 200) * 10 val durationHour = byteArrayToInt(getBytes(data, DATA_START + 3, 1)) - if (durationHour == 150) danaPump.tempBasalTotalSec = 15 * 60 else if (durationHour == 160) danaPump.tempBasalTotalSec = 30 * 60 else danaPump.tempBasalTotalSec = durationHour * 60 * 60 + tempBasalTotalSec = if (durationHour == 150) 15 * 60 else if (durationHour == 160) 30 * 60 else durationHour * 60 * 60 val runningMin = byteArrayToInt(getBytes(data, DATA_START + 4, 2)) if (error != 0) failed = true val tempBasalRemainingMin = (danaPump.tempBasalTotalSec - runningMin * 60) / 60 - val tempBasalStart = if (danaPump.isTempBasalInProgress) getDateFromTempBasalSecAgo(runningMin * 60) else 0 + val tempBasalStart = if (isTempBasalInProgress) getDateFromTempBasalSecAgo(runningMin * 60) else 0 + if (!isTempBasalInProgress) danaPump.isTempBasalInProgress = false aapsLogger.debug(LTag.PUMPCOMM, "Error code: $error") - aapsLogger.debug(LTag.PUMPCOMM, "Is temp basal running: " + danaPump.isTempBasalInProgress) + aapsLogger.debug(LTag.PUMPCOMM, "Is temp basal running: $isTempBasalInProgress") aapsLogger.debug(LTag.PUMPCOMM, "Is APS temp basal running: $isAPSTempBasalInProgress") - aapsLogger.debug(LTag.PUMPCOMM, "Current temp basal percent: " + danaPump.tempBasalPercent) + aapsLogger.debug(LTag.PUMPCOMM, "Current temp basal percent: $tempBasalPercent") aapsLogger.debug(LTag.PUMPCOMM, "Current temp basal remaining min: $tempBasalRemainingMin") - aapsLogger.debug(LTag.PUMPCOMM, "Current temp basal total sec: " + danaPump.tempBasalTotalSec) + aapsLogger.debug(LTag.PUMPCOMM, "Current temp basal total sec: $tempBasalTotalSec") aapsLogger.debug(LTag.PUMPCOMM, "Current temp basal start: " + dateUtil.dateAndTimeString(tempBasalStart)) } diff --git a/danars/src/main/java/info/nightscout/androidaps/danars/comm/DanaRS_Packet_Bolus_Get_Dual_Bolus.kt b/danars/src/main/java/info/nightscout/androidaps/danars/comm/DanaRS_Packet_Bolus_Get_Dual_Bolus.kt index babe627091..309f3ed561 100644 --- a/danars/src/main/java/info/nightscout/androidaps/danars/comm/DanaRS_Packet_Bolus_Get_Dual_Bolus.kt +++ b/danars/src/main/java/info/nightscout/androidaps/danars/comm/DanaRS_Packet_Bolus_Get_Dual_Bolus.kt @@ -20,13 +20,13 @@ class DanaRS_Packet_Bolus_Get_Dual_Bolus( override fun handleMessage(data: ByteArray) { val error = byteArrayToInt(getBytes(data, DATA_START, 1)) danaPump.bolusStep = byteArrayToInt(getBytes(data, DATA_START + 1, 2)) / 100.0 - danaPump.extendedBolusAbsoluteRate = byteArrayToInt(getBytes(data, DATA_START + 3, 2)) / 100.0 + val extendedBolusAbsoluteRate = byteArrayToInt(getBytes(data, DATA_START + 3, 2)) / 100.0 danaPump.maxBolus = byteArrayToInt(getBytes(data, DATA_START + 5, 2)) / 100.0 val bolusIncrement = byteArrayToInt(getBytes(data, DATA_START + 7, 1)) / 100.0 failed = error != 0 aapsLogger.debug(LTag.PUMPCOMM, "Result: $error") aapsLogger.debug(LTag.PUMPCOMM, "Bolus step: ${danaPump.bolusStep} U") - aapsLogger.debug(LTag.PUMPCOMM, "Extended bolus running: ${danaPump.extendedBolusAbsoluteRate} U/h") + aapsLogger.debug(LTag.PUMPCOMM, "Extended bolus running: $extendedBolusAbsoluteRate U/h") aapsLogger.debug(LTag.PUMPCOMM, "Max bolus: " + danaPump.maxBolus + " U") aapsLogger.debug(LTag.PUMPCOMM, "bolusIncrement: $bolusIncrement U") } diff --git a/danars/src/main/java/info/nightscout/androidaps/danars/comm/DanaRS_Packet_Bolus_Get_Extended_Bolus.kt b/danars/src/main/java/info/nightscout/androidaps/danars/comm/DanaRS_Packet_Bolus_Get_Extended_Bolus.kt index 8aae55b413..623e1f8361 100644 --- a/danars/src/main/java/info/nightscout/androidaps/danars/comm/DanaRS_Packet_Bolus_Get_Extended_Bolus.kt +++ b/danars/src/main/java/info/nightscout/androidaps/danars/comm/DanaRS_Packet_Bolus_Get_Extended_Bolus.kt @@ -23,7 +23,7 @@ class DanaRS_Packet_Bolus_Get_Extended_Bolus( val error = byteArrayToInt(getBytes(data, dataIndex, dataSize)) dataIndex += dataSize dataSize = 2 - danaPump.extendedBolusAbsoluteRate = byteArrayToInt(getBytes(data, dataIndex, dataSize)) / 100.0 + val extendedBolusAbsoluteRate = byteArrayToInt(getBytes(data, dataIndex, dataSize)) / 100.0 dataIndex += dataSize dataSize = 2 danaPump.maxBolus = byteArrayToInt(getBytes(data, dataIndex, dataSize)) / 100.0 @@ -32,7 +32,7 @@ class DanaRS_Packet_Bolus_Get_Extended_Bolus( danaPump.bolusStep = byteArrayToInt(getBytes(data, dataIndex, dataSize)) / 100.0 failed = error != 0 aapsLogger.debug(LTag.PUMPCOMM, "Result: $error") - aapsLogger.debug(LTag.PUMPCOMM, "Extended bolus running: " + danaPump.extendedBolusAbsoluteRate + " U/h") + aapsLogger.debug(LTag.PUMPCOMM, "Extended bolus running: $extendedBolusAbsoluteRate U/h") aapsLogger.debug(LTag.PUMPCOMM, "Max bolus: " + danaPump.maxBolus + " U") aapsLogger.debug(LTag.PUMPCOMM, "Bolus step: " + danaPump.bolusStep + " U") } diff --git a/danars/src/main/java/info/nightscout/androidaps/danars/comm/DanaRS_Packet_Bolus_Get_Extended_Bolus_State.kt b/danars/src/main/java/info/nightscout/androidaps/danars/comm/DanaRS_Packet_Bolus_Get_Extended_Bolus_State.kt index 7c859ed743..e3e6cb9e45 100644 --- a/danars/src/main/java/info/nightscout/androidaps/danars/comm/DanaRS_Packet_Bolus_Get_Extended_Bolus_State.kt +++ b/danars/src/main/java/info/nightscout/androidaps/danars/comm/DanaRS_Packet_Bolus_Get_Extended_Bolus_State.kt @@ -4,6 +4,7 @@ import dagger.android.HasAndroidInjector import info.nightscout.androidaps.logging.LTag import info.nightscout.androidaps.dana.DanaPump import info.nightscout.androidaps.danars.encryption.BleEncryption +import info.nightscout.androidaps.utils.T import javax.inject.Inject class DanaRS_Packet_Bolus_Get_Extended_Bolus_State( @@ -17,32 +18,34 @@ class DanaRS_Packet_Bolus_Get_Extended_Bolus_State( aapsLogger.debug(LTag.PUMPCOMM, "New message") } + var isExtendedInProgress: Boolean = false + override fun handleMessage(data: ByteArray) { var dataIndex = DATA_START var dataSize = 1 val error = byteArrayToInt(getBytes(data, dataIndex, dataSize)) dataIndex += dataSize dataSize = 1 - danaPump.isExtendedInProgress = byteArrayToInt(getBytes(data, dataIndex, dataSize)) == 0x01 + isExtendedInProgress = byteArrayToInt(getBytes(data, dataIndex, dataSize)) == 0x01 dataIndex += dataSize dataSize = 1 - danaPump.extendedBolusMinutes = byteArrayToInt(getBytes(data, dataIndex, dataSize)) * 30 + val extendedBolusDuration = T.mins(byteArrayToInt(getBytes(data, dataIndex, dataSize)) * 30L).msecs() dataIndex += dataSize dataSize = 2 - danaPump.extendedBolusAbsoluteRate = byteArrayToInt(getBytes(data, dataIndex, dataSize)) / 100.0 + val extendedBolusAbsoluteRate = byteArrayToInt(getBytes(data, dataIndex, dataSize)) / 100.0 // duration must be set first for recalculation to amount dataIndex += dataSize dataSize = 2 - danaPump.extendedBolusSoFarInMinutes = byteArrayToInt(getBytes(data, dataIndex, dataSize)) + val extendedBolusSoFarInMinutes = byteArrayToInt(getBytes(data, dataIndex, dataSize)) dataIndex += dataSize dataSize = 2 - danaPump.extendedBolusDeliveredSoFar = byteArrayToInt(getBytes(data, dataIndex, dataSize)) / 100.0 + val extendedBolusDeliveredSoFar = byteArrayToInt(getBytes(data, dataIndex, dataSize)) / 100.0 failed = error != 0 aapsLogger.debug(LTag.PUMPCOMM, "Result: $error") - aapsLogger.debug(LTag.PUMPCOMM, "Is extended bolus running: " + danaPump.isExtendedInProgress) - aapsLogger.debug(LTag.PUMPCOMM, "Extended bolus running: " + danaPump.extendedBolusAbsoluteRate + " U/h") - aapsLogger.debug(LTag.PUMPCOMM, "Extended bolus duration: " + danaPump.extendedBolusMinutes + " min") - aapsLogger.debug(LTag.PUMPCOMM, "Extended bolus so far: " + danaPump.extendedBolusSoFarInMinutes + " min") - aapsLogger.debug(LTag.PUMPCOMM, "Extended bolus delivered so far: " + danaPump.extendedBolusDeliveredSoFar + " U") + aapsLogger.debug(LTag.PUMPCOMM, "Is extended bolus running: $isExtendedInProgress") + aapsLogger.debug(LTag.PUMPCOMM, "Extended bolus running: $extendedBolusAbsoluteRate U/h") + aapsLogger.debug(LTag.PUMPCOMM, "Extended bolus duration: " + T.msecs(extendedBolusDuration).mins() + " min") + aapsLogger.debug(LTag.PUMPCOMM, "Extended bolus so far: $extendedBolusSoFarInMinutes min") + aapsLogger.debug(LTag.PUMPCOMM, "Extended bolus delivered so far: $extendedBolusDeliveredSoFar U") } override fun getFriendlyName(): String { diff --git a/danars/src/main/java/info/nightscout/androidaps/danars/comm/DanaRS_Packet_Bolus_Get_Extended_Menu_Option_State.kt b/danars/src/main/java/info/nightscout/androidaps/danars/comm/DanaRS_Packet_Bolus_Get_Extended_Menu_Option_State.kt index 3757188d4a..9f4a26da6f 100644 --- a/danars/src/main/java/info/nightscout/androidaps/danars/comm/DanaRS_Packet_Bolus_Get_Extended_Menu_Option_State.kt +++ b/danars/src/main/java/info/nightscout/androidaps/danars/comm/DanaRS_Packet_Bolus_Get_Extended_Menu_Option_State.kt @@ -17,13 +17,15 @@ class DanaRS_Packet_Bolus_Get_Extended_Menu_Option_State( aapsLogger.debug(LTag.PUMPCOMM, "New message") } + var isExtendedInProgress: Boolean = false + override fun handleMessage(data: ByteArray) { var dataIndex = DATA_START var dataSize = 1 val extendedMenuOption = byteArrayToInt(getBytes(data, dataIndex, dataSize)) dataIndex += dataSize dataSize = 1 - danaPump.isExtendedInProgress = byteArrayToInt(getBytes(data, dataIndex, dataSize)) == 0x01 + isExtendedInProgress = byteArrayToInt(getBytes(data, dataIndex, dataSize)) == 0x01 aapsLogger.debug(LTag.PUMPCOMM, "extendedMenuOption: $extendedMenuOption") } diff --git a/danars/src/main/java/info/nightscout/androidaps/danars/comm/DanaRS_Packet_General_Get_More_Information.kt b/danars/src/main/java/info/nightscout/androidaps/danars/comm/DanaRS_Packet_General_Get_More_Information.kt index 0d110deb71..4659e91dae 100644 --- a/danars/src/main/java/info/nightscout/androidaps/danars/comm/DanaRS_Packet_General_Get_More_Information.kt +++ b/danars/src/main/java/info/nightscout/androidaps/danars/comm/DanaRS_Packet_General_Get_More_Information.kt @@ -26,8 +26,8 @@ class DanaRS_Packet_General_Get_More_Information( } danaPump.iob = intFromBuff(data, 0, 2) / 100.0 danaPump.dailyTotalUnits = intFromBuff(data, 2, 2) / 100.0 - danaPump.isExtendedInProgress = intFromBuff(data, 4, 1) == 0x01 - danaPump.extendedBolusRemainingMinutes = intFromBuff(data, 5, 2) + val isExtendedInProgress = intFromBuff(data, 4, 1) == 0x01 + val extendedBolusRemainingMinutes = intFromBuff(data, 5, 2) // val remainRate = intFromBuff(data, 7, 2) / 100.0 val hours = intFromBuff(data, 9, 1) val minutes = intFromBuff(data, 10, 1) @@ -37,8 +37,8 @@ class DanaRS_Packet_General_Get_More_Information( // On DanaRS DailyUnits can't be more than 160 if (danaPump.dailyTotalUnits > 160) failed = true aapsLogger.debug(LTag.PUMPCOMM, "Daily total units: " + danaPump.dailyTotalUnits.toString() + " U") - aapsLogger.debug(LTag.PUMPCOMM, "Is extended in progress: " + danaPump.isExtendedInProgress) - aapsLogger.debug(LTag.PUMPCOMM, "Extended bolus remaining minutes: " + danaPump.extendedBolusRemainingMinutes) + aapsLogger.debug(LTag.PUMPCOMM, "Is extended in progress: $isExtendedInProgress") + aapsLogger.debug(LTag.PUMPCOMM, "Extended bolus remaining minutes: $extendedBolusRemainingMinutes") aapsLogger.debug(LTag.PUMPCOMM, "Last bolus time: " + dateUtil.dateAndTimeAndSecondsString(danaPump.lastBolusTime)) aapsLogger.debug(LTag.PUMPCOMM, "Last bolus amount: " + danaPump.lastBolusAmount) } diff --git a/danars/src/main/java/info/nightscout/androidaps/danars/comm/DanaRS_Packet_General_Initial_Screen_Information.kt b/danars/src/main/java/info/nightscout/androidaps/danars/comm/DanaRS_Packet_General_Initial_Screen_Information.kt index 8eeb017ebb..35a0e35487 100644 --- a/danars/src/main/java/info/nightscout/androidaps/danars/comm/DanaRS_Packet_General_Initial_Screen_Information.kt +++ b/danars/src/main/java/info/nightscout/androidaps/danars/comm/DanaRS_Packet_General_Initial_Screen_Information.kt @@ -26,9 +26,9 @@ class DanaRS_Packet_General_Initial_Screen_Information( var dataSize = 1 val status = byteArrayToInt(getBytes(data, dataIndex, dataSize)) danaPump.pumpSuspended = status and 0x01 == 0x01 - danaPump.isTempBasalInProgress = status and 0x10 == 0x10 - danaPump.isExtendedInProgress = status and 0x04 == 0x04 - danaPump.isDualBolusInProgress = status and 0x08 == 0x08 + val isTempBasalInProgress = status and 0x10 == 0x10 + val isExtendedInProgress = status and 0x04 == 0x04 + val isDualBolusInProgress = status and 0x08 == 0x08 dataIndex += dataSize dataSize = 2 danaPump.dailyTotalUnits = byteArrayToInt(getBytes(data, dataIndex, dataSize)) / 100.0 @@ -43,13 +43,13 @@ class DanaRS_Packet_General_Initial_Screen_Information( danaPump.currentBasal = byteArrayToInt(getBytes(data, dataIndex, dataSize)) / 100.0 dataIndex += dataSize dataSize = 1 - danaPump.tempBasalPercent = byteArrayToInt(getBytes(data, dataIndex, dataSize)) + val tempBasalPercent = byteArrayToInt(getBytes(data, dataIndex, dataSize)) dataIndex += dataSize dataSize = 1 danaPump.batteryRemaining = byteArrayToInt(getBytes(data, dataIndex, dataSize)) dataIndex += dataSize dataSize = 2 - danaPump.extendedBolusAbsoluteRate = byteArrayToInt(getBytes(data, dataIndex, dataSize)) / 100.0 + val extendedBolusAbsoluteRate = byteArrayToInt(getBytes(data, dataIndex, dataSize)) / 100.0 dataIndex += dataSize dataSize = 2 danaPump.iob = byteArrayToInt(getBytes(data, dataIndex, dataSize)) / 100.0 @@ -62,16 +62,16 @@ class DanaRS_Packet_General_Initial_Screen_Information( aapsLogger.debug(LTag.PUMPCOMM, "ErrorState: " + danaPump.errorState.name) } aapsLogger.debug(LTag.PUMPCOMM, "Pump suspended: " + danaPump.pumpSuspended) - aapsLogger.debug(LTag.PUMPCOMM, "Temp basal in progress: " + danaPump.isTempBasalInProgress) - aapsLogger.debug(LTag.PUMPCOMM, "Extended in progress: " + danaPump.isExtendedInProgress) - aapsLogger.debug(LTag.PUMPCOMM, "Dual in progress: " + danaPump.isDualBolusInProgress) + aapsLogger.debug(LTag.PUMPCOMM, "Temp basal in progress: $isTempBasalInProgress") + aapsLogger.debug(LTag.PUMPCOMM, "Extended in progress: $isExtendedInProgress") + aapsLogger.debug(LTag.PUMPCOMM, "Dual in progress: $isDualBolusInProgress") aapsLogger.debug(LTag.PUMPCOMM, "Daily units: " + danaPump.dailyTotalUnits) aapsLogger.debug(LTag.PUMPCOMM, "Max daily units: " + danaPump.maxDailyTotalUnits) aapsLogger.debug(LTag.PUMPCOMM, "Reservoir remaining units: " + danaPump.reservoirRemainingUnits) aapsLogger.debug(LTag.PUMPCOMM, "Battery: " + danaPump.batteryRemaining) aapsLogger.debug(LTag.PUMPCOMM, "Current basal: " + danaPump.currentBasal) - aapsLogger.debug(LTag.PUMPCOMM, "Temp basal percent: " + danaPump.tempBasalPercent) - aapsLogger.debug(LTag.PUMPCOMM, "Extended absolute rate: " + danaPump.extendedBolusAbsoluteRate) + aapsLogger.debug(LTag.PUMPCOMM, "Temp basal percent: " + tempBasalPercent) + aapsLogger.debug(LTag.PUMPCOMM, "Extended absolute rate: $extendedBolusAbsoluteRate") } override fun getFriendlyName(): String { diff --git a/danars/src/main/java/info/nightscout/androidaps/danars/comm/DanaRS_Packet_Notify_Alarm.kt b/danars/src/main/java/info/nightscout/androidaps/danars/comm/DanaRS_Packet_Notify_Alarm.kt index 43f873886f..f49f25010a 100644 --- a/danars/src/main/java/info/nightscout/androidaps/danars/comm/DanaRS_Packet_Notify_Alarm.kt +++ b/danars/src/main/java/info/nightscout/androidaps/danars/comm/DanaRS_Packet_Notify_Alarm.kt @@ -1,13 +1,14 @@ package info.nightscout.androidaps.danars.comm import dagger.android.HasAndroidInjector +import info.nightscout.androidaps.dana.DanaPump import info.nightscout.androidaps.danars.R +import info.nightscout.androidaps.danars.encryption.BleEncryption +import info.nightscout.androidaps.interfaces.PumpSync import info.nightscout.androidaps.logging.LTag import info.nightscout.androidaps.plugins.bus.RxBusWrapper -import info.nightscout.androidaps.plugins.general.nsclient.NSUpload import info.nightscout.androidaps.plugins.general.overview.events.EventNewNotification import info.nightscout.androidaps.plugins.general.overview.notifications.Notification -import info.nightscout.androidaps.danars.encryption.BleEncryption import info.nightscout.androidaps.utils.resources.ResourceHelper import javax.inject.Inject @@ -17,7 +18,8 @@ class DanaRS_Packet_Notify_Alarm( @Inject lateinit var rxBus: RxBusWrapper @Inject lateinit var resourceHelper: ResourceHelper - @Inject lateinit var nsUpload: NSUpload + @Inject lateinit var pumpSync: PumpSync + @Inject lateinit var danaPump: DanaPump init { type = BleEncryption.DANAR_PACKET__TYPE_NOTIFY @@ -64,7 +66,7 @@ class DanaRS_Packet_Notify_Alarm( } val notification = Notification(Notification.USER_MESSAGE, errorString, Notification.URGENT) rxBus.send(EventNewNotification(notification)) - nsUpload.uploadError(errorString) + pumpSync.insertAnnouncement(errorString, null, danaPump.pumpType(), danaPump.serialNumber) } override fun getFriendlyName(): String { diff --git a/danars/src/main/java/info/nightscout/androidaps/danars/services/BLEComm.kt b/danars/src/main/java/info/nightscout/androidaps/danars/services/BLEComm.kt index f9b81444dd..abd5cf6eb2 100644 --- a/danars/src/main/java/info/nightscout/androidaps/danars/services/BLEComm.kt +++ b/danars/src/main/java/info/nightscout/androidaps/danars/services/BLEComm.kt @@ -17,18 +17,18 @@ import info.nightscout.androidaps.danars.comm.DanaRS_Packet_Etc_Keep_Connection import info.nightscout.androidaps.danars.encryption.BleEncryption import info.nightscout.androidaps.danars.events.EventDanaRSPairingSuccess import info.nightscout.androidaps.events.EventPumpStatusChanged +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 -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 import info.nightscout.androidaps.plugins.general.overview.notifications.Notification import info.nightscout.androidaps.utils.DateUtil import info.nightscout.androidaps.utils.T import info.nightscout.androidaps.utils.ToastUtils -import info.nightscout.androidaps.utils.extensions.notify -import info.nightscout.androidaps.utils.extensions.waitMillis +import info.nightscout.androidaps.extensions.notify +import info.nightscout.androidaps.extensions.waitMillis import info.nightscout.androidaps.utils.resources.ResourceHelper import info.nightscout.androidaps.utils.sharedPreferences.SP import java.util.* @@ -48,7 +48,8 @@ class BLEComm @Inject internal constructor( private val danaPump: DanaPump, private val danaRSPlugin: DanaRSPlugin, private val bleEncryption: BleEncryption, - private val nsUpload: NSUpload + private val pumpSync: PumpSync, + private val dateUtil: DateUtil ) { companion object { @@ -140,7 +141,7 @@ class BLEComm @Inject internal constructor( // there was no response from pump after started encryption // assume pairing keys are invalid val lastClearRequest = sp.getLong(R.string.key_rs_last_clear_key_request, 0) - if (lastClearRequest != 0L && DateUtil.isOlderThan(lastClearRequest, 5)) { + if (lastClearRequest != 0L && dateUtil.isOlderThan(lastClearRequest, 5)) { aapsLogger.error("Clearing pairing keys !!!") sp.remove(resourceHelper.gs(R.string.key_danars_v3_randompairingkey) + danaRSPlugin.mDeviceName) sp.remove(resourceHelper.gs(R.string.key_danars_v3_pairingkey) + danaRSPlugin.mDeviceName) @@ -149,7 +150,7 @@ class BLEComm @Inject internal constructor( danaRSPlugin.changePump() } else if (lastClearRequest == 0L) { aapsLogger.error("Clearing pairing keys postponed") - sp.putLong(R.string.key_rs_last_clear_key_request, DateUtil.now()) + sp.putLong(R.string.key_rs_last_clear_key_request, dateUtil.now()) } } // cancel previous scheduled disconnection to prevent closing upcoming connection @@ -391,22 +392,22 @@ class BLEComm @Inject internal constructor( if (decryptedBuffer[0] == BleEncryption.DANAR_PACKET__TYPE_ENCRYPTION_RESPONSE.toByte()) { when (decryptedBuffer[1]) { // 1st packet exchange - BleEncryption.DANAR_PACKET__OPCODE_ENCRYPTION__PUMP_CHECK.toByte() -> + BleEncryption.DANAR_PACKET__OPCODE_ENCRYPTION__PUMP_CHECK.toByte() -> processConnectResponse(decryptedBuffer) - BleEncryption.DANAR_PACKET__OPCODE_ENCRYPTION__TIME_INFORMATION.toByte() -> + BleEncryption.DANAR_PACKET__OPCODE_ENCRYPTION__TIME_INFORMATION.toByte() -> processEncryptionResponse(decryptedBuffer) - BleEncryption.DANAR_PACKET__OPCODE_ENCRYPTION__CHECK_PASSKEY.toByte() -> + BleEncryption.DANAR_PACKET__OPCODE_ENCRYPTION__CHECK_PASSKEY.toByte() -> processPasskeyCheck(decryptedBuffer) - BleEncryption.DANAR_PACKET__OPCODE_ENCRYPTION__PASSKEY_REQUEST.toByte() -> + BleEncryption.DANAR_PACKET__OPCODE_ENCRYPTION__PASSKEY_REQUEST.toByte() -> processPairingRequest(decryptedBuffer) - BleEncryption.DANAR_PACKET__OPCODE_ENCRYPTION__PASSKEY_RETURN.toByte() -> + BleEncryption.DANAR_PACKET__OPCODE_ENCRYPTION__PASSKEY_RETURN.toByte() -> processPairingRequest2(decryptedBuffer) - BleEncryption.DANAR_PACKET__OPCODE_ENCRYPTION__GET_PUMP_CHECK.toByte() -> { + BleEncryption.DANAR_PACKET__OPCODE_ENCRYPTION__GET_PUMP_CHECK.toByte() -> { // not easy mode, request time info if (decryptedBuffer[2] == 0x05.toByte()) sendTimeInfo() // easy mode @@ -488,7 +489,7 @@ class BLEComm @Inject internal constructor( aapsLogger.debug(LTag.PUMPBTCOMM, "<<<<< " + "ENCRYPTION__PUMP_CHECK (PUMP)" + " " + DanaRS_Packet.toHexString(decryptedBuffer)) mSendQueue.clear() rxBus.send(EventPumpStatusChanged(EventPumpStatusChanged.Status.DISCONNECTED, resourceHelper.gs(R.string.pumperror))) - nsUpload.uploadError(resourceHelper.gs(R.string.pumperror)) + pumpSync.insertAnnouncement(resourceHelper.gs(R.string.pumperror), null, danaPump.pumpType(), danaPump.serialNumber) val n = Notification(Notification.PUMP_ERROR, resourceHelper.gs(R.string.pumperror), Notification.URGENT) rxBus.send(EventNewNotification(n)) // response BUSY: error status diff --git a/danars/src/main/java/info/nightscout/androidaps/danars/services/DanaRSService.kt b/danars/src/main/java/info/nightscout/androidaps/danars/services/DanaRSService.kt index 6cebbe7889..000b2800fb 100644 --- a/danars/src/main/java/info/nightscout/androidaps/danars/services/DanaRSService.kt +++ b/danars/src/main/java/info/nightscout/androidaps/danars/services/DanaRSService.kt @@ -18,20 +18,19 @@ import info.nightscout.androidaps.danars.R import info.nightscout.androidaps.danars.comm.* import info.nightscout.androidaps.data.Profile import info.nightscout.androidaps.data.PumpEnactResult -import info.nightscout.androidaps.db.Treatment import info.nightscout.androidaps.dialogs.BolusProgressDialog import info.nightscout.androidaps.events.EventAppExit import info.nightscout.androidaps.events.EventInitializationChanged import info.nightscout.androidaps.events.EventProfileNeedsUpdate import info.nightscout.androidaps.events.EventPumpStatusChanged -import info.nightscout.androidaps.interfaces.ActivePluginProvider +import info.nightscout.androidaps.interfaces.ActivePlugin import info.nightscout.androidaps.interfaces.CommandQueueProvider import info.nightscout.androidaps.interfaces.ProfileFunction +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 import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker -import info.nightscout.androidaps.plugins.general.nsclient.NSUpload import info.nightscout.androidaps.plugins.general.overview.events.EventNewNotification import info.nightscout.androidaps.plugins.general.overview.events.EventOverviewBolusProgress import info.nightscout.androidaps.plugins.general.overview.notifications.Notification @@ -66,17 +65,16 @@ class DanaRSService : DaggerService() { @Inject lateinit var danaRSPlugin: DanaRSPlugin @Inject lateinit var danaPump: DanaPump @Inject lateinit var danaRSMessageHashTable: DanaRSMessageHashTable - @Inject lateinit var activePlugin: ActivePluginProvider + @Inject lateinit var activePlugin: ActivePlugin @Inject lateinit var constraintChecker: ConstraintChecker @Inject lateinit var detailedBolusInfoStorage: DetailedBolusInfoStorage @Inject lateinit var bleComm: BLEComm @Inject lateinit var fabricPrivacy: FabricPrivacy - @Inject lateinit var nsUpload: NSUpload + @Inject lateinit var pumpSync: PumpSync @Inject lateinit var dateUtil: DateUtil private val disposable = CompositeDisposable() private val mBinder: IBinder = LocalBinder() - private var lastHistoryFetched: Long = 0 private var lastApproachingDailyLimit: Long = 0 override fun onCreate() { @@ -131,17 +129,12 @@ class DanaRSService : DaggerService() { sendMessage(DanaRS_Packet_Option_Get_User_Option(injector)) // Getting user options rxBus.send(EventPumpStatusChanged(resourceHelper.gs(R.string.gettingpumpstatus))) sendMessage(DanaRS_Packet_General_Initial_Screen_Information(injector)) - rxBus.send(EventPumpStatusChanged(resourceHelper.gs(R.string.gettingextendedbolusstatus))) - sendMessage(DanaRS_Packet_Bolus_Get_Extended_Bolus_State(injector)) rxBus.send(EventPumpStatusChanged(resourceHelper.gs(R.string.gettingbolusstatus))) sendMessage(DanaRS_Packet_Bolus_Get_Step_Bolus_Information(injector)) // last bolus, bolusStep, maxBolus - rxBus.send(EventPumpStatusChanged(resourceHelper.gs(R.string.gettingtempbasalstatus))) - sendMessage(DanaRS_Packet_Basal_Get_Temporary_Basal_State(injector)) danaPump.lastConnection = System.currentTimeMillis() val profile = profileFunction.getProfile() if (profile != null && abs(danaPump.currentBasal - profile.basal) >= pump.pumpDescription.basalStep) { rxBus.send(EventPumpStatusChanged(resourceHelper.gs(R.string.gettingpumpsettings))) - sendMessage(DanaRS_Packet_Basal_Get_Basal_Rate(injector)) // basal profile, basalStep, maxBasal if (!pump.isThisProfileSet(profile) && !commandQueue.isRunning(Command.CommandType.BASAL_PROFILE)) { rxBus.send(EventProfileNeedsUpdate()) } @@ -178,15 +171,17 @@ class DanaRSService : DaggerService() { } else { when { danaPump.usingUTC -> { - sendMessage(DanaRS_Packet_Option_Set_Pump_UTC_And_TimeZone(injector, DateUtil.now(), offset)) + sendMessage(DanaRS_Packet_Option_Set_Pump_UTC_And_TimeZone(injector, dateUtil.now(), offset)) } + danaPump.protocol >= 6 -> { // can set seconds - sendMessage(DanaRS_Packet_Option_Set_Pump_Time(injector, DateUtil.now())) + sendMessage(DanaRS_Packet_Option_Set_Pump_Time(injector, dateUtil.now())) } + else -> { waitForWholeMinute() // Dana can set only whole minute // add 10sec to be sure we are over minute (will be cut off anyway) - sendMessage(DanaRS_Packet_Option_Set_Pump_Time(injector, DateUtil.now() + T.secs(10).msecs())) + sendMessage(DanaRS_Packet_Option_Set_Pump_Time(injector, dateUtil.now() + T.secs(10).msecs())) } } if (danaPump.usingUTC) sendMessage(DanaRS_Packet_Option_Get_Pump_UTC_And_TimeZone(injector)) @@ -196,6 +191,11 @@ class DanaRSService : DaggerService() { } } loadEvents() + // RS doesn't provide exact timestamp = rely on history + val eb = pumpSync.expectedPumpState().extendedBolus + danaPump.fromExtendedBolus(eb) + val tbr = pumpSync.expectedPumpState().temporaryBasal + danaPump.fromTemporaryBasal(tbr) rxBus.send(EventDanaRNewStatus()) rxBus.send(EventInitializationChanged()) //NSUpload.uploadDeviceStatus(); @@ -204,7 +204,7 @@ class DanaRSService : DaggerService() { if (System.currentTimeMillis() > lastApproachingDailyLimit + 30 * 60 * 1000) { val reportFail = Notification(Notification.APPROACHING_DAILY_LIMIT, resourceHelper.gs(R.string.approachingdailylimit), Notification.URGENT) rxBus.send(EventNewNotification(reportFail)) - nsUpload.uploadError(resourceHelper.gs(R.string.approachingdailylimit) + ": " + danaPump.dailyTotalUnits + "/" + danaPump.maxDailyTotalUnits + "U") + pumpSync.insertAnnouncement(resourceHelper.gs(R.string.approachingdailylimit) + ": " + danaPump.dailyTotalUnits + "/" + danaPump.maxDailyTotalUnits + "U", null, danaPump.pumpType(), danaPump.serialNumber) lastApproachingDailyLimit = System.currentTimeMillis() } } @@ -222,18 +222,18 @@ class DanaRSService : DaggerService() { } SystemClock.sleep(1000) val msg: DanaRS_Packet_APS_History_Events - if (lastHistoryFetched == 0L) { + if (danaPump.lastHistoryFetched == 0L) { msg = DanaRS_Packet_APS_History_Events(injector, 0) aapsLogger.debug(LTag.PUMPCOMM, "Loading complete event history") } else { - msg = DanaRS_Packet_APS_History_Events(injector, lastHistoryFetched) - aapsLogger.debug(LTag.PUMPCOMM, "Loading event history from: " + dateUtil.dateAndTimeString(lastHistoryFetched)) + msg = DanaRS_Packet_APS_History_Events(injector, danaPump.lastHistoryFetched) + aapsLogger.debug(LTag.PUMPCOMM, "Loading event history from: " + dateUtil.dateAndTimeString(danaPump.lastHistoryFetched)) } sendMessage(msg) while (!danaPump.historyDoneReceived && bleComm.isConnected) { SystemClock.sleep(100) } - lastHistoryFetched = if (danaPump.lastEventTimeLoaded != 0L) danaPump.lastEventTimeLoaded - T.mins(1).msecs() else 0 + danaPump.lastHistoryFetched = if (danaPump.lastEventTimeLoaded != 0L) danaPump.lastEventTimeLoaded - T.mins(1).msecs() else 0 aapsLogger.debug(LTag.PUMPCOMM, "Events loaded") danaPump.lastConnection = System.currentTimeMillis() return PumpEnactResult(injector).success(msg.success()) @@ -245,7 +245,7 @@ class DanaRSService : DaggerService() { return PumpEnactResult(injector).success(message.success()) } - fun bolus(insulin: Double, carbs: Int, carbTime: Long, t: Treatment): Boolean { + fun bolus(insulin: Double, carbs: Int, carbTime: Long, t: EventOverviewBolusProgress.Treatment): Boolean { if (!isConnected) return false if (BolusProgressDialog.stopPressed) return false rxBus.send(EventPumpStatusChanged(resourceHelper.gs(R.string.startingbolus))) @@ -255,14 +255,14 @@ class DanaRSService : DaggerService() { danaPump.bolusAmountToBeDelivered = insulin danaPump.bolusStopped = false danaPump.bolusStopForced = false - danaPump.bolusProgressLastTimeStamp = DateUtil.now() + danaPump.bolusProgressLastTimeStamp = dateUtil.now() val start = DanaRS_Packet_Bolus_Set_Step_Bolus_Start(injector, insulin, preferencesSpeed) if (carbs > 0) { // MsgSetCarbsEntry msg = new MsgSetCarbsEntry(carbTime, carbs); #### // sendMessage(msg); val msgSetHistoryEntryV2 = DanaRS_Packet_APS_Set_Event_History(injector, DanaPump.CARBS, carbTime, carbs, 0) sendMessage(msgSetHistoryEntryV2) - lastHistoryFetched = min(lastHistoryFetched, carbTime - T.mins(1).msecs()) + danaPump.lastHistoryFetched = min(danaPump.lastHistoryFetched, carbTime - T.mins(1).msecs()) } val bolusStart = System.currentTimeMillis() if (insulin > 0) { @@ -339,8 +339,9 @@ class DanaRSService : DaggerService() { val msgTBR = DanaRS_Packet_Basal_Set_Temporary_Basal(injector, percent, durationInHours) sendMessage(msgTBR) SystemClock.sleep(200) - sendMessage(DanaRS_Packet_Basal_Get_Temporary_Basal_State(injector)) loadEvents() + val tbr = pumpSync.expectedPumpState().temporaryBasal + danaPump.fromTemporaryBasal(tbr) rxBus.send(EventPumpStatusChanged(EventPumpStatusChanged.Status.DISCONNECTING)) return msgTBR.success() } @@ -354,8 +355,9 @@ class DanaRSService : DaggerService() { rxBus.send(EventPumpStatusChanged(resourceHelper.gs(R.string.settingtempbasal))) val msgTBR = DanaRS_Packet_APS_Basal_Set_Temporary_Basal(injector, percent) sendMessage(msgTBR) - sendMessage(DanaRS_Packet_Basal_Get_Temporary_Basal_State(injector)) loadEvents() + val tbr = pumpSync.expectedPumpState().temporaryBasal + danaPump.fromTemporaryBasal(tbr) rxBus.send(EventPumpStatusChanged(EventPumpStatusChanged.Status.DISCONNECTING)) return msgTBR.success() } @@ -373,8 +375,9 @@ class DanaRSService : DaggerService() { rxBus.send(EventPumpStatusChanged(resourceHelper.gs(R.string.settingtempbasal))) val msgTBR = DanaRS_Packet_APS_Basal_Set_Temporary_Basal(injector, percent) sendMessage(msgTBR) - sendMessage(DanaRS_Packet_Basal_Get_Temporary_Basal_State(injector)) loadEvents() + val tbr = pumpSync.expectedPumpState().temporaryBasal + danaPump.fromTemporaryBasal(tbr) rxBus.send(EventPumpStatusChanged(EventPumpStatusChanged.Status.DISCONNECTING)) return msgTBR.success() } @@ -384,8 +387,9 @@ class DanaRSService : DaggerService() { rxBus.send(EventPumpStatusChanged(resourceHelper.gs(R.string.stoppingtempbasal))) val msgCancel = DanaRS_Packet_Basal_Set_Cancel_Temporary_Basal(injector) sendMessage(msgCancel) - sendMessage(DanaRS_Packet_Basal_Get_Temporary_Basal_State(injector)) loadEvents() + val tbr = pumpSync.expectedPumpState().temporaryBasal + danaPump.fromTemporaryBasal(tbr) rxBus.send(EventPumpStatusChanged(EventPumpStatusChanged.Status.DISCONNECTING)) return msgCancel.success() } @@ -396,8 +400,9 @@ class DanaRSService : DaggerService() { val msgExtended = DanaRS_Packet_Bolus_Set_Extended_Bolus(injector, insulin, durationInHalfHours) sendMessage(msgExtended) SystemClock.sleep(200) - sendMessage(DanaRS_Packet_Bolus_Get_Extended_Bolus_State(injector)) loadEvents() + val eb = pumpSync.expectedPumpState().extendedBolus + danaPump.fromExtendedBolus(eb) rxBus.send(EventPumpStatusChanged(EventPumpStatusChanged.Status.DISCONNECTING)) return msgExtended.success() } @@ -407,8 +412,9 @@ class DanaRSService : DaggerService() { rxBus.send(EventPumpStatusChanged(resourceHelper.gs(R.string.stoppingextendedbolus))) val msgStop = DanaRS_Packet_Bolus_Set_Extended_Bolus_Cancel(injector) sendMessage(msgStop) - sendMessage(DanaRS_Packet_Bolus_Get_Extended_Bolus_State(injector)) loadEvents() + val eb = pumpSync.expectedPumpState().extendedBolus + danaPump.fromExtendedBolus(eb) rxBus.send(EventPumpStatusChanged(EventPumpStatusChanged.Status.DISCONNECTING)) return msgStop.success() } @@ -435,15 +441,15 @@ class DanaRSService : DaggerService() { if (!isConnected) return result var msg: DanaRS_Packet_History_? = null when (type) { - RecordTypes.RECORD_TYPE_ALARM -> msg = DanaRS_Packet_History_Alarm(injector) - RecordTypes.RECORD_TYPE_PRIME -> msg = DanaRS_Packet_History_Prime(injector) + RecordTypes.RECORD_TYPE_ALARM -> msg = DanaRS_Packet_History_Alarm(injector) + RecordTypes.RECORD_TYPE_PRIME -> msg = DanaRS_Packet_History_Prime(injector) RecordTypes.RECORD_TYPE_BASALHOUR -> msg = DanaRS_Packet_History_Basal(injector) - RecordTypes.RECORD_TYPE_BOLUS -> msg = DanaRS_Packet_History_Bolus(injector) - RecordTypes.RECORD_TYPE_CARBO -> msg = DanaRS_Packet_History_Carbohydrate(injector) - RecordTypes.RECORD_TYPE_DAILY -> msg = DanaRS_Packet_History_Daily(injector) - RecordTypes.RECORD_TYPE_GLUCOSE -> msg = DanaRS_Packet_History_Blood_Glucose(injector) - RecordTypes.RECORD_TYPE_REFILL -> msg = DanaRS_Packet_History_Refill(injector) - RecordTypes.RECORD_TYPE_SUSPEND -> msg = DanaRS_Packet_History_Suspend(injector) + RecordTypes.RECORD_TYPE_BOLUS -> msg = DanaRS_Packet_History_Bolus(injector) + RecordTypes.RECORD_TYPE_CARBO -> msg = DanaRS_Packet_History_Carbohydrate(injector) + RecordTypes.RECORD_TYPE_DAILY -> msg = DanaRS_Packet_History_Daily(injector) + RecordTypes.RECORD_TYPE_GLUCOSE -> msg = DanaRS_Packet_History_Blood_Glucose(injector) + RecordTypes.RECORD_TYPE_REFILL -> msg = DanaRS_Packet_History_Refill(injector) + RecordTypes.RECORD_TYPE_SUSPEND -> msg = DanaRS_Packet_History_Suspend(injector) } if (msg != null) { sendMessage(DanaRS_Packet_General_Set_History_Upload_Mode(injector, 1)) @@ -475,7 +481,7 @@ class DanaRSService : DaggerService() { private fun waitForWholeMinute() { while (true) { - val time = DateUtil.now() + val time = dateUtil.now() val timeToWholeMinute = 60000 - time % 60000 if (timeToWholeMinute > 59800 || timeToWholeMinute < 300) break rxBus.send(EventPumpStatusChanged(resourceHelper.gs(R.string.waitingfortimesynchronization, (timeToWholeMinute / 1000).toInt()))) diff --git a/danars/src/test/java/info/nightscout/androidaps/TestBaseWithProfile.kt b/danars/src/test/java/info/nightscout/androidaps/TestBaseWithProfile.kt index e3e5c7391b..e3ca031cd5 100644 --- a/danars/src/test/java/info/nightscout/androidaps/TestBaseWithProfile.kt +++ b/danars/src/test/java/info/nightscout/androidaps/TestBaseWithProfile.kt @@ -4,9 +4,8 @@ import dagger.android.AndroidInjector import dagger.android.HasAndroidInjector import info.nightscout.androidaps.data.Profile import info.nightscout.androidaps.db.ProfileSwitch -import info.nightscout.androidaps.db.Treatment -import info.nightscout.androidaps.interfaces.ActivePluginProvider -import info.nightscout.androidaps.interfaces.ConfigInterface +import info.nightscout.androidaps.interfaces.ActivePlugin +import info.nightscout.androidaps.interfaces.Config import info.nightscout.androidaps.interfaces.ProfileFunction import info.nightscout.androidaps.interfaces.ProfileStore import info.nightscout.androidaps.interfaces.TreatmentsInterface @@ -24,14 +23,14 @@ import org.powermock.core.classloader.annotations.PrepareForTest @PrepareForTest(FabricPrivacy::class) open class TestBaseWithProfile : TestBase() { - @Mock lateinit var activePluginProvider: ActivePluginProvider + @Mock lateinit var activePluginProvider: ActivePlugin @Mock lateinit var resourceHelper: ResourceHelper @Mock lateinit var treatmentsInterface: TreatmentsInterface @Mock lateinit var fabricPrivacy: FabricPrivacy @Mock lateinit var profileFunction: ProfileFunction @Mock lateinit var defaultValueHelper: DefaultValueHelper @Mock lateinit var dateUtil: DateUtil - @Mock lateinit var configInterface: ConfigInterface + @Mock lateinit var config: Config val rxBus = RxBusWrapper(aapsSchedulers) @@ -43,7 +42,7 @@ open class TestBaseWithProfile : TestBase() { it.resourceHelper = resourceHelper it.rxBus = rxBus it.fabricPrivacy = fabricPrivacy - it.configInterface = configInterface + it.config = config } if (it is ProfileSwitch) { it.treatmentsPlugin = treatmentsInterface @@ -52,12 +51,6 @@ open class TestBaseWithProfile : TestBase() { it.resourceHelper = resourceHelper it.dateUtil = dateUtil } - if (it is Treatment) { - it.activePlugin = activePluginProvider - it.profileFunction = profileFunction - it.defaultValueHelper = defaultValueHelper - it.resourceHelper = resourceHelper - } } } diff --git a/danars/src/test/java/info/nightscout/androidaps/danars/DanaRSPluginTest.kt b/danars/src/test/java/info/nightscout/androidaps/danars/DanaRSPluginTest.kt index 70863cdf8d..61f2ea5d53 100644 --- a/danars/src/test/java/info/nightscout/androidaps/danars/DanaRSPluginTest.kt +++ b/danars/src/test/java/info/nightscout/androidaps/danars/DanaRSPluginTest.kt @@ -1,17 +1,16 @@ -package info.nightscout.androidaps.plugins.pump.danars +package info.nightscout.androidaps.danars import android.content.Context import dagger.android.AndroidInjector import info.nightscout.androidaps.Constants -import info.nightscout.androidaps.danars.DanaRSPlugin -import info.nightscout.androidaps.danars.DanaRSTestBase -import info.nightscout.androidaps.danars.R 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.plugins.bus.RxBusWrapper import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker import info.nightscout.androidaps.plugins.pump.common.bolusInfo.DetailedBolusInfoStorage +import info.nightscout.androidaps.plugins.pump.common.bolusInfo.TemporaryBasalStorage import org.junit.Assert import org.junit.Before import org.junit.Test @@ -24,13 +23,15 @@ import org.powermock.modules.junit4.PowerMockRunner @Suppress("SpellCheckingInspection") @RunWith(PowerMockRunner::class) -@PrepareForTest(ConstraintChecker::class, RxBusWrapper::class, DetailedBolusInfoStorage::class) +@PrepareForTest(ConstraintChecker::class, RxBusWrapper::class, DetailedBolusInfoStorage::class, TemporaryBasalStorage::class) class DanaRSPluginTest : DanaRSTestBase() { @Mock lateinit var context: Context @Mock lateinit var constraintChecker: ConstraintChecker @Mock lateinit var commandQueue: CommandQueueProvider @Mock lateinit var detailedBolusInfoStorage: DetailedBolusInfoStorage + @Mock lateinit var temporaryBasalStorage: TemporaryBasalStorage + @Mock lateinit var pumpSync: PumpSync private lateinit var danaRSPlugin: DanaRSPlugin @@ -64,6 +65,6 @@ class DanaRSPluginTest : DanaRSTestBase() { Mockito.`when`(resourceHelper.gs(eq(R.string.limitingbasalratio), anyObject(), anyObject())).thenReturn("limitingbasalratio") Mockito.`when`(resourceHelper.gs(eq(R.string.limitingpercentrate), anyObject(), anyObject())).thenReturn("limitingpercentrate") - danaRSPlugin = DanaRSPlugin({ AndroidInjector { } }, aapsLogger, aapsSchedulers, rxBus, context, resourceHelper, constraintChecker, profileFunction, activePluginProvider, sp, commandQueue, danaPump, detailedBolusInfoStorage, fabricPrivacy, dateUtil) + danaRSPlugin = DanaRSPlugin({ AndroidInjector { } }, aapsLogger, aapsSchedulers, rxBus, context, resourceHelper, constraintChecker, profileFunction, sp, commandQueue, danaPump, pumpSync, detailedBolusInfoStorage, temporaryBasalStorage, fabricPrivacy, dateUtil) } } \ No newline at end of file diff --git a/danars/src/test/java/info/nightscout/androidaps/danars/DanaRSTestBase.kt b/danars/src/test/java/info/nightscout/androidaps/danars/DanaRSTestBase.kt index 5168ab69df..05b06d4fca 100644 --- a/danars/src/test/java/info/nightscout/androidaps/danars/DanaRSTestBase.kt +++ b/danars/src/test/java/info/nightscout/androidaps/danars/DanaRSTestBase.kt @@ -5,7 +5,6 @@ import dagger.android.HasAndroidInjector import info.nightscout.androidaps.TestBaseWithProfile import info.nightscout.androidaps.dana.DanaPump import info.nightscout.androidaps.danars.comm.DanaRS_Packet -import info.nightscout.androidaps.db.TemporaryBasal import info.nightscout.androidaps.utils.sharedPreferences.SP import org.junit.Before import org.mockito.ArgumentMatchers @@ -16,16 +15,7 @@ open class DanaRSTestBase : TestBaseWithProfile() { @Mock lateinit var sp: SP - val injector = HasAndroidInjector { - AndroidInjector { - if (it is TemporaryBasal) { - it.aapsLogger = aapsLogger - it.activePlugin = activePluginProvider - it.profileFunction = profileFunction - it.sp = sp - } - } - } + val injector = HasAndroidInjector { AndroidInjector { } } lateinit var danaPump: DanaPump @@ -64,6 +54,6 @@ open class DanaRSTestBase : TestBaseWithProfile() { @Before fun setup() { - danaPump = DanaPump(aapsLogger, sp, injector) + danaPump = DanaPump(aapsLogger, sp, dateUtil, injector) } } \ No newline at end of file diff --git a/danars/src/test/java/info/nightscout/androidaps/danars/comm/DanaRSPacketNotifyDeliveryCompleteTest.kt b/danars/src/test/java/info/nightscout/androidaps/danars/comm/DanaRSPacketNotifyDeliveryCompleteTest.kt index 3ded5b81cd..7bbeef73b6 100644 --- a/danars/src/test/java/info/nightscout/androidaps/danars/comm/DanaRSPacketNotifyDeliveryCompleteTest.kt +++ b/danars/src/test/java/info/nightscout/androidaps/danars/comm/DanaRSPacketNotifyDeliveryCompleteTest.kt @@ -4,9 +4,9 @@ import dagger.android.AndroidInjector import dagger.android.HasAndroidInjector import info.nightscout.androidaps.danars.DanaRSPlugin import info.nightscout.androidaps.danars.DanaRSTestBase -import info.nightscout.androidaps.db.Treatment -import info.nightscout.androidaps.interfaces.ActivePluginProvider +import info.nightscout.androidaps.interfaces.ActivePlugin import info.nightscout.androidaps.plugins.bus.RxBusWrapper +import info.nightscout.androidaps.plugins.general.overview.events.EventOverviewBolusProgress import org.junit.Assert import org.junit.Test import org.junit.runner.RunWith @@ -21,7 +21,7 @@ import org.powermock.modules.junit4.PowerMockRunner @PrepareForTest(RxBusWrapper::class, DanaRSPlugin::class) class DanaRSPacketNotifyDeliveryCompleteTest : DanaRSTestBase() { - @Mock lateinit var activePlugin: ActivePluginProvider + @Mock lateinit var activePlugin: ActivePlugin private val packetInjector = HasAndroidInjector { AndroidInjector { @@ -31,19 +31,13 @@ class DanaRSPacketNotifyDeliveryCompleteTest : DanaRSTestBase() { it.resourceHelper = resourceHelper it.danaPump = danaPump } - if (it is Treatment) { - it.defaultValueHelper = defaultValueHelper - it.resourceHelper = resourceHelper - it.profileFunction = profileFunction - it.activePlugin = activePlugin - } } } @Test fun runTest() { `when`(resourceHelper.gs(anyInt(), anyDouble())).thenReturn("SomeString") - danaPump.bolusingTreatment = Treatment(packetInjector) + danaPump.bolusingTreatment = EventOverviewBolusProgress.Treatment(0.0, 0, true) val packet = DanaRS_Packet_Notify_Delivery_Complete(packetInjector) // test params Assert.assertEquals(null, packet.requestParams) diff --git a/danars/src/test/java/info/nightscout/androidaps/danars/comm/DanaRsMessageHashTableTest.kt b/danars/src/test/java/info/nightscout/androidaps/danars/comm/DanaRsMessageHashTableTest.kt index 2397295ffa..98c90be4ac 100644 --- a/danars/src/test/java/info/nightscout/androidaps/danars/comm/DanaRsMessageHashTableTest.kt +++ b/danars/src/test/java/info/nightscout/androidaps/danars/comm/DanaRsMessageHashTableTest.kt @@ -3,7 +3,7 @@ package info.nightscout.androidaps.danars.comm import dagger.android.AndroidInjector import dagger.android.HasAndroidInjector import info.nightscout.androidaps.danars.encryption.BleEncryption -import info.nightscout.androidaps.interfaces.ActivePluginProvider +import info.nightscout.androidaps.interfaces.ActivePlugin import info.nightscout.androidaps.interfaces.Constraint import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker import info.nightscout.androidaps.plugins.pump.common.bolusInfo.DetailedBolusInfoStorage @@ -20,7 +20,7 @@ import org.powermock.modules.junit4.PowerMockRunner @PrepareForTest(ConstraintChecker::class, DetailedBolusInfoStorage::class) class DanaRsMessageHashTableTest : DanaRSTestBase() { - @Mock lateinit var activePlugin: ActivePluginProvider + @Mock lateinit var activePlugin: ActivePlugin @Mock lateinit var constraintChecker: ConstraintChecker @Mock lateinit var detailedBolusInfoStorage: DetailedBolusInfoStorage diff --git a/danars/src/test/java/info/nightscout/androidaps/danars/comm/DanaRsPacketApsHistoryEventsTest.kt b/danars/src/test/java/info/nightscout/androidaps/danars/comm/DanaRsPacketApsHistoryEventsTest.kt index cea0e79c1c..093adb3fe3 100644 --- a/danars/src/test/java/info/nightscout/androidaps/danars/comm/DanaRsPacketApsHistoryEventsTest.kt +++ b/danars/src/test/java/info/nightscout/androidaps/danars/comm/DanaRsPacketApsHistoryEventsTest.kt @@ -4,11 +4,12 @@ import android.content.Context import dagger.android.AndroidInjector import dagger.android.HasAndroidInjector import info.nightscout.androidaps.danars.DanaRSPlugin -import info.nightscout.androidaps.interfaces.ActivePluginProvider +import info.nightscout.androidaps.danars.DanaRSTestBase +import info.nightscout.androidaps.interfaces.ActivePlugin +import info.nightscout.androidaps.interfaces.PumpSync import info.nightscout.androidaps.plugins.bus.RxBusWrapper import info.nightscout.androidaps.plugins.pump.common.bolusInfo.DetailedBolusInfoStorage -import info.nightscout.androidaps.danars.DanaRSTestBase -import info.nightscout.androidaps.utils.DateUtil +import info.nightscout.androidaps.plugins.pump.common.bolusInfo.TemporaryBasalStorage import org.junit.Assert import org.junit.Test import org.junit.runner.RunWith @@ -18,12 +19,14 @@ import org.powermock.modules.junit4.PowerMockRunner import java.util.* @RunWith(PowerMockRunner::class) -@PrepareForTest(RxBusWrapper::class, DetailedBolusInfoStorage::class, DanaRSPlugin::class) +@PrepareForTest(RxBusWrapper::class, DetailedBolusInfoStorage::class, TemporaryBasalStorage::class, DanaRSPlugin::class) class DanaRsPacketApsHistoryEventsTest : DanaRSTestBase() { @Mock lateinit var context: Context - @Mock lateinit var activePlugin: ActivePluginProvider + @Mock lateinit var activePlugin: ActivePlugin + @Mock lateinit var pumpSync: PumpSync @Mock lateinit var detailedBolusInfoStorage: DetailedBolusInfoStorage + @Mock lateinit var temporaryBasalStorage: TemporaryBasalStorage private val packetInjector = HasAndroidInjector { AndroidInjector { @@ -34,16 +37,17 @@ class DanaRsPacketApsHistoryEventsTest : DanaRSTestBase() { if (it is DanaRS_Packet_APS_History_Events) { it.rxBus = rxBus it.resourceHelper = resourceHelper - it.activePlugin = activePlugin + it.pumpSync = pumpSync it.danaPump = danaPump it.detailedBolusInfoStorage = detailedBolusInfoStorage + it.temporaryBasalStorage = temporaryBasalStorage it.sp = sp } } } @Test fun runTest() { - val now = DateUtil.now() + val now = dateUtil.now() val testPacket = DanaRS_Packet_APS_History_Events(packetInjector, now) // test getRequestedParams diff --git a/danars/src/test/java/info/nightscout/androidaps/danars/comm/DanaRsPacketApsSetEventHistoryTest.kt b/danars/src/test/java/info/nightscout/androidaps/danars/comm/DanaRsPacketApsSetEventHistoryTest.kt index c62418d039..07809e9dc5 100644 --- a/danars/src/test/java/info/nightscout/androidaps/danars/comm/DanaRsPacketApsSetEventHistoryTest.kt +++ b/danars/src/test/java/info/nightscout/androidaps/danars/comm/DanaRsPacketApsSetEventHistoryTest.kt @@ -3,7 +3,6 @@ package info.nightscout.androidaps.danars.comm import dagger.android.AndroidInjector import dagger.android.HasAndroidInjector import info.nightscout.androidaps.danars.DanaRSTestBase -import info.nightscout.androidaps.utils.DateUtil import org.junit.Assert import org.junit.Test import org.junit.runner.RunWith @@ -25,7 +24,7 @@ class DanaRsPacketApsSetEventHistoryTest : DanaRSTestBase() { } @Test fun runTest() { // test for negative carbs - val now = DateUtil.now() + val now = dateUtil.now() var historyTest = DanaRS_Packet_APS_Set_Event_History(packetInjector, info.nightscout.androidaps.dana.DanaPump.CARBS, now, -1, 0) var testParams = historyTest.requestParams Assert.assertEquals(0.toByte(), testParams[8]) diff --git a/danars/src/test/java/info/nightscout/androidaps/danars/comm/DanaRsPacketBasalGetTemporaryBasalStateTest.kt b/danars/src/test/java/info/nightscout/androidaps/danars/comm/DanaRsPacketBasalGetTemporaryBasalStateTest.kt index 86bf509924..e29ed61b41 100644 --- a/danars/src/test/java/info/nightscout/androidaps/danars/comm/DanaRsPacketBasalGetTemporaryBasalStateTest.kt +++ b/danars/src/test/java/info/nightscout/androidaps/danars/comm/DanaRsPacketBasalGetTemporaryBasalStateTest.kt @@ -34,9 +34,9 @@ class DanaRsPacketBasalGetTemporaryBasalStateTest : DanaRSTestBase() { putIntToArray(array, 4, 1) packet.handleMessage(array) Assert.assertTrue(packet.failed) - Assert.assertTrue(danaPump.isTempBasalInProgress) - Assert.assertEquals(300, danaPump.tempBasalPercent) - Assert.assertEquals(15 * 60, danaPump.tempBasalTotalSec) + Assert.assertTrue(packet.isTempBasalInProgress) + Assert.assertEquals(300, packet.tempBasalPercent) + Assert.assertEquals(15 * 60, packet.tempBasalTotalSec) Assert.assertEquals("BASAL__TEMPORARY_BASAL_STATE", packet.friendlyName) } } \ No newline at end of file diff --git a/danars/src/test/java/info/nightscout/androidaps/danars/comm/DanaRsPacketBolusGetDualBolusTest.kt b/danars/src/test/java/info/nightscout/androidaps/danars/comm/DanaRsPacketBolusGetDualBolusTest.kt index 5f04609ec5..9de5e53cb8 100644 --- a/danars/src/test/java/info/nightscout/androidaps/danars/comm/DanaRsPacketBolusGetDualBolusTest.kt +++ b/danars/src/test/java/info/nightscout/androidaps/danars/comm/DanaRsPacketBolusGetDualBolusTest.kt @@ -33,7 +33,6 @@ class DanaRsPacketBolusGetDualBolusTest : DanaRSTestBase() { packet.handleMessage(array) Assert.assertTrue(packet.failed) Assert.assertEquals(1.0, danaPump.bolusStep, 0.0) - Assert.assertEquals(0.55, danaPump.extendedBolusAbsoluteRate, 0.0) Assert.assertEquals(40.0, danaPump.maxBolus, 0.0) Assert.assertEquals("BOLUS__GET_DUAL_BOLUS", packet.friendlyName) diff --git a/danars/src/test/java/info/nightscout/androidaps/danars/comm/DanaRsPacketBolusGetExtendedBolusStateTest.kt b/danars/src/test/java/info/nightscout/androidaps/danars/comm/DanaRsPacketBolusGetExtendedBolusStateTest.kt index c74b203ff5..759b35e527 100644 --- a/danars/src/test/java/info/nightscout/androidaps/danars/comm/DanaRsPacketBolusGetExtendedBolusStateTest.kt +++ b/danars/src/test/java/info/nightscout/androidaps/danars/comm/DanaRsPacketBolusGetExtendedBolusStateTest.kt @@ -31,7 +31,7 @@ class DanaRsPacketBolusGetExtendedBolusStateTest : DanaRSTestBase() { testValue = 1.0 packet.handleMessage(createArray(11, testValue.toInt().toByte())) // is extended bolus in progress - Assert.assertEquals(testValue == 1.0, danaPump.isExtendedInProgress) + Assert.assertEquals(testValue == 1.0, packet.isExtendedInProgress) Assert.assertEquals(testValue != 0.0, packet.failed) Assert.assertEquals("BOLUS__GET_EXTENDED_BOLUS_STATE", packet.friendlyName) } diff --git a/danars/src/test/java/info/nightscout/androidaps/danars/comm/DanaRsPacketBolusGetExtendedMenuOptionStateTest.kt b/danars/src/test/java/info/nightscout/androidaps/danars/comm/DanaRsPacketBolusGetExtendedMenuOptionStateTest.kt index db66481f5a..50921c5ea5 100644 --- a/danars/src/test/java/info/nightscout/androidaps/danars/comm/DanaRsPacketBolusGetExtendedMenuOptionStateTest.kt +++ b/danars/src/test/java/info/nightscout/androidaps/danars/comm/DanaRsPacketBolusGetExtendedMenuOptionStateTest.kt @@ -26,10 +26,10 @@ class DanaRsPacketBolusGetExtendedMenuOptionStateTest : DanaRSTestBase() { // test message decoding packet.handleMessage(createArray(34, 0.toByte())) // isExtendedInProgress should be false - Assert.assertEquals(false, danaPump.isExtendedInProgress) + Assert.assertEquals(false, packet.isExtendedInProgress) // assertEquals(false, packet.failed); packet.handleMessage(createArray(34, 1.toByte())) - Assert.assertEquals(true, danaPump.isExtendedInProgress) + Assert.assertEquals(true, packet.isExtendedInProgress) Assert.assertEquals("BOLUS__GET_EXTENDED_MENU_OPTION_STATE", packet.friendlyName) } } \ No newline at end of file diff --git a/danars/src/test/java/info/nightscout/androidaps/danars/comm/DanaRsPacketBolusSetStepBolusStartTest.kt b/danars/src/test/java/info/nightscout/androidaps/danars/comm/DanaRsPacketBolusSetStepBolusStartTest.kt index 95b95df7a7..224dd6fee2 100644 --- a/danars/src/test/java/info/nightscout/androidaps/danars/comm/DanaRsPacketBolusSetStepBolusStartTest.kt +++ b/danars/src/test/java/info/nightscout/androidaps/danars/comm/DanaRsPacketBolusSetStepBolusStartTest.kt @@ -7,8 +7,10 @@ import info.nightscout.androidaps.danars.DanaRSPlugin import info.nightscout.androidaps.danars.DanaRSTestBase import info.nightscout.androidaps.interfaces.CommandQueueProvider import info.nightscout.androidaps.interfaces.Constraint +import info.nightscout.androidaps.interfaces.PumpSync import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker import info.nightscout.androidaps.plugins.pump.common.bolusInfo.DetailedBolusInfoStorage +import info.nightscout.androidaps.plugins.pump.common.bolusInfo.TemporaryBasalStorage import org.junit.Assert import org.junit.Before import org.junit.Test @@ -19,13 +21,15 @@ import org.powermock.core.classloader.annotations.PrepareForTest import org.powermock.modules.junit4.PowerMockRunner @RunWith(PowerMockRunner::class) -@PrepareForTest(ConstraintChecker::class, DetailedBolusInfoStorage::class) +@PrepareForTest(ConstraintChecker::class, DetailedBolusInfoStorage::class, TemporaryBasalStorage::class) class DanaRsPacketBolusSetStepBolusStartTest : DanaRSTestBase() { @Mock lateinit var constraintChecker: ConstraintChecker @Mock lateinit var commandQueue: CommandQueueProvider @Mock lateinit var context: Context @Mock lateinit var detailedBolusInfoStorage: DetailedBolusInfoStorage + @Mock lateinit var temporaryBasalStorage: TemporaryBasalStorage + @Mock lateinit var pumpSync: PumpSync private lateinit var danaRSPlugin: DanaRSPlugin @@ -55,7 +59,7 @@ class DanaRsPacketBolusSetStepBolusStartTest : DanaRSTestBase() { @Before fun mock() { - danaRSPlugin = DanaRSPlugin({ AndroidInjector { } }, aapsLogger, aapsSchedulers, rxBus, context, resourceHelper, constraintChecker, profileFunction, activePluginProvider, sp, commandQueue, danaPump, detailedBolusInfoStorage, fabricPrivacy, dateUtil) + danaRSPlugin = DanaRSPlugin({ AndroidInjector { } }, aapsLogger, aapsSchedulers, rxBus, context, resourceHelper, constraintChecker, profileFunction, sp, commandQueue, danaPump, pumpSync, detailedBolusInfoStorage, temporaryBasalStorage, fabricPrivacy, dateUtil) Mockito.`when`(constraintChecker.applyBolusConstraints(anyObject())).thenReturn(Constraint(0.0)) } } \ No newline at end of file diff --git a/danars/src/test/java/info/nightscout/androidaps/danars/comm/DanaRsPacketBolusSetStepBolusStopTest.kt b/danars/src/test/java/info/nightscout/androidaps/danars/comm/DanaRsPacketBolusSetStepBolusStopTest.kt index 2de51051ff..840f9c6b42 100644 --- a/danars/src/test/java/info/nightscout/androidaps/danars/comm/DanaRsPacketBolusSetStepBolusStopTest.kt +++ b/danars/src/test/java/info/nightscout/androidaps/danars/comm/DanaRsPacketBolusSetStepBolusStopTest.kt @@ -4,9 +4,9 @@ import dagger.android.AndroidInjector import dagger.android.HasAndroidInjector import info.nightscout.androidaps.danars.DanaRSPlugin import info.nightscout.androidaps.danars.DanaRSTestBase -import info.nightscout.androidaps.db.Treatment -import info.nightscout.androidaps.interfaces.ActivePluginProvider +import info.nightscout.androidaps.interfaces.ActivePlugin import info.nightscout.androidaps.plugins.bus.RxBusWrapper +import info.nightscout.androidaps.plugins.general.overview.events.EventOverviewBolusProgress import org.junit.Assert import org.junit.Test import org.junit.runner.RunWith @@ -20,7 +20,7 @@ import org.powermock.modules.junit4.PowerMockRunner @PrepareForTest(RxBusWrapper::class, DanaRSPlugin::class) class DanaRsPacketBolusSetStepBolusStopTest : DanaRSTestBase() { - @Mock lateinit var activePlugin: ActivePluginProvider + @Mock lateinit var activePlugin: ActivePlugin private val packetInjector = HasAndroidInjector { AndroidInjector { @@ -30,19 +30,13 @@ class DanaRsPacketBolusSetStepBolusStopTest : DanaRSTestBase() { it.resourceHelper = resourceHelper it.danaPump = danaPump } - if (it is Treatment) { - it.defaultValueHelper = defaultValueHelper - it.resourceHelper = resourceHelper - it.profileFunction = profileFunction - it.activePlugin = activePlugin - } } } @Test fun runTest() { `when`(resourceHelper.gs(Mockito.anyInt())).thenReturn("SomeString") - danaPump.bolusingTreatment = Treatment(packetInjector) + danaPump.bolusingTreatment = EventOverviewBolusProgress.Treatment(0.0, 0, true) val testPacket = DanaRS_Packet_Bolus_Set_Step_Bolus_Stop(packetInjector) // test message decoding testPacket.handleMessage(byteArrayOf(0.toByte(), 0.toByte(), 0.toByte())) diff --git a/danars/src/test/java/info/nightscout/androidaps/danars/comm/DanaRsPacketGeneralGetMoreInformationTest.kt b/danars/src/test/java/info/nightscout/androidaps/danars/comm/DanaRsPacketGeneralGetMoreInformationTest.kt index f21ae1b563..957553475f 100644 --- a/danars/src/test/java/info/nightscout/androidaps/danars/comm/DanaRsPacketGeneralGetMoreInformationTest.kt +++ b/danars/src/test/java/info/nightscout/androidaps/danars/comm/DanaRsPacketGeneralGetMoreInformationTest.kt @@ -44,8 +44,6 @@ class DanaRsPacketGeneralGetMoreInformationTest : DanaRSTestBase() { Assert.assertFalse(packet.failed) Assert.assertEquals(6.0, danaPump.iob, 0.01) Assert.assertEquals(12.5, danaPump.dailyTotalUnits, 0.01) - Assert.assertTrue(danaPump.isExtendedInProgress) - Assert.assertEquals(150, danaPump.extendedBolusRemainingMinutes) val lastBolus = Calendar.getInstance() lastBolus.timeInMillis = danaPump.lastBolusTime Assert.assertEquals(15, lastBolus.get(Calendar.HOUR_OF_DAY)) diff --git a/danars/src/test/java/info/nightscout/androidaps/danars/comm/DanaRsPacketNotifyAlarmTest.kt b/danars/src/test/java/info/nightscout/androidaps/danars/comm/DanaRsPacketNotifyAlarmTest.kt index 0abdb1606a..e002e8373b 100644 --- a/danars/src/test/java/info/nightscout/androidaps/danars/comm/DanaRsPacketNotifyAlarmTest.kt +++ b/danars/src/test/java/info/nightscout/androidaps/danars/comm/DanaRsPacketNotifyAlarmTest.kt @@ -3,7 +3,7 @@ package info.nightscout.androidaps.danars.comm import dagger.android.AndroidInjector import dagger.android.HasAndroidInjector import info.nightscout.androidaps.danars.DanaRSTestBase -import info.nightscout.androidaps.plugins.general.nsclient.NSUpload +import info.nightscout.androidaps.interfaces.PumpSync import org.junit.Assert import org.junit.Test import org.junit.runner.RunWith @@ -13,7 +13,7 @@ import org.powermock.modules.junit4.PowerMockRunner @RunWith(PowerMockRunner::class) class DanaRsPacketNotifyAlarmTest : DanaRSTestBase() { - @Mock lateinit var nsUpload: NSUpload + @Mock lateinit var pumpSync: PumpSync private val packetInjector = HasAndroidInjector { AndroidInjector { @@ -21,7 +21,8 @@ class DanaRsPacketNotifyAlarmTest : DanaRSTestBase() { it.aapsLogger = aapsLogger it.rxBus = rxBus it.resourceHelper = resourceHelper - it.nsUpload = nsUpload + it.pumpSync = pumpSync + it.danaPump = danaPump } } } diff --git a/danars/src/test/java/info/nightscout/androidaps/danars/comm/DanaRsPacketNotifyDeliveryRateDisplayTest.kt b/danars/src/test/java/info/nightscout/androidaps/danars/comm/DanaRsPacketNotifyDeliveryRateDisplayTest.kt index 18db110e5b..ab9b803ad9 100644 --- a/danars/src/test/java/info/nightscout/androidaps/danars/comm/DanaRsPacketNotifyDeliveryRateDisplayTest.kt +++ b/danars/src/test/java/info/nightscout/androidaps/danars/comm/DanaRsPacketNotifyDeliveryRateDisplayTest.kt @@ -5,12 +5,14 @@ import dagger.android.AndroidInjector import dagger.android.HasAndroidInjector import info.nightscout.androidaps.danars.DanaRSPlugin import info.nightscout.androidaps.danars.DanaRSTestBase -import info.nightscout.androidaps.db.Treatment -import info.nightscout.androidaps.interfaces.ActivePluginProvider +import info.nightscout.androidaps.interfaces.ActivePlugin import info.nightscout.androidaps.interfaces.CommandQueueProvider +import info.nightscout.androidaps.interfaces.PumpSync import info.nightscout.androidaps.plugins.bus.RxBusWrapper import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker +import info.nightscout.androidaps.plugins.general.overview.events.EventOverviewBolusProgress import info.nightscout.androidaps.plugins.pump.common.bolusInfo.DetailedBolusInfoStorage +import info.nightscout.androidaps.plugins.pump.common.bolusInfo.TemporaryBasalStorage import org.junit.Assert import org.junit.Before import org.junit.Test @@ -22,14 +24,16 @@ import org.powermock.core.classloader.annotations.PrepareForTest import org.powermock.modules.junit4.PowerMockRunner @RunWith(PowerMockRunner::class) -@PrepareForTest(ConstraintChecker::class, RxBusWrapper::class, DetailedBolusInfoStorage::class) +@PrepareForTest(ConstraintChecker::class, RxBusWrapper::class, DetailedBolusInfoStorage::class, TemporaryBasalStorage::class) class DanaRsPacketNotifyDeliveryRateDisplayTest : DanaRSTestBase() { - @Mock lateinit var activePlugin: ActivePluginProvider + @Mock lateinit var activePlugin: ActivePlugin @Mock lateinit var constraintChecker: ConstraintChecker @Mock lateinit var commandQueue: CommandQueueProvider @Mock lateinit var context: Context @Mock lateinit var detailedBolusInfoStorage: DetailedBolusInfoStorage + @Mock lateinit var temporaryBasalStorage: TemporaryBasalStorage + @Mock lateinit var pumpSync: PumpSync private lateinit var danaRSPlugin: DanaRSPlugin @@ -41,12 +45,6 @@ class DanaRsPacketNotifyDeliveryRateDisplayTest : DanaRSTestBase() { it.resourceHelper = resourceHelper it.danaPump = danaPump } - if (it is Treatment) { - it.defaultValueHelper = defaultValueHelper - it.resourceHelper = resourceHelper - it.profileFunction = profileFunction - it.activePlugin = activePlugin - } } } @@ -68,7 +66,7 @@ class DanaRsPacketNotifyDeliveryRateDisplayTest : DanaRSTestBase() { @Before fun mock() { - danaRSPlugin = DanaRSPlugin(packetInjector, aapsLogger, aapsSchedulers, rxBus, context, resourceHelper, constraintChecker, profileFunction, activePluginProvider, sp, commandQueue, danaPump, detailedBolusInfoStorage, fabricPrivacy, dateUtil) - danaPump.bolusingTreatment = Treatment(packetInjector) + danaRSPlugin = DanaRSPlugin(packetInjector, aapsLogger, aapsSchedulers, rxBus, context, resourceHelper, constraintChecker, profileFunction, sp, commandQueue, danaPump, pumpSync, detailedBolusInfoStorage, temporaryBasalStorage, fabricPrivacy, dateUtil) + danaPump.bolusingTreatment = EventOverviewBolusProgress.Treatment(0.0, 0, true) } } \ No newline at end of file diff --git a/database/build.gradle b/database/build.gradle index 0966d4b85e..d41e263136 100644 --- a/database/build.gradle +++ b/database/build.gradle @@ -39,4 +39,5 @@ dependencies { implementation "com.google.dagger:dagger-android:$dagger_version" implementation "com.google.dagger:dagger-android-support:$dagger_version" + api "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version" } 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/schemas/info.nightscout.androidaps.database.AppDatabase/11.json b/database/schemas/info.nightscout.androidaps.database.AppDatabase/11.json new file mode 100644 index 0000000000..15956090cc --- /dev/null +++ b/database/schemas/info.nightscout.androidaps.database.AppDatabase/11.json @@ -0,0 +1,2943 @@ +{ + "formatVersion": 1, + "database": { + "version": 11, + "identityHash": "5590bbcf7038e4422cf50dc16863b7c2", + "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, `endPumpId` INTEGER, `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": "endPumpId", + "columnName": "endPumpId", + "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_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, `endPumpId` 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": "endPumpId", + "columnName": "endPumpId", + "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, '5590bbcf7038e4422cf50dc16863b7c2')" + ] + } +} \ No newline at end of file diff --git a/database/schemas/info.nightscout.androidaps.database.AppDatabase/12.json b/database/schemas/info.nightscout.androidaps.database.AppDatabase/12.json new file mode 100644 index 0000000000..f0d6ba022f --- /dev/null +++ b/database/schemas/info.nightscout.androidaps.database.AppDatabase/12.json @@ -0,0 +1,2931 @@ +{ + "formatVersion": 1, + "database": { + "version": 12, + "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/schemas/info.nightscout.androidaps.database.AppDatabase/14.json b/database/schemas/info.nightscout.androidaps.database.AppDatabase/14.json new file mode 100644 index 0000000000..aa6ee5a8d8 --- /dev/null +++ b/database/schemas/info.nightscout.androidaps.database.AppDatabase/14.json @@ -0,0 +1,2937 @@ +{ + "formatVersion": 1, + "database": { + "version": 14, + "identityHash": "603fc16a317bf94aad5b6e9a2f0a96b7", + "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, `source` TEXT NOT NULL, `note` 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": "source", + "columnName": "source", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "note", + "columnName": "note", + "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, '603fc16a317bf94aad5b6e9a2f0a96b7')" + ] + } +} \ No newline at end of file diff --git a/database/schemas/info.nightscout.androidaps.database.AppDatabase/8.json b/database/schemas/info.nightscout.androidaps.database.AppDatabase/8.json new file mode 100644 index 0000000000..b7cc18ae83 --- /dev/null +++ b/database/schemas/info.nightscout.androidaps.database.AppDatabase/8.json @@ -0,0 +1,2800 @@ +{ + "formatVersion": 1, + "database": { + "version": 8, + "identityHash": "dab6024e846ee68708e8cfc047c39662", + "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" + ] + } + ] + } + ], + "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, 'dab6024e846ee68708e8cfc047c39662')" + ] + } +} \ No newline at end of file diff --git a/database/schemas/info.nightscout.androidaps.database.AppDatabase/9.json b/database/schemas/info.nightscout.androidaps.database.AppDatabase/9.json new file mode 100644 index 0000000000..ed66e112d9 --- /dev/null +++ b/database/schemas/info.nightscout.androidaps.database.AppDatabase/9.json @@ -0,0 +1,2800 @@ +{ + "formatVersion": 1, + "database": { + "version": 9, + "identityHash": "dab6024e846ee68708e8cfc047c39662", + "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" + ] + } + ] + } + ], + "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, 'dab6024e846ee68708e8cfc047c39662')" + ] + } +} \ 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 43da5e939a..276096240d 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 = 7 +const val DATABASE_VERSION = 14 @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, - MealLink::class, MultiwaveBolusLink::class, PreferenceChange::class, VersionChange::class, UserEntry::class, - Food::class], + MultiwaveBolusLink::class, PreferenceChange::class, VersionChange::class, UserEntry::class, + Food::class, DeviceStatus::class], exportSchema = true) @TypeConverters(Converters::class) internal abstract class AppDatabase : RoomDatabase() { @@ -34,8 +34,6 @@ internal abstract class AppDatabase : RoomDatabase() { abstract val carbsDao: CarbsDao - abstract val mealLinkDao: MealLinkDao - abstract val temporaryTargetDao: TemporaryTargetDao abstract val apsResultLinkDao: APSResultLinkDao @@ -56,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 b7cc2f707c..af800d028b 100644 --- a/database/src/main/java/info/nightscout/androidaps/database/AppRepository.kt +++ b/database/src/main/java/info/nightscout/androidaps/database/AppRepository.kt @@ -1,10 +1,6 @@ package info.nightscout.androidaps.database -import info.nightscout.androidaps.database.entities.Food -import info.nightscout.androidaps.database.entities.GlucoseValue -import info.nightscout.androidaps.database.entities.TemporaryTarget -import info.nightscout.androidaps.database.entities.TherapyEvent -import info.nightscout.androidaps.database.entities.UserEntry +import info.nightscout.androidaps.database.entities.* import info.nightscout.androidaps.database.interfaces.DBEntry import info.nightscout.androidaps.database.transactions.Transaction import io.reactivex.Completable @@ -16,6 +12,7 @@ import io.reactivex.subjects.PublishSubject import java.util.concurrent.Callable import javax.inject.Inject import javax.inject.Singleton +import kotlin.math.roundToInt @Singleton open class AppRepository @Inject internal constructor( @@ -79,6 +76,25 @@ open class AppRepository @Inject internal constructor( database.glucoseValueDao.getModifiedFrom(lastId) .subscribeOn(Schedulers.io()) + /* + * 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 getNextSyncElementGlucoseValue(id: Long): Maybe> = + database.glucoseValueDao.getNextModifiedOrNewAfter(id) + .flatMap { nextIdElement -> + val nextIdElemReferenceId = nextIdElement.referenceId + if (nextIdElemReferenceId == null) { + Maybe.just(nextIdElement to nextIdElement.id) + } else { + database.glucoseValueDao.getCurrentFromHistoric(nextIdElemReferenceId) + .map { it to nextIdElement.id } + } + } + fun getBgReadingsCorrespondingLastHistoryRecord(lastId: Long): GlucoseValue? = database.glucoseValueDao.getLastHistoryRecord(lastId) @@ -88,6 +104,25 @@ open class AppRepository @Inject internal constructor( .subscribeOn(Schedulers.io()) // TEMP TARGETS + /* + * 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 getNextSyncElementTemporaryTarget(id: Long): Maybe> = + database.temporaryTargetDao.getNextModifiedOrNewAfter(id) + .flatMap { nextIdElement -> + val nextIdElemReferenceId = nextIdElement.referenceId + if (nextIdElemReferenceId == null) { + Maybe.just(nextIdElement to nextIdElement.id) + } else { + database.temporaryTargetDao.getCurrentFromHistoric(nextIdElemReferenceId) + .map { it to nextIdElement.id } + } + } + fun compatGetTemporaryTargetData(): Single> = database.temporaryTargetDao.getTemporaryTargetData() .subscribeOn(Schedulers.io()) @@ -102,12 +137,6 @@ open class AppRepository @Inject internal constructor( .map { if (!ascending) it.reversed() else it } .subscribeOn(Schedulers.io()) - fun findTemporaryTargetByNSIdSingle(nsId: String): TemporaryTarget? = - database.temporaryTargetDao.findByNSId(nsId) - - fun findTemporaryTargetByTimestamp(timestamp: Long): TemporaryTarget? = - database.temporaryTargetDao.findByTimestamp(timestamp) - fun getModifiedTemporaryTargetsDataFromId(lastId: Long): Single> = database.temporaryTargetDao.getModifiedFrom(lastId) .subscribeOn(Schedulers.io()) @@ -128,11 +157,42 @@ open class AppRepository @Inject internal constructor( database.userEntryDao.getAll() .subscribeOn(Schedulers.io()) + fun getUserEntryDataFromTime(timestamp: Long): Single> = + database.userEntryDao.getUserEntryDataFromTime(timestamp) + .subscribeOn(Schedulers.io()) + + fun getUserEntryFilteredDataFromTime(timestamp: Long): Single> = + database.userEntryDao.getUserEntryFilteredDataFromTime(UserEntry.Sources.Loop, timestamp) + .subscribeOn(Schedulers.io()) + fun insert(word: UserEntry) { database.userEntryDao.insert(word) } // THERAPY EVENT + /* + * 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 getNextSyncElementTherapyEvent(id: Long): Maybe> = + database.therapyEventDao.getNextModifiedOrNewAfter(id) + .flatMap { nextIdElement -> + val nextIdElemReferenceId = nextIdElement.referenceId + if (nextIdElemReferenceId == null) { + Maybe.just(nextIdElement to nextIdElement.id) + } else { + database.therapyEventDao.getCurrentFromHistoric(nextIdElemReferenceId) + .map { it to nextIdElement.id } + } + } + + fun getModifiedTherapyEventDataFromId(lastId: Long): Single> = + database.therapyEventDao.getModifiedFrom(lastId) + .subscribeOn(Schedulers.io()) + fun getTherapyEventDataFromTime(timestamp: Long, ascending: Boolean): Single> = database.therapyEventDao.getTherapyEventDataFromTime(timestamp) .map { if (!ascending) it.reversed() else it } @@ -172,6 +232,29 @@ open class AppRepository @Inject internal constructor( .subscribeOn(Schedulers.io()) // FOOD + /* + * 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 getNextSyncElementFood(id: Long): Maybe> = + database.foodDao.getNextModifiedOrNewAfter(id) + .flatMap { nextIdElement -> + val nextIdElemReferenceId = nextIdElement.referenceId + if (nextIdElemReferenceId == null) { + Maybe.just(nextIdElement to nextIdElement.id) + } else { + database.foodDao.getCurrentFromHistoric(nextIdElemReferenceId) + .map { it to nextIdElement.id } + } + } + + fun getModifiedFoodDataFromId(lastId: Long): Single> = + database.foodDao.getModifiedFrom(lastId) + .subscribeOn(Schedulers.io()) + fun getFoodData(): Single> = database.foodDao.getFoodData() .subscribeOn(Schedulers.io()) @@ -179,6 +262,342 @@ open class AppRepository @Inject internal constructor( fun deleteAllFoods() = database.foodDao.deleteAllEntries() + // BOLUS + /* + * 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 getNextSyncElementBolus(id: Long): Maybe> = + database.bolusDao.getNextModifiedOrNewAfterExclude(id, Bolus.Type.PRIMING) + .flatMap { nextIdElement -> + val nextIdElemReferenceId = nextIdElement.referenceId + if (nextIdElemReferenceId == null) { + Maybe.just(nextIdElement to nextIdElement.id) + } else { + database.bolusDao.getCurrentFromHistoric(nextIdElemReferenceId) + .map { it to nextIdElement.id } + } + } + + fun getModifiedBolusesDataFromId(lastId: Long): Single> = + database.bolusDao.getModifiedFrom(lastId) + .subscribeOn(Schedulers.io()) + + fun getLastBolusRecord():Bolus? = + database.bolusDao.getLastBolusRecord() + + fun getLastBolusRecordWrapped():Single> = + database.bolusDao.getLastBolusRecordMaybe() + .subscribeOn(Schedulers.io()) + .toWrappedSingle() + + fun getLastBolusRecordOfType(type: Bolus.Type): Bolus? = + database.bolusDao.getLastBolusRecordOfType(type) + + fun getOldestBolusRecord(): Bolus? = + database.bolusDao.getOldestBolusRecord() + + fun getBolusesDataFromTime(timestamp: Long, ascending: Boolean): Single> = + database.bolusDao.getBolusesFromTime(timestamp) + .map { if (!ascending) it.reversed() else it } + .subscribeOn(Schedulers.io()) + + fun getBolusesDataFromTimeToTime(from: Long, to: Long, ascending: Boolean): Single> = + database.bolusDao.getBolusesFromTime(from, to) + .map { if (!ascending) it.reversed() else it } + .subscribeOn(Schedulers.io()) + + fun getBolusesIncludingInvalidFromTime(timestamp: Long, ascending: Boolean): Single> = + database.bolusDao.getBolusesIncludingInvalidFromTime(timestamp) + .map { if (!ascending) it.reversed() else it } + .subscribeOn(Schedulers.io()) + + fun getBolusesIncludingInvalidFromTimeToTime(from: Long, to: Long, ascending: Boolean): Single> = + database.bolusDao.getBolusesIncludingInvalidFromTimeToTime(from, to) + .map { if (!ascending) it.reversed() else it } + .subscribeOn(Schedulers.io()) + + fun deleteAllBoluses() = + database.bolusDao.deleteAllEntries() + + // CARBS + + private fun expandCarbs(carbs: Carbs): List = + if (carbs.duration == 0L) { + listOf(carbs) + } else { + var remainingCarbs = carbs.amount + val ticks = (carbs.duration / 1000 / 60 / 15).coerceAtLeast(1L) + (0 until ticks).map { + val carbTime = carbs.timestamp + it * 15 * 60 * 1000 + val smallCarbAmount = (1.0 * remainingCarbs / (ticks - it)).roundToInt() //on last iteration (ticks-i) is 1 -> smallCarbAmount == remainingCarbs + remainingCarbs -= smallCarbAmount.toLong() + Carbs(timestamp = carbTime, amount = smallCarbAmount.toDouble(), duration = 0) + }.filter { it.amount != 0.0 } + } + + 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 } } + + /* + * 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 getNextSyncElementCarbs(id: Long): Maybe> = + database.carbsDao.getNextModifiedOrNewAfter(id) + .flatMap { nextIdElement -> + val nextIdElemReferenceId = nextIdElement.referenceId + if (nextIdElemReferenceId == null) { + Maybe.just(nextIdElement to nextIdElement.id) + } else { + database.carbsDao.getCurrentFromHistoric(nextIdElemReferenceId) + .map { it to nextIdElement.id } + } + } + + fun getModifiedCarbsDataFromId(lastId: Long): Single> = + database.carbsDao.getModifiedFrom(lastId) + .subscribeOn(Schedulers.io()) + + fun getCarbsByTimestamp(timestamp: Long): Carbs? = + database.carbsDao.findByTimestamp(timestamp) + + fun getLastCarbsRecord(): Carbs? = + database.carbsDao.getLastCarbsRecord() + + fun getLastCarbsRecordWrapped(): Single> = + database.carbsDao.getLastCarbsRecordMaybe() + .subscribeOn(Schedulers.io()) + .toWrappedSingle() + + fun getOldestCarbsRecord(): Carbs? = + database.carbsDao.getOldestCarbsRecord() + + fun getCarbsDataFromTime(timestamp: Long, ascending: Boolean): Single> = + database.carbsDao.getCarbsFromTime(timestamp) + .map { if (!ascending) it.reversed() else it } + .subscribeOn(Schedulers.io()) + + fun getCarbsDataFromTimeExpanded(timestamp: Long, ascending: Boolean): Single> = + database.carbsDao.getCarbsFromTimeExpandable(timestamp) + .expand() + .from(timestamp) + .map { if (!ascending) it.reversed() else it } + .subscribeOn(Schedulers.io()) + + fun getCarbsDataFromTimeToTime(from: Long, to: Long, ascending: Boolean): Single> = + database.carbsDao.getCarbsFromTimeToTime(from, to) + .map { if (!ascending) it.reversed() else it } + .subscribeOn(Schedulers.io()) + + fun getCarbsDataFromTimeToTimeExpanded(from: Long, to: Long, ascending: Boolean): Single> = + database.carbsDao.getCarbsFromTimeToTimeExpandable(from, to) + .expand() + .fromTo(from, to) + .sort() + .map { if (!ascending) it.reversed() else it } + .subscribeOn(Schedulers.io()) + + fun getCarbsIncludingInvalidFromTime(timestamp: Long, ascending: Boolean): Single> = + 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()) + + fun getCarbsIncludingInvalidFromTimeToTimeExpanded(from: Long, to: Long, ascending: Boolean): Single> = + database.carbsDao.getCarbsIncludingInvalidFromTimeToTimeExpandable(from, to) + .expand() + .fromTo(from, to) + .sort() + .map { if (!ascending) it.reversed() else it } + .subscribeOn(Schedulers.io()) + + fun deleteAllCarbs() = + database.carbsDao.deleteAllEntries() + + // BOLUS CALCULATOR RESULT + /* + * 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 getNextSyncElementBolusCalculatorResult(id: Long): Maybe> = + database.bolusCalculatorResultDao.getNextModifiedOrNewAfter(id) + .flatMap { nextIdElement -> + val nextIdElemReferenceId = nextIdElement.referenceId + if (nextIdElemReferenceId == null) { + Maybe.just(nextIdElement to nextIdElement.id) + } else { + database.bolusCalculatorResultDao.getCurrentFromHistoric(nextIdElemReferenceId) + .map { it to nextIdElement.id } + } + } + + fun getModifiedBolusCalculatorResultsDataFromId(lastId: Long): Single> = + database.bolusCalculatorResultDao.getModifiedFrom(lastId) + .subscribeOn(Schedulers.io()) + + fun getBolusCalculatorResultsDataFromTime(timestamp: Long, ascending: Boolean): Single> = + database.bolusCalculatorResultDao.getBolusCalculatorResultsFromTime(timestamp) + .map { if (!ascending) it.reversed() else it } + .subscribeOn(Schedulers.io()) + + fun getBolusCalculatorResultsIncludingInvalidFromTime(timestamp: Long, ascending: Boolean): Single> = + database.bolusCalculatorResultDao.getBolusCalculatorResultsIncludingInvalidFromTime(timestamp) + .map { if (!ascending) it.reversed() else it } + .subscribeOn(Schedulers.io()) + + 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()) + + // TEMPORARY BASAL + /* + * 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 getNextSyncElementTemporaryBasal(id: Long): Maybe> = + database.temporaryBasalDao.getNextModifiedOrNewAfter(id) + .flatMap { nextIdElement -> + val nextIdElemReferenceId = nextIdElement.referenceId + if (nextIdElemReferenceId == null) { + Maybe.just(nextIdElement to nextIdElement.id) + } else { + database.temporaryBasalDao.getCurrentFromHistoric(nextIdElemReferenceId) + .map { it to nextIdElement.id } + } + } + + fun getModifiedTemporaryBasalDataFromId(lastId: Long): Single> = + database.temporaryBasalDao.getModifiedFrom(lastId) + .subscribeOn(Schedulers.io()) + + fun getTemporaryBasalsData(): Single> = + database.temporaryBasalDao.getTemporaryBasalData() + .subscribeOn(Schedulers.io()) + + fun getTemporaryBasalActiveAt(timestamp: Long): Single> = + database.temporaryBasalDao.getTemporaryBasalActiveAt(timestamp) + .subscribeOn(Schedulers.io()) + .toWrappedSingle() + + fun getTemporaryBasalsDataFromTime(timestamp: Long, ascending: Boolean): Single> = + database.temporaryBasalDao.getTemporaryBasalDataFromTime(timestamp) + .map { if (!ascending) it.reversed() else it } + .subscribeOn(Schedulers.io()) + + fun getTemporaryBasalsDataFromTimeToTime(from: Long, to: Long, ascending: Boolean): Single> = + database.temporaryBasalDao.getTemporaryBasalDataFromTimeToTime(from, to) + .map { if (!ascending) it.reversed() else it } + .subscribeOn(Schedulers.io()) + + fun getTemporaryBasalsDataIncludingInvalidFromTime(timestamp: Long, ascending: Boolean): Single> = + database.temporaryBasalDao.getTemporaryBasalDataIncludingInvalidFromTime(timestamp) + .map { if (!ascending) it.reversed() else it } + .subscribeOn(Schedulers.io()) + + fun getTemporaryBasalsDataIncludingInvalidFromTimeToTime(from: Long, to: Long, ascending: Boolean): Single> = + database.temporaryBasalDao.getTemporaryBasalDataIncludingInvalidFromTimeToTime(from, to) + .map { if (!ascending) it.reversed() else it } + .subscribeOn(Schedulers.io()) + + fun getOldestTemporaryBasalRecord(): TemporaryBasal? = + database.temporaryBasalDao.getOldestRecord() + + // EXTENDED BOLUS + /* + * 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 getNextSyncElementExtendedBolus(id: Long): Maybe> = + database.extendedBolusDao.getNextModifiedOrNewAfter(id) + .flatMap { nextIdElement -> + val nextIdElemReferenceId = nextIdElement.referenceId + if (nextIdElemReferenceId == null) { + Maybe.just(nextIdElement to nextIdElement.id) + } else { + database.extendedBolusDao.getCurrentFromHistoric(nextIdElemReferenceId) + .map { it to nextIdElement.id } + } + } + + fun getModifiedExtendedBolusDataFromId(lastId: Long): Single> = + database.extendedBolusDao.getModifiedFrom(lastId) + .subscribeOn(Schedulers.io()) + + fun getExtendedBolusActiveAt(timestamp: Long): Single> = + database.extendedBolusDao.getExtendedBolusActiveAt(timestamp) + .subscribeOn(Schedulers.io()) + .toWrappedSingle() + + fun getExtendedBolusDataFromTime(timestamp: Long, ascending: Boolean): Single> = + database.extendedBolusDao.getExtendedBolusDataFromTime(timestamp) + .map { if (!ascending) it.reversed() else it } + .subscribeOn(Schedulers.io()) + + fun getExtendedBolusDataFromTimeToTime(start: Long, end: Long, ascending: Boolean): Single> = + database.extendedBolusDao.getExtendedBolusDataFromTimeToTime(start, end) + .map { if (!ascending) it.reversed() else it } + .subscribeOn(Schedulers.io()) + + fun getExtendedBolusDataIncludingInvalidFromTime(timestamp: Long, ascending: Boolean): Single> = + database.extendedBolusDao.getExtendedBolusDataIncludingInvalidFromTime(timestamp) + .map { if (!ascending) it.reversed() else it } + .subscribeOn(Schedulers.io()) + + fun getExtendedBolusDataIncludingInvalidFromTimeToTime(start: Long, end: Long, ascending: Boolean): Single> = + database.extendedBolusDao.getExtendedBolusDataIncludingInvalidFromTimeToTime(start, end) + .map { if (!ascending) it.reversed() else it } + .subscribeOn(Schedulers.io()) + + fun getOldestExtendedBolusRecord(): ExtendedBolus? = + database.extendedBolusDao.getOldestRecord() + } @Suppress("USELESS_CAST") diff --git a/database/src/main/java/info/nightscout/androidaps/database/Converters.kt b/database/src/main/java/info/nightscout/androidaps/database/Converters.kt index 622846218a..7cd67f602f 100644 --- a/database/src/main/java/info/nightscout/androidaps/database/Converters.kt +++ b/database/src/main/java/info/nightscout/androidaps/database/Converters.kt @@ -5,7 +5,10 @@ import info.nightscout.androidaps.database.data.Block import info.nightscout.androidaps.database.data.TargetBlock import info.nightscout.androidaps.database.embedments.InterfaceIDs import info.nightscout.androidaps.database.entities.* -import info.nightscout.androidaps.database.entities.UserEntry.* +import info.nightscout.androidaps.database.entities.UserEntry.Action +import info.nightscout.androidaps.database.entities.UserEntry.Sources +import info.nightscout.androidaps.database.serialisation.SealedClassHelper +import info.nightscout.androidaps.database.serialisation.fromJson import org.json.JSONArray import org.json.JSONObject @@ -18,30 +21,20 @@ class Converters { fun toAction(action: String?) = action?.let { Action.fromString(it) } @TypeConverter - fun fromMutableListOfValueWithUnit(values: MutableList?): String? { - if (values == null) return null - val jsonArray = JSONArray() - values.forEach { - if (it.condition) { - val jsonObject = JSONObject() - jsonObject.put("dValue", it.dValue).put("iValue", it.iValue).put("lValue", it.lValue).put("sValue", it.sValue).put("unit", it.unit.name) - jsonArray.put(jsonObject) - } - } - return jsonArray.toString() - } + fun fromSource(source: Sources?) = source?.name @TypeConverter - fun toMutableListOfValueWithUnit(jsonString: String?): MutableList? { - if (jsonString == null) return null - val jsonArray = JSONArray(jsonString) - val list = mutableListOf() - for (i in 0 until jsonArray.length()) { - val jsonObject = jsonArray.getJSONObject(i) - list.add(ValueWithUnit(jsonObject.getDouble("dValue"), jsonObject.getInt("iValue"), jsonObject.getLong("lValue"), jsonObject.getString("sValue"), Units.fromString(jsonObject.getString("unit")))) - } - return list - } + fun toSource(source: String?) = source?.let { Sources.fromString(it) } + + @TypeConverter + fun fromListOfXXXValueWithUnit(values: List): String = values.map(::ValueWithUnitWrapper) + .let(SealedClassHelper.gson::toJson) + + @TypeConverter + fun toMutableListOfXXXValueWithUnit(string: String): List = SealedClassHelper.gson + .fromJson>(string).map { it.wrapped } + + private class ValueWithUnitWrapper(val wrapped: ValueWithUnit) @TypeConverter fun fromBolusType(bolusType: Bolus.Type?) = bolusType?.name diff --git a/database/src/main/java/info/nightscout/androidaps/database/DatabaseModule.kt b/database/src/main/java/info/nightscout/androidaps/database/DatabaseModule.kt index 97e0ec66f9..2c9f768e68 100644 --- a/database/src/main/java/info/nightscout/androidaps/database/DatabaseModule.kt +++ b/database/src/main/java/info/nightscout/androidaps/database/DatabaseModule.kt @@ -21,8 +21,10 @@ open class DatabaseModule { internal fun provideAppDatabase(context: Context, @DbFileName fileName: String) = Room .databaseBuilder(context, AppDatabase::class.java, fileName) - .addMigrations(migration5to6) - .addMigrations(migration6to7) + // .addMigrations(migration5to6) + // .addMigrations(migration6to7) + // .addMigrations(migration7to8) + // .addMigrations(migration11to12) .fallbackToDestructiveMigration() .build() @@ -38,8 +40,34 @@ open class DatabaseModule { private val migration6to7 = object : Migration(6, 7) { override fun migrate(database: SupportSQLiteDatabase) { + database.execSQL("DROP TABLE IF EXISTS foods") database.execSQL("CREATE TABLE IF NOT EXISTS foods (`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, `pumpId` INTEGER, `startId` INTEGER, `endId` INTEGER, FOREIGN KEY(`referenceId`) REFERENCES `foods`(`id`) ON UPDATE NO ACTION ON DELETE NO ACTION )") database.execSQL("CREATE INDEX IF NOT EXISTS `index_foods_referenceId` ON `foods` (`referenceId`)") } } + + private val migration7to8 = object : Migration(7, 8) { + override fun migrate(database: SupportSQLiteDatabase) { + database.execSQL("DROP TABLE IF EXISTS bolusCalculatorResults") + database.execSQL("CREATE TABLE IF NOT EXISTS bolusCalculatorResults (`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, `nightscoutSystemId` TEXT, `nightscoutId` TEXT, `pumpType` TEXT, `pumpSerial` TEXT, `pumpId` INTEGER, `startId` INTEGER, `endId` INTEGER, FOREIGN KEY(`referenceId`) REFERENCES `bolusCalculatorResults`(`id`) ON UPDATE NO ACTION ON DELETE NO ACTION )") + database.execSQL("CREATE INDEX IF NOT EXISTS `index_bolusCalculatorResults_referenceId` ON bolusCalculatorResults (`referenceId`)") + database.execSQL("CREATE INDEX IF NOT EXISTS `index_bolusCalculatorResults_timestamp` ON bolusCalculatorResults (`timestamp`)") + + database.execSQL("DROP TABLE IF EXISTS mealLinks") + database.execSQL("CREATE TABLE IF NOT EXISTS mealLinks (`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, `bolusId` INTEGER, `carbsId` INTEGER, `bolusCalcResultId` INTEGER, `superbolusTempBasalId` INTEGER, `noteId` INTEGER, `nightscoutSystemId` TEXT, `nightscoutId` TEXT, `pumpType` TEXT, `pumpSerial` TEXT, `pumpId` INTEGER, `startId` INTEGER, `endId` INTEGER, FOREIGN KEY(`bolusId`) REFERENCES `boluses`(`id`) ON UPDATE NO ACTION ON DELETE NO ACTION , FOREIGN KEY(`carbsId`) REFERENCES `carbs`(`id`) ON UPDATE NO ACTION ON DELETE NO ACTION , FOREIGN KEY(`bolusCalcResultId`) REFERENCES `bolusCalculatorResults`(`id`) ON UPDATE NO ACTION ON DELETE NO ACTION , FOREIGN KEY(`superbolusTempBasalId`) REFERENCES `temporaryBasals`(`id`) ON UPDATE NO ACTION ON DELETE NO ACTION , FOREIGN KEY(`noteId`) REFERENCES `therapyEvents`(`id`) ON UPDATE NO ACTION ON DELETE NO ACTION , FOREIGN KEY(`referenceId`) REFERENCES `mealLinks`(`id`) ON UPDATE NO ACTION ON DELETE NO ACTION )") + database.execSQL("CREATE INDEX IF NOT EXISTS `index_mealLinks_referenceId` ON mealLinks (`referenceId`)") + database.execSQL("CREATE INDEX IF NOT EXISTS `index_mealLinks_bolusId` ON `mealLinks (`bolusId`)") + database.execSQL("CREATE INDEX IF NOT EXISTS `index_mealLinks_carbsId` ON mealLinks (`carbsId`)") + database.execSQL("CREATE INDEX IF NOT EXISTS `index_mealLinks_bolusCalcResultId` ON mealLinks (`bolusCalcResultId`)") + database.execSQL("CREATE INDEX IF NOT EXISTS `index_mealLinks_superbolusTempBasalId` ON mealLinks (`superbolusTempBasalId`)") + database.execSQL("CREATE INDEX IF NOT EXISTS `index_mealLinks_noteId` ON mealLinks (`noteId`)") + } + } + + private val migration11to12 = object : Migration(11,12) { + override fun migrate(database: SupportSQLiteDatabase) { + database.execSQL("DROP TABLE IF EXISTS userEntry") + database.execSQL("CREATE TABLE IF NOT EXISTS userEntry (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `timestamp` INTEGER NOT NULL, `utcOffset` INTEGER NOT NULL, `action` TEXT NOT NULL, `source` TEXT NOT NULL, `note` TEXT NOT NULL, `values` TEXT NOT NULL)") + } + } } \ No newline at end of file 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 f9058a1d51..22ffbb4154 100644 --- a/database/src/main/java/info/nightscout/androidaps/database/DelegatedAppDatabase.kt +++ b/database/src/main/java/info/nightscout/androidaps/database/DelegatedAppDatabase.kt @@ -14,7 +14,6 @@ internal class DelegatedAppDatabase(val changes: MutableList, val datab val multiwaveBolusLinkDao: MultiwaveBolusLinkDao = DelegatedMultiwaveBolusLinkDao(changes, database.multiwaveBolusLinkDao) val totalDailyDoseDao: TotalDailyDoseDao = DelegatedTotalDailyDoseDao(changes, database.totalDailyDoseDao) val carbsDao: CarbsDao = DelegatedCarbsDao(changes, database.carbsDao) - val mealLinkDao: MealLinkDao = DelegatedMealLinkDao(changes, database.mealLinkDao) val temporaryTargetDao: TemporaryTargetDao = DelegatedTemporaryTargetDao(changes, database.temporaryTargetDao) val apsResultLinkDao: APSResultLinkDao = DelegatedAPSResultLinkLinkDao(changes, database.apsResultLinkDao) val bolusCalculatorResultDao: BolusCalculatorResultDao = DelegatedBolusCalculatorResultDao(changes, database.bolusCalculatorResultDao) @@ -25,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/BolusCalculatorResultDao.kt b/database/src/main/java/info/nightscout/androidaps/database/daos/BolusCalculatorResultDao.kt index a4602a7d73..a1f5788368 100644 --- a/database/src/main/java/info/nightscout/androidaps/database/daos/BolusCalculatorResultDao.kt +++ b/database/src/main/java/info/nightscout/androidaps/database/daos/BolusCalculatorResultDao.kt @@ -4,6 +4,7 @@ import androidx.room.Dao import androidx.room.Query import info.nightscout.androidaps.database.TABLE_BOLUS_CALCULATOR_RESULTS import info.nightscout.androidaps.database.entities.BolusCalculatorResult +import io.reactivex.Maybe import io.reactivex.Single @Suppress("FunctionName") @@ -14,5 +15,23 @@ internal interface BolusCalculatorResultDao : TraceableDao= :timestamp AND referenceId IS NULL ORDER BY id DESC") + fun getBolusCalculatorResultsFromTime(timestamp: Long): Single> + + @Query("SELECT * FROM $TABLE_BOLUS_CALCULATOR_RESULTS WHERE timestamp >= :timestamp AND referenceId IS NULL ORDER BY id DESC") + fun getBolusCalculatorResultsIncludingInvalidFromTime(timestamp: Long): Single> + + // This query will be used with v3 to get all changed records + @Query("SELECT * FROM $TABLE_BOLUS_CALCULATOR_RESULTS WHERE id > :id AND referenceId IS NULL OR id IN (SELECT DISTINCT referenceId FROM $TABLE_BOLUS_CALCULATOR_RESULTS WHERE id > :id) ORDER BY id ASC") + fun getModifiedFrom(id: Long): Single> + + // for WS we need 1 record only + @Query("SELECT * FROM $TABLE_BOLUS_CALCULATOR_RESULTS WHERE id > :id ORDER BY id ASC limit 1") + fun getNextModifiedOrNewAfter(id: Long): Maybe + + @Query("SELECT * FROM $TABLE_BOLUS_CALCULATOR_RESULTS WHERE id = :referenceId") + fun getCurrentFromHistoric(referenceId: Long): Maybe } \ No newline at end of file diff --git a/database/src/main/java/info/nightscout/androidaps/database/daos/BolusDao.kt b/database/src/main/java/info/nightscout/androidaps/database/daos/BolusDao.kt index 18e0ae0121..326e08e1dd 100644 --- a/database/src/main/java/info/nightscout/androidaps/database/daos/BolusDao.kt +++ b/database/src/main/java/info/nightscout/androidaps/database/daos/BolusDao.kt @@ -5,6 +5,7 @@ import androidx.room.Query import info.nightscout.androidaps.database.TABLE_BOLUSES import info.nightscout.androidaps.database.embedments.InterfaceIDs import info.nightscout.androidaps.database.entities.Bolus +import io.reactivex.Maybe import io.reactivex.Single @Suppress("FunctionName") @@ -16,4 +17,51 @@ internal interface BolusDao : TraceableDao { @Query("DELETE FROM $TABLE_BOLUSES") override fun deleteAllEntries() + + @Query("SELECT * FROM $TABLE_BOLUSES WHERE timestamp = :timestamp AND referenceId IS NULL") + fun findByTimestamp(timestamp: Long): Bolus? + + @Query("SELECT * FROM $TABLE_BOLUSES WHERE nightscoutId = :nsId AND referenceId IS NULL") + fun findByNSId(nsId: String): Bolus? + + @Query("SELECT * FROM $TABLE_BOLUSES WHERE pumpId = :pumpId AND pumpType = :pumpType AND pumpSerial = :pumpSerial AND referenceId IS NULL") + fun findByPumpIds(pumpId: Long, pumpType: InterfaceIDs.PumpType, pumpSerial: String): Bolus? + + @Query("SELECT * FROM $TABLE_BOLUSES WHERE temporaryId = :temporaryId AND pumpType = :pumpType AND pumpSerial = :pumpSerial AND referenceId IS NULL") + fun findByPumpTempIds(temporaryId: Long, pumpType: InterfaceIDs.PumpType, pumpSerial: String): Bolus? + + @Query("SELECT * FROM $TABLE_BOLUSES WHERE isValid = 1 AND type <> :exclude AND referenceId IS NULL ORDER BY id ASC LIMIT 1") + fun getLastBolusRecord(exclude: Bolus.Type = Bolus.Type.PRIMING): Bolus? + + @Query("SELECT * FROM $TABLE_BOLUSES WHERE isValid = 1 AND type <> :exclude AND referenceId IS NULL ORDER BY id ASC LIMIT 1") + fun getLastBolusRecordMaybe(exclude: Bolus.Type = Bolus.Type.PRIMING): Maybe + + @Query("SELECT * FROM $TABLE_BOLUSES WHERE isValid = 1 AND type == :only AND referenceId IS NULL ORDER BY id ASC LIMIT 1") + fun getLastBolusRecordOfType(only: Bolus.Type): Bolus? + + @Query("SELECT * FROM $TABLE_BOLUSES WHERE isValid = 1 AND type <> :exclude AND referenceId IS NULL ORDER BY id ASC LIMIT 1") + fun getOldestBolusRecord(exclude: Bolus.Type = Bolus.Type.PRIMING): Bolus? + + @Query("SELECT * FROM $TABLE_BOLUSES WHERE isValid = 1 AND timestamp >= :timestamp AND referenceId IS NULL ORDER BY id DESC") + fun getBolusesFromTime(timestamp: Long): Single> + + @Query("SELECT * FROM $TABLE_BOLUSES WHERE isValid = 1 AND timestamp >= :start AND timestamp <= :end AND referenceId IS NULL ORDER BY id DESC") + fun getBolusesFromTime(start: Long, end: Long): Single> + + @Query("SELECT * FROM $TABLE_BOLUSES WHERE timestamp >= :timestamp AND referenceId IS NULL ORDER BY id DESC") + fun getBolusesIncludingInvalidFromTime(timestamp: Long): Single> + + @Query("SELECT * FROM $TABLE_BOLUSES WHERE timestamp >= :from AND timestamp <= :to AND referenceId IS NULL ORDER BY id DESC") + fun getBolusesIncludingInvalidFromTimeToTime(from: Long, to: Long): Single> + + // This query will be used with v3 to get all changed records + @Query("SELECT * FROM $TABLE_BOLUSES WHERE id > :id AND type <> :exclude AND referenceId IS NULL OR id IN (SELECT DISTINCT referenceId FROM $TABLE_BOLUSES WHERE id > :id) ORDER BY id ASC") + fun getModifiedFrom(id: Long, exclude: Bolus.Type = Bolus.Type.PRIMING): Single> + + // for WS we need 1 record only + @Query("SELECT * FROM $TABLE_BOLUSES WHERE id > :id AND type <> :exclude ORDER BY id ASC limit 1") + fun getNextModifiedOrNewAfterExclude(id: Long, exclude: Bolus.Type = Bolus.Type.PRIMING): Maybe + + @Query("SELECT * FROM $TABLE_BOLUSES WHERE id = :referenceId") + fun getCurrentFromHistoric(referenceId: Long): Maybe } \ No newline at end of file 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 09d24908d0..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 @@ -4,6 +4,7 @@ import androidx.room.Dao import androidx.room.Query import info.nightscout.androidaps.database.TABLE_CARBS import info.nightscout.androidaps.database.entities.Carbs +import io.reactivex.Maybe import io.reactivex.Single @Suppress("FunctionName") @@ -15,4 +16,54 @@ internal interface CarbsDao : TraceableDao { @Query("DELETE FROM $TABLE_CARBS") override fun deleteAllEntries() + + @Query("SELECT * FROM $TABLE_CARBS WHERE nightscoutId = :nsId AND referenceId IS NULL") + fun findByNSId(nsId: String): Carbs? + + @Query("SELECT * FROM $TABLE_CARBS WHERE timestamp = :timestamp AND referenceId IS NULL") + fun findByTimestamp(timestamp: Long): Carbs? + + @Query("SELECT * FROM $TABLE_CARBS WHERE isValid = 1 AND referenceId IS NULL ORDER BY id DESC LIMIT 1") + fun getLastCarbsRecord(): Carbs? + + @Query("SELECT * FROM $TABLE_CARBS WHERE isValid = 1 AND referenceId IS NULL ORDER BY id DESC LIMIT 1") + fun getLastCarbsRecordMaybe(): Maybe + + @Query("SELECT * FROM $TABLE_CARBS WHERE isValid = 1 AND referenceId IS NULL ORDER BY id ASC LIMIT 1") + fun getOldestCarbsRecord(): Carbs? + + @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> + + @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 + 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 + 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 + @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> + + // for WS we need 1 record only + @Query("SELECT * FROM $TABLE_CARBS WHERE id > :id ORDER BY id ASC limit 1") + fun getNextModifiedOrNewAfter(id: Long): Maybe + + @Query("SELECT * FROM $TABLE_CARBS WHERE id = :referenceId") + fun getCurrentFromHistoric(referenceId: Long): Maybe } \ No newline at end of file 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/ExtendedBolusDao.kt b/database/src/main/java/info/nightscout/androidaps/database/daos/ExtendedBolusDao.kt index c5e0b979bd..8f318577f8 100644 --- a/database/src/main/java/info/nightscout/androidaps/database/daos/ExtendedBolusDao.kt +++ b/database/src/main/java/info/nightscout/androidaps/database/daos/ExtendedBolusDao.kt @@ -5,7 +5,7 @@ import androidx.room.Query import info.nightscout.androidaps.database.TABLE_EXTENDED_BOLUSES import info.nightscout.androidaps.database.embedments.InterfaceIDs import info.nightscout.androidaps.database.entities.ExtendedBolus -import io.reactivex.Flowable +import io.reactivex.Maybe import io.reactivex.Single @Suppress("FunctionName") @@ -17,4 +17,49 @@ internal interface ExtendedBolusDao : TraceableDao { @Query("DELETE FROM $TABLE_EXTENDED_BOLUSES") override fun deleteAllEntries() + + @Query("SELECT * FROM $TABLE_EXTENDED_BOLUSES WHERE timestamp = :timestamp AND referenceId IS NULL") + fun findByTimestamp(timestamp: Long): ExtendedBolus? + + @Query("SELECT * FROM $TABLE_EXTENDED_BOLUSES WHERE nightscoutId = :nsId AND referenceId IS NULL") + fun findByNSId(nsId: String): ExtendedBolus? + + @Query("SELECT * FROM $TABLE_EXTENDED_BOLUSES WHERE pumpId = :pumpId AND pumpType = :pumpType AND pumpSerial = :pumpSerial AND referenceId IS NULL") + fun findByPumpIds(pumpId: Long, pumpType: InterfaceIDs.PumpType, pumpSerial: String): ExtendedBolus? + + @Query("SELECT * FROM $TABLE_EXTENDED_BOLUSES WHERE endId = :endPumpId AND pumpType = :pumpType AND pumpSerial = :pumpSerial AND referenceId IS NULL") + fun findByPumpEndIds(endPumpId: Long, pumpType: InterfaceIDs.PumpType, pumpSerial: String): ExtendedBolus? + + @Query("SELECT * FROM $TABLE_EXTENDED_BOLUSES WHERE timestamp <= :timestamp AND (timestamp + duration) > :timestamp AND pumpType = :pumpType AND pumpSerial = :pumpSerial AND referenceId IS NULL AND isValid = 1 ORDER BY timestamp DESC LIMIT 1") + fun getExtendedBolusActiveAt(timestamp: Long, pumpType: InterfaceIDs.PumpType, pumpSerial: String): Maybe + + @Query("SELECT * FROM $TABLE_EXTENDED_BOLUSES WHERE timestamp <= :timestamp AND (timestamp + duration) > :timestamp AND referenceId IS NULL AND isValid = 1 ORDER BY timestamp DESC LIMIT 1") + fun getExtendedBolusActiveAt(timestamp: Long): Maybe + + @Query("SELECT * FROM $TABLE_EXTENDED_BOLUSES WHERE timestamp >= :timestamp AND isValid = 1 AND referenceId IS NULL ORDER BY timestamp ASC") + fun getExtendedBolusDataFromTime(timestamp: Long): Single> + + @Query("SELECT * FROM $TABLE_EXTENDED_BOLUSES WHERE timestamp >= :from AND timestamp <= :to AND isValid = 1 AND referenceId IS NULL ORDER BY timestamp ASC") + fun getExtendedBolusDataFromTimeToTime(from: Long, to: Long): Single> + + @Query("SELECT * FROM $TABLE_EXTENDED_BOLUSES WHERE timestamp >= :timestamp AND referenceId IS NULL ORDER BY timestamp ASC") + fun getExtendedBolusDataIncludingInvalidFromTime(timestamp: Long): Single> + + @Query("SELECT * FROM $TABLE_EXTENDED_BOLUSES WHERE timestamp >= :from AND timestamp <= :to AND referenceId IS NULL ORDER BY timestamp ASC") + fun getExtendedBolusDataIncludingInvalidFromTimeToTime(from: Long, to: Long): Single> + + // This query will be used with v3 to get all changed records + @Query("SELECT * FROM $TABLE_EXTENDED_BOLUSES WHERE id > :id AND referenceId IS NULL OR id IN (SELECT DISTINCT referenceId FROM $TABLE_EXTENDED_BOLUSES WHERE id > :id) ORDER BY id ASC") + fun getModifiedFrom(id: Long): Single> + + // for WS we need 1 record only + @Query("SELECT * FROM $TABLE_EXTENDED_BOLUSES WHERE id > :id ORDER BY id ASC limit 1") + fun getNextModifiedOrNewAfter(id: Long): Maybe + + @Query("SELECT * FROM $TABLE_EXTENDED_BOLUSES WHERE id = :referenceId") + fun getCurrentFromHistoric(referenceId: Long): Maybe + + @Query("SELECT * FROM $TABLE_EXTENDED_BOLUSES WHERE isValid = 1 AND referenceId IS NULL ORDER BY id ASC LIMIT 1") + fun getOldestRecord(): ExtendedBolus? + } \ No newline at end of file diff --git a/database/src/main/java/info/nightscout/androidaps/database/daos/FoodDao.kt b/database/src/main/java/info/nightscout/androidaps/database/daos/FoodDao.kt index 830a196f19..b7fe24d3a0 100644 --- a/database/src/main/java/info/nightscout/androidaps/database/daos/FoodDao.kt +++ b/database/src/main/java/info/nightscout/androidaps/database/daos/FoodDao.kt @@ -4,6 +4,7 @@ import androidx.room.Dao import androidx.room.Query import info.nightscout.androidaps.database.TABLE_FOODS import info.nightscout.androidaps.database.entities.Food +import io.reactivex.Maybe import io.reactivex.Single @Suppress("FunctionName") @@ -22,4 +23,14 @@ internal interface FoodDao : TraceableDao { @Query("SELECT * FROM $TABLE_FOODS WHERE isValid = 1 AND referenceId IS NULL ORDER BY id DESC") fun getFoodData(): Single> + // This query will be used with v3 to get all changed records + @Query("SELECT * FROM $TABLE_FOODS WHERE id > :id AND referenceId IS NULL OR id IN (SELECT DISTINCT referenceId FROM $TABLE_FOODS WHERE id > :id) ORDER BY id ASC") + fun getModifiedFrom(id: Long): Single> + + // for WS we need 1 record only + @Query("SELECT * FROM $TABLE_FOODS WHERE id > :id ORDER BY id ASC limit 1") + fun getNextModifiedOrNewAfter(id: Long): Maybe + + @Query("SELECT * FROM $TABLE_FOODS WHERE id = :referenceId") + fun getCurrentFromHistoric(referenceId: Long): Maybe } \ No newline at end of file diff --git a/database/src/main/java/info/nightscout/androidaps/database/daos/GlucoseValueDao.kt b/database/src/main/java/info/nightscout/androidaps/database/daos/GlucoseValueDao.kt index fdaefe78ad..0738101140 100644 --- a/database/src/main/java/info/nightscout/androidaps/database/daos/GlucoseValueDao.kt +++ b/database/src/main/java/info/nightscout/androidaps/database/daos/GlucoseValueDao.kt @@ -37,6 +37,14 @@ internal interface GlucoseValueDao : TraceableDao { @Query("SELECT * FROM $TABLE_GLUCOSE_VALUES WHERE referenceId = :id ORDER BY id DESC LIMIT 1") fun getLastHistoryRecord(id: Long): GlucoseValue? + // This query will be used with v3 to get all changed records @Query("SELECT * FROM $TABLE_GLUCOSE_VALUES WHERE id > :id AND referenceId IS NULL OR id IN (SELECT DISTINCT referenceId FROM $TABLE_GLUCOSE_VALUES WHERE id > :id) ORDER BY id ASC") fun getModifiedFrom(id: Long): Single> + + // for WS we need 1 record only + @Query("SELECT * FROM $TABLE_GLUCOSE_VALUES WHERE id > :id ORDER BY id ASC limit 1") + fun getNextModifiedOrNewAfter(id: Long): Maybe + + @Query("SELECT * FROM $TABLE_GLUCOSE_VALUES WHERE id = :referenceId") + fun getCurrentFromHistoric(referenceId: Long): Maybe } \ No newline at end of file diff --git a/database/src/main/java/info/nightscout/androidaps/database/daos/MealLinkDao.kt b/database/src/main/java/info/nightscout/androidaps/database/daos/MealLinkDao.kt deleted file mode 100644 index 86c6904e30..0000000000 --- a/database/src/main/java/info/nightscout/androidaps/database/daos/MealLinkDao.kt +++ /dev/null @@ -1,18 +0,0 @@ -package info.nightscout.androidaps.database.daos - -import androidx.room.Dao -import androidx.room.Query -import info.nightscout.androidaps.database.TABLE_MEAL_LINKS -import info.nightscout.androidaps.database.entities.MealLink -import io.reactivex.Single - -@Suppress("FunctionName") -@Dao -internal interface MealLinkDao : TraceableDao { - - @Query("SELECT * FROM $TABLE_MEAL_LINKS WHERE id = :id") - override fun findById(id: Long): MealLink? - - @Query("DELETE FROM $TABLE_MEAL_LINKS") - override fun deleteAllEntries() -} \ No newline at end of file diff --git a/database/src/main/java/info/nightscout/androidaps/database/daos/MultiwaveBolusLinkDao.kt b/database/src/main/java/info/nightscout/androidaps/database/daos/MultiwaveBolusLinkDao.kt index d7865779b7..df275b1837 100644 --- a/database/src/main/java/info/nightscout/androidaps/database/daos/MultiwaveBolusLinkDao.kt +++ b/database/src/main/java/info/nightscout/androidaps/database/daos/MultiwaveBolusLinkDao.kt @@ -2,10 +2,8 @@ package info.nightscout.androidaps.database.daos import androidx.room.Dao import androidx.room.Query -import info.nightscout.androidaps.database.TABLE_MEAL_LINKS import info.nightscout.androidaps.database.TABLE_MULTIWAVE_BOLUS_LINKS import info.nightscout.androidaps.database.entities.MultiwaveBolusLink -import io.reactivex.Single @Suppress("FunctionName") @Dao @@ -14,6 +12,6 @@ internal interface MultiwaveBolusLinkDao : TraceableDao { @Query("SELECT * FROM $TABLE_MULTIWAVE_BOLUS_LINKS WHERE id = :id") override fun findById(id: Long): MultiwaveBolusLink? - @Query("DELETE FROM $TABLE_MEAL_LINKS") + @Query("DELETE FROM $TABLE_MULTIWAVE_BOLUS_LINKS") override fun deleteAllEntries() } \ No newline at end of file diff --git a/database/src/main/java/info/nightscout/androidaps/database/daos/TemporaryBasalDao.kt b/database/src/main/java/info/nightscout/androidaps/database/daos/TemporaryBasalDao.kt index b2b88a1c7a..49f0c8342c 100644 --- a/database/src/main/java/info/nightscout/androidaps/database/daos/TemporaryBasalDao.kt +++ b/database/src/main/java/info/nightscout/androidaps/database/daos/TemporaryBasalDao.kt @@ -5,7 +5,6 @@ import androidx.room.Query import info.nightscout.androidaps.database.TABLE_TEMPORARY_BASALS import info.nightscout.androidaps.database.embedments.InterfaceIDs import info.nightscout.androidaps.database.entities.TemporaryBasal -import io.reactivex.Flowable import io.reactivex.Maybe import io.reactivex.Single @@ -18,4 +17,54 @@ internal interface TemporaryBasalDao : TraceableDao { @Query("DELETE FROM $TABLE_TEMPORARY_BASALS") override fun deleteAllEntries() + + @Query("SELECT * FROM $TABLE_TEMPORARY_BASALS WHERE timestamp = :timestamp AND referenceId IS NULL") + fun findByTimestamp(timestamp: Long): TemporaryBasal? + + @Query("SELECT * FROM $TABLE_TEMPORARY_BASALS WHERE pumpId = :pumpId AND pumpType = :pumpType AND pumpSerial = :pumpSerial AND referenceId IS NULL") + fun findByPumpIds(pumpId: Long, pumpType: InterfaceIDs.PumpType, pumpSerial: String): TemporaryBasal? + + @Query("SELECT * FROM $TABLE_TEMPORARY_BASALS WHERE endId = :endPumpId AND pumpType = :pumpType AND pumpSerial = :pumpSerial AND referenceId IS NULL") + fun findByPumpEndIds(endPumpId: Long, pumpType: InterfaceIDs.PumpType, pumpSerial: String): TemporaryBasal? + + @Query("SELECT * FROM $TABLE_TEMPORARY_BASALS WHERE nightscoutId = :nsId AND referenceId IS NULL") + fun findByNSId(nsId: String): TemporaryBasal? + + @Query("SELECT * FROM $TABLE_TEMPORARY_BASALS WHERE timestamp <= :timestamp AND (timestamp + duration) > :timestamp AND pumpType = :pumpType AND pumpSerial = :pumpSerial AND referenceId IS NULL AND isValid = 1 ORDER BY timestamp DESC LIMIT 1") + fun getTemporaryBasalActiveAt(timestamp: Long, pumpType: InterfaceIDs.PumpType, pumpSerial: String): Maybe + + @Query("SELECT * FROM $TABLE_TEMPORARY_BASALS WHERE timestamp <= :timestamp AND (timestamp + duration) > :timestamp AND referenceId IS NULL AND isValid = 1 ORDER BY timestamp DESC LIMIT 1") + fun getTemporaryBasalActiveAt(timestamp: Long): Maybe + + @Query("SELECT * FROM $TABLE_TEMPORARY_BASALS WHERE timestamp >= :timestamp AND isValid = 1 AND referenceId IS NULL ORDER BY timestamp ASC") + fun getTemporaryBasalDataFromTime(timestamp: Long): Single> + + @Query("SELECT * FROM $TABLE_TEMPORARY_BASALS WHERE timestamp >= :from AND timestamp <= :to AND isValid = 1 AND referenceId IS NULL ORDER BY timestamp ASC") + fun getTemporaryBasalDataFromTimeToTime(from: Long, to: Long): Single> + + @Query("SELECT * FROM $TABLE_TEMPORARY_BASALS WHERE timestamp >= :timestamp AND referenceId IS NULL ORDER BY timestamp ASC") + fun getTemporaryBasalDataIncludingInvalidFromTime(timestamp: Long): Single> + + @Query("SELECT * FROM $TABLE_TEMPORARY_BASALS WHERE timestamp >= :from AND timestamp <= :to AND referenceId IS NULL ORDER BY timestamp ASC") + fun getTemporaryBasalDataIncludingInvalidFromTimeToTime(from: Long, to: Long): Single> + + @Query("SELECT * FROM $TABLE_TEMPORARY_BASALS WHERE isValid = 1 AND referenceId IS NULL ORDER BY timestamp ASC") + fun getTemporaryBasalData(): Single> + + @Query("SELECT * FROM $TABLE_TEMPORARY_BASALS WHERE referenceId = :id ORDER BY id DESC LIMIT 1") + fun getLastHistoryRecord(id: Long): TemporaryBasal? + + // This query will be used with v3 to get all changed records + @Query("SELECT * FROM $TABLE_TEMPORARY_BASALS WHERE id > :id AND referenceId IS NULL OR id IN (SELECT DISTINCT referenceId FROM $TABLE_TEMPORARY_BASALS WHERE id > :id) ORDER BY id ASC") + fun getModifiedFrom(id: Long): Single> + + // for WS we need 1 record only + @Query("SELECT * FROM $TABLE_TEMPORARY_BASALS WHERE id > :id ORDER BY id ASC limit 1") + fun getNextModifiedOrNewAfter(id: Long): Maybe + + @Query("SELECT * FROM $TABLE_TEMPORARY_BASALS WHERE id = :referenceId") + fun getCurrentFromHistoric(referenceId: Long): Maybe + + @Query("SELECT * FROM $TABLE_TEMPORARY_BASALS WHERE isValid = 1 AND referenceId IS NULL ORDER BY id ASC LIMIT 1") + fun getOldestRecord(): TemporaryBasal? } \ No newline at end of file diff --git a/database/src/main/java/info/nightscout/androidaps/database/daos/TemporaryTargetDao.kt b/database/src/main/java/info/nightscout/androidaps/database/daos/TemporaryTargetDao.kt index 7126b14aa9..0bdaa08136 100644 --- a/database/src/main/java/info/nightscout/androidaps/database/daos/TemporaryTargetDao.kt +++ b/database/src/main/java/info/nightscout/androidaps/database/daos/TemporaryTargetDao.kt @@ -20,9 +20,6 @@ internal interface TemporaryTargetDao : TraceableDao { @Query("SELECT * FROM $TABLE_TEMPORARY_TARGETS WHERE nightscoutId = :nsId AND referenceId IS NULL") fun findByNSId(nsId: String): TemporaryTarget? - @Query("SELECT * FROM $TABLE_TEMPORARY_TARGETS WHERE timestamp = :timestamp AND referenceId IS NULL") - fun findByTimestamp(timestamp: Long): TemporaryTarget? - @Query("SELECT * FROM $TABLE_TEMPORARY_TARGETS WHERE timestamp <= :timestamp AND (timestamp + duration) > :timestamp AND referenceId IS NULL AND isValid = 1 ORDER BY timestamp DESC LIMIT 1") fun getTemporaryTargetActiveAt(timestamp: Long): Maybe @@ -38,6 +35,14 @@ internal interface TemporaryTargetDao : TraceableDao { @Query("SELECT * FROM $TABLE_TEMPORARY_TARGETS WHERE referenceId = :id ORDER BY id DESC LIMIT 1") fun getLastHistoryRecord(id: Long): TemporaryTarget? + // This query will be used with v3 to get all changed records @Query("SELECT * FROM $TABLE_TEMPORARY_TARGETS WHERE id > :id AND referenceId IS NULL OR id IN (SELECT DISTINCT referenceId FROM $TABLE_TEMPORARY_TARGETS WHERE id > :id) ORDER BY id ASC") fun getModifiedFrom(id: Long): Single> + + // for WS we need 1 record only + @Query("SELECT * FROM $TABLE_TEMPORARY_TARGETS WHERE id > :id ORDER BY id ASC limit 1") + fun getNextModifiedOrNewAfter(id: Long): Maybe + + @Query("SELECT * FROM $TABLE_TEMPORARY_TARGETS WHERE id = :referenceId") + fun getCurrentFromHistoric(referenceId: Long): Maybe } \ No newline at end of file diff --git a/database/src/main/java/info/nightscout/androidaps/database/daos/TherapyEventDao.kt b/database/src/main/java/info/nightscout/androidaps/database/daos/TherapyEventDao.kt index caa7b832bb..fcec0b020d 100644 --- a/database/src/main/java/info/nightscout/androidaps/database/daos/TherapyEventDao.kt +++ b/database/src/main/java/info/nightscout/androidaps/database/daos/TherapyEventDao.kt @@ -42,4 +42,15 @@ internal interface TherapyEventDao : TraceableDao { @Query("SELECT * FROM $TABLE_THERAPY_EVENTS WHERE timestamp >= :from AND timestamp <= :to AND isValid = 1 AND referenceId IS NULL ORDER BY timestamp ASC") fun compatGetTherapyEventDataFromToTime(from: Long, to: Long): Single> + + // This query will be used with v3 to get all changed records + @Query("SELECT * FROM $TABLE_THERAPY_EVENTS WHERE id > :id AND referenceId IS NULL OR id IN (SELECT DISTINCT referenceId FROM $TABLE_THERAPY_EVENTS WHERE id > :id) ORDER BY id ASC") + fun getModifiedFrom(id: Long): Single> + + // for WS we need 1 record only + @Query("SELECT * FROM $TABLE_THERAPY_EVENTS WHERE id > :id ORDER BY id ASC limit 1") + fun getNextModifiedOrNewAfter(id: Long): Maybe + + @Query("SELECT * FROM $TABLE_THERAPY_EVENTS WHERE id = :referenceId") + fun getCurrentFromHistoric(referenceId: Long): Maybe } \ No newline at end of file diff --git a/database/src/main/java/info/nightscout/androidaps/database/daos/UserEntryDao.kt b/database/src/main/java/info/nightscout/androidaps/database/daos/UserEntryDao.kt index adb712f0e4..91e0add323 100644 --- a/database/src/main/java/info/nightscout/androidaps/database/daos/UserEntryDao.kt +++ b/database/src/main/java/info/nightscout/androidaps/database/daos/UserEntryDao.kt @@ -5,6 +5,7 @@ import androidx.room.Insert import androidx.room.Query import info.nightscout.androidaps.database.TABLE_USER_ENTRY import info.nightscout.androidaps.database.entities.UserEntry +import info.nightscout.androidaps.database.entities.UserEntry.Sources import io.reactivex.Single @Dao @@ -16,4 +17,10 @@ interface UserEntryDao { @Query("SELECT * FROM $TABLE_USER_ENTRY ORDER BY id DESC") fun getAll(): Single> + @Query("SELECT * FROM $TABLE_USER_ENTRY WHERE timestamp >= :timestamp ORDER BY id DESC") + fun getUserEntryDataFromTime(timestamp: Long): Single> + + @Query("SELECT * FROM $TABLE_USER_ENTRY WHERE timestamp >= :timestamp AND source != :excludeSource ORDER BY id DESC") + fun getUserEntryFilteredDataFromTime(excludeSource: Sources, timestamp: Long): Single> + } \ 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/daos/delegated/DelegatedMealLinkDao.kt b/database/src/main/java/info/nightscout/androidaps/database/daos/delegated/DelegatedMealLinkDao.kt deleted file mode 100644 index a568dd5aed..0000000000 --- a/database/src/main/java/info/nightscout/androidaps/database/daos/delegated/DelegatedMealLinkDao.kt +++ /dev/null @@ -1,18 +0,0 @@ -package info.nightscout.androidaps.database.daos.delegated - -import info.nightscout.androidaps.database.daos.MealLinkDao -import info.nightscout.androidaps.database.entities.MealLink -import info.nightscout.androidaps.database.interfaces.DBEntry - -internal class DelegatedMealLinkDao(changes: MutableList, private val dao: MealLinkDao) : DelegatedDao(changes), MealLinkDao by dao { - - override fun insertNewEntry(entry: MealLink): Long { - changes.add(entry) - return dao.insertNewEntry(entry) - } - - override fun updateExistingEntry(entry: MealLink): Long { - changes.add(entry) - return dao.updateExistingEntry(entry) - } -} \ No newline at end of file diff --git a/database/src/main/java/info/nightscout/androidaps/database/embedments/InterfaceIDs.kt b/database/src/main/java/info/nightscout/androidaps/database/embedments/InterfaceIDs.kt index 86873d9915..beb7eb5184 100644 --- a/database/src/main/java/info/nightscout/androidaps/database/embedments/InterfaceIDs.kt +++ b/database/src/main/java/info/nightscout/androidaps/database/embedments/InterfaceIDs.kt @@ -1,20 +1,53 @@ package info.nightscout.androidaps.database.embedments +import info.nightscout.androidaps.database.entities.TherapyEvent + data class InterfaceIDs( - var nightscoutSystemId: String? = null, - var nightscoutId: String? = null, - var pumpType: PumpType? = null, - var pumpSerial: String? = null, - var pumpId: Long? = null, - var startId: Long? = null, - var endId: Long? = null + var nightscoutSystemId: String? = null, + var nightscoutId: String? = null, + var pumpType: PumpType? = null, // if == USER pumpSerial & pumpId can be null + var pumpSerial: String? = null, + var temporaryId: Long? = null, // temporary id for pump synchronization, when pump id is not available + var pumpId: Long? = null, + var startId: Long? = null, + var endId: Long? = null ) { + enum class PumpType { - ACCU_CHEK_INSIGHT, + GENERIC_AAPS, + CELLNOVO, ACCU_CHEK_COMBO, + ACCU_CHEK_SPIRIT, + ACCU_CHEK_INSIGHT, + ACCU_CHEK_INSIGHT_BLUETOOTH, + ACCU_CHEK_SOLO, + ANIMAS_VIBE, + ANIMAS_PING, DANA_R, + DANA_R_KOREAN, + DANA_RV2, + DANA_I, DANA_RS, - MEDTRONIC, - OMNIPOD + DANA_RS_KOREAN, + OMNIPOD_EROS, + OMNIPOD_DASH, + MEDTRONIC_512_517, + MEDTRONIC_515_715, + MEDTRONIC_522_722, + MEDTRONIC_523_723_REVEL, + MEDTRONIC_554_754_VEO, + MEDTRONIC_640G, + TANDEM_T_SLIM, + TANDEM_T_FLEX, + TANDEM_T_SLIM_G4, + TANDEM_T_SLIM_X2, + YPSOPUMP, + MDI, + USER; + + companion object { + + fun fromString(name: String?) = values().firstOrNull { it.name == name } + } } } \ No newline at end of file diff --git a/database/src/main/java/info/nightscout/androidaps/database/entities/Bolus.kt b/database/src/main/java/info/nightscout/androidaps/database/entities/Bolus.kt index a683ca31f3..afc6108867 100644 --- a/database/src/main/java/info/nightscout/androidaps/database/entities/Bolus.kt +++ b/database/src/main/java/info/nightscout/androidaps/database/entities/Bolus.kt @@ -1,39 +1,50 @@ package info.nightscout.androidaps.database.entities -import androidx.room.* +import androidx.room.Embedded +import androidx.room.Entity +import androidx.room.ForeignKey +import androidx.room.Index +import androidx.room.PrimaryKey import info.nightscout.androidaps.database.TABLE_BOLUSES import info.nightscout.androidaps.database.embedments.InsulinConfiguration import info.nightscout.androidaps.database.embedments.InterfaceIDs import info.nightscout.androidaps.database.interfaces.DBEntryWithTime import info.nightscout.androidaps.database.interfaces.TraceableDBEntry -import java.util.TimeZone +import java.util.* @Entity(tableName = TABLE_BOLUSES, - foreignKeys = [ForeignKey( - entity = Bolus::class, - parentColumns = ["id"], - childColumns = ["referenceId"])], - indices = [Index("referenceId"), Index("timestamp")]) + foreignKeys = [ + ForeignKey( + entity = Bolus::class, + parentColumns = ["id"], + childColumns = ["referenceId"])], + indices = [Index("referenceId"), Index("timestamp")]) data class Bolus( @PrimaryKey(autoGenerate = true) - override var id: Long = 0, + override var id: Long = 0, override var version: Int = 0, override var dateCreated: Long = -1, override var isValid: Boolean = true, override var referenceId: Long? = null, @Embedded - override var interfaceIDs_backing: InterfaceIDs? = null, + override var interfaceIDs_backing: InterfaceIDs? = null, override var timestamp: Long, override var utcOffset: Long = TimeZone.getDefault().getOffset(timestamp).toLong(), var amount: Double, var type: Type, - var isBasalInsulin: Boolean, + var isBasalInsulin: Boolean = false, @Embedded - var insulinConfiguration: InsulinConfiguration? = null + var insulinConfiguration: InsulinConfiguration? = null ) : TraceableDBEntry, DBEntryWithTime { + enum class Type { NORMAL, SMB, - PRIMING + PRIMING; + + companion object { + + fun fromString(name: String?) = values().firstOrNull { it.name == name } ?: NORMAL + } } } \ No newline at end of file diff --git a/database/src/main/java/info/nightscout/androidaps/database/entities/BolusCalculatorResult.kt b/database/src/main/java/info/nightscout/androidaps/database/entities/BolusCalculatorResult.kt index 056d1fd363..e88699f9ea 100644 --- a/database/src/main/java/info/nightscout/androidaps/database/entities/BolusCalculatorResult.kt +++ b/database/src/main/java/info/nightscout/androidaps/database/entities/BolusCalculatorResult.kt @@ -8,20 +8,20 @@ import info.nightscout.androidaps.database.interfaces.TraceableDBEntry import java.util.TimeZone @Entity(tableName = TABLE_BOLUS_CALCULATOR_RESULTS, - foreignKeys = [ForeignKey( - entity = BolusCalculatorResult::class, - parentColumns = ["id"], - childColumns = ["referenceId"])], - indices = [Index("referenceId"), Index("timestamp")]) + foreignKeys = [ForeignKey( + entity = BolusCalculatorResult::class, + parentColumns = ["id"], + childColumns = ["referenceId"])], + indices = [Index("referenceId"), Index("timestamp")]) data class BolusCalculatorResult( @PrimaryKey(autoGenerate = true) - override var id: Long = 0, + override var id: Long = 0, override var version: Int = 0, override var dateCreated: Long = -1, override var isValid: Boolean = true, override var referenceId: Long? = null, @Embedded - override var interfaceIDs_backing: InterfaceIDs? = null, + override var interfaceIDs_backing: InterfaceIDs? = null, override var timestamp: Long, override var utcOffset: Long = TimeZone.getDefault().getOffset(timestamp).toLong(), var targetBGLow: Double, @@ -49,5 +49,8 @@ data class BolusCalculatorResult( var wasSuperbolusUsed: Boolean, var superbolusInsulin: Double, var wasTempTargetUsed: Boolean, - var totalInsulin: Double + var totalInsulin: Double, + var percentageCorrection: Int, + var profileName: String, + var note: String ) : TraceableDBEntry, DBEntryWithTime \ No newline at end of file diff --git a/database/src/main/java/info/nightscout/androidaps/database/entities/Carbs.kt b/database/src/main/java/info/nightscout/androidaps/database/entities/Carbs.kt index 5694d1041a..cd5a41ab87 100644 --- a/database/src/main/java/info/nightscout/androidaps/database/entities/Carbs.kt +++ b/database/src/main/java/info/nightscout/androidaps/database/entities/Carbs.kt @@ -1,29 +1,33 @@ package info.nightscout.androidaps.database.entities -import androidx.room.* +import androidx.room.Embedded +import androidx.room.Entity +import androidx.room.ForeignKey +import androidx.room.Index +import androidx.room.PrimaryKey import info.nightscout.androidaps.database.TABLE_CARBS import info.nightscout.androidaps.database.embedments.InterfaceIDs import info.nightscout.androidaps.database.interfaces.DBEntryWithTimeAndDuration import info.nightscout.androidaps.database.interfaces.TraceableDBEntry -import java.util.TimeZone +import java.util.* @Entity(tableName = TABLE_CARBS, - foreignKeys = [ForeignKey( - entity = Carbs::class, - parentColumns = ["id"], - childColumns = ["referenceId"])], - indices = [Index("referenceId"), Index("timestamp")]) + foreignKeys = [ForeignKey( + entity = Carbs::class, + parentColumns = ["id"], + childColumns = ["referenceId"])], + indices = [Index("referenceId"), Index("timestamp")]) data class Carbs( @PrimaryKey(autoGenerate = true) - override var id: Long = 0, + override var id: Long = 0, override var version: Int = 0, override var dateCreated: Long = -1, override var isValid: Boolean = true, override var referenceId: Long? = null, @Embedded - override var interfaceIDs_backing: InterfaceIDs? = null, + override var interfaceIDs_backing: InterfaceIDs? = null, override var timestamp: Long, override var utcOffset: Long = TimeZone.getDefault().getOffset(timestamp).toLong(), - override var duration: Long, + override var duration: Long, // in milliseconds var amount: Double ) : TraceableDBEntry, DBEntryWithTimeAndDuration \ 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/entities/ExtendedBolus.kt b/database/src/main/java/info/nightscout/androidaps/database/entities/ExtendedBolus.kt index 40792c11c7..08a218aea8 100644 --- a/database/src/main/java/info/nightscout/androidaps/database/entities/ExtendedBolus.kt +++ b/database/src/main/java/info/nightscout/androidaps/database/entities/ExtendedBolus.kt @@ -1,30 +1,42 @@ package info.nightscout.androidaps.database.entities -import androidx.room.* +import androidx.room.Embedded +import androidx.room.Entity +import androidx.room.ForeignKey +import androidx.room.Index +import androidx.room.PrimaryKey import info.nightscout.androidaps.database.TABLE_EXTENDED_BOLUSES import info.nightscout.androidaps.database.embedments.InterfaceIDs import info.nightscout.androidaps.database.interfaces.DBEntryWithTimeAndDuration import info.nightscout.androidaps.database.interfaces.TraceableDBEntry -import java.util.TimeZone +import java.util.* @Entity(tableName = TABLE_EXTENDED_BOLUSES, - foreignKeys = [ForeignKey( - entity = ExtendedBolus::class, - parentColumns = ["id"], - childColumns = ["referenceId"])], - indices = [Index("referenceId"), Index("timestamp")]) + foreignKeys = [ForeignKey( + entity = ExtendedBolus::class, + parentColumns = ["id"], + childColumns = ["referenceId"])], + indices = [Index("referenceId"), Index("timestamp")]) data class ExtendedBolus( @PrimaryKey(autoGenerate = true) - override var id: Long = 0, + override var id: Long = 0, override var version: Int = 0, override var dateCreated: Long = -1, override var isValid: Boolean = true, override var referenceId: Long? = null, @Embedded - override var interfaceIDs_backing: InterfaceIDs? = InterfaceIDs(), + override var interfaceIDs_backing: InterfaceIDs? = InterfaceIDs(), override var timestamp: Long, override var utcOffset: Long = TimeZone.getDefault().getOffset(timestamp).toLong(), override var duration: Long, var amount: Double, - var isEmulatingTempBasal: Boolean -) : TraceableDBEntry, DBEntryWithTimeAndDuration \ No newline at end of file + var isEmulatingTempBasal: Boolean = false +) : TraceableDBEntry, DBEntryWithTimeAndDuration { + + init { + require(duration > 0) + } + + val rate: Double // in U/h + get() = amount * (60 * 60 * 1000.0) / duration +} \ No newline at end of file diff --git a/database/src/main/java/info/nightscout/androidaps/database/entities/GlucoseValue.kt b/database/src/main/java/info/nightscout/androidaps/database/entities/GlucoseValue.kt index 81e154102d..85fab0a92c 100644 --- a/database/src/main/java/info/nightscout/androidaps/database/entities/GlucoseValue.kt +++ b/database/src/main/java/info/nightscout/androidaps/database/entities/GlucoseValue.kt @@ -93,11 +93,11 @@ data class GlucoseValue( @SerializedName("Random") RANDOM("Random"), @SerializedName("Unknown") UNKNOWN("Unknown"), - @SerializedName("IOBPrediction") IOB_PREDICTION("IOBPrediction"), - @SerializedName("aCOBPrediction") aCOB_PREDICTION("aCOBPrediction"), - @SerializedName("COBPrediction") COB_PREDICTION("COBPrediction"), - @SerializedName("UAMPrediction") UAM_PREDICTION("UAMPrediction"), - @SerializedName("ZTPrediction") ZT_PREDICTION("ZTPrediction") + IOB_PREDICTION("IOBPrediction"), + A_COB_PREDICTION("aCOBPrediction"), + COB_PREDICTION("COBPrediction"), + UAM_PREDICTION("UAMPrediction"), + ZT_PREDICTION("ZTPrediction"), ; companion object { diff --git a/database/src/main/java/info/nightscout/androidaps/database/entities/MealLink.kt b/database/src/main/java/info/nightscout/androidaps/database/entities/MealLink.kt deleted file mode 100644 index 4c6a3c5f32..0000000000 --- a/database/src/main/java/info/nightscout/androidaps/database/entities/MealLink.kt +++ /dev/null @@ -1,54 +0,0 @@ -package info.nightscout.androidaps.database.entities - -import androidx.room.* -import info.nightscout.androidaps.database.TABLE_MEAL_LINKS -import info.nightscout.androidaps.database.embedments.InterfaceIDs -import info.nightscout.androidaps.database.interfaces.TraceableDBEntry - -@Entity(tableName = TABLE_MEAL_LINKS, - foreignKeys = [ForeignKey( - entity = Bolus::class, - parentColumns = arrayOf("id"), - childColumns = arrayOf("bolusId")), ForeignKey( - - entity = Carbs::class, - parentColumns = arrayOf("id"), - childColumns = arrayOf("carbsId")), ForeignKey( - - entity = BolusCalculatorResult::class, - parentColumns = arrayOf("id"), - childColumns = arrayOf("bolusCalcResultId")), ForeignKey( - - entity = TemporaryBasal::class, - parentColumns = arrayOf("id"), - childColumns = arrayOf("superbolusTempBasalId")), ForeignKey( - - entity = TherapyEvent::class, - parentColumns = arrayOf("id"), - childColumns = arrayOf("noteId")), ForeignKey( - - entity = MealLink::class, - parentColumns = ["id"], - childColumns = ["referenceId"])], - indices = [Index("referenceId"), Index("bolusId"), - Index("carbsId"), Index("bolusCalcResultId"), - Index("superbolusTempBasalId"), Index("noteId")]) -data class MealLink( - @PrimaryKey(autoGenerate = true) - override var id: Long = 0, - override var version: Int = 0, - override var dateCreated: Long = -1, - override var isValid: Boolean = true, - override var referenceId: Long? = null, - @Embedded - override var interfaceIDs_backing: InterfaceIDs? = null, - var bolusId: Long? = null, - var carbsId: Long? = null, - var bolusCalcResultId: Long? = null, - var superbolusTempBasalId: Long? = null, - var noteId: Long? = null -) : TraceableDBEntry { - override val foreignKeysValid: Boolean - get() = super.foreignKeysValid && bolusId != 0L && carbsId != 0L && - bolusCalcResultId != 0L && superbolusTempBasalId != 0L && noteId != 0L -} \ No newline at end of file diff --git a/database/src/main/java/info/nightscout/androidaps/database/entities/TemporaryBasal.kt b/database/src/main/java/info/nightscout/androidaps/database/entities/TemporaryBasal.kt index 01f034ae86..8f5e709790 100644 --- a/database/src/main/java/info/nightscout/androidaps/database/entities/TemporaryBasal.kt +++ b/database/src/main/java/info/nightscout/androidaps/database/entities/TemporaryBasal.kt @@ -1,27 +1,31 @@ package info.nightscout.androidaps.database.entities -import androidx.room.* +import androidx.room.Embedded +import androidx.room.Entity +import androidx.room.ForeignKey +import androidx.room.Index +import androidx.room.PrimaryKey import info.nightscout.androidaps.database.TABLE_TEMPORARY_BASALS import info.nightscout.androidaps.database.embedments.InterfaceIDs import info.nightscout.androidaps.database.interfaces.DBEntryWithTimeAndDuration import info.nightscout.androidaps.database.interfaces.TraceableDBEntry -import java.util.TimeZone +import java.util.* @Entity(tableName = TABLE_TEMPORARY_BASALS, - foreignKeys = [ForeignKey( - entity = TemporaryBasal::class, - parentColumns = ["id"], - childColumns = ["referenceId"])], - indices = [Index("referenceId"), Index("timestamp")]) + foreignKeys = [ForeignKey( + entity = TemporaryBasal::class, + parentColumns = ["id"], + childColumns = ["referenceId"])], + indices = [Index("referenceId"), Index("timestamp")]) data class TemporaryBasal( @PrimaryKey(autoGenerate = true) - override var id: Long = 0, + override var id: Long = 0, override var version: Int = 0, override var dateCreated: Long = -1, override var isValid: Boolean = true, override var referenceId: Long? = null, @Embedded - override var interfaceIDs_backing: InterfaceIDs? = InterfaceIDs(), + override var interfaceIDs_backing: InterfaceIDs? = InterfaceIDs(), override var timestamp: Long, override var utcOffset: Long = TimeZone.getDefault().getOffset(timestamp).toLong(), var type: Type, @@ -29,10 +33,26 @@ data class TemporaryBasal( var rate: Double, override var duration: Long ) : TraceableDBEntry, DBEntryWithTimeAndDuration { + + init { + if (duration <= 0) + require(duration > 0) + } + enum class Type { NORMAL, EMULATED_PUMP_SUSPEND, PUMP_SUSPEND, - SUPERBOLUS + SUPERBOLUS, + FAKE_EXTENDED // in memory only + ; + + companion object { + + fun fromString(name: String?) = values().firstOrNull { it.name == name } ?: NORMAL + } } + + val isInProgress: Boolean + get() = System.currentTimeMillis() in timestamp..timestamp + duration } \ No newline at end of file diff --git a/database/src/main/java/info/nightscout/androidaps/database/entities/TherapyEvent.kt b/database/src/main/java/info/nightscout/androidaps/database/entities/TherapyEvent.kt index 57222ce9f4..15e7a1a7fd 100644 --- a/database/src/main/java/info/nightscout/androidaps/database/entities/TherapyEvent.kt +++ b/database/src/main/java/info/nightscout/androidaps/database/entities/TherapyEvent.kt @@ -26,7 +26,7 @@ data class TherapyEvent( override var isValid: Boolean = true, override var referenceId: Long? = null, @Embedded - override var interfaceIDs_backing: InterfaceIDs? = InterfaceIDs(), + override var interfaceIDs_backing: InterfaceIDs? = null, override var timestamp: Long, override var utcOffset: Long = TimeZone.getDefault().getOffset(timestamp).toLong(), override var duration: Long = 0, diff --git a/database/src/main/java/info/nightscout/androidaps/database/entities/UserEntry.kt b/database/src/main/java/info/nightscout/androidaps/database/entities/UserEntry.kt index ff990de675..d4347542c2 100644 --- a/database/src/main/java/info/nightscout/androidaps/database/entities/UserEntry.kt +++ b/database/src/main/java/info/nightscout/androidaps/database/entities/UserEntry.kt @@ -2,7 +2,6 @@ package info.nightscout.androidaps.database.entities import androidx.room.Entity import androidx.room.PrimaryKey -import com.google.gson.annotations.SerializedName import info.nightscout.androidaps.database.TABLE_USER_ENTRY import info.nightscout.androidaps.database.interfaces.DBEntry import info.nightscout.androidaps.database.interfaces.DBEntryWithTime @@ -15,143 +14,168 @@ data class UserEntry( override var timestamp: Long, override var utcOffset: Long = TimeZone.getDefault().getOffset(timestamp).toLong(), var action: Action, - var s: String, - var values: MutableList + var source: Sources, + var note: String, + var values: List ) : DBEntry, DBEntryWithTime { enum class Action (val colorGroup: ColorGroup) { - @SerializedName("BOLUS") BOLUS (ColorGroup.InsulinTreatment), - @SerializedName("BOLUS_ADVISOR") BOLUS_ADVISOR (ColorGroup.InsulinTreatment), - @SerializedName("BOLUS_RECORD") BOLUS_RECORD (ColorGroup.InsulinTreatment), - @SerializedName("EXTENDED_BOLUS") EXTENDED_BOLUS (ColorGroup.InsulinTreatment), - @SerializedName("SUPERBOLUS_TBR") SUPERBOLUS_TBR (ColorGroup.InsulinTreatment), - @SerializedName("CARBS") CARBS (ColorGroup.CarbTreatment), - @SerializedName("EXTENDED_CARBS") EXTENDED_CARBS (ColorGroup.CarbTreatment), - @SerializedName("TEMP_BASAL") TEMP_BASAL (ColorGroup.InsulinTreatment), - @SerializedName("TT") TT (ColorGroup.TT), - @SerializedName("NEW_PROFILE") NEW_PROFILE (ColorGroup.Profile), - @SerializedName("CLONE_PROFILE") CLONE_PROFILE (ColorGroup.Profile), - @SerializedName("STORE_PROFILE") STORE_PROFILE (ColorGroup.Profile), - @SerializedName("PROFILE_SWITCH") PROFILE_SWITCH (ColorGroup.Profile), - @SerializedName("PROFILE_SWITCH_CLONED") PROFILE_SWITCH_CLONED (ColorGroup.Profile), - @SerializedName("CLOSED_LOOP_MODE") CLOSED_LOOP_MODE (ColorGroup.Loop), - @SerializedName("LGS_LOOP_MODE") LGS_LOOP_MODE (ColorGroup.Loop), - @SerializedName("OPEN_LOOP_MODE") OPEN_LOOP_MODE (ColorGroup.Loop), - @SerializedName("LOOP_DISABLED") LOOP_DISABLED (ColorGroup.Loop), - @SerializedName("LOOP_ENABLED") LOOP_ENABLED (ColorGroup.Loop), - @SerializedName("RECONNECT") RECONNECT (ColorGroup.Pump), - @SerializedName("DISCONNECT") DISCONNECT (ColorGroup.Pump), - @SerializedName("RESUME") RESUME (ColorGroup.Loop), - @SerializedName("SUSPEND") SUSPEND (ColorGroup.Loop), - @SerializedName("HW_PUMP_ALLOWED") HW_PUMP_ALLOWED (ColorGroup.Pump), - @SerializedName("CLEAR_PAIRING_KEYS") CLEAR_PAIRING_KEYS (ColorGroup.Pump), - @SerializedName("ACCEPTS_TEMP_BASAL") ACCEPTS_TEMP_BASAL (ColorGroup.InsulinTreatment), - @SerializedName("CANCEL_TEMP_BASAL") CANCEL_TEMP_BASAL (ColorGroup.InsulinTreatment), - @SerializedName("CANCEL_EXTENDED_BOLUS") CANCEL_EXTENDED_BOLUS (ColorGroup.InsulinTreatment), - @SerializedName("CANCEL_TT") CANCEL_TT (ColorGroup.TT), - @SerializedName("CAREPORTAL") CAREPORTAL (ColorGroup.Careportal), - @SerializedName("CALIBRATION") CALIBRATION (ColorGroup.Careportal), - @SerializedName("PRIME_BOLUS") PRIME_BOLUS (ColorGroup.Careportal), - @SerializedName("TREATMENT") TREATMENT (ColorGroup.InsulinTreatment), - @SerializedName("CAREPORTAL_NS_REFRESH") CAREPORTAL_NS_REFRESH (ColorGroup.Aaps), - @SerializedName("PROFILE_SWITCH_NS_REFRESH") PROFILE_SWITCH_NS_REFRESH (ColorGroup.Aaps), - @SerializedName("TREATMENTS_NS_REFRESH") TREATMENTS_NS_REFRESH (ColorGroup.Aaps), - @SerializedName("TT_NS_REFRESH") TT_NS_REFRESH (ColorGroup.Aaps), - @SerializedName("AUTOMATION_REMOVED") AUTOMATION_REMOVED (ColorGroup.Aaps), - @SerializedName("BG_REMOVED") BG_REMOVED (ColorGroup.Careportal), - @SerializedName("CAREPORTAL_REMOVED") CAREPORTAL_REMOVED (ColorGroup.Careportal), - @SerializedName("EXTENDED_BOLUS_REMOVED") EXTENDED_BOLUS_REMOVED (ColorGroup.InsulinTreatment), - @SerializedName("FOOD_REMOVED") FOOD_REMOVED (ColorGroup.Careportal), - @SerializedName("PROFILE_REMOVED") PROFILE_REMOVED (ColorGroup.Profile), - @SerializedName("PROFILE_SWITCH_REMOVED") PROFILE_SWITCH_REMOVED (ColorGroup.Profile), - @SerializedName("RESTART_EVENTS_REMOVED") RESTART_EVENTS_REMOVED (ColorGroup.Aaps), - @SerializedName("TREATMENT_REMOVED") TREATMENT_REMOVED (ColorGroup.InsulinTreatment), - @SerializedName("TT_REMOVED") TT_REMOVED (ColorGroup.TT), - @SerializedName("NS_PAUSED") NS_PAUSED (ColorGroup.Aaps), - @SerializedName("NS_RESUME") NS_RESUME (ColorGroup.Aaps), - @SerializedName("NS_QUEUE_CLEARED") NS_QUEUE_CLEARED (ColorGroup.Aaps), - @SerializedName("NS_SETTINGS_COPIED") NS_SETTINGS_COPIED (ColorGroup.Aaps), - @SerializedName("ERROR_DIALOG_OK") ERROR_DIALOG_OK (ColorGroup.Aaps), - @SerializedName("ERROR_DIALOG_MUTE") ERROR_DIALOG_MUTE (ColorGroup.Aaps), - @SerializedName("ERROR_DIALOG_MUTE_5MIN") ERROR_DIALOG_MUTE_5MIN (ColorGroup.Aaps), - @SerializedName("OBJECTIVE_STARTED") OBJECTIVE_STARTED (ColorGroup.Aaps), - @SerializedName("OBJECTIVE_UNSTARTED") OBJECTIVE_UNSTARTED (ColorGroup.Aaps), - @SerializedName("OBJECTIVES_SKIPPED") OBJECTIVES_SKIPPED (ColorGroup.Aaps), - @SerializedName("STAT_RESET") STAT_RESET (ColorGroup.Aaps), - @SerializedName("DELETE_LOGS") DELETE_LOGS (ColorGroup.Aaps), - @SerializedName("DELETE_FUTURE_TREATMENTS") DELETE_FUTURE_TREATMENTS (ColorGroup.Aaps), - @SerializedName("EXPORT_SETTINGS") EXPORT_SETTINGS (ColorGroup.Aaps), - @SerializedName("IMPORT_SETTINGS") IMPORT_SETTINGS (ColorGroup.Aaps), - @SerializedName("RESET_DATABASES") RESET_DATABASES (ColorGroup.Aaps), - @SerializedName("EXPORT_DATABASES") EXPORT_DATABASES (ColorGroup.Aaps), - @SerializedName("IMPORT_DATABASES") IMPORT_DATABASES (ColorGroup.Aaps), - @SerializedName("OTP_EXPORT") OTP_EXPORT (ColorGroup.Aaps), - @SerializedName("OTP_RESET") OTP_RESET (ColorGroup.Aaps), - @SerializedName("SMS_BASAL") SMS_BASAL (ColorGroup.InsulinTreatment), - @SerializedName("SMS_BOLUS") SMS_BOLUS (ColorGroup.InsulinTreatment), - @SerializedName("SMS_CAL") SMS_CAL (ColorGroup.Careportal), - @SerializedName("SMS_CARBS") SMS_CARBS (ColorGroup.CarbTreatment), - @SerializedName("SMS_EXTENDED_BOLUS") SMS_EXTENDED_BOLUS (ColorGroup.InsulinTreatment), - @SerializedName("SMS_LOOP_DISABLED") SMS_LOOP_DISABLED (ColorGroup.Loop), - @SerializedName("SMS_LOOP_ENABLED") SMS_LOOP_ENABLED (ColorGroup.Loop), - @SerializedName("SMS_LOOP_RESUME") SMS_LOOP_RESUME (ColorGroup.Loop), - @SerializedName("SMS_LOOP_SUSPEND") SMS_LOOP_SUSPEND (ColorGroup.Loop), - @SerializedName("SMS_PROFILE") SMS_PROFILE (ColorGroup.Profile), - @SerializedName("SMS_PUMP_CONNECT") SMS_PUMP_CONNECT (ColorGroup.Pump), - @SerializedName("SMS_PUMP_DISCONNECT") SMS_PUMP_DISCONNECT (ColorGroup.Pump), - @SerializedName("SMS_SMS") SMS_SMS (ColorGroup.Aaps), - @SerializedName("SMS_TT") SMS_TT (ColorGroup.TT), - @SerializedName("TT_DELETED_FROM_NS") TT_DELETED_FROM_NS (ColorGroup.TT), - @SerializedName("CAREPORTAL_DELETED_FROM_NS") CAREPORTAL_DELETED_FROM_NS (ColorGroup.Careportal), - @SerializedName("CAREPORTAL_FROM_NS") CAREPORTAL_FROM_NS (ColorGroup.Careportal), - @SerializedName("FOOD_FROM_NS") FOOD_FROM_NS (ColorGroup.Careportal), - @SerializedName("TT_FROM_NS") TT_FROM_NS (ColorGroup.TT), - @SerializedName("TT_CANCELED_FROM_NS") TT_CANCELED_FROM_NS (ColorGroup.TT), - @SerializedName("EXPORT_CSV") EXPORT_CSV (ColorGroup.Aaps), - @SerializedName("UNKNOWN") UNKNOWN (ColorGroup.Aaps) + BOLUS (ColorGroup.InsulinTreatment), + SMB (ColorGroup.InsulinTreatment), + BOLUS_ADVISOR (ColorGroup.InsulinTreatment), + EXTENDED_BOLUS (ColorGroup.InsulinTreatment), + SUPERBOLUS_TBR (ColorGroup.InsulinTreatment), + CARBS (ColorGroup.CarbTreatment), + EXTENDED_CARBS (ColorGroup.CarbTreatment), + TEMP_BASAL (ColorGroup.BasalTreatment), + TT (ColorGroup.TT), + NEW_PROFILE (ColorGroup.Profile), + CLONE_PROFILE (ColorGroup.Profile), + STORE_PROFILE (ColorGroup.Profile), + PROFILE_SWITCH (ColorGroup.Profile), + PROFILE_SWITCH_CLONED (ColorGroup.Profile), + CLOSED_LOOP_MODE (ColorGroup.Loop), + LGS_LOOP_MODE (ColorGroup.Loop), + OPEN_LOOP_MODE (ColorGroup.Loop), + LOOP_DISABLED (ColorGroup.Loop), + LOOP_ENABLED (ColorGroup.Loop), + RECONNECT (ColorGroup.Pump), + DISCONNECT (ColorGroup.Pump), + RESUME (ColorGroup.Loop), + SUSPEND (ColorGroup.Loop), + HW_PUMP_ALLOWED (ColorGroup.Pump), + CLEAR_PAIRING_KEYS (ColorGroup.Pump), + ACCEPTS_TEMP_BASAL (ColorGroup.BasalTreatment), + CANCEL_TEMP_BASAL (ColorGroup.BasalTreatment), + CANCEL_EXTENDED_BOLUS (ColorGroup.InsulinTreatment), + CANCEL_TT (ColorGroup.TT), + CAREPORTAL (ColorGroup.Careportal), + SITE_CHANGE (ColorGroup.Pump), + RESERVOIR_CHANGE (ColorGroup.Pump), + CALIBRATION (ColorGroup.Careportal), + PRIME_BOLUS (ColorGroup.Pump), + TREATMENT (ColorGroup.InsulinTreatment), + CAREPORTAL_NS_REFRESH (ColorGroup.Aaps), + PROFILE_SWITCH_NS_REFRESH (ColorGroup.Aaps), + TREATMENTS_NS_REFRESH (ColorGroup.Aaps), + TT_NS_REFRESH (ColorGroup.Aaps), + AUTOMATION_REMOVED (ColorGroup.Aaps), + BG_REMOVED (ColorGroup.Aaps), + CAREPORTAL_REMOVED (ColorGroup.Aaps), + EXTENDED_BOLUS_REMOVED (ColorGroup.Aaps), + FOOD_REMOVED (ColorGroup.CarbTreatment), + PROFILE_REMOVED (ColorGroup.Profile), + PROFILE_SWITCH_REMOVED (ColorGroup.Aaps), + RESTART_EVENTS_REMOVED (ColorGroup.Aaps), + TREATMENT_REMOVED (ColorGroup.Aaps), + BOLUS_REMOVED (ColorGroup.Aaps), + CARBS_REMOVED (ColorGroup.Aaps), + TEMP_BASAL_REMOVED (ColorGroup.Aaps), + TT_REMOVED (ColorGroup.Aaps), + NS_PAUSED (ColorGroup.Aaps), + NS_RESUME (ColorGroup.Aaps), + NS_QUEUE_CLEARED (ColorGroup.Aaps), + NS_SETTINGS_COPIED (ColorGroup.Aaps), + ERROR_DIALOG_OK (ColorGroup.Aaps), + ERROR_DIALOG_MUTE (ColorGroup.Aaps), + ERROR_DIALOG_MUTE_5MIN (ColorGroup.Aaps), + OBJECTIVE_STARTED (ColorGroup.Aaps), + OBJECTIVE_UNSTARTED (ColorGroup.Aaps), + OBJECTIVES_SKIPPED (ColorGroup.Aaps), + STAT_RESET (ColorGroup.Aaps), + DELETE_LOGS (ColorGroup.Aaps), + DELETE_FUTURE_TREATMENTS (ColorGroup.Aaps), + EXPORT_SETTINGS (ColorGroup.Aaps), + IMPORT_SETTINGS (ColorGroup.Aaps), + RESET_DATABASES (ColorGroup.Aaps), + EXPORT_DATABASES (ColorGroup.Aaps), + IMPORT_DATABASES (ColorGroup.Aaps), + OTP_EXPORT (ColorGroup.Aaps), + OTP_RESET (ColorGroup.Aaps), + STOP_SMS (ColorGroup.Aaps), + FOOD (ColorGroup.CarbTreatment), + EXPORT_CSV (ColorGroup.Aaps), + START_AAPS (ColorGroup.Aaps), + EXIT_AAPS (ColorGroup.Aaps), + PLUGIN_ENABLED (ColorGroup.Aaps), + PLUGIN_DISABLED (ColorGroup.Aaps), + UNKNOWN (ColorGroup.Aaps) ; companion object { fun fromString(source: String?) = values().firstOrNull { it.name == source } ?: UNKNOWN } } - data class ValueWithUnit (val dValue: Double=0.0, val iValue: Int=0, val lValue: Long=0, val sValue: String="", val unit: Units=Units.None, val condition:Boolean=true){ - constructor(dvalue: Double, unit: Units, condition:Boolean = true) : this(dvalue, 0, 0, "", unit, condition) - constructor(ivalue: Int, unit: Units, condition:Boolean = true) : this(0.0, ivalue, 0, "", unit, condition) - constructor(lvalue: Long, unit: Units, condition:Boolean = true) : this(0.0,0, lvalue, "", unit, condition) - constructor(svalue: String, unit:Units) : this(0.0,0, 0, svalue, unit, svalue != "") - constructor(dvalue: Double, unit:String) : this(dvalue,0, 0, "", Units.fromText(unit)) - constructor(rStringRef: Int, nbParam: Long) : this(0.0, rStringRef, nbParam, "", Units.R_String, !rStringRef.equals(0)) // additionnal constructors for formated strings with additional values as parameters (define number of parameters as long - fun value() : Any { - if (sValue != "") return sValue - if (!dValue.equals(0.0)) return dValue - if (!iValue.equals(0)) return iValue - return lValue - } - } - enum class Units(val text: String) { - @SerializedName("None") None (""), //Int or String - @SerializedName("Mg_Dl") Mg_Dl ("mg/dl"), //Double - @SerializedName("Mmol_L") Mmol_L ("mmol"), //Double - @SerializedName("Timestamp") Timestamp("Timestamp"), //long - @SerializedName("U") U ("U"), //Double - @SerializedName("U_H") U_H ("U/h"), //Double - @SerializedName("G") G ("g"), //Int - @SerializedName("M") M ("m"), //Int - @SerializedName("H") H ("h"), //Int - @SerializedName("Percent") Percent ("%"), //Int - @SerializedName("TherapyEvent") TherapyEvent ("TherapyEvent"), //String (All enum key translated by Translator function, mainly TherapyEvent) - @SerializedName("R_String") R_String ("R.string") //Int + enum class Sources { + TreatmentDialog, + InsulinDialog, + CarbDialog, + WizardDialog, + QuickWizard, + ExtendedBolusDialog, + TTDialog, + ProfileSwitchDialog, + LoopDialog, + TempBasalDialog, + CalibrationDialog, + FillDialog, + BgCheck, + SensorInsert, + BatteryChange, + Note, + Exercise, + Question, + Announcement, + Actions, //From Actions plugin + Automation, //From Automation plugin + BG, //From BG plugin => Add One Source per BG Source for Calibration or Sensor Change + Dexcom, + Eversense, + Glimp, + MM640g, + NSClientSource, + PocTech, + Tomato, + Xdrip, + LocalProfile, //From LocalProfile plugin + Loop, //From Loop plugin + Maintenance, //From Maintenance plugin + NSClient, //From NSClient plugin + NSProfile, //From NSProfile plugin + Objectives, //From Objectives plugin + Pump, //To update with one Source per pump + Dana, //Only one UserEntry in Common module Dana + DanaR, //No entry currently + DanaRC, //No entry currently + DanaRv2, //No entry currently + DanaRS, //No entry currently + Insight, //No entry currently + Combo, //No entry currently + Medtronic, //No entry currently + Omnipod, //No entry currently + OmnipodEros, //No entry currently + OmnipodDash, //No entry currently + MDI, //No entry currently + VirtualPump, //No entry currently + SMS, //From SMS plugin + Treatments, //From Treatments plugin + Wear, //From Wear plugin + Food, //From Food plugin + ConfigBuilder, //From ConfigBuilder Plugin + Overview, //From OverViewPlugin + Stats, //From Stat Activity + Aaps, // MainApp + Unknown //if necessary ; companion object { - fun fromString(unit: String?) = values().firstOrNull { it.name == unit } ?: None - fun fromText(unit: String?) = values().firstOrNull { it.text == unit } ?: None + fun fromString(source: String?) = values().firstOrNull { it.name == source } ?: Unknown } } - enum class ColorGroup() { + enum class ColorGroup { InsulinTreatment, + BasalTreatment, CarbTreatment, TT, Profile, diff --git a/database/src/main/java/info/nightscout/androidaps/database/entities/ValueWithUnit.kt b/database/src/main/java/info/nightscout/androidaps/database/entities/ValueWithUnit.kt new file mode 100644 index 0000000000..7cd94956f0 --- /dev/null +++ b/database/src/main/java/info/nightscout/androidaps/database/entities/ValueWithUnit.kt @@ -0,0 +1,67 @@ +package info.nightscout.androidaps.database.entities + +import androidx.annotation.StringRes + +sealed class ValueWithUnit { + + object UNKNOWN : ValueWithUnit() // formerly None used as fallback + + data class SimpleString(val value: String) : ValueWithUnit() // formerly one usage of None + + data class SimpleInt(val value: Int) : ValueWithUnit() // formerly one usage of None + + data class Mgdl(val value: Double) : ValueWithUnit() + + data class Mmoll(val value: Double) : ValueWithUnit() + + data class Timestamp(val value: Long) : ValueWithUnit() + + data class Insulin(val value: Double) : ValueWithUnit() + + data class UnitPerHour(val value: Double) : ValueWithUnit() + + data class Gram(val value: Int) : ValueWithUnit() + + data class Minute(val value: Int) : ValueWithUnit() + + data class Hour(val value: Int) : ValueWithUnit() + + data class Percent(val value: Int) : ValueWithUnit() + + data class TherapyEventType(val value: TherapyEvent.Type) : ValueWithUnit() + + data class TherapyEventMeterType(val value: TherapyEvent.MeterType) : ValueWithUnit() + + data class TherapyEventTTReason(val value: TemporaryTarget.Reason) : ValueWithUnit() + + fun value(): Any? { + return when(this) { + is Gram -> this.value + is Hour -> this.value + is Insulin -> this.value + is Mgdl -> this.value + is Minute -> this.value + is Mmoll -> this.value + is Percent -> this.value + is SimpleInt -> this.value + is SimpleString -> this.value + is TherapyEventMeterType -> this.value + is TherapyEventTTReason -> this.value + is TherapyEventType -> this.value + is Timestamp -> this.value + is UnitPerHour -> this.value + UNKNOWN -> null + } + } + companion object { + + const val MGDL = "mg/dl" // This is Nightscout's representation + const val MMOL = "mmol" + + fun fromGlucoseUnit(value: Double, string: String): ValueWithUnit? = when (string) { + MGDL, "mgdl" -> Mgdl(value) + MMOL, "mmol/l" -> Mmoll(value) + else -> null + } + } +} diff --git a/database/src/main/java/info/nightscout/androidaps/database/serialisation/SealedClassHelper.kt b/database/src/main/java/info/nightscout/androidaps/database/serialisation/SealedClassHelper.kt new file mode 100644 index 0000000000..704819908e --- /dev/null +++ b/database/src/main/java/info/nightscout/androidaps/database/serialisation/SealedClassHelper.kt @@ -0,0 +1,52 @@ +package info.nightscout.androidaps.database.serialisation + +import com.google.gson.Gson +import com.google.gson.GsonBuilder +import com.google.gson.TypeAdapter +import com.google.gson.TypeAdapterFactory +import com.google.gson.reflect.TypeToken +import com.google.gson.stream.JsonReader +import com.google.gson.stream.JsonWriter +import kotlin.jvm.internal.Reflection +import kotlin.reflect.KClass + +object SealedClassHelper { + + val gson: Gson = GsonBuilder().registerTypeAdapterFactory( + object : TypeAdapterFactory { + override fun create(gson: Gson, type: TypeToken): TypeAdapter { + val kClass = Reflection.getOrCreateKotlinClass(type.rawType) + return if (kClass.sealedSubclasses.any()) { + SealedClassTypeAdapter(kClass, gson) + } else + gson.getDelegateAdapter(this, type) + } + }).create() + + private class SealedClassTypeAdapter(private val kClass: KClass, val gson: Gson) : TypeAdapter() { + + override fun read(jsonReader: JsonReader): T? { + jsonReader.beginObject() + val nextName = jsonReader.nextName() + val innerClass = kClass.sealedSubclasses.firstOrNull { it.simpleName == nextName } + ?: throw Exception("$nextName is not a child of the sealed class ${kClass.qualifiedName}") + val x = gson.fromJson(jsonReader, innerClass.javaObjectType) + jsonReader.endObject() + // if there a static object, actually return that + @Suppress("UNCHECKED_CAST") + return innerClass.objectInstance as T? ?: x + } + + override fun write(out: JsonWriter, value: T) { + val jsonString = gson.toJson(value) + val name = value.javaClass.canonicalName + if (name != null) { + out.beginObject() + out.name(name.splitToSequence(".").last()).jsonValue(jsonString) + out.endObject() + } + } + } +} + +inline fun Gson.fromJson(json: String): T = fromJson(json, object : TypeToken() {}.type) diff --git a/database/src/main/java/info/nightscout/androidaps/database/transactions/InsertIfNewByTimestampCarbsTransaction.kt b/database/src/main/java/info/nightscout/androidaps/database/transactions/InsertIfNewByTimestampCarbsTransaction.kt new file mode 100644 index 0000000000..9fed606fde --- /dev/null +++ b/database/src/main/java/info/nightscout/androidaps/database/transactions/InsertIfNewByTimestampCarbsTransaction.kt @@ -0,0 +1,41 @@ +package info.nightscout.androidaps.database.transactions + +import info.nightscout.androidaps.database.embedments.InterfaceIDs +import info.nightscout.androidaps.database.entities.Carbs + +/** + * Creates Carbs if record doesn't exist + */ +class InsertIfNewByTimestampCarbsTransaction( + private val carbs: Carbs +) : Transaction() { + + constructor( + timestamp: Long, + amount: Double, + duration: Long, + interfaceIDs_backing: InterfaceIDs? = null + ) : this(Carbs( + timestamp = timestamp, + amount = amount, + duration = duration, + interfaceIDs_backing = interfaceIDs_backing + )) + + override fun run(): TransactionResult { + val result = TransactionResult() + val current = database.carbsDao.findByTimestamp(carbs.timestamp) + if (current == null) { + database.carbsDao.insertNewEntry(carbs) + result.inserted.add(carbs) + } else + result.existing.add(carbs) + return result + } + + class TransactionResult { + + val inserted = mutableListOf() + val existing = mutableListOf() + } +} \ No newline at end of file diff --git a/database/src/main/java/info/nightscout/androidaps/database/transactions/InsertTherapyEventIfNewTransaction.kt b/database/src/main/java/info/nightscout/androidaps/database/transactions/InsertIfNewByTimestampTherapyEventTransaction.kt similarity index 89% rename from database/src/main/java/info/nightscout/androidaps/database/transactions/InsertTherapyEventIfNewTransaction.kt rename to database/src/main/java/info/nightscout/androidaps/database/transactions/InsertIfNewByTimestampTherapyEventTransaction.kt index b8946777ed..d283f0c6ca 100644 --- a/database/src/main/java/info/nightscout/androidaps/database/transactions/InsertTherapyEventIfNewTransaction.kt +++ b/database/src/main/java/info/nightscout/androidaps/database/transactions/InsertIfNewByTimestampTherapyEventTransaction.kt @@ -2,9 +2,9 @@ package info.nightscout.androidaps.database.transactions import info.nightscout.androidaps.database.entities.TherapyEvent -class InsertTherapyEventIfNewTransaction( +class InsertIfNewByTimestampTherapyEventTransaction( val therapyEvent: TherapyEvent -) : Transaction() { +) : Transaction() { constructor(timestamp: Long, type: TherapyEvent.Type, duration: Long = 0, note: String? = null, enteredBy: String? = null, glucose: Double? = null, glucoseType: TherapyEvent.MeterType? = null, glucoseUnit: TherapyEvent.GlucoseUnit) : this(TherapyEvent(timestamp = timestamp, type = type, duration = duration, note = note, enteredBy = enteredBy, glucose = glucose, glucoseType = glucoseType, glucoseUnit = glucoseUnit)) diff --git a/database/src/main/java/info/nightscout/androidaps/database/transactions/InsertOrUpdateBolusCalculatorResultTransaction.kt b/database/src/main/java/info/nightscout/androidaps/database/transactions/InsertOrUpdateBolusCalculatorResultTransaction.kt new file mode 100644 index 0000000000..dfef194370 --- /dev/null +++ b/database/src/main/java/info/nightscout/androidaps/database/transactions/InsertOrUpdateBolusCalculatorResultTransaction.kt @@ -0,0 +1,31 @@ +package info.nightscout.androidaps.database.transactions + +import info.nightscout.androidaps.database.embedments.InterfaceIDs +import info.nightscout.androidaps.database.entities.BolusCalculatorResult + +/** + * Creates or updates the BolusCalculatorResult + */ +class InsertOrUpdateBolusCalculatorResultTransaction( + private val bolusCalculatorResult: BolusCalculatorResult +) : Transaction() { + + override fun run(): TransactionResult { + val result = TransactionResult() + val current = database.bolusCalculatorResultDao.findById(bolusCalculatorResult.id) + if (current == null) { + database.bolusCalculatorResultDao.insertNewEntry(bolusCalculatorResult) + result.inserted.add(bolusCalculatorResult) + } else { + database.bolusCalculatorResultDao.updateExistingEntry(bolusCalculatorResult) + result.updated.add(bolusCalculatorResult) + } + return result + } + + class TransactionResult { + + val inserted = mutableListOf() + val updated = mutableListOf() + } +} \ No newline at end of file diff --git a/database/src/main/java/info/nightscout/androidaps/database/transactions/InsertOrUpdateBolusTransaction.kt b/database/src/main/java/info/nightscout/androidaps/database/transactions/InsertOrUpdateBolusTransaction.kt new file mode 100644 index 0000000000..d7df6bedb3 --- /dev/null +++ b/database/src/main/java/info/nightscout/androidaps/database/transactions/InsertOrUpdateBolusTransaction.kt @@ -0,0 +1,48 @@ +package info.nightscout.androidaps.database.transactions + +import info.nightscout.androidaps.database.embedments.InsulinConfiguration +import info.nightscout.androidaps.database.embedments.InterfaceIDs +import info.nightscout.androidaps.database.entities.Bolus + +/** + * Creates or updates the Bolus + */ +class InsertOrUpdateBolusTransaction( + private val bolus: Bolus +) : Transaction() { + + constructor( + timestamp: Long, + amount: Double, + type: Bolus.Type, + isBasalInsulin: Boolean = false, + insulinConfiguration: InsulinConfiguration? = null, + interfaceIDs_backing: InterfaceIDs? = null + ) : this(Bolus( + timestamp = timestamp, + amount = amount, + type = type, + isBasalInsulin = isBasalInsulin, + insulinConfiguration = insulinConfiguration, + interfaceIDs_backing = interfaceIDs_backing + )) + + override fun run(): TransactionResult { + val result = TransactionResult() + val current = database.bolusDao.findById(bolus.id) + if (current == null) { + database.bolusDao.insertNewEntry(bolus) + result.inserted.add(bolus) + } else { + database.bolusDao.updateExistingEntry(bolus) + result.updated.add(bolus) + } + return result + } + + class TransactionResult { + + val inserted = mutableListOf() + val updated = mutableListOf() + } +} \ No newline at end of file diff --git a/database/src/main/java/info/nightscout/androidaps/database/transactions/InsertOrUpdateCarbsTransaction.kt b/database/src/main/java/info/nightscout/androidaps/database/transactions/InsertOrUpdateCarbsTransaction.kt new file mode 100644 index 0000000000..2cf4406206 --- /dev/null +++ b/database/src/main/java/info/nightscout/androidaps/database/transactions/InsertOrUpdateCarbsTransaction.kt @@ -0,0 +1,43 @@ +package info.nightscout.androidaps.database.transactions + +import info.nightscout.androidaps.database.embedments.InterfaceIDs +import info.nightscout.androidaps.database.entities.Carbs + +/** + * Creates or updates the Carbs + */ +class InsertOrUpdateCarbsTransaction( + private val carbs: Carbs +) : Transaction() { + + constructor( + timestamp: Long, + amount: Double, + duration: Long, + interfaceIDs_backing: InterfaceIDs? = null + ) : this(Carbs( + timestamp = timestamp, + amount = amount, + duration = duration, + interfaceIDs_backing = interfaceIDs_backing + )) + + override fun run(): TransactionResult { + val result = TransactionResult() + val current = database.carbsDao.findById(carbs.id) + if (current == null) { + database.carbsDao.insertNewEntry(carbs) + result.inserted.add(carbs) + } else { + database.carbsDao.updateExistingEntry(carbs) + result.updated.add(carbs) + } + return result + } + + class TransactionResult { + + val inserted = mutableListOf() + val updated = mutableListOf() + } +} \ No newline at end of file diff --git a/database/src/main/java/info/nightscout/androidaps/database/transactions/InsertPumpBolusWithTempIdTransaction.kt b/database/src/main/java/info/nightscout/androidaps/database/transactions/InsertPumpBolusWithTempIdTransaction.kt new file mode 100644 index 0000000000..97f8286eff --- /dev/null +++ b/database/src/main/java/info/nightscout/androidaps/database/transactions/InsertPumpBolusWithTempIdTransaction.kt @@ -0,0 +1,28 @@ +package info.nightscout.androidaps.database.transactions + +import info.nightscout.androidaps.database.entities.Bolus + +/** + * Creates or updates the Bolus from pump synchronization + */ +class InsertPumpBolusWithTempIdTransaction( + private val bolus: Bolus +) : Transaction() { + + override fun run(): TransactionResult { + bolus.interfaceIDs.temporaryId ?: bolus.interfaceIDs.pumpType ?: bolus.interfaceIDs.pumpSerial ?: + throw IllegalStateException("Some pump ID is null") + val result = TransactionResult() + val current = database.bolusDao.findByPumpTempIds(bolus.interfaceIDs.temporaryId!!, bolus.interfaceIDs.pumpType!!, bolus.interfaceIDs.pumpSerial!!) + if (current == null) { + database.bolusDao.insert(bolus) + result.inserted.add(bolus) + } + return result + } + + class TransactionResult { + + val inserted = mutableListOf() + } +} \ No newline at end of file diff --git a/database/src/main/java/info/nightscout/androidaps/database/transactions/InsertTherapyEventAnnouncementTransaction.kt b/database/src/main/java/info/nightscout/androidaps/database/transactions/InsertTherapyEventAnnouncementTransaction.kt new file mode 100644 index 0000000000..990b8b1c40 --- /dev/null +++ b/database/src/main/java/info/nightscout/androidaps/database/transactions/InsertTherapyEventAnnouncementTransaction.kt @@ -0,0 +1,38 @@ +package info.nightscout.androidaps.database.transactions + +import info.nightscout.androidaps.database.embedments.InterfaceIDs +import info.nightscout.androidaps.database.entities.TherapyEvent + +class InsertTherapyEventAnnouncementTransaction( + val therapyEvent: TherapyEvent +) : Transaction() { + + constructor(error: String, pumpId: Long? = null, pumpType: InterfaceIDs.PumpType? = null, pumpSerial: String? = null) : + this( + TherapyEvent( + timestamp = System.currentTimeMillis(), + type = TherapyEvent.Type.ANNOUNCEMENT, + duration = 0, note = error, + enteredBy = "AndroidAPS", + glucose = null, + glucoseType = null, + glucoseUnit = TherapyEvent.GlucoseUnit.MGDL, + interfaceIDs_backing = InterfaceIDs( + pumpId = pumpId, + pumpType = pumpType, + pumpSerial = pumpSerial) + ) + ) + + override fun run(): TransactionResult { + val result = TransactionResult() + database.therapyEventDao.insertNewEntry(therapyEvent) + result.inserted.add(therapyEvent) + return result + } + + class TransactionResult { + + val inserted = mutableListOf() + } +} \ No newline at end of file diff --git a/database/src/main/java/info/nightscout/androidaps/database/transactions/InvalidateAAPSStartedTherapyEventTransaction.kt b/database/src/main/java/info/nightscout/androidaps/database/transactions/InvalidateAAPSStartedTherapyEventTransaction.kt index fb1d347a15..248b51d412 100644 --- a/database/src/main/java/info/nightscout/androidaps/database/transactions/InvalidateAAPSStartedTherapyEventTransaction.kt +++ b/database/src/main/java/info/nightscout/androidaps/database/transactions/InvalidateAAPSStartedTherapyEventTransaction.kt @@ -2,15 +2,17 @@ package info.nightscout.androidaps.database.transactions import info.nightscout.androidaps.database.entities.TherapyEvent -class InvalidateAAPSStartedTherapyEventTransaction : Transaction() { +class InvalidateAAPSStartedTherapyEventTransaction(private val note: String) : Transaction() { override fun run(): TransactionResult { val result = TransactionResult() val therapyEvents = database.therapyEventDao.getValidByType(TherapyEvent.Type.NOTE) for (event in therapyEvents) { - event.isValid = false - database.therapyEventDao.updateExistingEntry(event) - result.invalidated.add(event) + if (event.note?.contains(note) == true) { + event.isValid = false + database.therapyEventDao.updateExistingEntry(event) + result.invalidated.add(event) + } } return result } diff --git a/database/src/main/java/info/nightscout/androidaps/database/transactions/InvalidateBolusCalculatorResultTransaction.kt b/database/src/main/java/info/nightscout/androidaps/database/transactions/InvalidateBolusCalculatorResultTransaction.kt new file mode 100644 index 0000000000..968efee665 --- /dev/null +++ b/database/src/main/java/info/nightscout/androidaps/database/transactions/InvalidateBolusCalculatorResultTransaction.kt @@ -0,0 +1,22 @@ +package info.nightscout.androidaps.database.transactions + +import info.nightscout.androidaps.database.entities.BolusCalculatorResult + +class InvalidateBolusCalculatorResultTransaction(val id: Long) : Transaction() { + + override fun run(): TransactionResult { + val result = TransactionResult() + val bolusCalculatorResult = database.bolusCalculatorResultDao.findById(id) + ?: throw IllegalArgumentException("There is no such BolusCalculatorResult with the specified ID.") + + bolusCalculatorResult.isValid = false + database.bolusCalculatorResultDao.updateExistingEntry(bolusCalculatorResult) + result.invalidated.add(bolusCalculatorResult) + return result + } + + class TransactionResult { + + val invalidated = mutableListOf() + } +} \ No newline at end of file diff --git a/database/src/main/java/info/nightscout/androidaps/database/transactions/InvalidateBolusTransaction.kt b/database/src/main/java/info/nightscout/androidaps/database/transactions/InvalidateBolusTransaction.kt new file mode 100644 index 0000000000..ac2dcad063 --- /dev/null +++ b/database/src/main/java/info/nightscout/androidaps/database/transactions/InvalidateBolusTransaction.kt @@ -0,0 +1,20 @@ +package info.nightscout.androidaps.database.transactions + +import info.nightscout.androidaps.database.entities.Bolus + +class InvalidateBolusTransaction(val id: Long) : Transaction() { + + override fun run() : TransactionResult { + val result = TransactionResult() + val bolus = database.bolusDao.findById(id) + ?: throw IllegalArgumentException("There is no such Bolus with the specified ID.") + bolus.isValid = false + database.bolusDao.updateExistingEntry(bolus) + result.invalidated.add(bolus) + return result + } + + class TransactionResult { + val invalidated = mutableListOf() + } +} \ No newline at end of file diff --git a/database/src/main/java/info/nightscout/androidaps/database/transactions/InvalidateCarbsTransaction.kt b/database/src/main/java/info/nightscout/androidaps/database/transactions/InvalidateCarbsTransaction.kt new file mode 100644 index 0000000000..9e9b373a33 --- /dev/null +++ b/database/src/main/java/info/nightscout/androidaps/database/transactions/InvalidateCarbsTransaction.kt @@ -0,0 +1,21 @@ +package info.nightscout.androidaps.database.transactions + +import info.nightscout.androidaps.database.entities.Carbs + +class InvalidateCarbsTransaction(val id: Long) : Transaction() { + + override fun run(): TransactionResult { + val result = TransactionResult() + val carbs = database.carbsDao.findById(id) + ?: throw IllegalArgumentException("There is no such Carbs with the specified ID.") + carbs.isValid = false + database.carbsDao.updateExistingEntry(carbs) + result.invalidated.add(carbs) + return result + } + + class TransactionResult { + + val invalidated = mutableListOf() + } +} \ No newline at end of file diff --git a/database/src/main/java/info/nightscout/androidaps/database/transactions/InvalidateExtendedBolusTransaction.kt b/database/src/main/java/info/nightscout/androidaps/database/transactions/InvalidateExtendedBolusTransaction.kt new file mode 100644 index 0000000000..7f28f09acf --- /dev/null +++ b/database/src/main/java/info/nightscout/androidaps/database/transactions/InvalidateExtendedBolusTransaction.kt @@ -0,0 +1,21 @@ +package info.nightscout.androidaps.database.transactions + +import info.nightscout.androidaps.database.entities.ExtendedBolus + +class InvalidateExtendedBolusTransaction(val id: Long) : Transaction() { + + override fun run(): TransactionResult { + val result = TransactionResult() + val extendedBolus = database.extendedBolusDao.findById(id) + ?: throw IllegalArgumentException("There is no such Extended Bolus with the specified ID.") + extendedBolus.isValid = false + database.extendedBolusDao.updateExistingEntry(extendedBolus) + result.invalidated.add(extendedBolus) + return result + } + + class TransactionResult { + + val invalidated = mutableListOf() + } +} \ No newline at end of file diff --git a/database/src/main/java/info/nightscout/androidaps/database/transactions/InvalidateTemporaryBasalTransaction.kt b/database/src/main/java/info/nightscout/androidaps/database/transactions/InvalidateTemporaryBasalTransaction.kt new file mode 100644 index 0000000000..5fcc6d90be --- /dev/null +++ b/database/src/main/java/info/nightscout/androidaps/database/transactions/InvalidateTemporaryBasalTransaction.kt @@ -0,0 +1,21 @@ +package info.nightscout.androidaps.database.transactions + +import info.nightscout.androidaps.database.entities.TemporaryBasal + +class InvalidateTemporaryBasalTransaction(val id: Long) : Transaction() { + + override fun run(): TransactionResult { + val result = TransactionResult() + val temporaryBasal = database.temporaryBasalDao.findById(id) + ?: throw IllegalArgumentException("There is no such Temporary Basal with the specified ID.") + temporaryBasal.isValid = false + database.temporaryBasalDao.updateExistingEntry(temporaryBasal) + result.invalidated.add(temporaryBasal) + return result + } + + class TransactionResult { + + val invalidated = mutableListOf() + } +} \ No newline at end of file diff --git a/database/src/main/java/info/nightscout/androidaps/database/transactions/InvalidateTherapyEventTransaction.kt b/database/src/main/java/info/nightscout/androidaps/database/transactions/InvalidateTherapyEventTransaction.kt index 6a66fa97a8..3368d05996 100644 --- a/database/src/main/java/info/nightscout/androidaps/database/transactions/InvalidateTherapyEventTransaction.kt +++ b/database/src/main/java/info/nightscout/androidaps/database/transactions/InvalidateTherapyEventTransaction.kt @@ -1,10 +1,21 @@ package info.nightscout.androidaps.database.transactions -class InvalidateTherapyEventTransaction(val id: Long) : Transaction() { - override fun run() { +import info.nightscout.androidaps.database.entities.TherapyEvent + +class InvalidateTherapyEventTransaction(val id: Long) : Transaction() { + + override fun run(): TransactionResult { + val result = TransactionResult() val therapyEvent = database.therapyEventDao.findById(id) ?: throw IllegalArgumentException("There is no such TherapyEvent with the specified ID.") therapyEvent.isValid = false database.therapyEventDao.updateExistingEntry(therapyEvent) + result.invalidated.add(therapyEvent) + return result + } + + class TransactionResult { + + val invalidated = mutableListOf() } } \ No newline at end of file diff --git a/database/src/main/java/info/nightscout/androidaps/database/transactions/SyncNsBolusTransaction.kt b/database/src/main/java/info/nightscout/androidaps/database/transactions/SyncNsBolusTransaction.kt new file mode 100644 index 0000000000..6fbaa57ca2 --- /dev/null +++ b/database/src/main/java/info/nightscout/androidaps/database/transactions/SyncNsBolusTransaction.kt @@ -0,0 +1,52 @@ +package info.nightscout.androidaps.database.transactions + +import info.nightscout.androidaps.database.entities.Bolus + +/** + * Sync the Bolus from NS + */ +class SyncNsBolusTransaction(private val bolus: Bolus, private val invalidateByNsOnly: Boolean) : Transaction() { + + override fun run(): TransactionResult { + val result = TransactionResult() + + val current: Bolus? = + bolus.interfaceIDs.nightscoutId?.let { + database.bolusDao.findByNSId(it) + } + + if (current != null) { + // nsId exists, allow only invalidation + if (current.isValid && !bolus.isValid) { + current.isValid = false + database.bolusDao.updateExistingEntry(current) + result.invalidated.add(current) + } + return result + } + + if (invalidateByNsOnly) return result + + // not known nsId + val existing = database.bolusDao.findByTimestamp(bolus.timestamp) + if (existing != null && existing.interfaceIDs.nightscoutId == null) { + // the same record, update nsId only + existing.interfaceIDs.nightscoutId = bolus.interfaceIDs.nightscoutId + existing.isValid = bolus.isValid + database.bolusDao.updateExistingEntry(existing) + result.updatedNsId.add(existing) + } else { + database.bolusDao.insertNewEntry(bolus) + result.inserted.add(bolus) + } + return result + + } + + class TransactionResult { + + val updatedNsId = mutableListOf() + val inserted = mutableListOf() + val invalidated = mutableListOf() + } +} \ No newline at end of file diff --git a/database/src/main/java/info/nightscout/androidaps/database/transactions/SyncNsCarbsTransaction.kt b/database/src/main/java/info/nightscout/androidaps/database/transactions/SyncNsCarbsTransaction.kt new file mode 100644 index 0000000000..40443b06e9 --- /dev/null +++ b/database/src/main/java/info/nightscout/androidaps/database/transactions/SyncNsCarbsTransaction.kt @@ -0,0 +1,52 @@ +package info.nightscout.androidaps.database.transactions + +import info.nightscout.androidaps.database.entities.Carbs + +/** + * Sync the carbs from NS + */ +class SyncNsCarbsTransaction(private val carbs: Carbs, private val invalidateByNsOnly: Boolean) : Transaction() { + + override fun run(): TransactionResult { + val result = TransactionResult() + + val current: Carbs? = + carbs.interfaceIDs.nightscoutId?.let { + database.carbsDao.findByNSId(it) + } + + if (current != null) { + // nsId exists, allow only invalidation + if (current.isValid && !carbs.isValid) { + current.isValid = false + database.carbsDao.updateExistingEntry(current) + result.invalidated.add(current) + } + return result + } + + if (invalidateByNsOnly) return result + + // not known nsId + val existing = database.carbsDao.findByTimestamp(carbs.timestamp) + if (existing != null && existing.interfaceIDs.nightscoutId == null) { + // the same record, update nsId only + existing.interfaceIDs.nightscoutId = carbs.interfaceIDs.nightscoutId + existing.isValid = carbs.isValid + database.carbsDao.updateExistingEntry(existing) + result.updatedNsId.add(existing) + } else { + database.carbsDao.insertNewEntry(carbs) + result.inserted.add(carbs) + } + return result + + } + + class TransactionResult { + + val updatedNsId = mutableListOf() + val inserted = mutableListOf() + val invalidated = mutableListOf() + } +} \ No newline at end of file diff --git a/database/src/main/java/info/nightscout/androidaps/database/transactions/SyncNsExtendedBolusTransaction.kt b/database/src/main/java/info/nightscout/androidaps/database/transactions/SyncNsExtendedBolusTransaction.kt new file mode 100644 index 0000000000..4984503890 --- /dev/null +++ b/database/src/main/java/info/nightscout/androidaps/database/transactions/SyncNsExtendedBolusTransaction.kt @@ -0,0 +1,73 @@ +package info.nightscout.androidaps.database.transactions + +import info.nightscout.androidaps.database.entities.ExtendedBolus +import info.nightscout.androidaps.database.interfaces.end +import kotlin.math.abs + +/** + * Sync the Extended bolus from NS + */ +class SyncNsExtendedBolusTransaction(private val extendedBolus: ExtendedBolus, private val invalidateByNsOnly: Boolean) : Transaction() { + + override fun run(): TransactionResult { + val result = TransactionResult() + + if (extendedBolus.duration != 0L) { + // not ending event + val current: ExtendedBolus? = + extendedBolus.interfaceIDs.nightscoutId?.let { + database.extendedBolusDao.findByNSId(it) + } + + if (current != null) { + // nsId exists, allow only invalidation + if (current.isValid && !extendedBolus.isValid) { + current.isValid = false + database.extendedBolusDao.updateExistingEntry(current) + result.invalidated.add(current) + } + return result + } + + if (invalidateByNsOnly) return result + + // not known nsId + val running = database.extendedBolusDao.getExtendedBolusActiveAt(extendedBolus.timestamp).blockingGet() + if (running != null && abs(running.timestamp - extendedBolus.timestamp) < 1000 && running.interfaceIDs.nightscoutId == null) { // allow missing milliseconds + // the same record, update nsId only + running.interfaceIDs.nightscoutId = extendedBolus.interfaceIDs.nightscoutId + database.extendedBolusDao.updateExistingEntry(running) + result.updatedNsId.add(running) + } else if (running != null) { + // another running record. end current and insert new + running.end = extendedBolus.timestamp + database.extendedBolusDao.updateExistingEntry(running) + database.extendedBolusDao.insertNewEntry(extendedBolus) + result.ended.add(running) + result.inserted.add(extendedBolus) + } else { + database.extendedBolusDao.insertNewEntry(extendedBolus) + result.inserted.add(extendedBolus) + } + return result + + } else { + // ending event + val running = database.extendedBolusDao.getExtendedBolusActiveAt(extendedBolus.timestamp).blockingGet() + if (running != null) { + running.end = extendedBolus.timestamp + database.extendedBolusDao.updateExistingEntry(running) + result.ended.add(running) + } + } + return result + } + + class TransactionResult { + + val updatedNsId = mutableListOf() + val inserted = mutableListOf() + val invalidated = mutableListOf() + val ended = mutableListOf() + } +} \ No newline at end of file diff --git a/database/src/main/java/info/nightscout/androidaps/database/transactions/SyncFoodTransaction.kt b/database/src/main/java/info/nightscout/androidaps/database/transactions/SyncNsFoodTransaction.kt similarity index 85% rename from database/src/main/java/info/nightscout/androidaps/database/transactions/SyncFoodTransaction.kt rename to database/src/main/java/info/nightscout/androidaps/database/transactions/SyncNsFoodTransaction.kt index bd2ab7b3cf..f651b0e7ee 100644 --- a/database/src/main/java/info/nightscout/androidaps/database/transactions/SyncFoodTransaction.kt +++ b/database/src/main/java/info/nightscout/androidaps/database/transactions/SyncNsFoodTransaction.kt @@ -5,7 +5,7 @@ import info.nightscout.androidaps.database.entities.Food /** * Sync the TherapyEvents from NS */ -class SyncFoodTransaction(private val food: Food) : Transaction() { +class SyncNsFoodTransaction(private val food: Food, private val invalidateByNsOnly: Boolean) : Transaction() { override fun run(): TransactionResult { val result = TransactionResult() @@ -26,6 +26,8 @@ class SyncFoodTransaction(private val food: Food) : Transaction() { + + override fun run(): TransactionResult { + val result = TransactionResult() + + if (temporaryBasal.duration != 0L) { + // not ending event + val current: TemporaryBasal? = + temporaryBasal.interfaceIDs.nightscoutId?.let { + database.temporaryBasalDao.findByNSId(it) + } + + if (current != null) { + // nsId exists, allow only invalidation + if (current.isValid && !temporaryBasal.isValid) { + current.isValid = false + database.temporaryBasalDao.updateExistingEntry(current) + result.invalidated.add(current) + } + return result + } + + if (invalidateByNsOnly) return result + + // not known nsId + val running = database.temporaryBasalDao.getTemporaryBasalActiveAt(temporaryBasal.timestamp).blockingGet() + if (running != null && abs(running.timestamp - temporaryBasal.timestamp) < 1000 && running.interfaceIDs.nightscoutId == null) { // allow missing milliseconds + // the same record, update nsId only + running.interfaceIDs.nightscoutId = temporaryBasal.interfaceIDs.nightscoutId + database.temporaryBasalDao.updateExistingEntry(running) + result.updatedNsId.add(running) + } else if (running != null) { + // another running record. end current and insert new + running.end = temporaryBasal.timestamp + database.temporaryBasalDao.updateExistingEntry(running) + database.temporaryBasalDao.insertNewEntry(temporaryBasal) + result.ended.add(running) + result.inserted.add(temporaryBasal) + } else { + database.temporaryBasalDao.insertNewEntry(temporaryBasal) + result.inserted.add(temporaryBasal) + } + return result + } + return result + } + + class TransactionResult { + + val updatedNsId = mutableListOf() + val inserted = mutableListOf() + val invalidated = mutableListOf() + val ended = mutableListOf() + } +} \ No newline at end of file diff --git a/database/src/main/java/info/nightscout/androidaps/database/transactions/SyncTemporaryTargetTransaction.kt b/database/src/main/java/info/nightscout/androidaps/database/transactions/SyncNsTemporaryTargetTransaction.kt similarity index 92% rename from database/src/main/java/info/nightscout/androidaps/database/transactions/SyncTemporaryTargetTransaction.kt rename to database/src/main/java/info/nightscout/androidaps/database/transactions/SyncNsTemporaryTargetTransaction.kt index ecfa1632ec..b5f0d694e2 100644 --- a/database/src/main/java/info/nightscout/androidaps/database/transactions/SyncTemporaryTargetTransaction.kt +++ b/database/src/main/java/info/nightscout/androidaps/database/transactions/SyncNsTemporaryTargetTransaction.kt @@ -7,7 +7,7 @@ import kotlin.math.abs /** * Sync the TemporaryTarget from NS */ -class SyncTemporaryTargetTransaction(private val temporaryTarget: TemporaryTarget) : Transaction() { +class SyncNsTemporaryTargetTransaction(private val temporaryTarget: TemporaryTarget, private val invalidateByNsOnly: Boolean) : Transaction() { override fun run(): TransactionResult { val result = TransactionResult() @@ -29,6 +29,8 @@ class SyncTemporaryTargetTransaction(private val temporaryTarget: TemporaryTarge return result } + if (invalidateByNsOnly) return result + // not known nsId val running = database.temporaryTargetDao.getTemporaryTargetActiveAt(temporaryTarget.timestamp).blockingGet() if (running != null && abs(running.timestamp - temporaryTarget.timestamp) < 1000 && running.interfaceIDs.nightscoutId == null) { // allow missing milliseconds diff --git a/database/src/main/java/info/nightscout/androidaps/database/transactions/SyncTherapyEventTransaction.kt b/database/src/main/java/info/nightscout/androidaps/database/transactions/SyncNsTherapyEventTransaction.kt similarity index 87% rename from database/src/main/java/info/nightscout/androidaps/database/transactions/SyncTherapyEventTransaction.kt rename to database/src/main/java/info/nightscout/androidaps/database/transactions/SyncNsTherapyEventTransaction.kt index 007419d9d8..64773a3739 100644 --- a/database/src/main/java/info/nightscout/androidaps/database/transactions/SyncTherapyEventTransaction.kt +++ b/database/src/main/java/info/nightscout/androidaps/database/transactions/SyncNsTherapyEventTransaction.kt @@ -5,7 +5,7 @@ import info.nightscout.androidaps.database.entities.TherapyEvent /** * Sync the TherapyEvents from NS */ -class SyncTherapyEventTransaction(private val therapyEvent: TherapyEvent) : Transaction() { +class SyncNsTherapyEventTransaction(private val therapyEvent: TherapyEvent, private val invalidateByNsOnly: Boolean) : Transaction() { override fun run(): TransactionResult { val result = TransactionResult() @@ -25,6 +25,8 @@ class SyncTherapyEventTransaction(private val therapyEvent: TherapyEvent) : Tran return result } + if (invalidateByNsOnly) return result + // not known nsId val existing = database.therapyEventDao.findByTimestamp(therapyEvent.type, therapyEvent.timestamp) if (existing != null && existing.interfaceIDs.nightscoutId == null) { diff --git a/database/src/main/java/info/nightscout/androidaps/database/transactions/SyncPumpBolusTransaction.kt b/database/src/main/java/info/nightscout/androidaps/database/transactions/SyncPumpBolusTransaction.kt new file mode 100644 index 0000000000..c7ff85ba21 --- /dev/null +++ b/database/src/main/java/info/nightscout/androidaps/database/transactions/SyncPumpBolusTransaction.kt @@ -0,0 +1,42 @@ +package info.nightscout.androidaps.database.transactions + +import info.nightscout.androidaps.database.entities.Bolus + +/** + * Creates or updates the Bolus from pump synchronization + */ +class SyncPumpBolusTransaction( + private val bolus: Bolus, + private val bolusType: Bolus.Type? // extra parameter because field is not nullable in Bolus.class +) : Transaction() { + + override fun run(): TransactionResult { + bolus.interfaceIDs.pumpId ?: bolus.interfaceIDs.pumpType ?: bolus.interfaceIDs.pumpSerial ?: + throw IllegalStateException("Some pump ID is null") + val result = TransactionResult() + val current = database.bolusDao.findByPumpIds(bolus.interfaceIDs.pumpId!!, bolus.interfaceIDs.pumpType!!, bolus.interfaceIDs.pumpSerial!!) + if (current == null) { + database.bolusDao.insertNewEntry(bolus) + result.inserted.add(bolus) + } else { + if ( + current.timestamp != bolus.timestamp || + current.amount != bolus.amount || + current.type != bolusType ?: current.type + ) { + current.timestamp = bolus.timestamp + current.amount = bolus.amount + current.type = bolusType ?: current.type + database.bolusDao.updateExistingEntry(current) + result.updated.add(current) + } + } + return result + } + + class TransactionResult { + + val inserted = mutableListOf() + val updated = mutableListOf() + } +} \ No newline at end of file diff --git a/database/src/main/java/info/nightscout/androidaps/database/transactions/SyncPumpBolusWithTempIdTransaction.kt b/database/src/main/java/info/nightscout/androidaps/database/transactions/SyncPumpBolusWithTempIdTransaction.kt new file mode 100644 index 0000000000..8fe8eb4fc3 --- /dev/null +++ b/database/src/main/java/info/nightscout/androidaps/database/transactions/SyncPumpBolusWithTempIdTransaction.kt @@ -0,0 +1,33 @@ +package info.nightscout.androidaps.database.transactions + +import info.nightscout.androidaps.database.entities.Bolus + +/** + * Creates or updates the Bolus from pump synchronization + */ +class SyncPumpBolusWithTempIdTransaction( + private val bolus: Bolus, + private val newType: Bolus.Type? +) : Transaction() { + + override fun run(): TransactionResult { + bolus.interfaceIDs.temporaryId ?: bolus.interfaceIDs.pumpType ?: bolus.interfaceIDs.pumpSerial ?: + throw IllegalStateException("Some pump ID is null") + val result = TransactionResult() + val current = database.bolusDao.findByPumpTempIds(bolus.interfaceIDs.temporaryId!!, bolus.interfaceIDs.pumpType!!, bolus.interfaceIDs.pumpSerial!!) + if (current != null) { + current.timestamp = bolus.timestamp + current.amount = bolus.amount + current.type = newType ?: current.type + current.interfaceIDs.pumpId = bolus.interfaceIDs.pumpId + database.bolusDao.updateExistingEntry(current) + result.updated.add(current) + } + return result + } + + class TransactionResult { + + val updated = mutableListOf() + } +} \ No newline at end of file diff --git a/database/src/main/java/info/nightscout/androidaps/database/transactions/SyncPumpCancelExtendedBolusIfAnyTransaction.kt b/database/src/main/java/info/nightscout/androidaps/database/transactions/SyncPumpCancelExtendedBolusIfAnyTransaction.kt new file mode 100644 index 0000000000..c73b7bb201 --- /dev/null +++ b/database/src/main/java/info/nightscout/androidaps/database/transactions/SyncPumpCancelExtendedBolusIfAnyTransaction.kt @@ -0,0 +1,32 @@ +package info.nightscout.androidaps.database.transactions + +import info.nightscout.androidaps.database.embedments.InterfaceIDs +import info.nightscout.androidaps.database.entities.ExtendedBolus +import info.nightscout.androidaps.database.interfaces.end + +class SyncPumpCancelExtendedBolusIfAnyTransaction( + private val timestamp: Long, private val endPumpId: Long, private val pumpType: InterfaceIDs.PumpType, private val pumpSerial: String +) : Transaction() { + + override fun run(): TransactionResult { + val result = TransactionResult() + val existing = database.extendedBolusDao.findByPumpEndIds(endPumpId, pumpType, pumpSerial) + if (existing != null) // assume EB has been cut already + return result + val running = database.extendedBolusDao.getExtendedBolusActiveAt(timestamp, pumpType, pumpSerial).blockingGet() + if (running != null && running.interfaceIDs.endId == null) { // do not allow overwrite if cut by end event + val pctRun = (timestamp - running.timestamp) / running.duration.toDouble() + running.amount *= pctRun + running.end = timestamp + running.interfaceIDs.endId = endPumpId + database.extendedBolusDao.updateExistingEntry(running) + result.updated.add(running) + } + return result + } + + class TransactionResult { + + val updated = mutableListOf() + } +} \ No newline at end of file diff --git a/database/src/main/java/info/nightscout/androidaps/database/transactions/SyncPumpCancelTemporaryBasalIfAnyTransaction.kt b/database/src/main/java/info/nightscout/androidaps/database/transactions/SyncPumpCancelTemporaryBasalIfAnyTransaction.kt new file mode 100644 index 0000000000..fb7eaaadb9 --- /dev/null +++ b/database/src/main/java/info/nightscout/androidaps/database/transactions/SyncPumpCancelTemporaryBasalIfAnyTransaction.kt @@ -0,0 +1,30 @@ +package info.nightscout.androidaps.database.transactions + +import info.nightscout.androidaps.database.embedments.InterfaceIDs +import info.nightscout.androidaps.database.entities.TemporaryBasal +import info.nightscout.androidaps.database.interfaces.end + +class SyncPumpCancelTemporaryBasalIfAnyTransaction( + private val timestamp: Long, private val endPumpId: Long, private val pumpType: InterfaceIDs.PumpType, private val pumpSerial: String +) : Transaction() { + + override fun run(): TransactionResult { + val result = TransactionResult() + val existing = database.temporaryBasalDao.findByPumpEndIds(endPumpId, pumpType, pumpSerial) + if (existing != null) // assume TBR has been cut already + return result + val current = database.temporaryBasalDao.getTemporaryBasalActiveAt(timestamp, pumpType, pumpSerial).blockingGet() + if (current != null && current.interfaceIDs.endId == null) { // do not allow overwrite if cut by end event + current.end = timestamp + current.interfaceIDs.endId = endPumpId + database.temporaryBasalDao.updateExistingEntry(current) + result.updated.add(current) + } + return result + } + + class TransactionResult { + + val updated = mutableListOf() + } +} \ No newline at end of file diff --git a/database/src/main/java/info/nightscout/androidaps/database/transactions/SyncPumpExtendedBolusTransaction.kt b/database/src/main/java/info/nightscout/androidaps/database/transactions/SyncPumpExtendedBolusTransaction.kt new file mode 100644 index 0000000000..f3cd17eaa6 --- /dev/null +++ b/database/src/main/java/info/nightscout/androidaps/database/transactions/SyncPumpExtendedBolusTransaction.kt @@ -0,0 +1,49 @@ +package info.nightscout.androidaps.database.transactions + +import info.nightscout.androidaps.database.entities.ExtendedBolus +import info.nightscout.androidaps.database.interfaces.end + +/** + * Creates or updates the extended bolus from pump synchronization + */ +class SyncPumpExtendedBolusTransaction(private val extendedBolus: ExtendedBolus) : Transaction() { + + override fun run(): TransactionResult { + extendedBolus.interfaceIDs.pumpId ?: extendedBolus.interfaceIDs.pumpType + ?: extendedBolus.interfaceIDs.pumpSerial + ?: throw IllegalStateException("Some pump ID is null") + val result = TransactionResult() + val current = database.extendedBolusDao.findByPumpIds(extendedBolus.interfaceIDs.pumpId!!, extendedBolus.interfaceIDs.pumpType!!, extendedBolus.interfaceIDs.pumpSerial!!) + if (current != null) { + if (current.interfaceIDs.endId == null && + (current.timestamp != extendedBolus.timestamp || + current.amount != extendedBolus.amount || + current.duration != extendedBolus.duration) + ) { + current.timestamp = extendedBolus.timestamp + current.amount = extendedBolus.amount + current.duration = extendedBolus.duration + database.extendedBolusDao.updateExistingEntry(current) + result.updated.add(current) + } + } else { + val running = database.extendedBolusDao.getExtendedBolusActiveAt(extendedBolus.timestamp, extendedBolus.interfaceIDs.pumpType!!, extendedBolus.interfaceIDs.pumpSerial!!).blockingGet() + if (running != null) { + val pctRun = (extendedBolus.timestamp - running.timestamp) / running.duration.toDouble() + running.amount /= pctRun + running.end = extendedBolus.timestamp + database.extendedBolusDao.updateExistingEntry(running) + result.updated.add(running) + } + database.extendedBolusDao.insertNewEntry(extendedBolus) + result.inserted.add(extendedBolus) + } + return result + } + + class TransactionResult { + + val inserted = mutableListOf() + val updated = mutableListOf() + } +} \ No newline at end of file diff --git a/database/src/main/java/info/nightscout/androidaps/database/transactions/SyncPumpTemporaryBasalTransaction.kt b/database/src/main/java/info/nightscout/androidaps/database/transactions/SyncPumpTemporaryBasalTransaction.kt new file mode 100644 index 0000000000..bd4c64cf2d --- /dev/null +++ b/database/src/main/java/info/nightscout/androidaps/database/transactions/SyncPumpTemporaryBasalTransaction.kt @@ -0,0 +1,52 @@ +package info.nightscout.androidaps.database.transactions + +import info.nightscout.androidaps.database.entities.TemporaryBasal +import info.nightscout.androidaps.database.interfaces.end + +/** + * Creates or updates the Temporary basal from pump synchronization + */ +class SyncPumpTemporaryBasalTransaction( + private val temporaryBasal: TemporaryBasal, + private val type: TemporaryBasal.Type? // extra parameter because field is not nullable in TemporaryBasal.class +) : Transaction() { + + override fun run(): TransactionResult { + temporaryBasal.interfaceIDs.pumpId ?: temporaryBasal.interfaceIDs.pumpType + ?: temporaryBasal.interfaceIDs.pumpSerial + ?: throw IllegalStateException("Some pump ID is null") + val result = TransactionResult() + val current = database.temporaryBasalDao.findByPumpIds(temporaryBasal.interfaceIDs.pumpId!!, temporaryBasal.interfaceIDs.pumpType!!, temporaryBasal.interfaceIDs.pumpSerial!!) + if (current != null) { + if ( + current.timestamp != temporaryBasal.timestamp || + current.rate != temporaryBasal.rate || + current.duration != temporaryBasal.duration && current.interfaceIDs.endId == null || + current.type != type ?: current.type + ) { + current.timestamp = temporaryBasal.timestamp + current.rate = temporaryBasal.rate + current.duration = temporaryBasal.duration + current.type = type ?: current.type + database.temporaryBasalDao.updateExistingEntry(current) + result.updated.add(current) + } + } else { + val running = database.temporaryBasalDao.getTemporaryBasalActiveAt(temporaryBasal.timestamp, temporaryBasal.interfaceIDs.pumpType!!, temporaryBasal.interfaceIDs.pumpSerial!!).blockingGet() + if (running != null) { + running.end = temporaryBasal.timestamp + database.temporaryBasalDao.updateExistingEntry(running) + result.updated.add(running) + } + database.temporaryBasalDao.insertNewEntry(temporaryBasal) + result.inserted.add(temporaryBasal) + } + return result + } + + class TransactionResult { + + val inserted = mutableListOf() + val updated = mutableListOf() + } +} \ No newline at end of file diff --git a/database/src/main/java/info/nightscout/androidaps/database/transactions/UpdateNsIdBolusCalculatorResultTransaction.kt b/database/src/main/java/info/nightscout/androidaps/database/transactions/UpdateNsIdBolusCalculatorResultTransaction.kt new file mode 100644 index 0000000000..da50ce0a55 --- /dev/null +++ b/database/src/main/java/info/nightscout/androidaps/database/transactions/UpdateNsIdBolusCalculatorResultTransaction.kt @@ -0,0 +1,12 @@ +package info.nightscout.androidaps.database.transactions + +import info.nightscout.androidaps.database.entities.BolusCalculatorResult + +class UpdateNsIdBolusCalculatorResultTransaction(val bolusCalculatorResult: BolusCalculatorResult) : Transaction() { + + override fun run() { + val current = database.bolusCalculatorResultDao.findById(bolusCalculatorResult.id) + if (current != null && current.interfaceIDs.nightscoutId != bolusCalculatorResult.interfaceIDs.nightscoutId) + database.bolusCalculatorResultDao.updateExistingEntry(bolusCalculatorResult) + } +} \ No newline at end of file diff --git a/database/src/main/java/info/nightscout/androidaps/database/transactions/UpdateNsIdBolusTransaction.kt b/database/src/main/java/info/nightscout/androidaps/database/transactions/UpdateNsIdBolusTransaction.kt new file mode 100644 index 0000000000..a6e0a574ff --- /dev/null +++ b/database/src/main/java/info/nightscout/androidaps/database/transactions/UpdateNsIdBolusTransaction.kt @@ -0,0 +1,12 @@ +package info.nightscout.androidaps.database.transactions + +import info.nightscout.androidaps.database.entities.Bolus + +class UpdateNsIdBolusTransaction(val bolus: Bolus) : Transaction() { + + override fun run() { + val current = database.bolusDao.findById(bolus.id) + if (current != null && current.interfaceIDs.nightscoutId != bolus.interfaceIDs.nightscoutId) + database.bolusDao.updateExistingEntry(bolus) + } +} \ No newline at end of file diff --git a/database/src/main/java/info/nightscout/androidaps/database/transactions/UpdateNsIdCarbsTransaction.kt b/database/src/main/java/info/nightscout/androidaps/database/transactions/UpdateNsIdCarbsTransaction.kt new file mode 100644 index 0000000000..2cba4540f9 --- /dev/null +++ b/database/src/main/java/info/nightscout/androidaps/database/transactions/UpdateNsIdCarbsTransaction.kt @@ -0,0 +1,12 @@ +package info.nightscout.androidaps.database.transactions + +import info.nightscout.androidaps.database.entities.Carbs + +class UpdateNsIdCarbsTransaction(val carbs: Carbs) : Transaction() { + + override fun run() { + val current = database.carbsDao.findById(carbs.id) + if (current != null && current.interfaceIDs.nightscoutId != carbs.interfaceIDs.nightscoutId) + database.carbsDao.updateExistingEntry(carbs) + } +} \ 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 diff --git a/database/src/main/java/info/nightscout/androidaps/database/transactions/UpdateNsIdExtendedBolusTransaction.kt b/database/src/main/java/info/nightscout/androidaps/database/transactions/UpdateNsIdExtendedBolusTransaction.kt new file mode 100644 index 0000000000..cfa12027b1 --- /dev/null +++ b/database/src/main/java/info/nightscout/androidaps/database/transactions/UpdateNsIdExtendedBolusTransaction.kt @@ -0,0 +1,12 @@ +package info.nightscout.androidaps.database.transactions + +import info.nightscout.androidaps.database.entities.ExtendedBolus + +class UpdateNsIdExtendedBolusTransaction(val bolus: ExtendedBolus) : Transaction() { + + override fun run() { + val current = database.extendedBolusDao.findById(bolus.id) + if (current != null && current.interfaceIDs.nightscoutId != bolus.interfaceIDs.nightscoutId) + database.extendedBolusDao.updateExistingEntry(bolus) + } +} \ No newline at end of file diff --git a/database/src/main/java/info/nightscout/androidaps/database/transactions/UpdateNsIdFoodTransaction.kt b/database/src/main/java/info/nightscout/androidaps/database/transactions/UpdateNsIdFoodTransaction.kt new file mode 100644 index 0000000000..e03e38e343 --- /dev/null +++ b/database/src/main/java/info/nightscout/androidaps/database/transactions/UpdateNsIdFoodTransaction.kt @@ -0,0 +1,12 @@ +package info.nightscout.androidaps.database.transactions + +import info.nightscout.androidaps.database.entities.Food + +class UpdateNsIdFoodTransaction(val food: Food) : Transaction() { + + override fun run() { + val current = database.foodDao.findById(food.id) + if (current != null && current.interfaceIDs.nightscoutId != food.interfaceIDs.nightscoutId) + database.foodDao.updateExistingEntry(food) + } +} \ No newline at end of file diff --git a/database/src/main/java/info/nightscout/androidaps/database/transactions/UpdateNsIdGlucoseValueTransaction.kt b/database/src/main/java/info/nightscout/androidaps/database/transactions/UpdateNsIdGlucoseValueTransaction.kt new file mode 100644 index 0000000000..954aadd39b --- /dev/null +++ b/database/src/main/java/info/nightscout/androidaps/database/transactions/UpdateNsIdGlucoseValueTransaction.kt @@ -0,0 +1,12 @@ +package info.nightscout.androidaps.database.transactions + +import info.nightscout.androidaps.database.entities.GlucoseValue + +class UpdateNsIdGlucoseValueTransaction(val glucoseValue: GlucoseValue) : Transaction() { + + override fun run() { + val current = database.glucoseValueDao.findById(glucoseValue.id) + if (current != null && current.interfaceIDs.nightscoutId != glucoseValue.interfaceIDs.nightscoutId) + database.glucoseValueDao.updateExistingEntry(glucoseValue) + } +} \ No newline at end of file diff --git a/database/src/main/java/info/nightscout/androidaps/database/transactions/UpdateNsIdTemporaryBasalTransaction.kt b/database/src/main/java/info/nightscout/androidaps/database/transactions/UpdateNsIdTemporaryBasalTransaction.kt new file mode 100644 index 0000000000..be9a3c3efa --- /dev/null +++ b/database/src/main/java/info/nightscout/androidaps/database/transactions/UpdateNsIdTemporaryBasalTransaction.kt @@ -0,0 +1,12 @@ +package info.nightscout.androidaps.database.transactions + +import info.nightscout.androidaps.database.entities.TemporaryBasal + +class UpdateNsIdTemporaryBasalTransaction(val bolus: TemporaryBasal) : Transaction() { + + override fun run() { + val current = database.temporaryBasalDao.findById(bolus.id) + if (current != null && current.interfaceIDs.nightscoutId != bolus.interfaceIDs.nightscoutId) + database.temporaryBasalDao.updateExistingEntry(bolus) + } +} \ No newline at end of file diff --git a/database/src/main/java/info/nightscout/androidaps/database/transactions/UpdateNsIdTemporaryTargetTransaction.kt b/database/src/main/java/info/nightscout/androidaps/database/transactions/UpdateNsIdTemporaryTargetTransaction.kt new file mode 100644 index 0000000000..419fba854d --- /dev/null +++ b/database/src/main/java/info/nightscout/androidaps/database/transactions/UpdateNsIdTemporaryTargetTransaction.kt @@ -0,0 +1,12 @@ +package info.nightscout.androidaps.database.transactions + +import info.nightscout.androidaps.database.entities.TemporaryTarget + +class UpdateNsIdTemporaryTargetTransaction(val temporaryTarget: TemporaryTarget) : Transaction() { + + override fun run() { + val current = database.temporaryTargetDao.findById(temporaryTarget.id) + if (current != null && current.interfaceIDs.nightscoutId != temporaryTarget.interfaceIDs.nightscoutId) + database.temporaryTargetDao.updateExistingEntry(temporaryTarget) + } +} \ No newline at end of file diff --git a/database/src/main/java/info/nightscout/androidaps/database/transactions/UpdateNsIdTherapyEventTransaction.kt b/database/src/main/java/info/nightscout/androidaps/database/transactions/UpdateNsIdTherapyEventTransaction.kt new file mode 100644 index 0000000000..680fbe7ca3 --- /dev/null +++ b/database/src/main/java/info/nightscout/androidaps/database/transactions/UpdateNsIdTherapyEventTransaction.kt @@ -0,0 +1,12 @@ +package info.nightscout.androidaps.database.transactions + +import info.nightscout.androidaps.database.entities.TherapyEvent + +class UpdateNsIdTherapyEventTransaction(val therapyEvent: TherapyEvent) : Transaction() { + + override fun run() { + val current = database.therapyEventDao.findById(therapyEvent.id) + if (current != null && current.interfaceIDs.nightscoutId != therapyEvent.interfaceIDs.nightscoutId) + database.therapyEventDao.updateExistingEntry(therapyEvent) + } +} \ No newline at end of file diff --git a/database/src/main/java/info/nightscout/androidaps/database/transactions/UpdateTemporaryTargetTransaction.kt b/database/src/main/java/info/nightscout/androidaps/database/transactions/UpdateTemporaryTargetTransaction.kt index 0a9f140c20..f07a57fce2 100644 --- a/database/src/main/java/info/nightscout/androidaps/database/transactions/UpdateTemporaryTargetTransaction.kt +++ b/database/src/main/java/info/nightscout/androidaps/database/transactions/UpdateTemporaryTargetTransaction.kt @@ -2,11 +2,7 @@ package info.nightscout.androidaps.database.transactions import info.nightscout.androidaps.database.entities.TemporaryTarget -/** - * Updates the TemporaryTarget - */ -class UpdateTemporaryTargetTransaction(private val temporaryTarget: TemporaryTarget) : Transaction() { - +class UpdateTemporaryTargetTransaction(val temporaryTarget: TemporaryTarget) : Transaction() { override fun run() { database.temporaryTargetDao.updateExistingEntry(temporaryTarget) } diff --git a/database/src/main/java/info/nightscout/androidaps/database/transactions/UserEntryTransaction.kt b/database/src/main/java/info/nightscout/androidaps/database/transactions/UserEntryTransaction.kt index 3537f2bd83..714661fc36 100644 --- a/database/src/main/java/info/nightscout/androidaps/database/transactions/UserEntryTransaction.kt +++ b/database/src/main/java/info/nightscout/androidaps/database/transactions/UserEntryTransaction.kt @@ -1,19 +1,23 @@ package info.nightscout.androidaps.database.transactions import info.nightscout.androidaps.database.entities.UserEntry -import info.nightscout.androidaps.database.entities.UserEntry.* +import info.nightscout.androidaps.database.entities.UserEntry.Action +import info.nightscout.androidaps.database.entities.UserEntry.Sources +import info.nightscout.androidaps.database.entities.ValueWithUnit class UserEntryTransaction( val action: Action, - val s: String, - val values: MutableList = mutableListOf() + val source: Sources, + val note: String, + val values: List = listOf() ) : Transaction() { override fun run() { database.userEntryDao.insert(UserEntry( timestamp = System.currentTimeMillis(), action = action, - s = s, + source = source, + note = note, values = values )) } diff --git a/gradle/android_dependencies.gradle b/gradle/android_dependencies.gradle index 690d19ba83..c07f69eea0 100644 --- a/gradle/android_dependencies.gradle +++ b/gradle/android_dependencies.gradle @@ -9,7 +9,7 @@ android { } kotlinOptions { - jvmTarget = '1.8' + jvmTarget = JavaVersion.VERSION_1_8.toString() } buildFeatures { diff --git a/insight/build.gradle b/insight/build.gradle index 55565f892b..8020051b31 100644 --- a/insight/build.gradle +++ b/insight/build.gradle @@ -17,5 +17,4 @@ android { dependencies { implementation project(':core') - implementation project(':database') } \ No newline at end of file diff --git a/insight/src/main/java/info/nightscout/androidaps/plugins/pump/insight/LocalInsightPlugin.java b/insight/src/main/java/info/nightscout/androidaps/plugins/pump/insight/LocalInsightPlugin.java index 689fc018fd..2ba8ced252 100644 --- a/insight/src/main/java/info/nightscout/androidaps/plugins/pump/insight/LocalInsightPlugin.java +++ b/insight/src/main/java/info/nightscout/androidaps/plugins/pump/insight/LocalInsightPlugin.java @@ -1,5 +1,8 @@ package info.nightscout.androidaps.plugins.pump.insight; +import static info.nightscout.androidaps.extensions.PumpStateExtensionKt.convertedToAbsolute; +import static info.nightscout.androidaps.extensions.PumpStateExtensionKt.getPlannedRemainingMinutes; + import android.app.NotificationChannel; import android.app.NotificationManager; import android.content.ComponentName; @@ -30,9 +33,6 @@ import dagger.android.HasAndroidInjector; import info.nightscout.androidaps.data.DetailedBolusInfo; import info.nightscout.androidaps.data.Profile; import info.nightscout.androidaps.data.PumpEnactResult; -import info.nightscout.androidaps.database.AppRepository; -import info.nightscout.androidaps.database.entities.TherapyEvent; -import info.nightscout.androidaps.database.transactions.InsertTherapyEventIfNewTransaction; import info.nightscout.androidaps.db.ExtendedBolus; import info.nightscout.androidaps.db.InsightBolusID; import info.nightscout.androidaps.db.InsightHistoryOffset; @@ -40,21 +40,21 @@ import info.nightscout.androidaps.db.InsightPumpID; import info.nightscout.androidaps.db.Source; import info.nightscout.androidaps.db.TDD; import info.nightscout.androidaps.db.TemporaryBasal; -import info.nightscout.androidaps.db.Treatment; import info.nightscout.androidaps.events.EventInitializationChanged; import info.nightscout.androidaps.events.EventRefreshOverview; import info.nightscout.androidaps.insight.R; import info.nightscout.androidaps.interfaces.CommandQueueProvider; -import info.nightscout.androidaps.interfaces.ConfigInterface; +import info.nightscout.androidaps.interfaces.Config; import info.nightscout.androidaps.interfaces.Constraint; -import info.nightscout.androidaps.interfaces.ConstraintsInterface; +import info.nightscout.androidaps.interfaces.Constraints; import info.nightscout.androidaps.interfaces.DatabaseHelperInterface; import info.nightscout.androidaps.interfaces.PluginDescription; import info.nightscout.androidaps.interfaces.PluginType; import info.nightscout.androidaps.interfaces.ProfileFunction; import info.nightscout.androidaps.interfaces.PumpDescription; -import info.nightscout.androidaps.interfaces.PumpInterface; +import info.nightscout.androidaps.interfaces.Pump; import info.nightscout.androidaps.interfaces.PumpPluginBase; +import info.nightscout.androidaps.interfaces.PumpSync; import info.nightscout.androidaps.interfaces.TreatmentsInterface; import info.nightscout.androidaps.interfaces.UploadQueueInterface; import info.nightscout.androidaps.logging.AAPSLogger; @@ -136,10 +136,9 @@ import info.nightscout.androidaps.plugins.pump.insight.utils.ParameterBlockUtil; import info.nightscout.androidaps.utils.DateUtil; import info.nightscout.androidaps.utils.resources.ResourceHelper; import info.nightscout.androidaps.utils.sharedPreferences.SP; -import io.reactivex.disposables.CompositeDisposable; @Singleton -public class LocalInsightPlugin extends PumpPluginBase implements PumpInterface, ConstraintsInterface, InsightConnectionService.StateCallback { +public class LocalInsightPlugin extends PumpPluginBase implements Pump, Constraints, InsightConnectionService.StateCallback { private final AAPSLogger aapsLogger; private final RxBusWrapper rxBus; @@ -153,7 +152,7 @@ public class LocalInsightPlugin extends PumpPluginBase implements PumpInterface, private final UploadQueueInterface uploadQueue; private final DateUtil dateUtil; private final DatabaseHelperInterface databaseHelper; - private final AppRepository repository; + private final PumpSync pumpSync; public static final String ALERT_CHANNEL_ID = "AndroidAPS-InsightAlert"; @@ -199,8 +198,6 @@ public class LocalInsightPlugin extends PumpPluginBase implements PumpInterface, private boolean statusLoaded; private TBROverNotificationBlock tbrOverNotificationBlock; - private final CompositeDisposable disposable = new CompositeDisposable(); - @Inject public LocalInsightPlugin( HasAndroidInjector injector, @@ -214,10 +211,10 @@ public class LocalInsightPlugin extends PumpPluginBase implements PumpInterface, NSUpload nsUpload, Context context, UploadQueueInterface uploadQueue, - ConfigInterface config, + Config config, DateUtil dateUtil, DatabaseHelperInterface databaseHelper, - AppRepository repository + PumpSync pumpSync ) { super(new PluginDescription() .pluginIcon(R.drawable.ic_insight_128) @@ -242,10 +239,10 @@ public class LocalInsightPlugin extends PumpPluginBase implements PumpInterface, this.uploadQueue = uploadQueue; this.dateUtil = dateUtil; this.databaseHelper = databaseHelper; - this.repository = repository; + this.pumpSync = pumpSync; pumpDescription = new PumpDescription(); - pumpDescription.setPumpDescription(PumpType.AccuChekInsightBluetooth); + pumpDescription.setPumpDescription(PumpType.ACCU_CHEK_INSIGHT_BLUETOOTH); } public TBROverNotificationBlock getTBROverNotificationBlock() { @@ -591,13 +588,12 @@ public class LocalInsightPlugin extends PumpPluginBase implements PumpInterface, bolusMessage.setDuration(0); bolusMessage.setExtendedAmount(0); bolusMessage.setImmediateAmount(insulin); - bolusMessage.setVibration(sp.getBoolean(detailedBolusInfo.isSMB ? R.string.key_disable_vibration_auto : R.string.key_disable_vibration, false)); + bolusMessage.setVibration(sp.getBoolean(detailedBolusInfo.getBolusType() == DetailedBolusInfo.BolusType.SMB ? R.string.key_disable_vibration_auto : R.string.key_disable_vibration, false)); bolusID = connectionService.requestMessage(bolusMessage).await().getBolusId(); bolusCancelled = false; } result.success(true).enacted(true); - Treatment t = new Treatment(); - t.isSMB = detailedBolusInfo.isSMB; + EventOverviewBolusProgress.Treatment t = new EventOverviewBolusProgress.Treatment(0, 0, detailedBolusInfo.getBolusType() == DetailedBolusInfo.BolusType.SMB); final EventOverviewBolusProgress bolusingEvent = EventOverviewBolusProgress.INSTANCE; bolusingEvent.setT(t); bolusingEvent.setStatus(resourceHelper.gs(R.string.insight_delivered, 0d, insulin)); @@ -609,14 +605,15 @@ public class LocalInsightPlugin extends PumpPluginBase implements PumpInterface, insightBolusID.timestamp = System.currentTimeMillis(); insightBolusID.pumpSerial = connectionService.getPumpSystemIdentification().getSerialNumber(); databaseHelper.createOrUpdate(insightBolusID); - detailedBolusInfo.date = insightBolusID.timestamp; - detailedBolusInfo.source = Source.PUMP; - detailedBolusInfo.pumpId = insightBolusID.id; + detailedBolusInfo.setBolusTimestamp(insightBolusID.timestamp); + detailedBolusInfo.setPumpType(PumpType.ACCU_CHEK_INSIGHT); + detailedBolusInfo.setPumpSerial(serialNumber()); + detailedBolusInfo.setBolusPumpId(insightBolusID.id); if (detailedBolusInfo.carbs > 0 && detailedBolusInfo.carbTime != 0) { DetailedBolusInfo carbInfo = new DetailedBolusInfo(); carbInfo.carbs = detailedBolusInfo.carbs; - carbInfo.date = detailedBolusInfo.date + detailedBolusInfo.carbTime * 60L * 1000L; - carbInfo.source = Source.USER; + carbInfo.setCarbsTimestamp(detailedBolusInfo.timestamp + detailedBolusInfo.carbTime * 60L * 1000L); + carbInfo.setPumpType(PumpType.USER); treatmentsPlugin.addToHistoryTreatment(carbInfo, false); detailedBolusInfo.carbTime = 0; detailedBolusInfo.carbs = 0; @@ -700,7 +697,7 @@ public class LocalInsightPlugin extends PumpPluginBase implements PumpInterface, } @NonNull @Override - public PumpEnactResult setTempBasalAbsolute(double absoluteRate, int durationInMinutes, @NonNull Profile profile, boolean enforceNew) { + public PumpEnactResult setTempBasalAbsolute(double absoluteRate, int durationInMinutes, @NonNull Profile profile, boolean enforceNew, @NonNull PumpSync.TemporaryBasalType tbrType) { PumpEnactResult result = new PumpEnactResult(getInjector()); if (activeBasalRate == null) return result; if (activeBasalRate.getActiveBasalRate() == 0) return result; @@ -728,13 +725,13 @@ public class LocalInsightPlugin extends PumpPluginBase implements PumpInterface, result.comment(cancelTBRResult.getComment()); } } else { - return setTempBasalPercent((int) Math.round(percent), durationInMinutes, profile, enforceNew); + return setTempBasalPercent((int) Math.round(percent), durationInMinutes, profile, enforceNew, tbrType); } } else { result.comment(cancelEBResult.getComment()); } } else { - return setTempBasalPercent((int) Math.round(percent), durationInMinutes, profile, enforceNew); + return setTempBasalPercent((int) Math.round(percent), durationInMinutes, profile, enforceNew, tbrType); } try { fetchStatus(); @@ -750,7 +747,7 @@ public class LocalInsightPlugin extends PumpPluginBase implements PumpInterface, } @NonNull @Override - public PumpEnactResult setTempBasalPercent(int percent, int durationInMinutes, @NonNull Profile profile, boolean enforceNew) { + public PumpEnactResult setTempBasalPercent(int percent, int durationInMinutes, @NonNull Profile profile, boolean enforceNew, @NonNull PumpSync.TemporaryBasalType tbrType) { PumpEnactResult result = new PumpEnactResult(getInjector()); percent = (int) Math.round(((double) percent) / 10d) * 10; if (percent == 100) return cancelTempBasal(true); @@ -986,27 +983,27 @@ public class LocalInsightPlugin extends PumpPluginBase implements PumpInterface, final JSONObject status = new JSONObject(); final JSONObject extended = new JSONObject(); try { - status.put("timestamp", DateUtil.toISOString(connectionService.getLastConnected())); + status.put("timestamp", dateUtil.toISOString(connectionService.getLastConnected())); extended.put("Version", version); try { extended.put("ActiveProfile", profileFunction.getProfileName()); } catch (Exception e) { e.printStackTrace(); } - TemporaryBasal tb = treatmentsPlugin.getTempBasalFromHistory(now); + PumpSync.PumpState.TemporaryBasal tb = pumpSync.expectedPumpState().getTemporaryBasal(); if (tb != null) { - extended.put("TempBasalAbsoluteRate", tb.tempBasalConvertedToAbsolute(now, profile)); - extended.put("TempBasalStart", dateUtil.dateAndTimeString(tb.date)); - extended.put("TempBasalRemaining", tb.getPlannedRemainingMinutes()); + extended.put("TempBasalAbsoluteRate", convertedToAbsolute(tb, now, profile)); + extended.put("TempBasalStart", dateUtil.dateAndTimeString(tb.getTimestamp())); + extended.put("TempBasalRemaining", getPlannedRemainingMinutes(tb)); } - ExtendedBolus eb = treatmentsPlugin.getExtendedBolusFromHistory(now); + PumpSync.PumpState.ExtendedBolus eb = pumpSync.expectedPumpState().getExtendedBolus(); if (eb != null) { - extended.put("ExtendedBolusAbsoluteRate", eb.absoluteRate()); - extended.put("ExtendedBolusStart", dateUtil.dateAndTimeString(eb.date)); - extended.put("ExtendedBolusRemaining", eb.getPlannedRemainingMinutes()); + extended.put("ExtendedBolusAbsoluteRate", eb.getRate()); + extended.put("ExtendedBolusStart", dateUtil.dateAndTimeString(eb.getTimestamp())); + extended.put("ExtendedBolusRemaining", getPlannedRemainingMinutes(eb)); } extended.put("BaseBasalRate", getBaseBasalRate()); - status.put("timestamp", DateUtil.toISOString(now)); + status.put("timestamp", dateUtil.toISOString(now)); pump.put("extended", extended); if (statusLoaded) { @@ -1016,7 +1013,7 @@ public class LocalInsightPlugin extends PumpPluginBase implements PumpInterface, pump.put("battery", battery); pump.put("reservoir", cartridgeStatus.getRemainingAmount()); } - pump.put("clock", DateUtil.toISOString(now)); + pump.put("clock", dateUtil.toISOString(now)); } catch (JSONException e) { aapsLogger.error("Unhandled exception", e); } @@ -1030,7 +1027,7 @@ public class LocalInsightPlugin extends PumpPluginBase implements PumpInterface, @NonNull @Override public PumpType model() { - return PumpType.AccuChekInsightBluetooth; + return PumpType.ACCU_CHEK_INSIGHT_BLUETOOTH; } @NonNull @Override @@ -1269,7 +1266,7 @@ public class LocalInsightPlugin extends PumpPluginBase implements PumpInterface, if (!sp.getBoolean("insight_log_site_changes", false)) return; long timestamp = parseDate(event.getEventYear(), event.getEventMonth(), event.getEventDay(), event.getEventHour(), event.getEventMinute(), event.getEventSecond()) + timeOffset; - uploadCareportalEvent(timestamp, TherapyEvent.Type.CANNULA_CHANGE); + uploadCareportalEvent(timestamp, DetailedBolusInfo.EventType.CANNULA_CHANGE); } private void processTotalDailyDoseEvent(TotalDailyDoseEvent event) { @@ -1297,14 +1294,14 @@ public class LocalInsightPlugin extends PumpPluginBase implements PumpInterface, if (!sp.getBoolean("insight_log_reservoir_changes", false)) return; long timestamp = parseDate(event.getEventYear(), event.getEventMonth(), event.getEventDay(), event.getEventHour(), event.getEventMinute(), event.getEventSecond()) + timeOffset; - uploadCareportalEvent(timestamp, TherapyEvent.Type.INSULIN_CHANGE); + uploadCareportalEvent(timestamp, DetailedBolusInfo.EventType.INSULIN_CHANGE); } private void processPowerUpEvent(PowerUpEvent event) { if (!sp.getBoolean("insight_log_battery_changes", false)) return; long timestamp = parseDate(event.getEventYear(), event.getEventMonth(), event.getEventDay(), event.getEventHour(), event.getEventMinute(), event.getEventSecond()) + timeOffset; - uploadCareportalEvent(timestamp, TherapyEvent.Type.PUMP_BATTERY_CHANGE); + uploadCareportalEvent(timestamp, DetailedBolusInfo.EventType.PUMP_BATTERY_CHANGE); } private void processOperatingModeChangedEvent(String serial, List pumpStartedEvents, OperatingModeChangedEvent event) { @@ -1390,9 +1387,10 @@ public class LocalInsightPlugin extends PumpPluginBase implements PumpInterface, databaseHelper.createOrUpdate(bolusID); if (event.getBolusType() == BolusType.STANDARD || event.getBolusType() == BolusType.MULTIWAVE) { DetailedBolusInfo detailedBolusInfo = new DetailedBolusInfo(); - detailedBolusInfo.date = bolusID.timestamp; - detailedBolusInfo.source = Source.PUMP; - detailedBolusInfo.pumpId = bolusID.id; + detailedBolusInfo.timestamp = bolusID.timestamp; + detailedBolusInfo.setPumpType(PumpType.ACCU_CHEK_INSIGHT); + detailedBolusInfo.setPumpSerial(serialNumber()); + detailedBolusInfo.setBolusPumpId(bolusID.id); detailedBolusInfo.insulin = event.getImmediateAmount(); treatmentsPlugin.addToHistoryTreatment(detailedBolusInfo, true); } @@ -1424,9 +1422,10 @@ public class LocalInsightPlugin extends PumpPluginBase implements PumpInterface, databaseHelper.createOrUpdate(bolusID); if (event.getBolusType() == BolusType.STANDARD || event.getBolusType() == BolusType.MULTIWAVE) { DetailedBolusInfo detailedBolusInfo = new DetailedBolusInfo(); - detailedBolusInfo.date = bolusID.timestamp; - detailedBolusInfo.source = Source.PUMP; - detailedBolusInfo.pumpId = bolusID.id; + detailedBolusInfo.setBolusTimestamp(bolusID.timestamp); + detailedBolusInfo.setPumpType(PumpType.ACCU_CHEK_INSIGHT); + detailedBolusInfo.setPumpSerial(serialNumber()); + detailedBolusInfo.setBolusPumpId(bolusID.id); detailedBolusInfo.insulin = event.getImmediateAmount(); treatmentsPlugin.addToHistoryTreatment(detailedBolusInfo, true); } @@ -1552,12 +1551,7 @@ public class LocalInsightPlugin extends PumpPluginBase implements PumpInterface, } private void logNote(long date, String note) { - if (repository.getTherapyEventByTimestamp(TherapyEvent.Type.NOTE, date) != null) return; - disposable.add(repository.runTransactionForResult(new InsertTherapyEventIfNewTransaction(date, TherapyEvent.Type.NOTE, 0, note, sp.getString("careportal_enteredby", "AndroidAPS"), null, null, null)) - .subscribe( - result -> result.getInserted().forEach(nsUpload::uploadEvent), - error -> aapsLogger.error(LTag.DATABASE, "Error while saving therapy event", error) - )); + pumpSync.insertTherapyEventIfNewWithTimestamp(date, DetailedBolusInfo.EventType.NOTE, note, null, PumpType.ACCU_CHEK_INSIGHT, serialNumber()); } private long parseRelativeDate(int year, int month, int day, int hour, int minute, int second, int relativeHour, int relativeMinute, int relativeSecond) { @@ -1573,13 +1567,8 @@ public class LocalInsightPlugin extends PumpPluginBase implements PumpInterface, return calendar.getTimeInMillis(); } - private void uploadCareportalEvent(long date, TherapyEvent.Type event) { - if (repository.getTherapyEventByTimestamp(event, date) != null) return; - disposable.add(repository.runTransactionForResult(new InsertTherapyEventIfNewTransaction(date, event, 0, null, sp.getString("careportal_enteredby", "AndroidAPS"), null, null, null)) - .subscribe( - result -> result.getInserted().forEach(nsUpload::uploadEvent), - error -> aapsLogger.error(LTag.DATABASE, "Error while saving therapy event", error) - )); + private void uploadCareportalEvent(long date, DetailedBolusInfo.EventType event) { + pumpSync.insertTherapyEventIfNewWithTimestamp(date, event, null, null, PumpType.ACCU_CHEK_INSIGHT, serialNumber()); } @NonNull @Override diff --git a/medtronic/build.gradle b/medtronic/build.gradle index 6578de3917..a3cb9f789e 100644 --- a/medtronic/build.gradle +++ b/medtronic/build.gradle @@ -17,5 +17,4 @@ android { dependencies { implementation project(':core') implementation project(':rileylink') - implementation project(':database') } diff --git a/core/src/main/java/info/nightscout/androidaps/plugins/pump/common/PumpPluginAbstract.java b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/common/PumpPluginAbstract.java similarity index 87% rename from core/src/main/java/info/nightscout/androidaps/plugins/pump/common/PumpPluginAbstract.java rename to medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/common/PumpPluginAbstract.java index 99fac2e83b..47077d5135 100644 --- a/core/src/main/java/info/nightscout/androidaps/plugins/pump/common/PumpPluginAbstract.java +++ b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/common/PumpPluginAbstract.java @@ -1,5 +1,8 @@ package info.nightscout.androidaps.plugins.pump.common; +import static info.nightscout.androidaps.extensions.PumpStateExtensionKt.convertedToAbsolute; +import static info.nightscout.androidaps.extensions.PumpStateExtensionKt.getPlannedRemainingMinutes; + import android.content.Context; import android.content.Intent; import android.content.ServiceConnection; @@ -9,25 +12,22 @@ import androidx.annotation.NonNull; import org.json.JSONException; import org.json.JSONObject; -import java.util.Date; - import dagger.android.HasAndroidInjector; import info.nightscout.androidaps.core.R; import info.nightscout.androidaps.data.DetailedBolusInfo; import info.nightscout.androidaps.data.Profile; import info.nightscout.androidaps.data.PumpEnactResult; -import info.nightscout.androidaps.db.ExtendedBolus; -import info.nightscout.androidaps.db.TemporaryBasal; -import info.nightscout.androidaps.db.Treatment; import info.nightscout.androidaps.events.EventAppExit; import info.nightscout.androidaps.events.EventCustomActionsChanged; -import info.nightscout.androidaps.interfaces.ActivePluginProvider; +import info.nightscout.androidaps.extensions.PumpStateExtensionKt; +import info.nightscout.androidaps.interfaces.ActivePlugin; import info.nightscout.androidaps.interfaces.CommandQueueProvider; -import info.nightscout.androidaps.interfaces.ConstraintsInterface; +import info.nightscout.androidaps.interfaces.Constraints; import info.nightscout.androidaps.interfaces.PluginDescription; import info.nightscout.androidaps.interfaces.PumpDescription; -import info.nightscout.androidaps.interfaces.PumpInterface; +import info.nightscout.androidaps.interfaces.Pump; 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; @@ -50,13 +50,13 @@ import io.reactivex.disposables.CompositeDisposable; // When using this class, make sure that your first step is to create mConnection (see MedtronicPumpPlugin) -public abstract class PumpPluginAbstract extends PumpPluginBase implements PumpInterface, ConstraintsInterface { +public abstract class PumpPluginAbstract extends PumpPluginBase implements Pump, Constraints { private final CompositeDisposable disposable = new CompositeDisposable(); protected HasAndroidInjector injector; protected AAPSLogger aapsLogger; protected RxBusWrapper rxBus; - protected ActivePluginProvider activePlugin; + protected ActivePlugin activePlugin; protected Context context; protected FabricPrivacy fabricPrivacy; protected ResourceHelper resourceHelper; @@ -70,7 +70,7 @@ public abstract class PumpPluginAbstract extends PumpPluginBase implements PumpI protected boolean displayConnectionMessages = false; protected PumpType pumpType; protected AapsSchedulers aapsSchedulers; - + protected PumpSync pumpSync; protected PumpPluginAbstract( PluginDescription pluginDescription, @@ -80,12 +80,13 @@ public abstract class PumpPluginAbstract extends PumpPluginBase implements PumpI AAPSLogger aapsLogger, CommandQueueProvider commandQueue, RxBusWrapper rxBus, - ActivePluginProvider activePlugin, + ActivePlugin activePlugin, SP sp, Context context, FabricPrivacy fabricPrivacy, DateUtil dateUtil, - AapsSchedulers aapsSchedulers + AapsSchedulers aapsSchedulers, + PumpSync pumpSync ) { super(pluginDescription, injector, aapsLogger, resourceHelper, commandQueue); @@ -102,6 +103,7 @@ public abstract class PumpPluginAbstract extends PumpPluginBase implements PumpI this.pumpType = pumpType; this.dateUtil = dateUtil; this.aapsSchedulers = aapsSchedulers; + this.pumpSync = pumpSync; } @@ -157,7 +159,7 @@ public abstract class PumpPluginAbstract extends PumpPluginBase implements PumpI public boolean isInitialized() { - return PumpDriverState.isInitialized(pumpState); + return pumpState.isInitialized(); } @@ -174,7 +176,7 @@ public abstract class PumpPluginAbstract extends PumpPluginBase implements PumpI public boolean isConnected() { if (displayConnectionMessages) aapsLogger.debug(LTag.PUMP, "isConnected [PumpPluginAbstract]."); - return PumpDriverState.isConnected(pumpState); + return pumpState.isConnected(); } @@ -248,14 +250,14 @@ public abstract class PumpPluginAbstract extends PumpPluginBase implements PumpI @NonNull @Override - public PumpEnactResult setTempBasalAbsolute(double absoluteRate, int durationInMinutes, @NonNull Profile profile, boolean enforceNew) { + public PumpEnactResult setTempBasalAbsolute(double absoluteRate, int durationInMinutes, @NonNull Profile profile, boolean enforceNew, @NonNull PumpSync.TemporaryBasalType tbrType) { aapsLogger.debug(LTag.PUMP, "setTempBasalAbsolute [PumpPluginAbstract] - Not implemented."); return getOperationNotSupportedWithCustomText(R.string.pump_operation_not_supported_by_pump_driver); } @NonNull @Override - public PumpEnactResult setTempBasalPercent(int percent, int durationInMinutes, @NonNull Profile profile, boolean enforceNew) { + public PumpEnactResult setTempBasalPercent(int percent, int durationInMinutes, @NonNull Profile profile, boolean enforceNew, @NonNull PumpSync.TemporaryBasalType tbrType) { aapsLogger.debug(LTag.PUMP, "setTempBasalPercent [PumpPluginAbstract] - Not implemented."); return getOperationNotSupportedWithCustomText(R.string.pump_operation_not_supported_by_pump_driver); } @@ -323,6 +325,7 @@ public abstract class PumpPluginAbstract extends PumpPluginBase implements PumpI return new JSONObject(); } + long now = System.currentTimeMillis(); JSONObject pump = new JSONObject(); JSONObject battery = new JSONObject(); JSONObject status = new JSONObject(); @@ -336,28 +339,27 @@ public abstract class PumpPluginAbstract extends PumpPluginBase implements PumpI } catch (Exception ignored) { } - TemporaryBasal tb = activePlugin.getActiveTreatments().getTempBasalFromHistory(System.currentTimeMillis()); + PumpSync.PumpState.TemporaryBasal tb = pumpSync.expectedPumpState().getTemporaryBasal(); if (tb != null) { - extended.put("TempBasalAbsoluteRate", - tb.tempBasalConvertedToAbsolute(System.currentTimeMillis(), profile)); - extended.put("TempBasalStart", dateUtil.dateAndTimeString(tb.date)); - extended.put("TempBasalRemaining", tb.getPlannedRemainingMinutes()); + extended.put("TempBasalAbsoluteRate", convertedToAbsolute(tb, now, profile)); + extended.put("TempBasalStart", dateUtil.dateAndTimeString(tb.getTimestamp())); + extended.put("TempBasalRemaining", getPlannedRemainingMinutes(tb)); } - ExtendedBolus eb = activePlugin.getActiveTreatments().getExtendedBolusFromHistory(System.currentTimeMillis()); + PumpSync.PumpState.ExtendedBolus eb = pumpSync.expectedPumpState().getExtendedBolus(); if (eb != null) { - extended.put("ExtendedBolusAbsoluteRate", eb.absoluteRate()); - extended.put("ExtendedBolusStart", dateUtil.dateAndTimeString(eb.date)); - extended.put("ExtendedBolusRemaining", eb.getPlannedRemainingMinutes()); + extended.put("ExtendedBolusAbsoluteRate", eb.getRate()); + extended.put("ExtendedBolusStart", dateUtil.dateAndTimeString(eb.getTimestamp())); + extended.put("ExtendedBolusRemaining", getPlannedRemainingMinutes(eb)); } - status.put("timestamp", DateUtil.toISOString(new Date())); + status.put("timestamp", dateUtil.toISOString(dateUtil.now())); pump.put("battery", battery); pump.put("status", status); pump.put("extended", extended); pump.put("reservoir", getPumpStatusData().reservoirRemainingUnits); - pump.put("clock", DateUtil.toISOString(new Date())); + pump.put("clock", dateUtil.toISOString(dateUtil.now())); } catch (JSONException e) { aapsLogger.error("Unhandled exception", e); } @@ -378,14 +380,13 @@ public abstract class PumpPluginAbstract extends PumpPluginBase implements PumpI ret += "LastBolus: " + DecimalFormatter.INSTANCE.to2Decimal(getPumpStatusData().lastBolusAmount) + "U @" + // android.text.format.DateFormat.format("HH:mm", getPumpStatusData().lastBolusTime) + "\n"; } - TemporaryBasal activeTemp = activePlugin.getActiveTreatments().getRealTempBasalFromHistory(System.currentTimeMillis()); + PumpSync.PumpState.TemporaryBasal activeTemp = pumpSync.expectedPumpState().getTemporaryBasal(); if (activeTemp != null) { - ret += "Temp: " + activeTemp.toStringFull() + "\n"; + ret += "Temp: " + PumpStateExtensionKt.toStringFull(activeTemp, dateUtil) + "\n"; } - ExtendedBolus activeExtendedBolus = activePlugin.getActiveTreatments().getExtendedBolusFromHistory( - System.currentTimeMillis()); + PumpSync.PumpState.ExtendedBolus activeExtendedBolus = pumpSync.expectedPumpState().getExtendedBolus(); if (activeExtendedBolus != null) { - ret += "Extended: " + activeExtendedBolus.toString() + "\n"; + ret += "Extended: " + PumpStateExtensionKt.toStringFull(activeExtendedBolus, dateUtil) + "\n"; } // if (!veryShort) { // ret += "TDD: " + DecimalFormatter.to0Decimal(pumpStatus.dailyTotalUnits) + " / " @@ -418,8 +419,7 @@ public abstract class PumpPluginAbstract extends PumpPluginBase implements PumpI activePlugin.getActiveTreatments().addToHistoryTreatment(detailedBolusInfo, true); EventOverviewBolusProgress bolusingEvent = EventOverviewBolusProgress.INSTANCE; - bolusingEvent.setT(new Treatment()); - bolusingEvent.getT().isSMB = detailedBolusInfo.isSMB; + bolusingEvent.setT(new EventOverviewBolusProgress.Treatment(0, 0, detailedBolusInfo.getBolusType() == DetailedBolusInfo.BolusType.SMB)); bolusingEvent.setPercent(100); rxBus.send(bolusingEvent); diff --git a/core/src/main/java/info/nightscout/androidaps/plugins/pump/common/data/PumpStatus.java b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/common/data/PumpStatus.java similarity index 97% rename from core/src/main/java/info/nightscout/androidaps/plugins/pump/common/data/PumpStatus.java rename to medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/common/data/PumpStatus.java index bd30efd423..505cd1388f 100644 --- a/core/src/main/java/info/nightscout/androidaps/plugins/pump/common/data/PumpStatus.java +++ b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/common/data/PumpStatus.java @@ -62,7 +62,7 @@ public abstract class PumpStatus { public abstract void initSettings(); public void setLastCommunicationToNow() { - this.lastDataTime = DateUtil.now(); + this.lastDataTime = System.currentTimeMillis(); this.lastConnection = System.currentTimeMillis(); } diff --git a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/common/defs/PumpDriverState.kt b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/common/defs/PumpDriverState.kt new file mode 100644 index 0000000000..f72163ce92 --- /dev/null +++ b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/common/defs/PumpDriverState.kt @@ -0,0 +1,14 @@ +package info.nightscout.androidaps.plugins.pump.common.defs + +enum class PumpDriverState { + + NotInitialized, + Connecting, + Connected, + Initialized, + Ready, Busy, + Suspended; + + fun isConnected(): Boolean = this == Connected || this == Initialized || this == Busy || this == Suspended + fun isInitialized(): Boolean = this == Initialized || this == Busy || this == Suspended +} \ No newline at end of file diff --git a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/common/defs/PumpStatusType.kt b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/common/defs/PumpStatusType.kt new file mode 100644 index 0000000000..8a6c1a6a9a --- /dev/null +++ b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/common/defs/PumpStatusType.kt @@ -0,0 +1,7 @@ +package info.nightscout.androidaps.plugins.pump.common.defs + +enum class PumpStatusType(val status: String) { + + Running("normal"), + Suspended("suspended"); +} \ No newline at end of file diff --git a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/MedtronicFragment.kt b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/MedtronicFragment.kt index b18d539464..d9124ec15e 100644 --- a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/MedtronicFragment.kt +++ b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/MedtronicFragment.kt @@ -12,8 +12,10 @@ import dagger.android.support.DaggerFragment import info.nightscout.androidaps.events.EventExtendedBolusChange import info.nightscout.androidaps.events.EventPumpStatusChanged import info.nightscout.androidaps.events.EventTempBasalChange -import info.nightscout.androidaps.interfaces.ActivePluginProvider +import info.nightscout.androidaps.extensions.toStringFull +import info.nightscout.androidaps.interfaces.ActivePlugin import info.nightscout.androidaps.interfaces.CommandQueueProvider +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 @@ -51,9 +53,10 @@ class MedtronicFragment : DaggerFragment() { @Inject lateinit var aapsLogger: AAPSLogger @Inject lateinit var fabricPrivacy: FabricPrivacy @Inject lateinit var resourceHelper: ResourceHelper + @Inject lateinit var dateUtil: DateUtil @Inject lateinit var rxBus: RxBusWrapper @Inject lateinit var commandQueue: CommandQueueProvider - @Inject lateinit var activePlugin: ActivePluginProvider + @Inject lateinit var activePlugin: ActivePlugin @Inject lateinit var medtronicPumpPlugin: MedtronicPumpPlugin @Inject lateinit var warnColors: WarnColors @Inject lateinit var rileyLinkUtil: RileyLinkUtil @@ -61,6 +64,7 @@ class MedtronicFragment : DaggerFragment() { @Inject lateinit var medtronicPumpStatus: MedtronicPumpStatus @Inject lateinit var rileyLinkServiceData: RileyLinkServiceData @Inject lateinit var aapsSchedulers: AapsSchedulers + @Inject lateinit var pumpSync: PumpSync private var disposable: CompositeDisposable = CompositeDisposable() @@ -263,7 +267,7 @@ class MedtronicFragment : DaggerFragment() { // last connection if (medtronicPumpStatus.lastConnection != 0L) { - val minAgo = DateUtil.minAgo(resourceHelper, medtronicPumpStatus.lastConnection) + val minAgo = dateUtil.minAgo(resourceHelper, medtronicPumpStatus.lastConnection) val min = (System.currentTimeMillis() - medtronicPumpStatus.lastConnection) / 1000 / 60 if (medtronicPumpStatus.lastConnection + 60 * 1000 > System.currentTimeMillis()) { binding.lastConnection.setText(R.string.medtronic_pump_connected_now) @@ -299,19 +303,20 @@ class MedtronicFragment : DaggerFragment() { val unit = resourceHelper.gs(R.string.insulin_unit_shortname) val ago = when { agoMsc < 60 * 1000 -> resourceHelper.gs(R.string.medtronic_pump_connected_now) - bolusMinAgo < 60 -> DateUtil.minAgo(resourceHelper, medtronicPumpStatus.lastBolusTime.time) - else -> DateUtil.hourAgo(medtronicPumpStatus.lastBolusTime.time, resourceHelper) + bolusMinAgo < 60 -> dateUtil.minAgo(resourceHelper, medtronicPumpStatus.lastBolusTime.time) + else -> dateUtil.hourAgo(medtronicPumpStatus.lastBolusTime.time, resourceHelper) } binding.lastBolus.text = resourceHelper.gs(R.string.mdt_last_bolus, bolus, unit, ago) } else { binding.lastBolus.text = "" } + val pumpState = pumpSync.expectedPumpState() // base basal rate binding.baseBasalRate.text = ("(" + medtronicPumpStatus.activeProfileName + ") " + resourceHelper.gs(R.string.pump_basebasalrate, medtronicPumpPlugin.baseBasalRate)) - binding.tempBasal.text = activePlugin.activeTreatments.getTempBasalFromHistory(System.currentTimeMillis())?.toStringFull() + binding.tempBasal.text = pumpState.temporaryBasal?.toStringFull(dateUtil) ?: "" // battery @@ -329,7 +334,7 @@ class MedtronicFragment : DaggerFragment() { medtronicPumpPlugin.rileyLinkService?.verifyConfiguration() binding.errors.text = medtronicPumpStatus.errorInfo - var showRileyLinkBatteryLevel: Boolean = rileyLinkServiceData.showBatteryLevel + val showRileyLinkBatteryLevel: Boolean = rileyLinkServiceData.showBatteryLevel if (showRileyLinkBatteryLevel) { binding.rlBatteryView.visibility = View.VISIBLE diff --git a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/MedtronicPumpPlugin.java b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/MedtronicPumpPlugin.java index af16b76bd1..490bf90359 100644 --- a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/MedtronicPumpPlugin.java +++ b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/MedtronicPumpPlugin.java @@ -35,11 +35,12 @@ import info.nightscout.androidaps.data.PumpEnactResult; import info.nightscout.androidaps.db.Source; import info.nightscout.androidaps.db.TemporaryBasal; import info.nightscout.androidaps.events.EventRefreshOverview; -import info.nightscout.androidaps.interfaces.ActivePluginProvider; +import info.nightscout.androidaps.interfaces.ActivePlugin; import info.nightscout.androidaps.interfaces.CommandQueueProvider; import info.nightscout.androidaps.interfaces.PluginDescription; import info.nightscout.androidaps.interfaces.PluginType; -import info.nightscout.androidaps.interfaces.PumpInterface; +import info.nightscout.androidaps.interfaces.Pump; +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; @@ -54,7 +55,6 @@ import info.nightscout.androidaps.plugins.pump.common.defs.PumpDriverState; import info.nightscout.androidaps.plugins.pump.common.defs.PumpType; import info.nightscout.androidaps.plugins.pump.common.events.EventRefreshButtonState; import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.RileyLinkConst; -import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.RileyLinkUtil; import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.defs.RileyLinkPumpDevice; import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.defs.RileyLinkPumpInfo; import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.defs.RileyLinkServiceState; @@ -97,10 +97,9 @@ import info.nightscout.androidaps.utils.sharedPreferences.SP; * @author Andy Rozman (andy.rozman@gmail.com) */ @Singleton -public class MedtronicPumpPlugin extends PumpPluginAbstract implements PumpInterface, RileyLinkPumpDevice { +public class MedtronicPumpPlugin extends PumpPluginAbstract implements Pump, RileyLinkPumpDevice { private final SP sp; - private final RileyLinkUtil rileyLinkUtil; private final MedtronicUtil medtronicUtil; private final MedtronicPumpStatus medtronicPumpStatus; private final MedtronicHistoryData medtronicHistoryData; @@ -128,18 +127,18 @@ public class MedtronicPumpPlugin extends PumpPluginAbstract implements PumpInter RxBusWrapper rxBus, Context context, ResourceHelper resourceHelper, - ActivePluginProvider activePlugin, + ActivePlugin activePlugin, SP sp, CommandQueueProvider commandQueue, FabricPrivacy fabricPrivacy, - RileyLinkUtil rileyLinkUtil, MedtronicUtil medtronicUtil, MedtronicPumpStatus medtronicPumpStatus, MedtronicHistoryData medtronicHistoryData, RileyLinkServiceData rileyLinkServiceData, ServiceTaskExecutor serviceTaskExecutor, DateUtil dateUtil, - AapsSchedulers aapsSchedulers + AapsSchedulers aapsSchedulers, + PumpSync pumpSync ) { super(new PluginDescription() // @@ -150,11 +149,10 @@ public class MedtronicPumpPlugin extends PumpPluginAbstract implements PumpInter .shortName(R.string.medtronic_name_short) // .preferencesId(R.xml.pref_medtronic) .description(R.string.description_pump_medtronic), // - PumpType.Medtronic_522_722, // we default to most basic model, correct model from config is loaded later - injector, resourceHelper, aapsLogger, commandQueue, rxBus, activePlugin, sp, context, fabricPrivacy, dateUtil, aapsSchedulers + PumpType.MEDTRONIC_522_722, // we default to most basic model, correct model from config is loaded later + injector, resourceHelper, aapsLogger, commandQueue, rxBus, activePlugin, sp, context, fabricPrivacy, dateUtil, aapsSchedulers, pumpSync ); - this.rileyLinkUtil = rileyLinkUtil; this.medtronicUtil = medtronicUtil; this.sp = sp; this.medtronicPumpStatus = medtronicPumpStatus; @@ -879,15 +877,15 @@ public class MedtronicPumpPlugin extends PumpPluginAbstract implements PumpInter long now = System.currentTimeMillis(); - detailedBolusInfo.date = now; - detailedBolusInfo.deliverAt = now; // not sure about that one + detailedBolusInfo.timestamp = now; + detailedBolusInfo.deliverAtTheLatest = now; // not sure about that one activePlugin.getActiveTreatments().addToHistoryTreatment(detailedBolusInfo, true); // we subtract insulin, exact amount will be visible with next remainingInsulin update. medtronicPumpStatus.reservoirRemainingUnits -= detailedBolusInfo.insulin; - incrementStatistics(detailedBolusInfo.isSMB ? MedtronicConst.Statistics.SMBBoluses + incrementStatistics(detailedBolusInfo.getBolusType() == DetailedBolusInfo.BolusType.SMB ? MedtronicConst.Statistics.SMBBoluses : MedtronicConst.Statistics.StandardBoluses); @@ -956,8 +954,7 @@ public class MedtronicPumpPlugin extends PumpPluginAbstract implements PumpInter // if enforceNew===true current temp basal is canceled and new TBR set (duration is prolonged), // if false and the same rate is requested enacted=false and success=true is returned and TBR is not changed @NonNull @Override - public PumpEnactResult setTempBasalAbsolute(double absoluteRate, int durationInMinutes, Profile profile, - boolean enforceNew) { + public PumpEnactResult setTempBasalAbsolute(double absoluteRate, int durationInMinutes, Profile profile, boolean enforceNew, @NonNull PumpSync.TemporaryBasalType tbrType) { setRefreshButtonEnabled(false); @@ -1068,14 +1065,14 @@ public class MedtronicPumpPlugin extends PumpPluginAbstract implements PumpInter @NonNull @Override - public PumpEnactResult setTempBasalPercent(int percent, int durationInMinutes, @NonNull Profile profile, boolean enforceNew) { + public PumpEnactResult setTempBasalPercent(int percent, int durationInMinutes, @NonNull Profile profile, boolean enforceNew, @NonNull PumpSync.TemporaryBasalType tbrType) { if (percent == 0) { - return setTempBasalAbsolute(0.0d, durationInMinutes, profile, enforceNew); + return setTempBasalAbsolute(0.0d, durationInMinutes, profile, enforceNew, tbrType); } else { double absoluteValue = profile.getBasal() * (percent / 100.0d); absoluteValue = pumpDescription.getPumpType().determineCorrectBasalSize(absoluteValue); aapsLogger.warn(LTag.PUMP, "setTempBasalPercent [MedtronicPumpPlugin] - You are trying to use setTempBasalPercent with percent other then 0% (" + percent + "). This will start setTempBasalAbsolute, with calculated value (" + absoluteValue + "). Result might not be 100% correct."); - return setTempBasalAbsolute(absoluteValue, durationInMinutes, profile, enforceNew); + return setTempBasalAbsolute(absoluteValue, durationInMinutes, profile, enforceNew, tbrType); } } diff --git a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/cgms/MedtronicCGMSHistoryDecoder.java b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/cgms/MedtronicCGMSHistoryDecoder.java index 9d040fc105..2854d49c41 100644 --- a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/cgms/MedtronicCGMSHistoryDecoder.java +++ b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/cgms/MedtronicCGMSHistoryDecoder.java @@ -22,7 +22,7 @@ import info.nightscout.androidaps.plugins.pump.medtronic.comm.history.RecordDeco public class MedtronicCGMSHistoryDecoder extends MedtronicHistoryDecoder { - private static final Logger LOG = StacktraceLoggerWrapper.getLogger(LTag.PUMPCOMM); + //private static final Logger LOG = StacktraceLoggerWrapper.getLogger(LTag.PUMPCOMM); // CGMSValuesWriter cgmsValuesWriter = null; @@ -35,7 +35,7 @@ public class MedtronicCGMSHistoryDecoder extends MedtronicHistoryDecoder allHistory; private List newHistory = null; @@ -95,10 +91,9 @@ public class MedtronicHistoryData { private long lastIdUsed = 0; - private final CompositeDisposable disposable = new CompositeDisposable(); /** * Double bolus debug. We seem to have small problem with double Boluses (or sometimes also missing boluses - * from history. This flag turns on debugging for that (default is off=false)... Debuging is pretty detailed, + * from history. This flag turns on debugging for that (default is off=false)... Debugging is pretty detailed, * so log files will get bigger. * Note: June 2020. Since this seems to be fixed, I am disabling this per default. I will leave code inside * in case we need it again. Code that turns this on is commented out RileyLinkMedtronicService#verifyConfiguration() @@ -110,12 +105,12 @@ public class MedtronicHistoryData { HasAndroidInjector injector, AAPSLogger aapsLogger, SP sp, - ActivePluginProvider activePlugin, - NSUpload nsUpload, + ActivePlugin activePlugin, MedtronicUtil medtronicUtil, MedtronicPumpHistoryDecoder medtronicPumpHistoryDecoder, + MedtronicPumpStatus medtronicPumpStatus, DatabaseHelperInterface databaseHelperInterface, - AppRepository repository + PumpSync pumpSync ) { this.allHistory = new ArrayList<>(); @@ -123,11 +118,11 @@ public class MedtronicHistoryData { this.aapsLogger = aapsLogger; this.sp = sp; this.activePlugin = activePlugin; - this.nsUpload = nsUpload; this.medtronicUtil = medtronicUtil; this.medtronicPumpHistoryDecoder = medtronicPumpHistoryDecoder; + this.medtronicPumpStatus = medtronicPumpStatus; this.databaseHelper = databaseHelperInterface; - this.repository = repository; + this.pumpSync = pumpSync; } private Gson gson() { @@ -553,7 +548,7 @@ public class MedtronicHistoryData { long lastPrimeFromAAPS = sp.getLong(MedtronicConst.Statistics.LastPrime, 0L); if (lastPrimeRecord != lastPrimeFromAAPS) { - uploadCareportalEvent(DateTimeUtil.toMillisFromATD(lastPrimeRecord), TherapyEvent.Type.CANNULA_CHANGE); + uploadCareportalEvent(DateTimeUtil.toMillisFromATD(lastPrimeRecord), DetailedBolusInfo.EventType.CANNULA_CHANGE); sp.putLong(MedtronicConst.Statistics.LastPrime, lastPrimeRecord); } @@ -576,7 +571,7 @@ public class MedtronicHistoryData { long lastRewindFromAAPS = sp.getLong(MedtronicConst.Statistics.LastRewind, 0L); if (lastRewindRecord != lastRewindFromAAPS) { - uploadCareportalEvent(DateTimeUtil.toMillisFromATD(lastRewindRecord), TherapyEvent.Type.INSULIN_CHANGE); + uploadCareportalEvent(DateTimeUtil.toMillisFromATD(lastRewindRecord), DetailedBolusInfo.EventType.INSULIN_CHANGE); sp.putLong(MedtronicConst.Statistics.LastRewind, lastRewindRecord); } @@ -584,15 +579,8 @@ public class MedtronicHistoryData { } - private void uploadCareportalEvent(long date, TherapyEvent.Type event) { - if (repository.getTherapyEventByTimestamp(event, date) != null) return; - disposable.add(repository.runTransactionForResult(new InsertTherapyEventIfNewTransaction(date, - event, 0, null, sp.getString("careportal_enteredby", "AndroidAPS"), - null, null, TherapyEvent.GlucoseUnit.MGDL)) - .subscribe( - result -> result.getInserted().forEach(nsUpload::uploadEvent), - error -> aapsLogger.error(LTag.DATABASE, "Error while saving therapy event", error) - )); + private void uploadCareportalEvent(long date, DetailedBolusInfo.EventType event) { + pumpSync.insertTherapyEventIfNewWithTimestamp(date, event, null, null, medtronicPumpStatus.pumpType, medtronicPumpStatus.serialNumber); } private void processTDDs(List tddsIn) { @@ -982,9 +970,10 @@ public class MedtronicHistoryData { case Normal: { DetailedBolusInfo detailedBolusInfo = new DetailedBolusInfo(); - detailedBolusInfo.date = tryToGetByLocalTime(bolus.atechDateTime); - detailedBolusInfo.source = Source.PUMP; - detailedBolusInfo.pumpId = bolus.getPumpId(); + detailedBolusInfo.setBolusTimestamp(tryToGetByLocalTime(bolus.atechDateTime)); + detailedBolusInfo.setPumpType(PumpType.MEDTRONIC_512_712); // TODO grab real model + detailedBolusInfo.setPumpSerial(medtronicPumpStatus.serialNumber); + detailedBolusInfo.setBolusPumpId(bolus.getPumpId()); detailedBolusInfo.insulin = bolusDTO.getDeliveredAmount(); addCarbsFromEstimate(detailedBolusInfo, bolus); @@ -996,8 +985,8 @@ public class MedtronicHistoryData { bolus.setLinkedObject(detailedBolusInfo); - aapsLogger.debug(LTag.PUMP, String.format(Locale.ENGLISH, "addBolus - [date=%d,pumpId=%d, insulin=%.2f, newRecord=%b]", detailedBolusInfo.date, - detailedBolusInfo.pumpId, detailedBolusInfo.insulin, newRecord)); + aapsLogger.debug(LTag.PUMP, String.format(Locale.ENGLISH, "addBolus - [date=%d,pumpId=%d, insulin=%.2f, newRecord=%b]", detailedBolusInfo.timestamp, + detailedBolusInfo.getBolusPumpId(), detailedBolusInfo.insulin, newRecord)); } break; diff --git a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/data/dto/TempBasalPair.java b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/data/dto/TempBasalPair.java index d6399beafd..418770d4b6 100644 --- a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/data/dto/TempBasalPair.java +++ b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/data/dto/TempBasalPair.java @@ -16,7 +16,7 @@ import info.nightscout.androidaps.plugins.pump.medtronic.util.MedtronicUtil; *

* Just need a class to keep the pair together, for parcel transport. */ -public class TempBasalPair extends info.nightscout.androidaps.plugins.pump.common.data.TempBasalPair { +public class TempBasalPair extends info.nightscout.androidaps.plugins.pump.common.defs.TempBasalPair { /** * This constructor is for use with PumpHistoryDecoder @@ -30,11 +30,11 @@ public class TempBasalPair extends info.nightscout.androidaps.plugins.pump.commo int rateInt = ByteUtil.asUINT8(rateByte); if (isPercent) - this.insulinRate = rateByte; + this.setInsulinRate(rateByte); else - this.insulinRate = rateInt * 0.025; - this.durationMinutes = startTimeByte * 30; - this.isPercent = isPercent; + this.setInsulinRate(rateInt * 0.025); + this.setDurationMinutes(startTimeByte * 30); + this.setPercent(isPercent); } @@ -47,12 +47,12 @@ public class TempBasalPair extends info.nightscout.androidaps.plugins.pump.commo */ public TempBasalPair(byte rateByte0, byte rateByte1, int startTimeByte, boolean isPercent) { if (isPercent) { - this.insulinRate = rateByte0; + this.setInsulinRate(rateByte0); } else { - this.insulinRate = ByteUtil.toInt(rateByte1, rateByte0) * 0.025; + this.setInsulinRate(ByteUtil.toInt(rateByte1, rateByte0) * 0.025); } - this.durationMinutes = startTimeByte * 30; - this.isPercent = isPercent; + this.setDurationMinutes(startTimeByte * 30); + this.setPercent(isPercent); } public TempBasalPair(AAPSLogger aapsLogger, byte[] response) { @@ -60,20 +60,20 @@ public class TempBasalPair extends info.nightscout.androidaps.plugins.pump.commo aapsLogger.debug(LTag.PUMPBTCOMM, "Received TempBasal response: " + ByteUtil.getHex(response)); - isPercent = response[0] == 1; + setPercent(response[0] == 1); - if (isPercent) { - insulinRate = response[1]; + if (isPercent()) { + setInsulinRate(response[1]); } else { int strokes = MedtronicUtil.makeUnsignedShort(response[2], response[3]); - insulinRate = strokes / 40.0d; + setInsulinRate(strokes / 40.0d); } if (response.length < 6) { - durationMinutes = ByteUtil.asUINT8(response[4]); + setDurationMinutes(ByteUtil.asUINT8(response[4])); } else { - durationMinutes = MedtronicUtil.makeUnsignedShort(response[4], response[5]); + setDurationMinutes(MedtronicUtil.makeUnsignedShort(response[4], response[5])); } aapsLogger.warn(LTag.PUMPBTCOMM, String.format(Locale.ENGLISH, "TempBasalPair (with %d byte response): %s", response.length, toString())); @@ -92,8 +92,8 @@ public class TempBasalPair extends info.nightscout.androidaps.plugins.pump.commo list.add((byte) 5); - byte[] insulinRate = MedtronicUtil.getBasalStrokes(this.insulinRate, true); - byte timeMin = (byte) MedtronicUtil.getIntervalFromMinutes(durationMinutes); + byte[] insulinRate = MedtronicUtil.getBasalStrokes(this.getInsulinRate(), true); + byte timeMin = (byte) MedtronicUtil.getIntervalFromMinutes(getDurationMinutes()); // list.add((byte) 0); // ? @@ -120,7 +120,7 @@ public class TempBasalPair extends info.nightscout.androidaps.plugins.pump.commo } public boolean isCancelTBR() { - return (MedtronicUtil.isSame(insulinRate, 0.0d) && durationMinutes == 0); + return (MedtronicUtil.isSame(getInsulinRate(), 0.0d) && getDurationMinutes() == 0); } @@ -129,17 +129,17 @@ public class TempBasalPair extends info.nightscout.androidaps.plugins.pump.commo return "Cancel TBR"; } - if (isPercent) { - return String.format(Locale.ENGLISH, "Rate: %.0f%%, Duration: %d min", insulinRate, durationMinutes); + if (isPercent()) { + return String.format(Locale.ENGLISH, "Rate: %.0f%%, Duration: %d min", getInsulinRate(), getDurationMinutes()); } else { - return String.format(Locale.ENGLISH, "Rate: %.3f U, Duration: %d min", insulinRate, durationMinutes); + return String.format(Locale.ENGLISH, "Rate: %.3f U, Duration: %d min", getInsulinRate(), getDurationMinutes()); } } @NonNull @Override public String toString() { - return "TempBasalPair [" + "Rate=" + insulinRate + ", DurationMinutes=" + durationMinutes + ", IsPercent=" - + isPercent + "]"; + return "TempBasalPair [" + "Rate=" + getInsulinRate() + ", DurationMinutes=" + getDurationMinutes() + ", IsPercent=" + + isPercent() + "]"; } } diff --git a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/driver/MedtronicPumpStatus.java b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/driver/MedtronicPumpStatus.java index 870bbe273d..905a005e29 100644 --- a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/driver/MedtronicPumpStatus.java +++ b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/driver/MedtronicPumpStatus.java @@ -65,7 +65,7 @@ public class MedtronicPumpStatus extends info.nightscout.androidaps.plugins.pump RxBusWrapper rxBus, RileyLinkUtil rileyLinkUtil ) { - super(PumpType.Medtronic_522_722); + super(PumpType.MEDTRONIC_522_722); this.resourceHelper = resourceHelper; this.sp = sp; this.rxBus = rxBus; @@ -110,17 +110,17 @@ public class MedtronicPumpStatus extends info.nightscout.androidaps.plugins.pump private void createMedtronicPumpMap() { medtronicPumpMap = new HashMap<>(); - medtronicPumpMap.put("512", PumpType.Medtronic_512_712); - medtronicPumpMap.put("712", PumpType.Medtronic_512_712); - medtronicPumpMap.put("515", PumpType.Medtronic_515_715); - medtronicPumpMap.put("715", PumpType.Medtronic_515_715); + medtronicPumpMap.put("512", PumpType.MEDTRONIC_512_712); + medtronicPumpMap.put("712", PumpType.MEDTRONIC_512_712); + medtronicPumpMap.put("515", PumpType.MEDTRONIC_515_715); + medtronicPumpMap.put("715", PumpType.MEDTRONIC_515_715); - medtronicPumpMap.put("522", PumpType.Medtronic_522_722); - medtronicPumpMap.put("722", PumpType.Medtronic_522_722); - medtronicPumpMap.put("523", PumpType.Medtronic_523_723_Revel); - medtronicPumpMap.put("723", PumpType.Medtronic_523_723_Revel); - medtronicPumpMap.put("554", PumpType.Medtronic_554_754_Veo); - medtronicPumpMap.put("754", PumpType.Medtronic_554_754_Veo); + medtronicPumpMap.put("522", PumpType.MEDTRONIC_522_722); + medtronicPumpMap.put("722", PumpType.MEDTRONIC_522_722); + medtronicPumpMap.put("523", PumpType.MEDTRONIC_523_723_REVEL); + medtronicPumpMap.put("723", PumpType.MEDTRONIC_523_723_REVEL); + medtronicPumpMap.put("554", PumpType.MEDTRONIC_554_754_VEO); + medtronicPumpMap.put("754", PumpType.MEDTRONIC_554_754_VEO); } diff --git a/medtronic/src/test/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/pump/MedtronicPumpHistoryDecoderUTest.java b/medtronic/src/test/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/pump/MedtronicPumpHistoryDecoderUTest.java index 0a9e827ece..14a4c2926a 100644 --- a/medtronic/src/test/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/pump/MedtronicPumpHistoryDecoderUTest.java +++ b/medtronic/src/test/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/pump/MedtronicPumpHistoryDecoderUTest.java @@ -11,7 +11,7 @@ import org.powermock.modules.junit4.PowerMockRunner; import java.util.List; import dagger.android.HasAndroidInjector; -import info.nightscout.androidaps.interfaces.ActivePluginProvider; +import info.nightscout.androidaps.interfaces.ActivePlugin; import info.nightscout.androidaps.logging.AAPSLogger; import info.nightscout.androidaps.logging.AAPSLoggerTest; import info.nightscout.androidaps.plugins.bus.RxBusWrapper; @@ -35,7 +35,7 @@ public class MedtronicPumpHistoryDecoderUTest { AAPSLogger aapsLogger = new AAPSLoggerTest(); RxBusWrapper rxBusWrapper = new RxBusWrapper(new TestAapsSchedulers()); @Mock ResourceHelper resourceHelper; - @Mock(answer = Answers.RETURNS_DEEP_STUBS) ActivePluginProvider activePluginProvider; + @Mock(answer = Answers.RETURNS_DEEP_STUBS) ActivePlugin activePlugin; @Mock RileyLinkUtil rileyLinkUtil; @Mock SP sp; MedtronicPumpStatus medtronicPumpStatus; diff --git a/medtronic/src/test/java/info/nightscout/androidaps/plugins/pump/medtronic/data/dto/BasalProfileUTest.java b/medtronic/src/test/java/info/nightscout/androidaps/plugins/pump/medtronic/data/dto/BasalProfileUTest.java index 8b2eaa3e7e..125e067164 100644 --- a/medtronic/src/test/java/info/nightscout/androidaps/plugins/pump/medtronic/data/dto/BasalProfileUTest.java +++ b/medtronic/src/test/java/info/nightscout/androidaps/plugins/pump/medtronic/data/dto/BasalProfileUTest.java @@ -9,16 +9,15 @@ import info.nightscout.androidaps.plugins.pump.medtronic.util.MedtronicUtil; * Created by andy on 6/16/18. */ //@RunWith(PowerMockRunner.class) -//@PrepareForTest({ MainApp.class, DatabaseHelper.class, DateUtil.class, SP.class }) +//@PrepareForTest({ DatabaseHelper.class, DateUtil.class, SP.class }) @Ignore public class BasalProfileUTest { /* - // MainApp mainApp = new MainApp(); @Before public void initMocking() { PowerMockito.mockStatic(DateUtil.class); - when(DateUtil.now()).thenReturn(1514766900000L + T.mins(1).msecs()); + when(dateUtil._now()).thenReturn(1514766900000L + T.mins(1).msecs()); } diff --git a/omnipod-common/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/common/ui/wizard/common/fragment/ActionFragmentBase.kt b/omnipod-common/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/common/ui/wizard/common/fragment/ActionFragmentBase.kt index 945ebfae50..681f837150 100644 --- a/omnipod-common/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/common/ui/wizard/common/fragment/ActionFragmentBase.kt +++ b/omnipod-common/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/common/ui/wizard/common/fragment/ActionFragmentBase.kt @@ -10,7 +10,7 @@ import android.widget.TextView import androidx.annotation.LayoutRes import info.nightscout.androidaps.plugins.pump.omnipod.common.R import info.nightscout.androidaps.plugins.pump.omnipod.common.ui.wizard.common.viewmodel.ActionViewModelBase -import info.nightscout.androidaps.utils.extensions.toVisibility +import info.nightscout.androidaps.extensions.toVisibility abstract class ActionFragmentBase : WizardFragmentBase() { diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/OmnipodDashPumpPlugin.java b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/OmnipodDashPumpPlugin.java index b62959e4f4..3386d9f8a0 100644 --- a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/OmnipodDashPumpPlugin.java +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/OmnipodDashPumpPlugin.java @@ -1,5 +1,6 @@ package info.nightscout.androidaps.plugins.pump.omnipod.dash; +import androidx.annotation.NonNull; import androidx.annotation.Nullable; import org.jetbrains.annotations.NotNull; @@ -19,8 +20,9 @@ import info.nightscout.androidaps.interfaces.CommandQueueProvider; import info.nightscout.androidaps.interfaces.PluginDescription; import info.nightscout.androidaps.interfaces.PluginType; import info.nightscout.androidaps.interfaces.PumpDescription; -import info.nightscout.androidaps.interfaces.PumpInterface; +import info.nightscout.androidaps.interfaces.Pump; 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.common.ManufacturerType; @@ -33,8 +35,8 @@ import info.nightscout.androidaps.utils.TimeChangeType; import info.nightscout.androidaps.utils.resources.ResourceHelper; @Singleton -public class OmnipodDashPumpPlugin extends PumpPluginBase implements PumpInterface { - private static final PumpDescription PUMP_DESCRIPTION = new PumpDescription(PumpType.Omnipod_Dash); +public class OmnipodDashPumpPlugin extends PumpPluginBase implements Pump { + private static final PumpDescription PUMP_DESCRIPTION = new PumpDescription(PumpType.OMNIPOD_DASH); private final AAPSLogger aapsLogger; private final ResourceHelper resourceHelper; @@ -131,11 +133,11 @@ public class OmnipodDashPumpPlugin extends PumpPluginBase implements PumpInterfa } - @NotNull @Override public PumpEnactResult setTempBasalAbsolute(double absoluteRate, int durationInMinutes, @NotNull Profile profile, boolean enforceNew) { + @NotNull @Override public PumpEnactResult setTempBasalAbsolute(double absoluteRate, int durationInMinutes, @NotNull Profile profile, boolean enforceNew, @NonNull PumpSync.TemporaryBasalType tbrType) { return null; } - @NotNull @Override public PumpEnactResult setTempBasalPercent(int percent, int durationInMinutes, @NotNull Profile profile, boolean enforceNew) { + @NotNull @Override public PumpEnactResult setTempBasalPercent(int percent, int durationInMinutes, @NotNull Profile profile, boolean enforceNew, @NonNull PumpSync.TemporaryBasalType tbrType) { return null; } diff --git a/omnipod-eros/build.gradle b/omnipod-eros/build.gradle index 046d3a5060..63fcffcef6 100644 --- a/omnipod-eros/build.gradle +++ b/omnipod-eros/build.gradle @@ -18,5 +18,4 @@ dependencies { implementation project(':core') implementation project(':omnipod-common') implementation project(':rileylink') - implementation project(':database') } diff --git a/omnipod-eros/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/eros/OmnipodErosPumpPlugin.java b/omnipod-eros/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/eros/OmnipodErosPumpPlugin.java index 47058ca1fc..da8af74d7a 100644 --- a/omnipod-eros/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/eros/OmnipodErosPumpPlugin.java +++ b/omnipod-eros/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/eros/OmnipodErosPumpPlugin.java @@ -1,5 +1,10 @@ package info.nightscout.androidaps.plugins.pump.omnipod.eros; +import static info.nightscout.androidaps.plugins.pump.omnipod.eros.driver.definition.OmnipodConstants.BASAL_STEP_DURATION; +import static info.nightscout.androidaps.extensions.PumpStateExtensionKt.convertedToAbsolute; +import static info.nightscout.androidaps.extensions.PumpStateExtensionKt.getPlannedRemainingMinutes; +import static info.nightscout.androidaps.extensions.PumpStateExtensionKt.toStringFull; + import android.content.ComponentName; import android.content.Context; import android.content.Intent; @@ -11,13 +16,13 @@ import android.os.SystemClock; import android.text.TextUtils; import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import org.joda.time.DateTime; import org.joda.time.Duration; import org.json.JSONException; import org.json.JSONObject; -import java.util.Date; import java.util.List; import java.util.Objects; import java.util.Optional; @@ -31,32 +36,29 @@ import info.nightscout.androidaps.activities.ErrorHelperActivity; import info.nightscout.androidaps.data.DetailedBolusInfo; import info.nightscout.androidaps.data.Profile; import info.nightscout.androidaps.data.PumpEnactResult; -import info.nightscout.androidaps.db.ExtendedBolus; -import info.nightscout.androidaps.db.Source; -import info.nightscout.androidaps.db.TemporaryBasal; import info.nightscout.androidaps.events.EventAppExit; import info.nightscout.androidaps.events.EventAppInitialized; import info.nightscout.androidaps.events.EventPreferenceChange; import info.nightscout.androidaps.events.EventRefreshOverview; -import info.nightscout.androidaps.interfaces.ActivePluginProvider; +import info.nightscout.androidaps.interfaces.ActivePlugin; import info.nightscout.androidaps.interfaces.CommandQueueProvider; import info.nightscout.androidaps.interfaces.PluginDescription; import info.nightscout.androidaps.interfaces.PluginType; import info.nightscout.androidaps.interfaces.ProfileFunction; import info.nightscout.androidaps.interfaces.PumpDescription; -import info.nightscout.androidaps.interfaces.PumpInterface; +import info.nightscout.androidaps.interfaces.Pump; 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; import info.nightscout.androidaps.plugins.common.ManufacturerType; import info.nightscout.androidaps.plugins.general.actions.defs.CustomActionType; -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; import info.nightscout.androidaps.plugins.general.overview.notifications.Notification; -import info.nightscout.androidaps.plugins.pump.common.data.TempBasalPair; import info.nightscout.androidaps.plugins.pump.common.defs.PumpType; +import info.nightscout.androidaps.plugins.pump.common.defs.TempBasalPair; import info.nightscout.androidaps.plugins.pump.common.events.EventRileyLinkDeviceStatusChange; import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.RileyLinkConst; import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.RileyLinkUtil; @@ -72,7 +74,6 @@ import info.nightscout.androidaps.plugins.pump.omnipod.common.queue.command.Comm import info.nightscout.androidaps.plugins.pump.omnipod.common.queue.command.CommandResumeDelivery; import info.nightscout.androidaps.plugins.pump.omnipod.common.queue.command.CommandSuspendDelivery; import info.nightscout.androidaps.plugins.pump.omnipod.common.queue.command.CommandUpdateAlertConfiguration; -import info.nightscout.androidaps.plugins.pump.omnipod.eros.data.ActiveBolus; import info.nightscout.androidaps.plugins.pump.omnipod.eros.data.RLHistoryItemOmnipod; import info.nightscout.androidaps.plugins.pump.omnipod.eros.definition.OmnipodErosStorageKeys; import info.nightscout.androidaps.plugins.pump.omnipod.eros.driver.communication.action.service.ExpirationReminderBuilder; @@ -102,21 +103,20 @@ import info.nightscout.androidaps.utils.DateUtil; import info.nightscout.androidaps.utils.DecimalFormatter; import info.nightscout.androidaps.utils.FabricPrivacy; import info.nightscout.androidaps.utils.Round; +import info.nightscout.androidaps.utils.T; import info.nightscout.androidaps.utils.TimeChangeType; import info.nightscout.androidaps.utils.resources.ResourceHelper; import info.nightscout.androidaps.utils.rx.AapsSchedulers; import info.nightscout.androidaps.utils.sharedPreferences.SP; import io.reactivex.disposables.CompositeDisposable; -import static info.nightscout.androidaps.plugins.pump.omnipod.eros.driver.definition.OmnipodConstants.BASAL_STEP_DURATION; - /** * Created by andy on 23.04.18. * * @author Andy Rozman (andy.rozman@gmail.com) */ @Singleton -public class OmnipodErosPumpPlugin extends PumpPluginBase implements PumpInterface, RileyLinkPumpDevice { +public class OmnipodErosPumpPlugin extends PumpPluginBase implements Pump, RileyLinkPumpDevice { private static final long RILEY_LINK_CONNECT_TIMEOUT_MILLIS = 3 * 60 * 1_000L; // 3 minutes private static final long STATUS_CHECK_INTERVAL_MILLIS = 60 * 1_000L; // 1 minute public static final int STARTUP_STATUS_REQUEST_TRIES = 2; @@ -132,7 +132,7 @@ public class OmnipodErosPumpPlugin extends PumpPluginBase implements PumpInterfa private final AAPSLogger aapsLogger; private final AapsSchedulers aapsSchedulers; private final RxBusWrapper rxBus; - private final ActivePluginProvider activePlugin; + private final ActivePlugin activePlugin; private final Context context; private final FabricPrivacy fabricPrivacy; private final ResourceHelper resourceHelper; @@ -140,9 +140,10 @@ public class OmnipodErosPumpPlugin extends PumpPluginBase implements PumpInterfa private final DateUtil dateUtil; private final PumpDescription pumpDescription; private final ServiceConnection serviceConnection; - private final PumpType pumpType = PumpType.Omnipod_Eros; - private final CompositeDisposable disposables = new CompositeDisposable(); - private final NSUpload nsUpload; + private final PumpType pumpType = PumpType.OMNIPOD_EROS; + private final PumpSync pumpSync; + + private final CompositeDisposable disposable = new CompositeDisposable(); // variables for handling statuses and history private boolean firstRun = true; @@ -165,7 +166,7 @@ public class OmnipodErosPumpPlugin extends PumpPluginBase implements PumpInterfa RxBusWrapper rxBus, Context context, ResourceHelper resourceHelper, - ActivePluginProvider activePlugin, + ActivePlugin activePlugin, SP sp, PodStateManager podStateManager, AapsOmnipodErosManager aapsOmnipodErosManager, @@ -177,7 +178,7 @@ public class OmnipodErosPumpPlugin extends PumpPluginBase implements PumpInterfa RileyLinkUtil rileyLinkUtil, OmnipodAlertUtil omnipodAlertUtil, ProfileFunction profileFunction, - NSUpload nsUpload + PumpSync pumpSync ) { super(new PluginDescription() // .mainType(PluginType.PUMP) // @@ -204,7 +205,7 @@ public class OmnipodErosPumpPlugin extends PumpPluginBase implements PumpInterfa this.rileyLinkUtil = rileyLinkUtil; this.omnipodAlertUtil = omnipodAlertUtil; this.profileFunction = profileFunction; - this.nsUpload = nsUpload; + this.pumpSync = pumpSync; pumpDescription = new PumpDescription(pumpType); @@ -283,32 +284,32 @@ public class OmnipodErosPumpPlugin extends PumpPluginBase implements PumpInterfa Intent intent = new Intent(context, RileyLinkOmnipodService.class); context.bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE); - disposables.add(rxBus + disposable.add(rxBus .toObservable(EventAppExit.class) .observeOn(aapsSchedulers.getIo()) .subscribe(event -> context.unbindService(serviceConnection), fabricPrivacy::logException) ); - disposables.add(rxBus + disposable.add(rxBus .toObservable(EventOmnipodErosTbrChanged.class) .observeOn(aapsSchedulers.getIo()) .subscribe(event -> handleCancelledTbr(), fabricPrivacy::logException) ); - disposables.add(rxBus + disposable.add(rxBus .toObservable(EventOmnipodErosUncertainTbrRecovered.class) .observeOn(aapsSchedulers.getIo()) .subscribe(event -> handleUncertainTbrRecovery(), fabricPrivacy::logException) ); - disposables.add(rxBus + disposable.add(rxBus .toObservable(EventOmnipodErosActiveAlertsChanged.class) .observeOn(aapsSchedulers.getIo()) .subscribe(event -> handleActivePodAlerts(), fabricPrivacy::logException) ); - disposables.add(rxBus + disposable.add(rxBus .toObservable(EventOmnipodErosFaultEventChanged.class) .observeOn(aapsSchedulers.getIo()) .subscribe(event -> handlePodFaultEvent(), fabricPrivacy::logException) ); - disposables.add(rxBus + disposable.add(rxBus .toObservable(EventPreferenceChange.class) .observeOn(aapsSchedulers.getIo()) .subscribe(event -> { @@ -337,7 +338,7 @@ public class OmnipodErosPumpPlugin extends PumpPluginBase implements PumpInterfa } }, fabricPrivacy::logException) ); - disposables.add(rxBus + disposable.add(rxBus .toObservable(EventAppInitialized.class) .observeOn(aapsSchedulers.getIo()) .subscribe(event -> { @@ -349,8 +350,7 @@ public class OmnipodErosPumpPlugin extends PumpPluginBase implements PumpInterfa String activeBolusString = sp.getString(OmnipodErosStorageKeys.Preferences.ACTIVE_BOLUS, ""); aapsLogger.warn(LTag.PUMP, "Found active bolus in SP: {}. Adding Treatment.", activeBolusString); try { - ActiveBolus activeBolus = aapsOmnipodUtil.getGsonInstance().fromJson(activeBolusString, ActiveBolus.class); - aapsOmnipodErosManager.addBolusToHistory(activeBolus.toDetailedBolusInfo(aapsLogger)); + aapsOmnipodErosManager.addBolusToHistory(DetailedBolusInfo.Companion.fromJsonString(activeBolusString)); } catch (Exception ex) { aapsLogger.error(LTag.PUMP, "Failed to add active bolus to history", ex); } @@ -365,13 +365,14 @@ public class OmnipodErosPumpPlugin extends PumpPluginBase implements PumpInterfa } private void handleCancelledTbr() { - if (!podStateManager.isTempBasalRunning() && activePlugin.getActiveTreatments().isTempBasalInProgress() && !aapsOmnipodErosManager.hasSuspendedFakeTbr()) { + PumpSync.PumpState.TemporaryBasal tbr = pumpSync.expectedPumpState().getTemporaryBasal(); + if (!podStateManager.isTempBasalRunning() && tbr != null && !aapsOmnipodErosManager.hasSuspendedFakeTbr()) { aapsOmnipodErosManager.reportCancelledTbr(); } } private void handleUncertainTbrRecovery() { - TemporaryBasal tempBasal = activePlugin.getActiveTreatments().getTempBasalFromHistory(System.currentTimeMillis()); + PumpSync.PumpState.TemporaryBasal tempBasal = pumpSync.expectedPumpState().getTemporaryBasal(); if (podStateManager.isTempBasalRunning() && tempBasal == null) { if (podStateManager.hasTempBasal()) { @@ -379,14 +380,16 @@ public class OmnipodErosPumpPlugin extends PumpPluginBase implements PumpInterfa long pumpId = aapsOmnipodErosManager.addTbrSuccessToHistory(podStateManager.getTempBasalStartTime().getMillis(), new TempBasalPair(podStateManager.getTempBasalAmount(), false, (int) podStateManager.getTempBasalDuration().getStandardMinutes())); - TemporaryBasal temporaryBasal = new TemporaryBasal(getInjector()) // - .absolute(podStateManager.getTempBasalAmount()) // - .duration((int) podStateManager.getTempBasalDuration().getStandardMinutes()) - .date(podStateManager.getTempBasalStartTime().getMillis()) // - .source(Source.PUMP) // - .pumpId(pumpId); - - activePlugin.getActiveTreatments().addToHistoryTempBasal(temporaryBasal); + pumpSync.syncTemporaryBasalWithPumpId( + podStateManager.getTempBasalStartTime().getMillis(), + podStateManager.getTempBasalAmount(), + podStateManager.getTempBasalDuration().getMillis(), + true, + PumpSync.TemporaryBasalType.NORMAL, + pumpId, + PumpType.OMNIPOD_EROS, + serialNumber() + ); } else { // Not sure what's going on. Notify the user aapsLogger.error(LTag.PUMP, "Unknown TBR in both Pod state and AAPS"); @@ -394,7 +397,7 @@ public class OmnipodErosPumpPlugin extends PumpPluginBase implements PumpInterfa } } else if (!podStateManager.isTempBasalRunning() && tempBasal != null) { aapsLogger.warn(LTag.PUMP, "Removing AAPS TBR that actually hadn't succeeded"); - activePlugin.getActiveTreatments().removeTempBasal(tempBasal); + pumpSync.invalidateTemporaryBasal(tempBasal.getId()); } rxBus.send(new EventDismissNotification(Notification.OMNIPOD_TBR_ALERTS)); @@ -408,7 +411,7 @@ public class OmnipodErosPumpPlugin extends PumpPluginBase implements PumpInterfa String notificationText = resourceHelper.gq(R.plurals.omnipod_common_pod_alerts, activeAlerts.size(), alerts); Notification notification = new Notification(Notification.OMNIPOD_POD_ALERTS, notificationText, Notification.URGENT); rxBus.send(new EventNewNotification(notification)); - nsUpload.uploadError(notificationText); + pumpSync.insertAnnouncement(notificationText, null, PumpType.OMNIPOD_EROS, serialNumber()); if (aapsOmnipodErosManager.isAutomaticallyAcknowledgeAlertsEnabled() && !getCommandQueue().isCustomCommandInQueue(CommandAcknowledgeAlerts.class)) { queueAcknowledgeAlertsCommand(); @@ -420,7 +423,7 @@ public class OmnipodErosPumpPlugin extends PumpPluginBase implements PumpInterfa private void handlePodFaultEvent() { if (podStateManager.isPodFaulted()) { String notificationText = resourceHelper.gs(R.string.omnipod_common_pod_status_pod_fault_description, podStateManager.getFaultEventCode().getValue(), podStateManager.getFaultEventCode().name()); - nsUpload.uploadError(notificationText); + pumpSync.insertAnnouncement(notificationText, null, PumpType.OMNIPOD_EROS, serialNumber()); } } @@ -433,7 +436,7 @@ public class OmnipodErosPumpPlugin extends PumpPluginBase implements PumpInterfa context.unbindService(serviceConnection); - disposables.clear(); + disposable.clear(); } private void queueAcknowledgeAlertsCommand() { @@ -661,7 +664,7 @@ public class OmnipodErosPumpPlugin extends PumpPluginBase implements PumpInterfa // if false and the same rate is requested enacted=false and success=true is returned and TBR is not changed @Override @NonNull - public PumpEnactResult setTempBasalAbsolute(double absoluteRate, int durationInMinutes, @NonNull Profile profile, boolean enforceNew) { + public PumpEnactResult setTempBasalAbsolute(double absoluteRate, int durationInMinutes, @NonNull Profile profile, boolean enforceNew, @NonNull PumpSync.TemporaryBasalType tbrType) { aapsLogger.info(LTag.PUMP, "setTempBasalAbsolute: rate: {}, duration={}", absoluteRate, durationInMinutes); if (durationInMinutes <= 0 || durationInMinutes % BASAL_STEP_DURATION.getStandardMinutes() != 0) { @@ -669,15 +672,15 @@ public class OmnipodErosPumpPlugin extends PumpPluginBase implements PumpInterfa } // read current TBR - TemporaryBasal tbrCurrent = readTBR(); + PumpSync.PumpState.TemporaryBasal tbrCurrent = readTBR(); if (tbrCurrent != null) { aapsLogger.info(LTag.PUMP, "setTempBasalAbsolute: Current Basal: duration: {} min, rate={}", - tbrCurrent.durationInMinutes, tbrCurrent.absoluteRate); + T.msecs(tbrCurrent.getDuration()).mins(), tbrCurrent.getRate()); } if (tbrCurrent != null && !enforceNew) { - if (Round.isSame(tbrCurrent.absoluteRate, absoluteRate)) { + if (Round.isSame(tbrCurrent.getRate(), absoluteRate)) { aapsLogger.info(LTag.PUMP, "setTempBasalAbsolute - No enforceNew and same rate. Exiting."); return new PumpEnactResult(getInjector()).success(true).enacted(false); } @@ -697,7 +700,7 @@ public class OmnipodErosPumpPlugin extends PumpPluginBase implements PumpInterfa @Override @NonNull public PumpEnactResult cancelTempBasal(boolean enforceNew) { - TemporaryBasal tbrCurrent = readTBR(); + PumpSync.PumpState.TemporaryBasal tbrCurrent = readTBR(); if (tbrCurrent == null) { aapsLogger.info(LTag.PUMP, "cancelTempBasal - TBR already cancelled."); @@ -715,13 +718,14 @@ public class OmnipodErosPumpPlugin extends PumpPluginBase implements PumpInterfa return new JSONObject(); } + long now = System.currentTimeMillis(); JSONObject pump = new JSONObject(); JSONObject battery = new JSONObject(); JSONObject status = new JSONObject(); JSONObject extended = new JSONObject(); try { status.put("status", podStateManager.isPodRunning() ? (podStateManager.isSuspended() ? "suspended" : "normal") : "no active Pod"); - status.put("timestamp", DateUtil.toISOString(new Date())); + status.put("timestamp", dateUtil.toISOString(dateUtil.now())); battery.put("percent", getBatteryLevel()); @@ -731,22 +735,20 @@ public class OmnipodErosPumpPlugin extends PumpPluginBase implements PumpInterfa } catch (Exception ignored) { } - TemporaryBasal tb = activePlugin.getActiveTreatments().getRealTempBasalFromHistory(System.currentTimeMillis()); + PumpSync.PumpState.TemporaryBasal tb = pumpSync.expectedPumpState().getTemporaryBasal(); if (tb != null) { - extended.put("TempBasalAbsoluteRate", - tb.tempBasalConvertedToAbsolute(System.currentTimeMillis(), profile)); - extended.put("TempBasalStart", dateUtil.dateAndTimeString(tb.date)); - extended.put("TempBasalRemaining", tb.getPlannedRemainingMinutes()); + extended.put("TempBasalAbsoluteRate", convertedToAbsolute(tb, now, profile)); + extended.put("TempBasalStart", dateUtil.dateAndTimeString(tb.getTimestamp())); + extended.put("TempBasalRemaining", getPlannedRemainingMinutes(tb)); } - - ExtendedBolus eb = activePlugin.getActiveTreatments().getExtendedBolusFromHistory(System.currentTimeMillis()); + PumpSync.PumpState.ExtendedBolus eb = pumpSync.expectedPumpState().getExtendedBolus(); if (eb != null) { - extended.put("ExtendedBolusAbsoluteRate", eb.absoluteRate()); - extended.put("ExtendedBolusStart", dateUtil.dateAndTimeString(eb.date)); - extended.put("ExtendedBolusRemaining", eb.getPlannedRemainingMinutes()); + extended.put("ExtendedBolusAbsoluteRate", eb.getRate()); + extended.put("ExtendedBolusStart", dateUtil.dateAndTimeString(eb.getTimestamp())); + extended.put("ExtendedBolusRemaining", getPlannedRemainingMinutes(eb)); } - status.put("timestamp", DateUtil.toISOString(new Date())); + status.put("timestamp", dateUtil.toISOString(dateUtil.now())); if (isUseRileyLinkBatteryLevel()) { pump.put("battery", battery); @@ -763,7 +765,7 @@ public class OmnipodErosPumpPlugin extends PumpPluginBase implements PumpInterfa pump.put("reservoir", reservoirLevel); } - pump.put("clock", DateUtil.toISOString(podStateManager.getTime().toDate())); + pump.put("clock", dateUtil.toISOString(podStateManager.getTime().getMillis())); } catch (JSONException e) { aapsLogger.error(LTag.PUMP, "Unhandled exception", e); } @@ -804,14 +806,12 @@ public class OmnipodErosPumpPlugin extends PumpPluginBase implements PumpInterfa ret += resourceHelper.gs(R.string.omnipod_common_short_status_last_bolus, DecimalFormatter.INSTANCE.to2Decimal(podStateManager.getLastBolusAmount()), android.text.format.DateFormat.format("HH:mm", podStateManager.getLastBolusStartTime().toDate())) + "\n"; } - TemporaryBasal activeTemp = activePlugin.getActiveTreatments().getRealTempBasalFromHistory(System.currentTimeMillis()); - if (activeTemp != null) { - ret += resourceHelper.gs(R.string.omnipod_common_short_status_temp_basal, activeTemp.toStringFull()) + "\n"; + PumpSync.PumpState pumpState = pumpSync.expectedPumpState(); + if (pumpState.getTemporaryBasal() != null && pumpState.getProfile() != null) { + ret += resourceHelper.gs(R.string.omnipod_common_short_status_temp_basal, toStringFull(pumpState.getTemporaryBasal(), dateUtil) + "\n"); } - ExtendedBolus activeExtendedBolus = activePlugin.getActiveTreatments().getExtendedBolusFromHistory( - System.currentTimeMillis()); - if (activeExtendedBolus != null) { - ret += resourceHelper.gs(R.string.omnipod_common_short_status_extended_bolus, activeExtendedBolus.toString()) + "\n"; + if (pumpState.getExtendedBolus() != null) { + ret += resourceHelper.gs(R.string.omnipod_common_short_status_extended_bolus, toStringFull(pumpState.getExtendedBolus(), dateUtil) + "\n"); } ret += resourceHelper.gs(R.string.omnipod_common_short_status_reservoir, (getReservoirLevel() > OmnipodConstants.MAX_RESERVOIR_READING ? "50+" : DecimalFormatter.INSTANCE.to0Decimal(getReservoirLevel()))) + "\n"; if (isUseRileyLinkBatteryLevel()) { @@ -1027,14 +1027,14 @@ public class OmnipodErosPumpPlugin extends PumpPluginBase implements PumpInterfa aapsLogger.debug(LTag.PUMP, "stopConnecting [PumpPluginAbstract] - default (empty) implementation."); } - @NonNull @Override public PumpEnactResult setTempBasalPercent(int percent, int durationInMinutes, @NonNull Profile profile, boolean enforceNew) { + @NonNull @Override public PumpEnactResult setTempBasalPercent(int percent, int durationInMinutes, @NonNull Profile profile, boolean enforceNew, @NonNull PumpSync.TemporaryBasalType tbrType) { if (percent == 0) { - return setTempBasalAbsolute(0.0d, durationInMinutes, profile, enforceNew); + return setTempBasalAbsolute(0.0d, durationInMinutes, profile, enforceNew, tbrType); } else { double absoluteValue = profile.getBasal() * (percent / 100.0d); absoluteValue = pumpDescription.getPumpType().determineCorrectBasalSize(absoluteValue); aapsLogger.warn(LTag.PUMP, "setTempBasalPercent [OmnipodPumpPlugin] - You are trying to use setTempBasalPercent with percent other then 0% (" + percent + "). This will start setTempBasalAbsolute, with calculated value (" + absoluteValue + "). Result might not be 100% correct."); - return setTempBasalAbsolute(absoluteValue, durationInMinutes, profile, enforceNew); + return setTempBasalAbsolute(absoluteValue, durationInMinutes, profile, enforceNew, tbrType); } } @@ -1087,7 +1087,7 @@ public class OmnipodErosPumpPlugin extends PumpPluginBase implements PumpInterfa PumpEnactResult result = executeCommand(OmnipodCommandType.SET_BOLUS, () -> aapsOmnipodErosManager.bolus(detailedBolusInfo)); if (result.getSuccess()) { - incrementStatistics(detailedBolusInfo.isSMB ? OmnipodErosStorageKeys.Statistics.SMB_BOLUSES_DELIVERED + incrementStatistics(detailedBolusInfo.getBolusType() == DetailedBolusInfo.BolusType.SMB ? OmnipodErosStorageKeys.Statistics.SMB_BOLUSES_DELIVERED : OmnipodErosStorageKeys.Statistics.STANDARD_BOLUSES_DELIVERED); result.carbsDelivered(detailedBolusInfo.carbs); @@ -1131,8 +1131,8 @@ public class OmnipodErosPumpPlugin extends PumpPluginBase implements PumpInterfa sp.putLong(statsKey, currentCount); } - private TemporaryBasal readTBR() { - return activePlugin.getActiveTreatments().getTempBasalFromHistory(System.currentTimeMillis()); + @Nullable private PumpSync.PumpState.TemporaryBasal readTBR() { + return pumpSync.expectedPumpState().getTemporaryBasal(); } private PumpEnactResult getOperationNotSupportedWithCustomText(int resourceId) { diff --git a/omnipod-eros/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/eros/data/ActiveBolus.java b/omnipod-eros/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/eros/data/ActiveBolus.java index 171685878b..e69de29bb2 100644 --- a/omnipod-eros/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/eros/data/ActiveBolus.java +++ b/omnipod-eros/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/eros/data/ActiveBolus.java @@ -1,79 +0,0 @@ -package info.nightscout.androidaps.plugins.pump.omnipod.eros.data; - -import org.apache.commons.lang3.StringUtils; -import org.json.JSONException; -import org.json.JSONObject; - -import info.nightscout.androidaps.data.DetailedBolusInfo; -import info.nightscout.androidaps.logging.AAPSLogger; -import info.nightscout.androidaps.logging.LTag; - -// Used for storing active bolus during bolus, -// so we can recover it and add it to treatments after the app crashed or got killed -// Storing DetailedBolusInfo itself is no good because it contains a reference to Context -// and to JSONObject, which are both not serializable -// TODO add tests -public class ActiveBolus { - private long date; - private long lastKnownBolusTime; - private String eventType; - private double insulin; - private double carbs; - private int source; - private boolean isValid; - private double glucose; - private String glucoseType; - private int carbTime; - private String boluscalc; - private long pumpId; - private boolean isSMB; - private long deliverAt; - private String notes; - - public static ActiveBolus fromDetailedBolusInfo(DetailedBolusInfo detailedBolusInfo) { - ActiveBolus activeBolus = new ActiveBolus(); - activeBolus.date = detailedBolusInfo.date; - activeBolus.lastKnownBolusTime = detailedBolusInfo.lastKnownBolusTime; - activeBolus.eventType = detailedBolusInfo.eventType; - activeBolus.insulin = detailedBolusInfo.insulin; - activeBolus.carbs = detailedBolusInfo.carbs; - activeBolus.source = detailedBolusInfo.source; - activeBolus.isValid = detailedBolusInfo.isValid; - activeBolus.glucose = detailedBolusInfo.glucose; - activeBolus.glucoseType = detailedBolusInfo.glucoseType; - activeBolus.carbTime = detailedBolusInfo.carbTime; - activeBolus.boluscalc = detailedBolusInfo.boluscalc == null ? null : detailedBolusInfo.boluscalc.toString(); - activeBolus.pumpId = detailedBolusInfo.pumpId; - activeBolus.isSMB = detailedBolusInfo.isSMB; - activeBolus.deliverAt = detailedBolusInfo.deliverAt; - activeBolus.notes = detailedBolusInfo.notes; - return activeBolus; - } - - public DetailedBolusInfo toDetailedBolusInfo(AAPSLogger aapsLogger) { - DetailedBolusInfo detailedBolusInfo = new DetailedBolusInfo(); - detailedBolusInfo.date = date; - detailedBolusInfo.lastKnownBolusTime = lastKnownBolusTime; - detailedBolusInfo.eventType = eventType; - detailedBolusInfo.insulin = insulin; - detailedBolusInfo.carbs = carbs; - detailedBolusInfo.source = source; - detailedBolusInfo.isValid = isValid; - detailedBolusInfo.glucose = glucose; - detailedBolusInfo.glucoseType = glucoseType; - detailedBolusInfo.carbTime = carbTime; - if (!StringUtils.isEmpty(boluscalc)) { - try { - detailedBolusInfo.boluscalc = new JSONObject(boluscalc); - } catch (JSONException ex) { - // ignore - aapsLogger.warn(LTag.PUMP, "Could not parse bolusCalc string to JSON: " + boluscalc, ex); - } - } - detailedBolusInfo.pumpId = pumpId; - detailedBolusInfo.isSMB = isSMB; - detailedBolusInfo.deliverAt = deliverAt; - detailedBolusInfo.notes = notes; - return detailedBolusInfo; - } -} diff --git a/omnipod-eros/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/eros/manager/AapsOmnipodErosManager.java b/omnipod-eros/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/eros/manager/AapsOmnipodErosManager.java index 70317d68ac..d394747a58 100644 --- a/omnipod-eros/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/eros/manager/AapsOmnipodErosManager.java +++ b/omnipod-eros/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/eros/manager/AapsOmnipodErosManager.java @@ -18,30 +18,25 @@ import info.nightscout.androidaps.activities.ErrorHelperActivity; import info.nightscout.androidaps.data.DetailedBolusInfo; import info.nightscout.androidaps.data.Profile; import info.nightscout.androidaps.data.PumpEnactResult; -import info.nightscout.androidaps.database.AppRepository; -import info.nightscout.androidaps.database.entities.TherapyEvent; -import info.nightscout.androidaps.database.transactions.InsertTherapyEventIfNewTransaction; import info.nightscout.androidaps.db.OmnipodHistoryRecord; -import info.nightscout.androidaps.db.Source; -import info.nightscout.androidaps.db.TemporaryBasal; import info.nightscout.androidaps.events.Event; import info.nightscout.androidaps.events.EventRefreshOverview; -import info.nightscout.androidaps.interfaces.ActivePluginProvider; +import info.nightscout.androidaps.extensions.PumpStateExtensionKt; +import info.nightscout.androidaps.interfaces.ActivePlugin; import info.nightscout.androidaps.interfaces.DatabaseHelperInterface; +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; -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; import info.nightscout.androidaps.plugins.general.overview.events.EventOverviewBolusProgress; import info.nightscout.androidaps.plugins.general.overview.notifications.Notification; -import info.nightscout.androidaps.plugins.pump.common.data.TempBasalPair; import info.nightscout.androidaps.plugins.pump.common.defs.PumpType; +import info.nightscout.androidaps.plugins.pump.common.defs.TempBasalPair; import info.nightscout.androidaps.plugins.pump.common.utils.ByteUtil; import info.nightscout.androidaps.plugins.pump.omnipod.common.definition.OmnipodCommandType; import info.nightscout.androidaps.plugins.pump.omnipod.eros.R; -import info.nightscout.androidaps.plugins.pump.omnipod.eros.data.ActiveBolus; import info.nightscout.androidaps.plugins.pump.omnipod.eros.definition.OmnipodErosStorageKeys; import info.nightscout.androidaps.plugins.pump.omnipod.eros.definition.PodHistoryEntryType; import info.nightscout.androidaps.plugins.pump.omnipod.eros.driver.communication.message.response.StatusResponse; @@ -84,10 +79,10 @@ import info.nightscout.androidaps.plugins.pump.omnipod.eros.event.EventOmnipodEr import info.nightscout.androidaps.plugins.pump.omnipod.eros.rileylink.manager.OmnipodRileyLinkCommunicationManager; import info.nightscout.androidaps.plugins.pump.omnipod.eros.util.AapsOmnipodUtil; import info.nightscout.androidaps.plugins.pump.omnipod.eros.util.OmnipodAlertUtil; +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; -import io.reactivex.disposables.CompositeDisposable; import io.reactivex.subjects.SingleSubject; @Singleton @@ -99,14 +94,13 @@ public class AapsOmnipodErosManager { private final RxBusWrapper rxBus; private final ResourceHelper resourceHelper; private final HasAndroidInjector injector; - private final ActivePluginProvider activePlugin; + private final ActivePlugin activePlugin; private final SP sp; private final OmnipodManager delegate; private final DatabaseHelperInterface databaseHelper; private final OmnipodAlertUtil omnipodAlertUtil; - private final NSUpload nsUpload; private final Context context; - private final AppRepository repository; + private final PumpSync pumpSync; private boolean basalBeepsEnabled; private boolean bolusBeepsEnabled; @@ -123,9 +117,6 @@ public class AapsOmnipodErosManager { private boolean showRileyLinkBatteryLevel; private boolean batteryChangeLoggingEnabled; - private final CompositeDisposable disposable = new CompositeDisposable(); - private boolean aBoolean; - @Inject public AapsOmnipodErosManager(OmnipodRileyLinkCommunicationManager communicationService, PodStateManager podStateManager, @@ -136,12 +127,11 @@ public class AapsOmnipodErosManager { SP sp, ResourceHelper resourceHelper, HasAndroidInjector injector, - ActivePluginProvider activePlugin, + ActivePlugin activePlugin, DatabaseHelperInterface databaseHelper, OmnipodAlertUtil omnipodAlertUtil, - NSUpload nsUpload, Context context, - AppRepository repository) { + PumpSync pumpSync) { this.podStateManager = podStateManager; this.aapsOmnipodUtil = aapsOmnipodUtil; @@ -153,9 +143,8 @@ public class AapsOmnipodErosManager { this.activePlugin = activePlugin; this.databaseHelper = databaseHelper; this.omnipodAlertUtil = omnipodAlertUtil; - this.nsUpload = nsUpload; this.context = context; - this.repository = repository; + this.pumpSync = pumpSync; delegate = new OmnipodManager(aapsLogger, aapsSchedulers, communicationService, podStateManager); @@ -224,8 +213,8 @@ public class AapsOmnipodErosManager { addToHistory(System.currentTimeMillis(), PodHistoryEntryType.INSERT_CANNULA, result.getComment(), result.getSuccess()); if (result.getSuccess()) { - uploadCareportalEvent(System.currentTimeMillis() - 1000, TherapyEvent.Type.INSULIN_CHANGE); - uploadCareportalEvent(System.currentTimeMillis(), TherapyEvent.Type.CANNULA_CHANGE); + uploadCareportalEvent(System.currentTimeMillis() - 1000, DetailedBolusInfo.EventType.INSULIN_CHANGE); + uploadCareportalEvent(System.currentTimeMillis(), DetailedBolusInfo.EventType.CANNULA_CHANGE); dismissNotification(Notification.OMNIPOD_POD_NOT_ATTACHED); @@ -374,11 +363,11 @@ public class AapsOmnipodErosManager { public PumpEnactResult bolus(DetailedBolusInfo detailedBolusInfo) { OmnipodManager.BolusCommandResult bolusCommandResult; - boolean beepsEnabled = detailedBolusInfo.isSMB ? isSmbBeepsEnabled() : isBolusBeepsEnabled(); + boolean beepsEnabled = detailedBolusInfo.getBolusType() == DetailedBolusInfo.BolusType.SMB ? isSmbBeepsEnabled() : isBolusBeepsEnabled(); Date bolusStarted; try { - bolusCommandResult = executeCommand(() -> delegate.bolus(PumpType.Omnipod_Eros.determineCorrectBolusSize(detailedBolusInfo.insulin), beepsEnabled, beepsEnabled, detailedBolusInfo.isSMB ? null : + bolusCommandResult = executeCommand(() -> delegate.bolus(PumpType.OMNIPOD_EROS.determineCorrectBolusSize(detailedBolusInfo.insulin), beepsEnabled, beepsEnabled, detailedBolusInfo.getBolusType() == DetailedBolusInfo.BolusType.SMB ? null : (estimatedUnitsDelivered, percentage) -> { EventOverviewBolusProgress progressUpdateEvent = EventOverviewBolusProgress.INSTANCE; progressUpdateEvent.setStatus(getStringResource(R.string.bolusdelivering, detailedBolusInfo.insulin)); @@ -395,15 +384,16 @@ public class AapsOmnipodErosManager { if (OmnipodManager.CommandDeliveryStatus.UNCERTAIN_FAILURE.equals(bolusCommandResult.getCommandDeliveryStatus())) { // For safety reasons, we treat this as a bolus that has successfully been delivered, in order to prevent insulin overdose - if (detailedBolusInfo.isSMB) { + if (detailedBolusInfo.getBolusType() == DetailedBolusInfo.BolusType.SMB) { showNotification(Notification.OMNIPOD_UNCERTAIN_SMB, getStringResource(R.string.omnipod_eros_error_bolus_failed_uncertain_smb, detailedBolusInfo.insulin), Notification.URGENT, isNotificationUncertainSmbSoundEnabled() ? R.raw.boluserror : null); } else { showErrorDialog(getStringResource(R.string.omnipod_eros_error_bolus_failed_uncertain), isNotificationUncertainBolusSoundEnabled() ? R.raw.boluserror : null); } } - detailedBolusInfo.date = bolusStarted.getTime(); - detailedBolusInfo.source = Source.PUMP; + detailedBolusInfo.timestamp = bolusStarted.getTime(); + detailedBolusInfo.setPumpType(PumpType.OMNIPOD_EROS); + detailedBolusInfo.setPumpSerial(serialNumber()); // Store the current bolus for in case the app crashes, gets killed, the phone dies or whatever before the bolus finishes // If we have a stored value for the current bolus on startup, we'll create a Treatment for it @@ -423,8 +413,7 @@ public class AapsOmnipodErosManager { // // I discussed this with the AAPS team but nobody seems to care so we're stuck with this ugly workaround for now try { - ActiveBolus activeBolus = ActiveBolus.fromDetailedBolusInfo(detailedBolusInfo); - sp.putString(OmnipodErosStorageKeys.Preferences.ACTIVE_BOLUS, aapsOmnipodUtil.getGsonInstance().toJson(activeBolus)); + sp.putString(OmnipodErosStorageKeys.Preferences.ACTIVE_BOLUS, detailedBolusInfo.toJsonString()); aapsLogger.debug(LTag.PUMP, "Stored active bolus to SP for recovery"); } catch (Exception ex) { aapsLogger.error(LTag.PUMP, "Failed to store active bolus to SP", ex); @@ -490,7 +479,7 @@ public class AapsOmnipodErosManager { public PumpEnactResult setTemporaryBasal(TempBasalPair tempBasalPair) { boolean beepsEnabled = isTbrBeepsEnabled(); try { - executeCommand(() -> delegate.setTemporaryBasal(PumpType.Omnipod_Eros.determineCorrectBasalSize(tempBasalPair.getInsulinRate()), Duration.standardMinutes(tempBasalPair.getDurationMinutes()), beepsEnabled, beepsEnabled)); + executeCommand(() -> delegate.setTemporaryBasal(PumpType.OMNIPOD_EROS.determineCorrectBasalSize(tempBasalPair.getInsulinRate()), Duration.standardMinutes(tempBasalPair.getDurationMinutes()), beepsEnabled, beepsEnabled)); } catch (CommandFailedAfterChangingDeliveryStatusException ex) { String errorMessage = translateException(ex.getCause()); addFailureToHistory(PodHistoryEntryType.SET_TEMPORARY_BASAL, errorMessage); @@ -532,7 +521,7 @@ public class AapsOmnipodErosManager { return new PumpEnactResult(injector) .duration(tempBasalPair.getDurationMinutes()) - .absolute(PumpType.Omnipod_Eros.determineCorrectBasalSize(tempBasalPair.getInsulinRate())) + .absolute(PumpType.OMNIPOD_EROS.determineCorrectBasalSize(tempBasalPair.getInsulinRate())) .success(true).enacted(true); } @@ -552,13 +541,12 @@ public class AapsOmnipodErosManager { long pumpId = addSuccessToHistory(PodHistoryEntryType.CANCEL_TEMPORARY_BASAL, null); - TemporaryBasal tempBasal = new TemporaryBasal(injector) // - .date(System.currentTimeMillis()) // - .duration(0) // - .pumpId(pumpId) // - .source(Source.PUMP); - - activePlugin.getActiveTreatments().addToHistoryTempBasal(tempBasal); + pumpSync.syncStopTemporaryBasalWithPumpId( + System.currentTimeMillis(), + pumpId, + PumpType.OMNIPOD_EROS, + serialNumber() + ); sendEvent(new EventDismissNotification(Notification.OMNIPOD_TBR_ALERTS)); @@ -705,14 +693,17 @@ public class AapsOmnipodErosManager { public void addBolusToHistory(DetailedBolusInfo originalDetailedBolusInfo) { DetailedBolusInfo detailedBolusInfo = originalDetailedBolusInfo.copy(); - detailedBolusInfo.pumpId = addSuccessToHistory(detailedBolusInfo.date, PodHistoryEntryType.SET_BOLUS, detailedBolusInfo.insulin + ";" + detailedBolusInfo.carbs); + detailedBolusInfo.setBolusTimestamp(detailedBolusInfo.timestamp); + detailedBolusInfo.setPumpType(PumpType.OMNIPOD_EROS); + detailedBolusInfo.setPumpSerial(serialNumber()); + detailedBolusInfo.setBolusPumpId(addSuccessToHistory(detailedBolusInfo.timestamp, PodHistoryEntryType.SET_BOLUS, detailedBolusInfo.insulin + ";" + detailedBolusInfo.carbs)); if (detailedBolusInfo.carbs > 0 && detailedBolusInfo.carbTime > 0) { // split out a separate carbs record without a pumpId DetailedBolusInfo carbInfo = new DetailedBolusInfo(); - carbInfo.date = detailedBolusInfo.date + detailedBolusInfo.carbTime * 60L * 1000L; + carbInfo.setCarbsTimestamp(detailedBolusInfo.timestamp + detailedBolusInfo.carbTime * 60L * 1000L); carbInfo.carbs = detailedBolusInfo.carbs; - carbInfo.source = Source.USER; + carbInfo.setPumpType(PumpType.USER); activePlugin.getActiveTreatments().addToHistoryTreatment(carbInfo, false); // remove carbs from bolusInfo to not trigger any unwanted code paths in @@ -729,14 +720,16 @@ public class AapsOmnipodErosManager { long pumpId = addSuccessToHistory(System.currentTimeMillis(), PodHistoryEntryType.SET_FAKE_SUSPENDED_TEMPORARY_BASAL, null); - TemporaryBasal temporaryBasal = new TemporaryBasal(injector) // - .date(System.currentTimeMillis()) // - .absolute(0.0) // - .duration((int) OmnipodConstants.SERVICE_DURATION.getStandardMinutes()) // - .source(Source.PUMP) // - .pumpId(pumpId); - - activePlugin.getActiveTreatments().addToHistoryTempBasal(temporaryBasal); + pumpSync.syncTemporaryBasalWithPumpId( + System.currentTimeMillis(), + 0.0, + OmnipodConstants.SERVICE_DURATION.getMillis(), + true, + PumpSync.TemporaryBasalType.EMULATED_PUMP_SUSPEND, + pumpId, + PumpType.OMNIPOD_EROS, + serialNumber() + ); } } @@ -745,20 +738,19 @@ public class AapsOmnipodErosManager { aapsLogger.debug(LTag.PUMP, "Cancelling fake suspended TBR"); long pumpId = addSuccessToHistory(System.currentTimeMillis(), PodHistoryEntryType.CANCEL_FAKE_SUSPENDED_TEMPORARY_BASAL, null); - TemporaryBasal temporaryBasal = new TemporaryBasal(injector) // - .date(System.currentTimeMillis()) // - .duration(0) // - .source(Source.PUMP) // - .pumpId(pumpId); - - activePlugin.getActiveTreatments().addToHistoryTempBasal(temporaryBasal); + pumpSync.syncStopTemporaryBasalWithPumpId( + System.currentTimeMillis(), + pumpId, + PumpType.OMNIPOD_EROS, + serialNumber() + ); } } public boolean hasSuspendedFakeTbr() { - if (activePlugin.getActiveTreatments().isTempBasalInProgress()) { - TemporaryBasal tempBasal = activePlugin.getActiveTreatments().getTempBasalFromHistory(System.currentTimeMillis()); - OmnipodHistoryRecord historyRecord = databaseHelper.findOmnipodHistoryRecordByPumpId(tempBasal.pumpId); + PumpSync.PumpState pumpState = pumpSync.expectedPumpState(); + if (pumpState.getTemporaryBasal() != null && pumpState.getTemporaryBasal().getPumpId() != null) { + OmnipodHistoryRecord historyRecord = databaseHelper.findOmnipodHistoryRecordByPumpId(pumpState.getTemporaryBasal().getPumpId()); return historyRecord != null && PodHistoryEntryType.getByCode(historyRecord.getPodEntryTypeCode()).equals(PodHistoryEntryType.SET_FAKE_SUSPENDED_TEMPORARY_BASAL); } return false; @@ -773,13 +765,12 @@ public class AapsOmnipodErosManager { long pumpId = addSuccessToHistory(PodHistoryEntryType.CANCEL_TEMPORARY_BASAL_BY_DRIVER, null); - TemporaryBasal temporaryBasal = new TemporaryBasal(injector) // - .date(time) // - .duration(0) // - .source(Source.PUMP) // - .pumpId(pumpId); - - activePlugin.getActiveTreatments().addToHistoryTempBasal(temporaryBasal); + pumpSync.syncStopTemporaryBasalWithPumpId( + time, + pumpId, + PumpType.OMNIPOD_EROS, + serialNumber() + ); sendEvent(new EventRefreshOverview("AapsOmnipodManager.reportCancelledTbr()", false)); } @@ -790,39 +781,44 @@ public class AapsOmnipodErosManager { // Cancels current TBR and adds a new TBR for the remaining duration private void splitActiveTbr() { - TemporaryBasal previouslyRunningTempBasal = activePlugin.getActiveTreatments().getTempBasalFromHistory(System.currentTimeMillis()); + PumpSync.PumpState pumpState = pumpSync.expectedPumpState(); + PumpSync.PumpState.TemporaryBasal previouslyRunningTempBasal = pumpSync.expectedPumpState().getTemporaryBasal(); if (previouslyRunningTempBasal != null) { // Cancel the previously running TBR and start a NEW TBR here for the remaining duration, // so that we only cancel the remaining part when recovering from an uncertain failure in the cancellation - int minutesRemaining = previouslyRunningTempBasal.getPlannedRemainingMinutesRoundedUp(); + int minutesRemaining = PumpStateExtensionKt.getPlannedRemainingMinutesRoundedUp(previouslyRunningTempBasal); if (minutesRemaining > 0) { reportCancelledTbr(System.currentTimeMillis() - 1000); - TempBasalPair newTempBasalPair = new TempBasalPair(previouslyRunningTempBasal.absoluteRate, false, minutesRemaining); + TempBasalPair newTempBasalPair = new TempBasalPair(previouslyRunningTempBasal.getRate(), false, minutesRemaining); long pumpId = addSuccessToHistory(PodHistoryEntryType.SPLIT_TEMPORARY_BASAL, newTempBasalPair); - TemporaryBasal tempBasal = new TemporaryBasal(injector) // - .date(System.currentTimeMillis()) // - .absolute(previouslyRunningTempBasal.absoluteRate) - .duration(minutesRemaining) // - .pumpId(pumpId) // - .source(Source.PUMP); - - activePlugin.getActiveTreatments().addToHistoryTempBasal(tempBasal); + pumpSync.syncTemporaryBasalWithPumpId( + System.currentTimeMillis(), + previouslyRunningTempBasal.getRate(), + minutesRemaining, + true, + PumpSync.TemporaryBasalType.NORMAL, + pumpId, + PumpType.OMNIPOD_EROS, + serialNumber() + ); } } } private void addTempBasalTreatment(long time, long pumpId, TempBasalPair tempBasalPair) { - TemporaryBasal tempStart = new TemporaryBasal(injector) // - .date(time) // - .duration(tempBasalPair.getDurationMinutes()) // - .absolute(tempBasalPair.getInsulinRate()) // - .pumpId(pumpId) // - .source(Source.PUMP); - - activePlugin.getActiveTreatments().addToHistoryTempBasal(tempStart); + pumpSync.syncTemporaryBasalWithPumpId( + time, + tempBasalPair.getInsulinRate(), + T.mins(tempBasalPair.getDurationMinutes()).msecs(), + true, + PumpSync.TemporaryBasalType.NORMAL, + pumpId, + PumpType.OMNIPOD_EROS, + serialNumber() + ); } private long addSuccessToHistory(PodHistoryEntryType entryType, Object data) { @@ -995,19 +991,18 @@ public class AapsOmnipodErosManager { } List entries = new ArrayList<>(); for (Profile.ProfileValue basalValue : basalValues) { - entries.add(new BasalScheduleEntry(PumpType.Omnipod_Eros.determineCorrectBasalSize(basalValue.value), + entries.add(new BasalScheduleEntry(PumpType.OMNIPOD_EROS.determineCorrectBasalSize(basalValue.value), Duration.standardSeconds(basalValue.timeAsSeconds))); } return new BasalSchedule(entries); } - private void uploadCareportalEvent(long date, TherapyEvent.Type event) { - if (repository.getTherapyEventByTimestamp(event, date) != null) return; - disposable.add(repository.runTransactionForResult(new InsertTherapyEventIfNewTransaction(date, event, 0, null, sp.getString("careportal_enteredby", "AndroidAPS"), null, null, TherapyEvent.GlucoseUnit.MGDL)) - .subscribe( - result -> result.getInserted().forEach(nsUpload::uploadEvent), - error -> aapsLogger.error(LTag.DATABASE, "Error while saving therapy event", error) - )); + private void uploadCareportalEvent(long date, DetailedBolusInfo.EventType event) { + pumpSync.insertTherapyEventIfNewWithTimestamp(date, event, null, null, PumpType.OMNIPOD_EROS, Integer.toString(podStateManager.getAddress())); + } + + public String serialNumber() { + return podStateManager.isPodInitialized() ? String.valueOf(podStateManager.getAddress()) : "-"; } } diff --git a/omnipod-eros/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/eros/ui/ErosPodHistoryActivity.java b/omnipod-eros/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/eros/ui/ErosPodHistoryActivity.java index 77a71f6714..9ec2a3685a 100644 --- a/omnipod-eros/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/eros/ui/ErosPodHistoryActivity.java +++ b/omnipod-eros/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/eros/ui/ErosPodHistoryActivity.java @@ -29,7 +29,7 @@ import info.nightscout.androidaps.db.OmnipodHistoryRecord; import info.nightscout.androidaps.interfaces.DatabaseHelperInterface; import info.nightscout.androidaps.logging.AAPSLogger; import info.nightscout.androidaps.logging.LTag; -import info.nightscout.androidaps.plugins.pump.common.data.TempBasalPair; +import info.nightscout.androidaps.plugins.pump.common.defs.TempBasalPair; import info.nightscout.androidaps.plugins.pump.common.defs.PumpHistoryEntryGroup; import info.nightscout.androidaps.plugins.pump.common.defs.PumpType; import info.nightscout.androidaps.plugins.pump.common.utils.ProfileUtil; @@ -309,7 +309,7 @@ public class ErosPodHistoryActivity extends NoSplashAppCompatActivity { try { Profile.ProfileValue[] profileValuesArray = aapsOmnipodUtil.getGsonInstance().fromJson(data, Profile.ProfileValue[].class); - valueView.setText(ProfileUtil.getBasalProfilesDisplayable(profileValuesArray, PumpType.Omnipod_Eros)); + valueView.setText(ProfileUtil.getBasalProfilesDisplayable(profileValuesArray, PumpType.OMNIPOD_EROS)); } catch (Exception e) { aapsLogger.error(LTag.PUMP, "Problem parsing Profile json. Ex: {}, Data:\n{}", e.getMessage(), data); valueView.setText(""); diff --git a/omnipod-eros/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/eros/ui/ErosPodManagementActivity.kt b/omnipod-eros/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/eros/ui/ErosPodManagementActivity.kt index 95c3e7e586..3d16b252e6 100644 --- a/omnipod-eros/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/eros/ui/ErosPodManagementActivity.kt +++ b/omnipod-eros/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/eros/ui/ErosPodManagementActivity.kt @@ -29,7 +29,7 @@ import info.nightscout.androidaps.queue.Callback import info.nightscout.androidaps.queue.events.EventQueueChanged import info.nightscout.androidaps.utils.FabricPrivacy import info.nightscout.androidaps.utils.alertDialogs.OKDialog -import info.nightscout.androidaps.utils.extensions.toVisibility +import info.nightscout.androidaps.extensions.toVisibility import info.nightscout.androidaps.utils.rx.AapsSchedulers import info.nightscout.androidaps.utils.ui.UIRunnable import io.reactivex.disposables.CompositeDisposable diff --git a/omnipod-eros/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/eros/ui/OmnipodErosOverviewFragment.kt b/omnipod-eros/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/eros/ui/OmnipodErosOverviewFragment.kt index 356f3d0444..fe2bd876a2 100644 --- a/omnipod-eros/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/eros/ui/OmnipodErosOverviewFragment.kt +++ b/omnipod-eros/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/eros/ui/OmnipodErosOverviewFragment.kt @@ -13,7 +13,7 @@ import dagger.android.support.DaggerFragment import info.nightscout.androidaps.Constants import info.nightscout.androidaps.activities.ErrorHelperActivity import info.nightscout.androidaps.events.EventPreferenceChange -import info.nightscout.androidaps.interfaces.ActivePluginProvider +import info.nightscout.androidaps.interfaces.ActivePlugin import info.nightscout.androidaps.interfaces.CommandQueueProvider import info.nightscout.androidaps.plugins.bus.RxBusWrapper import info.nightscout.androidaps.plugins.general.overview.events.EventDismissNotification @@ -72,7 +72,7 @@ class OmnipodErosOverviewFragment : DaggerFragment() { @Inject lateinit var resourceHelper: ResourceHelper @Inject lateinit var rxBus: RxBusWrapper @Inject lateinit var commandQueue: CommandQueueProvider - @Inject lateinit var activePlugin: ActivePluginProvider + @Inject lateinit var activePlugin: ActivePlugin @Inject lateinit var omnipodErosPumpPlugin: OmnipodErosPumpPlugin @Inject lateinit var podStateManager: PodStateManager @Inject lateinit var sp: SP @@ -567,13 +567,13 @@ class OmnipodErosOverviewFragment : DaggerFragment() { val timeAsJavaData = time.toLocalDateTime().toDate() val timeZone = podStateManager.timeZone.toTimeZone() if (timeZone == TimeZone.getDefault()) { - return dateUtil.dateAndTimeString(timeAsJavaData) + return dateUtil.dateAndTimeString(timeAsJavaData.time) } val isDaylightTime = timeZone.inDaylightTime(timeAsJavaData) val locale = resources.configuration.locales.get(0) val timeZoneDisplayName = timeZone.getDisplayName(isDaylightTime, TimeZone.SHORT, locale) + " " + timeZone.getDisplayName(isDaylightTime, TimeZone.LONG, locale) - return resourceHelper.gs(R.string.omnipod_common_time_with_timezone, dateUtil.dateAndTimeString(timeAsJavaData), timeZoneDisplayName) + return resourceHelper.gs(R.string.omnipod_common_time_with_timezone, dateUtil.dateAndTimeString(timeAsJavaData.time), timeZoneDisplayName) } private fun readableDuration(dateTime: DateTime): String { diff --git a/omnipod-eros/src/test/java/info/nightscout/androidaps/plugins/pump/omnipod/eros/OmnipodErosPumpPluginTest.java b/omnipod-eros/src/test/java/info/nightscout/androidaps/plugins/pump/omnipod/eros/OmnipodErosPumpPluginTest.java index 0d09c36f57..bb0ba03b19 100644 --- a/omnipod-eros/src/test/java/info/nightscout/androidaps/plugins/pump/omnipod/eros/OmnipodErosPumpPluginTest.java +++ b/omnipod-eros/src/test/java/info/nightscout/androidaps/plugins/pump/omnipod/eros/OmnipodErosPumpPluginTest.java @@ -1,5 +1,12 @@ package info.nightscout.androidaps.plugins.pump.omnipod.eros; +import static org.junit.Assert.assertEquals; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.anyLong; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + import android.os.Looper; import org.joda.time.DateTimeZone; @@ -18,26 +25,19 @@ import java.util.ArrayList; import dagger.android.HasAndroidInjector; import info.nightscout.androidaps.data.Profile; import info.nightscout.androidaps.data.PumpEnactResult; -import info.nightscout.androidaps.interfaces.ActivePluginProvider; +import info.nightscout.androidaps.interfaces.ActivePlugin; import info.nightscout.androidaps.interfaces.CommandQueueProvider; +import info.nightscout.androidaps.interfaces.PumpSync; import info.nightscout.androidaps.logging.AAPSLogger; import info.nightscout.androidaps.logging.AAPSLoggerTest; import info.nightscout.androidaps.plugins.bus.RxBusWrapper; -import info.nightscout.androidaps.plugins.pump.common.data.TempBasalPair; import info.nightscout.androidaps.plugins.pump.common.defs.PumpType; +import info.nightscout.androidaps.plugins.pump.common.defs.TempBasalPair; import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.RileyLinkUtil; import info.nightscout.androidaps.plugins.pump.omnipod.eros.manager.AapsOmnipodErosManager; import info.nightscout.androidaps.utils.resources.ResourceHelper; import info.nightscout.androidaps.utils.rx.TestAapsSchedulers; -import static info.nightscout.androidaps.plugins.pump.omnipod.eros.driver.definition.OmnipodConstants.BASAL_STEP_DURATION; -import static org.junit.Assert.assertEquals; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyInt; -import static org.mockito.ArgumentMatchers.anyLong; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - @RunWith(PowerMockRunner.class) public class OmnipodErosPumpPluginTest { @@ -46,10 +46,11 @@ public class OmnipodErosPumpPluginTest { AAPSLogger aapsLogger = new AAPSLoggerTest(); RxBusWrapper rxBusWrapper = new RxBusWrapper(new TestAapsSchedulers()); @Mock ResourceHelper resourceHelper; - @Mock(answer = Answers.RETURNS_DEEP_STUBS) ActivePluginProvider activePluginProvider; + @Mock(answer = Answers.RETURNS_DEEP_STUBS) ActivePlugin activePlugin; @Mock AapsOmnipodErosManager aapsOmnipodErosManager; @Mock CommandQueueProvider commandQueueProvider; @Mock RileyLinkUtil rileyLinkUtil; + @Mock PumpSync pumpSync; @Before public void prepare() { @@ -65,11 +66,12 @@ public class OmnipodErosPumpPluginTest { // mock all the things PowerMockito.mockStatic(Looper.class); OmnipodErosPumpPlugin plugin = new OmnipodErosPumpPlugin(injector, aapsLogger, new TestAapsSchedulers(), rxBusWrapper, null, - resourceHelper, activePluginProvider, null, null, aapsOmnipodErosManager, commandQueueProvider, + resourceHelper, activePlugin, null, null, aapsOmnipodErosManager, commandQueueProvider, null, null, null, null, - rileyLinkUtil, null, null, null + rileyLinkUtil, null, null, pumpSync ); - when(activePluginProvider.getActiveTreatments().getTempBasalFromHistory(anyLong())).thenReturn(null); + PumpSync.PumpState pumpState = new PumpSync.PumpState(null, null, null, null); + when(pumpSync.expectedPumpState()).thenReturn(pumpState); when(rileyLinkUtil.getRileyLinkHistory()).thenReturn(new ArrayList<>()); when(injector.androidInjector()).thenReturn(instance -> { }); @@ -90,11 +92,11 @@ public class OmnipodErosPumpPluginTest { // Given standard basal when(profile.getBasal()).thenReturn(0.5d); // When - PumpEnactResult result1 = plugin.setTempBasalPercent(80, 30, profile, false); - PumpEnactResult result2 = plugin.setTempBasalPercent(5000, 30000, profile, false); - PumpEnactResult result3 = plugin.setTempBasalPercent(0, 30, profile, false); - PumpEnactResult result4 = plugin.setTempBasalPercent(0, 0, profile, false); - PumpEnactResult result5 = plugin.setTempBasalPercent(-50, 60, profile, false); + PumpEnactResult result1 = plugin.setTempBasalPercent(80, 30, profile, false, PumpSync.TemporaryBasalType.NORMAL); + PumpEnactResult result2 = plugin.setTempBasalPercent(5000, 30000, profile, false, PumpSync.TemporaryBasalType.NORMAL); + PumpEnactResult result3 = plugin.setTempBasalPercent(0, 30, profile, false, PumpSync.TemporaryBasalType.NORMAL); + PumpEnactResult result4 = plugin.setTempBasalPercent(0, 0, profile, false, PumpSync.TemporaryBasalType.NORMAL); + PumpEnactResult result5 = plugin.setTempBasalPercent(-50, 60, profile, false, PumpSync.TemporaryBasalType.NORMAL); // Then return correct values assertEquals(result1.getAbsolute(), 0.4d, 0.01d); assertEquals(result1.getDuration(), 30); @@ -111,8 +113,8 @@ public class OmnipodErosPumpPluginTest { // Given zero basal when(profile.getBasal()).thenReturn(0d); // When - result1 = plugin.setTempBasalPercent(8000, 90, profile, false); - result2 = plugin.setTempBasalPercent(0, 0, profile, false); + result1 = plugin.setTempBasalPercent(8000, 90, profile, false, PumpSync.TemporaryBasalType.NORMAL); + result2 = plugin.setTempBasalPercent(0, 0, profile, false, PumpSync.TemporaryBasalType.NORMAL); // Then return zero values assertEquals(result1.getAbsolute(), 0d, 0.01d); assertEquals(result1.getDuration(), 90); @@ -122,15 +124,15 @@ public class OmnipodErosPumpPluginTest { // Given unhealthy basal when(profile.getBasal()).thenReturn(500d); // When treatment - result1 = plugin.setTempBasalPercent(80, 30, profile, false); + result1 = plugin.setTempBasalPercent(80, 30, profile, false, PumpSync.TemporaryBasalType.NORMAL); // Then return sane values - assertEquals(result1.getAbsolute(), PumpType.Omnipod_Eros.determineCorrectBasalSize(500d * 0.8), 0.01d); + assertEquals(result1.getAbsolute(), PumpType.OMNIPOD_EROS.determineCorrectBasalSize(500d * 0.8), 0.01d); assertEquals(result1.getDuration(), 30); // Given weird basal when(profile.getBasal()).thenReturn(1.234567d); // When treatment - result1 = plugin.setTempBasalPercent(280, 600, profile, false); + result1 = plugin.setTempBasalPercent(280, 600, profile, false, PumpSync.TemporaryBasalType.NORMAL); // Then return sane values assertEquals(result1.getAbsolute(), 3.4567876, 0.01d); assertEquals(result1.getDuration(), 600); @@ -138,7 +140,7 @@ public class OmnipodErosPumpPluginTest { // Given negative basal when(profile.getBasal()).thenReturn(-1.234567d); // When treatment - result1 = plugin.setTempBasalPercent(280, 510, profile, false); + result1 = plugin.setTempBasalPercent(280, 510, profile, false, PumpSync.TemporaryBasalType.NORMAL); // Then return negative value (this is validated further downstream, see TempBasalExtraCommand) assertEquals(result1.getAbsolute(), -3.4567876, 0.01d); assertEquals(result1.getDuration(), 510); diff --git a/rileylink/src/main/java/info/nightscout/androidaps/plugins/pump/common/defs/PumpDeviceState.kt b/rileylink/src/main/java/info/nightscout/androidaps/plugins/pump/common/defs/PumpDeviceState.kt new file mode 100644 index 0000000000..b41a6bd4c1 --- /dev/null +++ b/rileylink/src/main/java/info/nightscout/androidaps/plugins/pump/common/defs/PumpDeviceState.kt @@ -0,0 +1,17 @@ +package info.nightscout.androidaps.plugins.pump.common.defs + +import info.nightscout.androidaps.core.R + +enum class PumpDeviceState(var resourceId: Int) { + + NeverContacted(R.string.pump_status_never_contacted), + Sleeping(R.string.pump_status_sleeping), + WakingUp(R.string.pump_status_waking_up), + Active(R.string.pump_status_active), + ErrorWhenCommunicating(R.string.pump_status_error_comm), + TimeoutWhenCommunicating(R.string.pump_status_timeout_comm), + + // ProblemContacting(R.string.medtronic_pump_status_problem_contacting), + PumpUnreachable(R.string.pump_status_pump_unreachable), + InvalidConfiguration(R.string.pump_status_invalid_config); +} \ No newline at end of file diff --git a/core/src/main/java/info/nightscout/androidaps/plugins/pump/common/defs/PumpHistoryEntryGroup.java b/rileylink/src/main/java/info/nightscout/androidaps/plugins/pump/common/defs/PumpHistoryEntryGroup.java similarity index 100% rename from core/src/main/java/info/nightscout/androidaps/plugins/pump/common/defs/PumpHistoryEntryGroup.java rename to rileylink/src/main/java/info/nightscout/androidaps/plugins/pump/common/defs/PumpHistoryEntryGroup.java diff --git a/rileylink/src/main/java/info/nightscout/androidaps/plugins/pump/common/defs/TempBasalPair.kt b/rileylink/src/main/java/info/nightscout/androidaps/plugins/pump/common/defs/TempBasalPair.kt new file mode 100644 index 0000000000..320be53927 --- /dev/null +++ b/rileylink/src/main/java/info/nightscout/androidaps/plugins/pump/common/defs/TempBasalPair.kt @@ -0,0 +1,32 @@ +package info.nightscout.androidaps.plugins.pump.common.defs + +import com.google.gson.annotations.Expose + +open class TempBasalPair { + + @Expose var insulinRate = 0.0 + @Expose var durationMinutes = 0 + @Expose var isPercent = false + private var start: Long? = null + private var end: Long? = null + + constructor() + constructor(insulinRate: Double, isPercent: Boolean, durationMinutes: Int) { + this.insulinRate = insulinRate + this.isPercent = isPercent + this.durationMinutes = durationMinutes + } + + fun setStartTime(startTime: Long?) { + start = startTime + } + + fun setEndTime(endTime: Long?) { + end = endTime + } + + override fun toString(): String { + return ("TempBasalPair [" + "Rate=" + insulinRate + ", DurationMinutes=" + durationMinutes + ", IsPercent=" + + isPercent + "]") + } +} \ No newline at end of file diff --git a/core/src/main/java/info/nightscout/androidaps/plugins/pump/common/dialog/RefreshableInterface.java b/rileylink/src/main/java/info/nightscout/androidaps/plugins/pump/common/dialog/RefreshableInterface.java similarity index 100% rename from core/src/main/java/info/nightscout/androidaps/plugins/pump/common/dialog/RefreshableInterface.java rename to rileylink/src/main/java/info/nightscout/androidaps/plugins/pump/common/dialog/RefreshableInterface.java diff --git a/rileylink/src/main/java/info/nightscout/androidaps/plugins/pump/common/dialog/RileyLinkBLEConfigActivity.java b/rileylink/src/main/java/info/nightscout/androidaps/plugins/pump/common/dialog/RileyLinkBLEConfigActivity.java index 7a65e186ee..3f2482c2cc 100644 --- a/rileylink/src/main/java/info/nightscout/androidaps/plugins/pump/common/dialog/RileyLinkBLEConfigActivity.java +++ b/rileylink/src/main/java/info/nightscout/androidaps/plugins/pump/common/dialog/RileyLinkBLEConfigActivity.java @@ -32,7 +32,7 @@ import java.util.Map; import javax.inject.Inject; import info.nightscout.androidaps.activities.NoSplashAppCompatActivity; -import info.nightscout.androidaps.interfaces.ActivePluginProvider; +import info.nightscout.androidaps.interfaces.ActivePlugin; import info.nightscout.androidaps.logging.AAPSLogger; import info.nightscout.androidaps.logging.LTag; import info.nightscout.androidaps.plugins.pump.common.R; @@ -52,7 +52,7 @@ public class RileyLinkBLEConfigActivity extends NoSplashAppCompatActivity { @Inject ResourceHelper resourceHelper; @Inject BlePreCheck blePrecheck; @Inject RileyLinkUtil rileyLinkUtil; - @Inject ActivePluginProvider activePlugin; + @Inject ActivePlugin activePlugin; private static final String TAG = "RileyLinkBLEConfigActivity"; private static final long SCAN_PERIOD_MILLIS = 15_000; diff --git a/core/src/main/java/info/nightscout/androidaps/plugins/pump/common/events/EventRefreshButtonState.kt b/rileylink/src/main/java/info/nightscout/androidaps/plugins/pump/common/events/EventRefreshButtonState.kt similarity index 100% rename from core/src/main/java/info/nightscout/androidaps/plugins/pump/common/events/EventRefreshButtonState.kt rename to rileylink/src/main/java/info/nightscout/androidaps/plugins/pump/common/events/EventRefreshButtonState.kt diff --git a/rileylink/src/main/java/info/nightscout/androidaps/plugins/pump/common/hw/rileylink/RileyLinkCommunicationManager.java b/rileylink/src/main/java/info/nightscout/androidaps/plugins/pump/common/hw/rileylink/RileyLinkCommunicationManager.java index 0a88d5b510..fcaf8e3bcd 100644 --- a/rileylink/src/main/java/info/nightscout/androidaps/plugins/pump/common/hw/rileylink/RileyLinkCommunicationManager.java +++ b/rileylink/src/main/java/info/nightscout/androidaps/plugins/pump/common/hw/rileylink/RileyLinkCommunicationManager.java @@ -5,7 +5,7 @@ import java.util.Locale; import javax.inject.Inject; import dagger.android.HasAndroidInjector; -import info.nightscout.androidaps.interfaces.ActivePluginProvider; +import info.nightscout.androidaps.interfaces.ActivePlugin; import info.nightscout.androidaps.logging.AAPSLogger; import info.nightscout.androidaps.logging.LTag; import info.nightscout.androidaps.plugins.pump.common.defs.PumpDeviceState; @@ -39,7 +39,7 @@ public abstract class RileyLinkCommunicationManager { @Inject protected ServiceTaskExecutor serviceTaskExecutor; @Inject protected RFSpy rfspy; @Inject protected HasAndroidInjector injector; - @Inject protected ActivePluginProvider activePluginProvider; + @Inject protected ActivePlugin activePlugin; private final int SCAN_TIMEOUT = 1500; private final int ALLOWED_PUMP_UNREACHABLE = 10 * 60 * 1000; // 10 minutes @@ -427,7 +427,7 @@ public abstract class RileyLinkCommunicationManager { } private RileyLinkPumpDevice getPumpDevice() { - return (RileyLinkPumpDevice) activePluginProvider.getActivePump(); + return (RileyLinkPumpDevice) activePlugin.getActivePump(); } public abstract boolean isDeviceReachable(); diff --git a/rileylink/src/main/java/info/nightscout/androidaps/plugins/pump/common/hw/rileylink/dialog/RileyLinkStatusGeneralFragment.java b/rileylink/src/main/java/info/nightscout/androidaps/plugins/pump/common/hw/rileylink/dialog/RileyLinkStatusGeneralFragment.java index e9dddd92f6..2ae48e3f5a 100644 --- a/rileylink/src/main/java/info/nightscout/androidaps/plugins/pump/common/hw/rileylink/dialog/RileyLinkStatusGeneralFragment.java +++ b/rileylink/src/main/java/info/nightscout/androidaps/plugins/pump/common/hw/rileylink/dialog/RileyLinkStatusGeneralFragment.java @@ -13,7 +13,7 @@ import java.util.Optional; import javax.inject.Inject; import dagger.android.support.DaggerFragment; -import info.nightscout.androidaps.interfaces.ActivePluginProvider; +import info.nightscout.androidaps.interfaces.ActivePlugin; import info.nightscout.androidaps.logging.AAPSLogger; import info.nightscout.androidaps.plugins.pump.common.R; import info.nightscout.androidaps.plugins.pump.common.dialog.RefreshableInterface; @@ -35,7 +35,7 @@ public class RileyLinkStatusGeneralFragment extends DaggerFragment implements Re private static final String PLACEHOLDER = "-"; - @Inject ActivePluginProvider activePlugin; + @Inject ActivePlugin activePlugin; @Inject ResourceHelper resourceHelper; @Inject AAPSLogger aapsLogger; @Inject RileyLinkServiceData rileyLinkServiceData; diff --git a/rileylink/src/main/java/info/nightscout/androidaps/plugins/pump/common/hw/rileylink/service/RileyLinkBluetoothStateReceiver.kt b/rileylink/src/main/java/info/nightscout/androidaps/plugins/pump/common/hw/rileylink/service/RileyLinkBluetoothStateReceiver.kt index 54e2f59cbd..a72093cc98 100644 --- a/rileylink/src/main/java/info/nightscout/androidaps/plugins/pump/common/hw/rileylink/service/RileyLinkBluetoothStateReceiver.kt +++ b/rileylink/src/main/java/info/nightscout/androidaps/plugins/pump/common/hw/rileylink/service/RileyLinkBluetoothStateReceiver.kt @@ -5,7 +5,7 @@ import android.content.Context import android.content.Intent import android.content.IntentFilter import dagger.android.DaggerBroadcastReceiver -import info.nightscout.androidaps.interfaces.ActivePluginProvider +import info.nightscout.androidaps.interfaces.ActivePlugin import info.nightscout.androidaps.logging.AAPSLogger import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.RileyLinkConst import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.RileyLinkUtil @@ -13,7 +13,7 @@ import javax.inject.Inject class RileyLinkBluetoothStateReceiver : DaggerBroadcastReceiver() { @Inject lateinit var aapsLogger: AAPSLogger - @Inject lateinit var activePlugin: ActivePluginProvider + @Inject lateinit var activePlugin: ActivePlugin @Inject lateinit var rileyLinkUtil: RileyLinkUtil override fun onReceive(context: Context, intent: Intent) { diff --git a/rileylink/src/main/java/info/nightscout/androidaps/plugins/pump/common/hw/rileylink/service/RileyLinkBroadcastReceiver.java b/rileylink/src/main/java/info/nightscout/androidaps/plugins/pump/common/hw/rileylink/service/RileyLinkBroadcastReceiver.java index dbe2731e89..096b1e0b20 100644 --- a/rileylink/src/main/java/info/nightscout/androidaps/plugins/pump/common/hw/rileylink/service/RileyLinkBroadcastReceiver.java +++ b/rileylink/src/main/java/info/nightscout/androidaps/plugins/pump/common/hw/rileylink/service/RileyLinkBroadcastReceiver.java @@ -20,7 +20,7 @@ import javax.inject.Inject; import dagger.android.DaggerBroadcastReceiver; import dagger.android.HasAndroidInjector; -import info.nightscout.androidaps.interfaces.ActivePluginProvider; +import info.nightscout.androidaps.interfaces.ActivePlugin; import info.nightscout.androidaps.logging.AAPSLogger; import info.nightscout.androidaps.logging.LTag; import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.RileyLinkConst; @@ -47,7 +47,7 @@ public class RileyLinkBroadcastReceiver extends DaggerBroadcastReceiver { @Inject AAPSLogger aapsLogger; @Inject RileyLinkServiceData rileyLinkServiceData; @Inject ServiceTaskExecutor serviceTaskExecutor; - @Inject ActivePluginProvider activePlugin; + @Inject ActivePlugin activePlugin; RileyLinkService serviceInstance; protected Map> broadcastIdentifiers = null; diff --git a/rileylink/src/main/java/info/nightscout/androidaps/plugins/pump/common/hw/rileylink/service/RileyLinkService.java b/rileylink/src/main/java/info/nightscout/androidaps/plugins/pump/common/hw/rileylink/service/RileyLinkService.java index 5c8e47d74a..c1c4bebc3b 100644 --- a/rileylink/src/main/java/info/nightscout/androidaps/plugins/pump/common/hw/rileylink/service/RileyLinkService.java +++ b/rileylink/src/main/java/info/nightscout/androidaps/plugins/pump/common/hw/rileylink/service/RileyLinkService.java @@ -12,7 +12,7 @@ import javax.inject.Inject; import dagger.android.DaggerService; import dagger.android.HasAndroidInjector; -import info.nightscout.androidaps.interfaces.ActivePluginProvider; +import info.nightscout.androidaps.interfaces.ActivePlugin; import info.nightscout.androidaps.logging.AAPSLogger; import info.nightscout.androidaps.logging.LTag; import info.nightscout.androidaps.plugins.bus.RxBusWrapper; @@ -43,7 +43,7 @@ public abstract class RileyLinkService extends DaggerService { @Inject protected HasAndroidInjector injector; @Inject protected ResourceHelper resourceHelper; @Inject protected RileyLinkServiceData rileyLinkServiceData; - @Inject protected ActivePluginProvider activePlugin; + @Inject protected ActivePlugin activePlugin; @Inject protected RileyLinkBLE rileyLinkBLE; // android-bluetooth management @Inject protected RFSpy rfspy; // interface for RL xxx Mhz radio. diff --git a/rileylink/src/main/java/info/nightscout/androidaps/plugins/pump/common/hw/rileylink/service/RileyLinkServiceData.java b/rileylink/src/main/java/info/nightscout/androidaps/plugins/pump/common/hw/rileylink/service/RileyLinkServiceData.java index 7b68549902..249c94d74b 100644 --- a/rileylink/src/main/java/info/nightscout/androidaps/plugins/pump/common/hw/rileylink/service/RileyLinkServiceData.java +++ b/rileylink/src/main/java/info/nightscout/androidaps/plugins/pump/common/hw/rileylink/service/RileyLinkServiceData.java @@ -5,7 +5,7 @@ import java.util.Locale; import javax.inject.Inject; import javax.inject.Singleton; -import info.nightscout.androidaps.interfaces.ActivePluginProvider; +import info.nightscout.androidaps.interfaces.ActivePlugin; import info.nightscout.androidaps.logging.AAPSLogger; import info.nightscout.androidaps.logging.LTag; import info.nightscout.androidaps.plugins.bus.RxBusWrapper; @@ -29,7 +29,7 @@ public class RileyLinkServiceData { @Inject AAPSLogger aapsLogger; @Inject RileyLinkUtil rileyLinkUtil; @Inject RxBusWrapper rxBus; - @Inject ActivePluginProvider activePlugin; + @Inject ActivePlugin activePlugin; boolean tuneUpDone = false; public RileyLinkError rileyLinkError; diff --git a/rileylink/src/main/java/info/nightscout/androidaps/plugins/pump/common/hw/rileylink/service/tasks/DiscoverGattServicesTask.java b/rileylink/src/main/java/info/nightscout/androidaps/plugins/pump/common/hw/rileylink/service/tasks/DiscoverGattServicesTask.java index d0916911ea..06ea7e3831 100644 --- a/rileylink/src/main/java/info/nightscout/androidaps/plugins/pump/common/hw/rileylink/service/tasks/DiscoverGattServicesTask.java +++ b/rileylink/src/main/java/info/nightscout/androidaps/plugins/pump/common/hw/rileylink/service/tasks/DiscoverGattServicesTask.java @@ -3,7 +3,6 @@ package info.nightscout.androidaps.plugins.pump.common.hw.rileylink.service.task import javax.inject.Inject; import dagger.android.HasAndroidInjector; -import info.nightscout.androidaps.interfaces.ActivePluginProvider; import info.nightscout.androidaps.logging.AAPSLogger; import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.defs.RileyLinkPumpDevice; diff --git a/rileylink/src/main/java/info/nightscout/androidaps/plugins/pump/common/hw/rileylink/service/tasks/ResetRileyLinkConfigurationTask.java b/rileylink/src/main/java/info/nightscout/androidaps/plugins/pump/common/hw/rileylink/service/tasks/ResetRileyLinkConfigurationTask.java index 45e16b6487..28a56795a7 100644 --- a/rileylink/src/main/java/info/nightscout/androidaps/plugins/pump/common/hw/rileylink/service/tasks/ResetRileyLinkConfigurationTask.java +++ b/rileylink/src/main/java/info/nightscout/androidaps/plugins/pump/common/hw/rileylink/service/tasks/ResetRileyLinkConfigurationTask.java @@ -3,7 +3,7 @@ package info.nightscout.androidaps.plugins.pump.common.hw.rileylink.service.task import javax.inject.Inject; import dagger.android.HasAndroidInjector; -import info.nightscout.androidaps.interfaces.ActivePluginProvider; +import info.nightscout.androidaps.interfaces.ActivePlugin; import info.nightscout.androidaps.plugins.bus.RxBusWrapper; import info.nightscout.androidaps.plugins.pump.common.events.EventRefreshButtonState; import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.ble.RFSpy; @@ -14,7 +14,7 @@ import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.defs.RileyLin */ public class ResetRileyLinkConfigurationTask extends PumpTask { - @Inject ActivePluginProvider activePlugin; + @Inject ActivePlugin activePlugin; @Inject RxBusWrapper rxBus; @Inject RFSpy rfSpy; diff --git a/rileylink/src/main/java/info/nightscout/androidaps/plugins/pump/common/hw/rileylink/service/tasks/ServiceTask.java b/rileylink/src/main/java/info/nightscout/androidaps/plugins/pump/common/hw/rileylink/service/tasks/ServiceTask.java index 74193bda1c..498344913b 100644 --- a/rileylink/src/main/java/info/nightscout/androidaps/plugins/pump/common/hw/rileylink/service/tasks/ServiceTask.java +++ b/rileylink/src/main/java/info/nightscout/androidaps/plugins/pump/common/hw/rileylink/service/tasks/ServiceTask.java @@ -3,7 +3,7 @@ package info.nightscout.androidaps.plugins.pump.common.hw.rileylink.service.task import javax.inject.Inject; import dagger.android.HasAndroidInjector; -import info.nightscout.androidaps.interfaces.ActivePluginProvider; +import info.nightscout.androidaps.interfaces.ActivePlugin; import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.defs.RileyLinkPumpDevice; import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.service.data.ServiceTransport; @@ -12,7 +12,7 @@ import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.service.data. */ public class ServiceTask implements Runnable { - @Inject protected ActivePluginProvider activePlugin; + @Inject protected ActivePlugin activePlugin; public boolean completed = false; protected ServiceTransport mTransport; diff --git a/rileylink/src/main/java/info/nightscout/androidaps/plugins/pump/common/hw/rileylink/service/tasks/WakeAndTuneTask.java b/rileylink/src/main/java/info/nightscout/androidaps/plugins/pump/common/hw/rileylink/service/tasks/WakeAndTuneTask.java index 911b078e46..cf4ace58c8 100644 --- a/rileylink/src/main/java/info/nightscout/androidaps/plugins/pump/common/hw/rileylink/service/tasks/WakeAndTuneTask.java +++ b/rileylink/src/main/java/info/nightscout/androidaps/plugins/pump/common/hw/rileylink/service/tasks/WakeAndTuneTask.java @@ -3,7 +3,6 @@ package info.nightscout.androidaps.plugins.pump.common.hw.rileylink.service.task import javax.inject.Inject; import dagger.android.HasAndroidInjector; -import info.nightscout.androidaps.interfaces.ActivePluginProvider; import info.nightscout.androidaps.plugins.bus.RxBusWrapper; import info.nightscout.androidaps.plugins.pump.common.events.EventRefreshButtonState; import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.defs.RileyLinkPumpDevice; diff --git a/core/src/main/java/info/nightscout/androidaps/plugins/pump/common/utils/ByteUtil.java b/rileylink/src/main/java/info/nightscout/androidaps/plugins/pump/common/utils/ByteUtil.java similarity index 100% rename from core/src/main/java/info/nightscout/androidaps/plugins/pump/common/utils/ByteUtil.java rename to rileylink/src/main/java/info/nightscout/androidaps/plugins/pump/common/utils/ByteUtil.java diff --git a/core/src/main/java/info/nightscout/androidaps/plugins/pump/common/utils/CRC.java b/rileylink/src/main/java/info/nightscout/androidaps/plugins/pump/common/utils/CRC.java similarity index 100% rename from core/src/main/java/info/nightscout/androidaps/plugins/pump/common/utils/CRC.java rename to rileylink/src/main/java/info/nightscout/androidaps/plugins/pump/common/utils/CRC.java diff --git a/core/src/main/java/info/nightscout/androidaps/plugins/pump/common/utils/ProfileUtil.java b/rileylink/src/main/java/info/nightscout/androidaps/plugins/pump/common/utils/ProfileUtil.java similarity index 100% rename from core/src/main/java/info/nightscout/androidaps/plugins/pump/common/utils/ProfileUtil.java rename to rileylink/src/main/java/info/nightscout/androidaps/plugins/pump/common/utils/ProfileUtil.java diff --git a/core/src/main/java/info/nightscout/androidaps/plugins/pump/common/utils/StringUtil.java b/rileylink/src/main/java/info/nightscout/androidaps/plugins/pump/common/utils/StringUtil.java similarity index 100% rename from core/src/main/java/info/nightscout/androidaps/plugins/pump/common/utils/StringUtil.java rename to rileylink/src/main/java/info/nightscout/androidaps/plugins/pump/common/utils/StringUtil.java diff --git a/core/src/main/java/info/nightscout/androidaps/plugins/pump/common/utils/ThreadUtil.java b/rileylink/src/main/java/info/nightscout/androidaps/plugins/pump/common/utils/ThreadUtil.java similarity index 100% rename from core/src/main/java/info/nightscout/androidaps/plugins/pump/common/utils/ThreadUtil.java rename to rileylink/src/main/java/info/nightscout/androidaps/plugins/pump/common/utils/ThreadUtil.java diff --git a/rileylink/src/main/res/values/strings.xml b/rileylink/src/main/res/values/strings.xml index 0fbfee6e56..a2e2f723f1 100644 --- a/rileylink/src/main/res/values/strings.xml +++ b/rileylink/src/main/res/values/strings.xml @@ -77,7 +77,7 @@ No - Show battery level reported by OrangeLink/EmaLink + Show battery level reported by OrangeLink/EmaLink/DiaLink DOES NOT work with the original RileyLink. May not work with other RileyLink alternatives.