Merge branch 'meallink' into meallink-mdt

This commit is contained in:
Andy Rozman 2021-04-14 19:34:46 +01:00
commit 1e29239bde
508 changed files with 21447 additions and 7212 deletions

View file

@ -2,6 +2,22 @@
<code_scheme name="Project" version="173"> <code_scheme name="Project" version="173">
<option name="AUTODETECT_INDENTS" value="false" /> <option name="AUTODETECT_INDENTS" value="false" />
<JetCodeStyleSettings> <JetCodeStyleSettings>
<option name="PACKAGES_TO_USE_STAR_IMPORTS">
<value>
<package name="java.util" alias="false" withSubpackages="false" />
<package name="kotlinx.android.synthetic" alias="false" withSubpackages="true" />
<package name="io.ktor" alias="false" withSubpackages="true" />
</value>
</option>
<option name="PACKAGES_IMPORT_LAYOUT">
<value>
<package name="" alias="false" withSubpackages="true" />
<package name="java" alias="false" withSubpackages="true" />
<package name="javax" alias="false" withSubpackages="true" />
<package name="kotlin" alias="false" withSubpackages="true" />
<package name="" alias="true" withSubpackages="true" />
</value>
</option>
<option name="ALIGN_IN_COLUMNS_CASE_BRANCH" value="true" /> <option name="ALIGN_IN_COLUMNS_CASE_BRANCH" value="true" />
<option name="NAME_COUNT_TO_USE_STAR_IMPORT" value="6" /> <option name="NAME_COUNT_TO_USE_STAR_IMPORT" value="6" />
<option name="NAME_COUNT_TO_USE_STAR_IMPORT_FOR_MEMBERS" value="6" /> <option name="NAME_COUNT_TO_USE_STAR_IMPORT_FOR_MEMBERS" value="6" />

View file

@ -2,19 +2,24 @@
<dictionary name="project-dictionary"> <dictionary name="project-dictionary">
<words> <words>
<w>aaps</w> <w>aaps</w>
<w>acked</w>
<w>actionstring</w> <w>actionstring</w>
<w>allowednumbers</w> <w>allowednumbers</w>
<w>androidaps</w> <w>androidaps</w>
<w>autosens</w> <w>autosens</w>
<w>autosensdata</w> <w>autosensdata</w>
<w>autosense</w>
<w>bage</w> <w>bage</w>
<w>basaliob</w>
<w>basals</w> <w>basals</w>
<w>bgcheck</w> <w>bgcheck</w>
<w>bgsource</w>
<w>bolusing</w> <w>bolusing</w>
<w>carb</w> <w>carb</w>
<w>carbs</w> <w>carbs</w>
<w>carbsreq</w> <w>carbsreq</w>
<w>careportal</w> <w>careportal</w>
<w>cellnovo</w>
<w>crashlytics</w> <w>crashlytics</w>
<w>danar</w> <w>danar</w>
<w>danars</w> <w>danars</w>
@ -23,6 +28,7 @@
<w>dexcom</w> <w>dexcom</w>
<w>dexdrip</w> <w>dexdrip</w>
<w>enteredby</w> <w>enteredby</w>
<w>enteredinsulin</w>
<w>eveningoutpost</w> <w>eveningoutpost</w>
<w>eversense</w> <w>eversense</w>
<w>extendedbolus</w> <w>extendedbolus</w>
@ -32,12 +38,15 @@
<w>gson</w> <w>gson</w>
<w>hmac</w> <w>hmac</w>
<w>iage</w> <w>iage</w>
<w>insulet</w>
<w>iobtotal</w> <w>iobtotal</w>
<w>libre</w>
<w>listdelimiter</w> <w>listdelimiter</w>
<w>localprofile</w> <w>localprofile</w>
<w>medtronic</w> <w>medtronic</w>
<w>mgdl</w> <w>mgdl</w>
<w>mmol</w> <w>mmol</w>
<w>multiwave</w>
<w>netinsulin</w> <w>netinsulin</w>
<w>netratio</w> <w>netratio</w>
<w>nightscout</w> <w>nightscout</w>
@ -45,6 +54,7 @@
<w>nsclient</w> <w>nsclient</w>
<w>okcancel</w> <w>okcancel</w>
<w>omnipod</w> <w>omnipod</w>
<w>openaps</w>
<w>oref</w> <w>oref</w>
<w>passcode</w> <w>passcode</w>
<w>poctech</w> <w>poctech</w>
@ -56,7 +66,9 @@
<w>refresheventsfromnightscout</w> <w>refresheventsfromnightscout</w>
<w>rileylink</w> <w>rileylink</w>
<w>roboelectric</w> <w>roboelectric</w>
<w>sitechange</w>
<w>smscommunicator</w> <w>smscommunicator</w>
<w>sooil</w>
<w>soundid</w> <w>soundid</w>
<w>splitted</w> <w>splitted</w>
<w>superbolus</w> <w>superbolus</w>
@ -73,6 +85,9 @@
<w>uart</w> <w>uart</w>
<w>wizzardpage</w> <w>wizzardpage</w>
<w>xdrip</w> <w>xdrip</w>
<w>ypso</w>
<w>ypsomed</w>
<w>ypsopump</w>
</words> </words>
</dictionary> </dictionary>
</component> </component>

View file

@ -111,7 +111,7 @@ android {
defaultConfig { defaultConfig {
multiDexEnabled true multiDexEnabled true
versionCode 1500 versionCode 1500
version "2.8.2.1-dev-e1" version "2.8.2.1-dev-e3"
buildConfigField "String", "VERSION", '"' + version + '"' buildConfigField "String", "VERSION", '"' + version + '"'
buildConfigField "String", "BUILDVERSION", '"' + generateGitBuild() + '-' + generateDate() + '"' buildConfigField "String", "BUILDVERSION", '"' + generateGitBuild() + '-' + generateDate() + '"'
buildConfigField "String", "REMOTE", '"' + generateGitRemote() + '"' buildConfigField "String", "REMOTE", '"' + generateGitRemote() + '"'

View file

@ -89,7 +89,7 @@ class RealPumpTest {
localProfilePlugin.numOfProfiles = 0 localProfilePlugin.numOfProfiles = 0
val singleProfile = LocalProfilePlugin.SingleProfile().copyFrom(localProfilePlugin.rawProfile, profile, "TestProfile") val singleProfile = LocalProfilePlugin.SingleProfile().copyFrom(localProfilePlugin.rawProfile, profile, "TestProfile")
localProfilePlugin.addProfile(singleProfile) 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) treatmentsPlugin.addToHistoryProfileSwitch(profileSwitch)
// Insulin // Insulin
configBuilderPlugin.performPluginSwitch(insulinOrefUltraRapidActingPlugin, true, PluginType.INSULIN) configBuilderPlugin.performPluginSwitch(insulinOrefUltraRapidActingPlugin, true, PluginType.INSULIN)

View file

@ -32,6 +32,8 @@ import info.nightscout.androidaps.activities.PreferencesActivity
import info.nightscout.androidaps.activities.ProfileHelperActivity import info.nightscout.androidaps.activities.ProfileHelperActivity
import info.nightscout.androidaps.activities.SingleFragmentActivity import info.nightscout.androidaps.activities.SingleFragmentActivity
import info.nightscout.androidaps.activities.StatsActivity 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.databinding.ActivityMainBinding
import info.nightscout.androidaps.events.EventAppExit import info.nightscout.androidaps.events.EventAppExit
import info.nightscout.androidaps.events.EventPreferenceChange import info.nightscout.androidaps.events.EventPreferenceChange
@ -41,6 +43,7 @@ import info.nightscout.androidaps.interfaces.ActivePluginProvider
import info.nightscout.androidaps.interfaces.PluginType import info.nightscout.androidaps.interfaces.PluginType
import info.nightscout.androidaps.logging.AAPSLogger import info.nightscout.androidaps.logging.AAPSLogger
import info.nightscout.androidaps.logging.LTag 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.aps.loop.LoopPlugin
import info.nightscout.androidaps.plugins.bus.RxBusWrapper import info.nightscout.androidaps.plugins.bus.RxBusWrapper
import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker
@ -87,6 +90,7 @@ class MainActivity : NoSplashAppCompatActivity() {
@Inject lateinit var constraintChecker: ConstraintChecker @Inject lateinit var constraintChecker: ConstraintChecker
@Inject lateinit var signatureVerifierPlugin: SignatureVerifierPlugin @Inject lateinit var signatureVerifierPlugin: SignatureVerifierPlugin
@Inject lateinit var config: Config @Inject lateinit var config: Config
@Inject lateinit var uel: UserEntryLogger
private lateinit var actionBarDrawerToggle: ActionBarDrawerToggle private lateinit var actionBarDrawerToggle: ActionBarDrawerToggle
private var pluginPreferencesMenuItem: MenuItem? = null private var pluginPreferencesMenuItem: MenuItem? = null
@ -316,6 +320,7 @@ class MainActivity : NoSplashAppCompatActivity() {
R.id.nav_exit -> { R.id.nav_exit -> {
aapsLogger.debug(LTag.CORE, "Exiting") aapsLogger.debug(LTag.CORE, "Exiting")
uel.log(Action.EXIT_AAPS, Sources.Aaps)
rxBus.send(EventAppExit()) rxBus.send(EventAppExit())
finish() finish()
System.runFinalization() System.runFinalization()

View file

@ -11,6 +11,7 @@ import dagger.android.AndroidInjector
import dagger.android.DaggerApplication import dagger.android.DaggerApplication
import info.nightscout.androidaps.database.AppRepository import info.nightscout.androidaps.database.AppRepository
import info.nightscout.androidaps.database.entities.TherapyEvent 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.InsertIfNewByTimestampTherapyEventTransaction
import info.nightscout.androidaps.database.transactions.VersionChangeTransaction import info.nightscout.androidaps.database.transactions.VersionChangeTransaction
import info.nightscout.androidaps.db.CompatDBHelper import info.nightscout.androidaps.db.CompatDBHelper
@ -20,10 +21,10 @@ import info.nightscout.androidaps.dependencyInjection.DaggerAppComponent
import info.nightscout.androidaps.interfaces.PluginBase import info.nightscout.androidaps.interfaces.PluginBase
import info.nightscout.androidaps.logging.AAPSLogger import info.nightscout.androidaps.logging.AAPSLogger
import info.nightscout.androidaps.logging.LTag import info.nightscout.androidaps.logging.LTag
import info.nightscout.androidaps.logging.UserEntryLogger
import info.nightscout.androidaps.plugins.configBuilder.ConfigBuilderPlugin import info.nightscout.androidaps.plugins.configBuilder.ConfigBuilderPlugin
import info.nightscout.androidaps.plugins.configBuilder.PluginStore import info.nightscout.androidaps.plugins.configBuilder.PluginStore
import info.nightscout.androidaps.plugins.constraints.versionChecker.VersionCheckerUtils 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.BTReceiver
import info.nightscout.androidaps.receivers.ChargingStateReceiver import info.nightscout.androidaps.receivers.ChargingStateReceiver
import info.nightscout.androidaps.receivers.KeepAliveReceiver.KeepAliveManager import info.nightscout.androidaps.receivers.KeepAliveReceiver.KeepAliveManager
@ -47,7 +48,6 @@ class MainApp : DaggerApplication() {
@Inject lateinit var activityMonitor: ActivityMonitor @Inject lateinit var activityMonitor: ActivityMonitor
@Inject lateinit var versionCheckersUtils: VersionCheckerUtils @Inject lateinit var versionCheckersUtils: VersionCheckerUtils
@Inject lateinit var sp: SP @Inject lateinit var sp: SP
@Inject lateinit var nsUpload: NSUpload
@Inject lateinit var config: Config @Inject lateinit var config: Config
@Inject lateinit var configBuilderPlugin: ConfigBuilderPlugin @Inject lateinit var configBuilderPlugin: ConfigBuilderPlugin
@Inject lateinit var keepAliveManager: KeepAliveManager @Inject lateinit var keepAliveManager: KeepAliveManager
@ -56,6 +56,7 @@ class MainApp : DaggerApplication() {
@Inject lateinit var repository: AppRepository @Inject lateinit var repository: AppRepository
@Inject lateinit var dateUtil: DateUtil @Inject lateinit var dateUtil: DateUtil
@Inject lateinit var staticInjector: StaticInjector// TODO avoid , here fake only to initialize @Inject lateinit var staticInjector: StaticInjector// TODO avoid , here fake only to initialize
@Inject lateinit var uel: UserEntryLogger
override fun onCreate() { override fun onCreate() {
super.onCreate() super.onCreate()
@ -70,7 +71,7 @@ class MainApp : DaggerApplication() {
commitHash = null commitHash = null
} }
disposable += repository.runTransaction(VersionChangeTransaction(BuildConfig.VERSION_NAME, BuildConfig.VERSION_CODE, gitRemote, commitHash)).subscribe() 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 += 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() disposable += compatDBHelper.dbChangeDisposable()
registerActivityLifecycleCallbacks(activityMonitor) registerActivityLifecycleCallbacks(activityMonitor)
JodaTimeAndroid.init(this) JodaTimeAndroid.init(this)
@ -87,6 +88,7 @@ class MainApp : DaggerApplication() {
configBuilderPlugin.initialize() configBuilderPlugin.initialize()
keepAliveManager.setAlarm(this) keepAliveManager.setAlarm(this)
doMigrations() doMigrations()
uel.log(UserEntry.Action.START_AAPS, UserEntry.Sources.Aaps)
} }
private fun doMigrations() { private fun doMigrations() {

View file

@ -24,7 +24,7 @@ import info.nightscout.androidaps.utils.DateUtil
import info.nightscout.androidaps.utils.T import info.nightscout.androidaps.utils.T
import info.nightscout.androidaps.utils.ToastUtils import info.nightscout.androidaps.utils.ToastUtils
import info.nightscout.androidaps.utils.alertDialogs.OKDialog 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 info.nightscout.androidaps.utils.stats.TddCalculator
import java.text.DecimalFormat import java.text.DecimalFormat
import javax.inject.Inject import javax.inject.Inject
@ -114,7 +114,7 @@ class ProfileHelperActivity : NoSplashAppCompatActivity() {
} }
// Profile switch // 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 { binding.profileswitchList.setOnClickListener {
PopupMenu(this, binding.profileswitchList).apply { PopupMenu(this, binding.profileswitchList).apply {
@ -141,7 +141,7 @@ class ProfileHelperActivity : NoSplashAppCompatActivity() {
profile?.let { profile?.let {
OKDialog.showConfirmation(this, resourceHelper.gs(R.string.careportal_profileswitch), resourceHelper.gs(R.string.copytolocalprofile), Runnable { OKDialog.showConfirmation(this, resourceHelper.gs(R.string.careportal_profileswitch), resourceHelper.gs(R.string.copytolocalprofile), Runnable {
localProfilePlugin.addProfile(localProfilePlugin.copyFrom(it, "DefaultProfile " + localProfilePlugin.addProfile(localProfilePlugin.copyFrom(it, "DefaultProfile " +
dateUtil.dateAndTimeAndSecondsString(dateUtil._now()) dateUtil.dateAndTimeAndSecondsString(dateUtil.now())
.replace(".", "/") .replace(".", "/")
)) ))
rxBus.send(EventLocalProfileChanged()) rxBus.send(EventLocalProfileChanged())
@ -210,7 +210,7 @@ class ProfileHelperActivity : NoSplashAppCompatActivity() {
getProfile(ageUsed[1], tddUsed[1], weightUsed[1], pctUsed[1] / 100.0, 1)?.let { profile1 -> getProfile(ageUsed[1], tddUsed[1], weightUsed[1], pctUsed[1] / 100.0, 1)?.let { profile1 ->
ProfileViewerDialog().also { pvd -> ProfileViewerDialog().also { pvd ->
pvd.arguments = Bundle().also { pvd.arguments = Bundle().also {
it.putLong("time", DateUtil.now()) it.putLong("time", dateUtil.now())
it.putInt("mode", ProfileViewerDialog.Mode.PROFILE_COMPARE.ordinal) it.putInt("mode", ProfileViewerDialog.Mode.PROFILE_COMPARE.ordinal)
it.putString("customProfile", profile0.data.toString()) it.putString("customProfile", profile0.data.toString())
it.putString("customProfile2", profile1.data.toString()) it.putString("customProfile2", profile1.data.toString())

View file

@ -2,7 +2,8 @@ package info.nightscout.androidaps.activities
import android.os.Bundle import android.os.Bundle
import info.nightscout.androidaps.R 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.databinding.ActivityStatsBinding
import info.nightscout.androidaps.logging.UserEntryLogger import info.nightscout.androidaps.logging.UserEntryLogger
import info.nightscout.androidaps.utils.ActivityMonitor import info.nightscout.androidaps.utils.ActivityMonitor
@ -32,7 +33,7 @@ class StatsActivity : NoSplashAppCompatActivity() {
binding.ok.setOnClickListener { finish() } binding.ok.setOnClickListener { finish() }
binding.reset.setOnClickListener { binding.reset.setOnClickListener {
OKDialog.showConfirmation(this, resourceHelper.gs(R.string.doyouwantresetstats)) { OKDialog.showConfirmation(this, resourceHelper.gs(R.string.doyouwantresetstats)) {
uel.log(Action.STAT_RESET) uel.log(Action.STAT_RESET, Sources.Stats)
activityMonitor.reset() activityMonitor.reset()
recreate() recreate()
} }

View file

@ -30,6 +30,7 @@ class SurveyActivity : NoSplashAppCompatActivity() {
@Inject lateinit var profileFunction: ProfileFunction @Inject lateinit var profileFunction: ProfileFunction
@Inject lateinit var activityMonitor: ActivityMonitor @Inject lateinit var activityMonitor: ActivityMonitor
@Inject lateinit var defaultProfile: DefaultProfile @Inject lateinit var defaultProfile: DefaultProfile
@Inject lateinit var dateUtil: DateUtil
private lateinit var binding: ActivitySurveyBinding private lateinit var binding: ActivitySurveyBinding
@ -68,7 +69,7 @@ class SurveyActivity : NoSplashAppCompatActivity() {
defaultProfile.profile(age, tdd, weight, profileFunction.getUnits())?.let { profile -> defaultProfile.profile(age, tdd, weight, profileFunction.getUnits())?.let { profile ->
ProfileViewerDialog().also { pvd -> ProfileViewerDialog().also { pvd ->
pvd.arguments = Bundle().also { pvd.arguments = Bundle().also {
it.putLong("time", DateUtil.now()) it.putLong("time", dateUtil.now())
it.putInt("mode", ProfileViewerDialog.Mode.PROFILE_COMPARE.ordinal) it.putInt("mode", ProfileViewerDialog.Mode.PROFILE_COMPARE.ordinal)
it.putString("customProfile", runningProfile.data.toString()) it.putString("customProfile", runningProfile.data.toString())
it.putString("customProfile2", profile.data.toString()) it.putString("customProfile2", profile.data.toString())

View file

@ -2,11 +2,9 @@ package info.nightscout.androidaps.db
import info.nightscout.androidaps.database.AppRepository import info.nightscout.androidaps.database.AppRepository
import info.nightscout.androidaps.database.entities.* import info.nightscout.androidaps.database.entities.*
import info.nightscout.androidaps.events.EventFoodDatabaseChanged import info.nightscout.androidaps.database.entities.ExtendedBolus
import info.nightscout.androidaps.events.EventNewBG import info.nightscout.androidaps.database.entities.TemporaryBasal
import info.nightscout.androidaps.events.EventTempTargetChange import info.nightscout.androidaps.events.*
import info.nightscout.androidaps.events.EventTherapyEventChange
import info.nightscout.androidaps.events.EventTreatmentChange
import info.nightscout.androidaps.logging.AAPSLogger import info.nightscout.androidaps.logging.AAPSLogger
import info.nightscout.androidaps.logging.LTag import info.nightscout.androidaps.logging.LTag
import info.nightscout.androidaps.plugins.bus.RxBusWrapper import info.nightscout.androidaps.plugins.bus.RxBusWrapper
@ -28,13 +26,41 @@ class CompatDBHelper @Inject constructor(
rxBus.send(EventNewBG(null)) rxBus.send(EventNewBG(null))
} }
.subscribe { .subscribe {
it.filterIsInstance<GlucoseValue>().firstOrNull()?.let { /**
aapsLogger.debug(LTag.DATABASE, "Firing EventNewHistoryData") * GlucoseValues can come in batch
rxBus.send(EventNewHistoryData(it.timestamp)) * oldest one should be used for invalidation, newest one for for triggering Loop.
} * Thus we need to collect both
it.filterIsInstance<GlucoseValue>().lastOrNull()?.let { *
*/
var newestGlucoseValue : GlucoseValue? = null
it.filterIsInstance<GlucoseValue>().lastOrNull()?.let { gv ->
aapsLogger.debug(LTag.DATABASE, "Firing EventNewBg") aapsLogger.debug(LTag.DATABASE, "Firing EventNewBg")
rxBus.send(EventNewBG(it)) rxBus.send(EventNewBG(gv))
newestGlucoseValue = gv
}
it.filterIsInstance<GlucoseValue>().map { gv -> gv.timestamp }.minOrNull()?.let { timestamp ->
aapsLogger.debug(LTag.DATABASE, "Firing EventNewHistoryData")
rxBus.send(EventNewHistoryData(timestamp, true, newestGlucoseValue))
}
it.filterIsInstance<Carbs>().map { t -> t.timestamp }.minOrNull()?.let { timestamp ->
aapsLogger.debug(LTag.DATABASE, "Firing EventTreatmentChange")
rxBus.send(EventTreatmentChange())
rxBus.send(EventNewHistoryData(timestamp, false))
}
it.filterIsInstance<Bolus>().map { t -> t.timestamp }.minOrNull()?.let { timestamp ->
aapsLogger.debug(LTag.DATABASE, "Firing EventTreatmentChange")
rxBus.send(EventTreatmentChange())
rxBus.send(EventNewHistoryData(timestamp, false))
}
it.filterIsInstance<TemporaryBasal>().map { t -> t.timestamp }.minOrNull()?.let { timestamp ->
aapsLogger.debug(LTag.DATABASE, "Firing EventTempBasalChange")
rxBus.send(EventTempBasalChange())
rxBus.send(EventNewHistoryData(timestamp, false))
}
it.filterIsInstance<ExtendedBolus>().map { t -> t.timestamp }.minOrNull()?.let { timestamp ->
aapsLogger.debug(LTag.DATABASE, "Firing EventExtendedBolusChange")
rxBus.send(EventExtendedBolusChange())
rxBus.send(EventNewHistoryData(timestamp, false))
} }
it.filterIsInstance<TemporaryTarget>().firstOrNull()?.let { it.filterIsInstance<TemporaryTarget>().firstOrNull()?.let {
aapsLogger.debug(LTag.DATABASE, "Firing EventTempTargetChange") aapsLogger.debug(LTag.DATABASE, "Firing EventTempTargetChange")
@ -48,13 +74,5 @@ class CompatDBHelper @Inject constructor(
aapsLogger.debug(LTag.DATABASE, "Firing EventFoodDatabaseChanged") aapsLogger.debug(LTag.DATABASE, "Firing EventFoodDatabaseChanged")
rxBus.send(EventFoodDatabaseChanged()) rxBus.send(EventFoodDatabaseChanged())
} }
it.filterIsInstance<Carbs>().firstOrNull()?.let {
aapsLogger.debug(LTag.DATABASE, "Firing EventFoodDatabaseChanged")
rxBus.send(EventTreatmentChange())
}
it.filterIsInstance<Bolus>().firstOrNull()?.let {
aapsLogger.debug(LTag.DATABASE, "Firing EventFoodDatabaseChanged")
rxBus.send(EventTreatmentChange())
}
} }
} }

View file

@ -34,13 +34,9 @@ import javax.inject.Inject;
import info.nightscout.androidaps.dana.comm.RecordTypes; import info.nightscout.androidaps.dana.comm.RecordTypes;
import info.nightscout.androidaps.data.Profile; import info.nightscout.androidaps.data.Profile;
import info.nightscout.androidaps.events.EventExtendedBolusChange;
import info.nightscout.androidaps.events.EventProfileNeedsUpdate; import info.nightscout.androidaps.events.EventProfileNeedsUpdate;
import info.nightscout.androidaps.events.EventRefreshOverview; import info.nightscout.androidaps.events.EventRefreshOverview;
import info.nightscout.androidaps.events.EventReloadProfileSwitchData; 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.ActivePluginProvider;
import info.nightscout.androidaps.interfaces.DatabaseHelperInterface; import info.nightscout.androidaps.interfaces.DatabaseHelperInterface;
import info.nightscout.androidaps.interfaces.ProfileInterface; import info.nightscout.androidaps.interfaces.ProfileInterface;
@ -50,8 +46,8 @@ import info.nightscout.androidaps.logging.LTag;
import info.nightscout.androidaps.plugins.bus.RxBusWrapper; import info.nightscout.androidaps.plugins.bus.RxBusWrapper;
import info.nightscout.androidaps.plugins.general.nsclient.NSUpload; import info.nightscout.androidaps.plugins.general.nsclient.NSUpload;
import info.nightscout.androidaps.plugins.general.openhumans.OpenHumansUploader; 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.plugins.pump.virtual.VirtualPumpPlugin;
import info.nightscout.androidaps.utils.DateUtil;
import info.nightscout.androidaps.utils.PercentageSplitter; import info.nightscout.androidaps.utils.PercentageSplitter;
/** /**
@ -69,23 +65,16 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
@Inject OpenHumansUploader openHumansUploader; @Inject OpenHumansUploader openHumansUploader;
@Inject ActivePluginProvider activePlugin; @Inject ActivePluginProvider activePlugin;
@Inject NSUpload nsUpload; @Inject NSUpload nsUpload;
@Inject DateUtil dateUtil;
public static final String DATABASE_NAME = "AndroidAPSDb"; 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_DANARHISTORY = "DanaRHistory";
public static final String DATABASE_DBREQUESTS = "DBRequests"; public static final String DATABASE_DBREQUESTS = "DBRequests";
public static final String DATABASE_TDDS = "TDDs";
private static final int DATABASE_VERSION = 13; private static final int DATABASE_VERSION = 13;
public static Long earliestDataChange = null; 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 final ScheduledExecutorService profileSwitchEventWorker = Executors.newSingleThreadScheduledExecutor();
private static ScheduledFuture<?> scheduledProfileSwitchEventPost = null; private static ScheduledFuture<?> scheduledProfileSwitchEventPost = null;
@ -198,8 +187,6 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
aapsLogger.error("Unhandled exception", e); aapsLogger.error("Unhandled exception", e);
} }
virtualPumpPlugin.setFakingStatus(true); virtualPumpPlugin.setFakingStatus(true);
scheduleTemporaryBasalChange();
scheduleExtendedBolusChange();
scheduleProfileSwitchChange(); scheduleProfileSwitchChange();
new java.util.Timer().schedule( new java.util.Timer().schedule(
new java.util.TimerTask() { 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() { public void resetProfileSwitch() {
try { try {
TableUtils.dropTable(connectionSource, ProfileSwitch.class, true); TableUtils.dropTable(connectionSource, ProfileSwitch.class, true);
@ -507,7 +471,7 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
openHumansUploader.enqueueTemporaryBasal(old); openHumansUploader.enqueueTemporaryBasal(old);
updateEarliestDataChange(tempBasal.date); updateEarliestDataChange(tempBasal.date);
scheduleTemporaryBasalChange(); // scheduleTemporaryBasalChange();
return false; return false;
} }
@ -516,7 +480,7 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
openHumansUploader.enqueueTemporaryBasal(tempBasal); openHumansUploader.enqueueTemporaryBasal(tempBasal);
aapsLogger.debug(LTag.DATABASE, "TEMPBASAL: New record from: " + Source.getString(tempBasal.source) + " " + tempBasal.toString()); aapsLogger.debug(LTag.DATABASE, "TEMPBASAL: New record from: " + Source.getString(tempBasal.source) + " " + tempBasal.toString());
updateEarliestDataChange(tempBasal.date); updateEarliestDataChange(tempBasal.date);
scheduleTemporaryBasalChange(); // scheduleTemporaryBasalChange();
return true; return true;
} }
if (tempBasal.source == Source.NIGHTSCOUT) { 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()); aapsLogger.debug(LTag.DATABASE, "TEMPBASAL: Updating record by date from: " + Source.getString(tempBasal.source) + " " + old.toString());
updateEarliestDataChange(oldDate); updateEarliestDataChange(oldDate);
updateEarliestDataChange(old.date); updateEarliestDataChange(old.date);
scheduleTemporaryBasalChange(); // scheduleTemporaryBasalChange();
return true; return true;
} }
return false; 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()); aapsLogger.debug(LTag.DATABASE, "TEMPBASAL: Updating record by _id from: " + Source.getString(tempBasal.source) + " " + old.toString());
updateEarliestDataChange(oldDate); updateEarliestDataChange(oldDate);
updateEarliestDataChange(old.date); updateEarliestDataChange(old.date);
scheduleTemporaryBasalChange(); // scheduleTemporaryBasalChange();
return true; return true;
} }
} }
@ -567,7 +531,7 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
openHumansUploader.enqueueTemporaryBasal(tempBasal); openHumansUploader.enqueueTemporaryBasal(tempBasal);
aapsLogger.debug(LTag.DATABASE, "TEMPBASAL: New record from: " + Source.getString(tempBasal.source) + " " + tempBasal.toString()); aapsLogger.debug(LTag.DATABASE, "TEMPBASAL: New record from: " + Source.getString(tempBasal.source) + " " + tempBasal.toString());
updateEarliestDataChange(tempBasal.date); updateEarliestDataChange(tempBasal.date);
scheduleTemporaryBasalChange(); // scheduleTemporaryBasalChange();
return true; return true;
} }
if (tempBasal.source == Source.USER) { if (tempBasal.source == Source.USER) {
@ -575,7 +539,7 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
openHumansUploader.enqueueTemporaryBasal(tempBasal); openHumansUploader.enqueueTemporaryBasal(tempBasal);
aapsLogger.debug(LTag.DATABASE, "TEMPBASAL: New record from: " + Source.getString(tempBasal.source) + " " + tempBasal.toString()); aapsLogger.debug(LTag.DATABASE, "TEMPBASAL: New record from: " + Source.getString(tempBasal.source) + " " + tempBasal.toString());
updateEarliestDataChange(tempBasal.date); updateEarliestDataChange(tempBasal.date);
scheduleTemporaryBasalChange(); // scheduleTemporaryBasalChange();
return true; return true;
} }
} catch (SQLException e) { } catch (SQLException e) {
@ -592,16 +556,7 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
} catch (SQLException e) { } catch (SQLException e) {
aapsLogger.error("Unhandled exception", e); aapsLogger.error("Unhandled exception", e);
} }
scheduleTemporaryBasalChange(); // scheduleTemporaryBasalChange();
}
public List<TemporaryBasal> getAllTemporaryBasals() {
try {
return getDaoTemporaryBasal().queryForAll();
} catch (SQLException e) {
aapsLogger.error("Unhandled exception", e);
}
return Collections.emptyList();
} }
public List<TemporaryBasal> getTemporaryBasalsDataFromTime(long mills, boolean ascending) { public List<TemporaryBasal> getTemporaryBasalsDataFromTime(long mills, boolean ascending) {
@ -620,44 +575,6 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
return new ArrayList<TemporaryBasal>(); return new ArrayList<TemporaryBasal>();
} }
public List<TemporaryBasal> getTemporaryBasalsDataFromTime(long from, long to, boolean ascending) {
try {
List<TemporaryBasal> tempbasals;
QueryBuilder<TemporaryBasal, Long> queryBuilder = getDaoTemporaryBasal().queryBuilder();
queryBuilder.orderBy("date", ascending);
Where where = queryBuilder.where();
where.between("date", from, to);
PreparedQuery<TemporaryBasal> preparedQuery = queryBuilder.prepare();
tempbasals = getDaoTemporaryBasal().query(preparedQuery);
return tempbasals;
} catch (SQLException e) {
aapsLogger.error("Unhandled exception", e);
}
return new ArrayList<TemporaryBasal>();
}
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", "_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<TemporaryBasal, Long> queryBuilder = null;
queryBuilder = getDaoTemporaryBasal().queryBuilder();
Where where = queryBuilder.where();
where.eq("_id", _id);
PreparedQuery<TemporaryBasal> preparedQuery = queryBuilder.prepare();
List<TemporaryBasal> 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) { public TemporaryBasal findTempBasalByPumpId(Long pumpId) {
try { try {
QueryBuilder<TemporaryBasal, Long> queryBuilder = null; QueryBuilder<TemporaryBasal, Long> queryBuilder = null;
@ -785,109 +615,6 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
// ------------ ExtendedBolus handling --------------- // ------------ 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<ExtendedBolus, Long> queryBuilder = getDaoExtendedBolus().queryBuilder();
Where where = queryBuilder.where();
where.eq("pumpId", extendedBolus.pumpId);
PreparedQuery<ExtendedBolus> preparedQuery = queryBuilder.prepare();
List<ExtendedBolus> 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<ExtendedBolus, Long> queryBuilder = getDaoExtendedBolus().queryBuilder();
Where where = queryBuilder.where();
where.eq("_id", extendedBolus._id);
PreparedQuery<ExtendedBolus> preparedQuery = queryBuilder.prepare();
List<ExtendedBolus> 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<ExtendedBolus> getAllExtendedBoluses() {
try {
return getDaoExtendedBolus().queryForAll();
} catch (SQLException e) {
aapsLogger.error("Unhandled exception", e);
}
return Collections.emptyList();
}
public ExtendedBolus getExtendedBolusByPumpId(long pumpId) { public ExtendedBolus getExtendedBolusByPumpId(long pumpId) {
try { try {
return getDaoExtendedBolus().queryBuilder() return getDaoExtendedBolus().queryBuilder()
@ -907,69 +634,7 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
} catch (SQLException e) { } catch (SQLException e) {
aapsLogger.error("Unhandled exception", e); aapsLogger.error("Unhandled exception", e);
} }
scheduleExtendedBolusChange(); // scheduleExtendedBolusChange();
}
public List<ExtendedBolus> getExtendedBolusDataFromTime(long mills, boolean ascending) {
try {
List<ExtendedBolus> extendedBoluses;
QueryBuilder<ExtendedBolus, Long> queryBuilder = getDaoExtendedBolus().queryBuilder();
queryBuilder.orderBy("date", ascending);
Where where = queryBuilder.where();
where.ge("date", mills);
PreparedQuery<ExtendedBolus> preparedQuery = queryBuilder.prepare();
extendedBoluses = getDaoExtendedBolus().query(preparedQuery);
return extendedBoluses;
} catch (SQLException e) {
aapsLogger.error("Unhandled exception", e);
}
return new ArrayList<ExtendedBolus>();
}
public List<ExtendedBolus> getExtendedBolusDataFromTime(long from, long to, boolean ascending) {
try {
List<ExtendedBolus> extendedBoluses;
QueryBuilder<ExtendedBolus, Long> queryBuilder = getDaoExtendedBolus().queryBuilder();
queryBuilder.orderBy("date", ascending);
Where where = queryBuilder.where();
where.between("date", from, to);
PreparedQuery<ExtendedBolus> preparedQuery = queryBuilder.prepare();
extendedBoluses = getDaoExtendedBolus().query(preparedQuery);
return extendedBoluses;
} catch (SQLException e) {
aapsLogger.error("Unhandled exception", e);
}
return new ArrayList<ExtendedBolus>();
}
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<ExtendedBolus, Long> queryBuilder = null;
queryBuilder = getDaoExtendedBolus().queryBuilder();
Where where = queryBuilder.where();
where.eq("_id", _id);
PreparedQuery<ExtendedBolus> preparedQuery = queryBuilder.prepare();
List<ExtendedBolus> 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;
} }
/* /*
@ -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 --------------- // ---------------- ProfileSwitch handling ---------------
public List<ProfileSwitch> getProfileSwitchData(long from, boolean ascending) { public List<ProfileSwitch> getProfileSwitchData(long from, boolean ascending) {
@ -1243,7 +881,7 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
profileSwitch.profileJson = profile.getData().toString(); profileSwitch.profileJson = profile.getData().toString();
aapsLogger.debug(LTag.DATABASE, "Profile switch prefilled with JSON from local store"); aapsLogger.debug(LTag.DATABASE, "Profile switch prefilled with JSON from local store");
// Update data in NS // Update data in NS
nsUpload.updateProfileSwitch(profileSwitch); nsUpload.updateProfileSwitch(profileSwitch, dateUtil);
} else { } else {
aapsLogger.debug(LTag.DATABASE, "JSON for profile switch doesn't exist. Ignoring: " + trJson.toString()); aapsLogger.debug(LTag.DATABASE, "JSON for profile switch doesn't exist. Ignoring: " + trJson.toString());
return; return;

View file

@ -1,10 +1,10 @@
package info.nightscout.androidaps.db; package info.nightscout.androidaps.db;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.j256.ormlite.dao.CloseableIterator; import com.j256.ormlite.dao.CloseableIterator;
import org.jetbrains.annotations.Nullable;
import org.json.JSONObject; import org.json.JSONObject;
import java.sql.SQLException; import java.sql.SQLException;
@ -16,6 +16,7 @@ import javax.inject.Singleton;
import info.nightscout.androidaps.MainApp; import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.interfaces.DatabaseHelperInterface; import info.nightscout.androidaps.interfaces.DatabaseHelperInterface;
@Deprecated
@Singleton @Singleton
public class DatabaseHelperProvider implements DatabaseHelperInterface { public class DatabaseHelperProvider implements DatabaseHelperInterface {
@ -78,10 +79,11 @@ public class DatabaseHelperProvider implements DatabaseHelperInterface {
return MainApp.Companion.getDbHelper().createOrUpdate(tempBasal); 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); return MainApp.Companion.getDbHelper().findTempBasalByPumpId(id);
} }
@Deprecated
@NonNull @Override public List<TemporaryBasal> getTemporaryBasalsDataFromTime(long mills, boolean ascending) { @NonNull @Override public List<TemporaryBasal> getTemporaryBasalsDataFromTime(long mills, boolean ascending) {
return MainApp.Companion.getDbHelper().getTemporaryBasalsDataFromTime(mills, ascending); return MainApp.Companion.getDbHelper().getTemporaryBasalsDataFromTime(mills, ascending);
} }
@ -134,42 +136,14 @@ public class DatabaseHelperProvider implements DatabaseHelperInterface {
return MainApp.Companion.getDbHelper().getPumpStoppedEvent(pumpSerial, before); 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) { @Override public void createOrUpdate(@NonNull ProfileSwitch profileSwitch) {
MainApp.Companion.getDbHelper().createOrUpdate(profileSwitch); MainApp.Companion.getDbHelper().createOrUpdate(profileSwitch);
} }
@Override public void delete(@NonNull TemporaryBasal tempBasal) {
MainApp.Companion.getDbHelper().delete(tempBasal);
}
@NonNull @Override public List<ExtendedBolus> 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) { @Override public void deleteProfileSwitchById(@NonNull String _id) {
MainApp.Companion.getDbHelper().deleteProfileSwitchById(_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) { @Override public void createProfileSwitchFromJsonIfNotExists(@NonNull JSONObject trJson) {
MainApp.Companion.getDbHelper().createProfileSwitchFromJsonIfNotExists(trJson); MainApp.Companion.getDbHelper().createProfileSwitchFromJsonIfNotExists(trJson);
} }
@ -194,10 +168,6 @@ public class DatabaseHelperProvider implements DatabaseHelperInterface {
return MainApp.Companion.getDbHelper().getProfileSwitchEventsFromTime(mills, ascending); return MainApp.Companion.getDbHelper().getProfileSwitchEventsFromTime(mills, ascending);
} }
@NonNull @Override public List<ExtendedBolus> getAllExtendedBoluses() {
return MainApp.Companion.getDbHelper().getAllExtendedBoluses();
}
@NonNull @Override public List<ProfileSwitch> getAllProfileSwitches() { @NonNull @Override public List<ProfileSwitch> getAllProfileSwitches() {
return MainApp.Companion.getDbHelper().getAllProfileSwitches(); return MainApp.Companion.getDbHelper().getAllProfileSwitches();
} }
@ -206,10 +176,6 @@ public class DatabaseHelperProvider implements DatabaseHelperInterface {
return MainApp.Companion.getDbHelper().getAllTDDs(); return MainApp.Companion.getDbHelper().getAllTDDs();
} }
@NonNull @Override public List<TemporaryBasal> getAllTemporaryBasals() {
return MainApp.Companion.getDbHelper().getAllTemporaryBasals();
}
@NonNull @Override public List<OHQueueItem> getAllOHQueueItems(long maxEntries) { @NonNull @Override public List<OHQueueItem> getAllOHQueueItems(long maxEntries) {
return MainApp.Companion.getDbHelper().getAllOHQueueItems(maxEntries); return MainApp.Companion.getDbHelper().getAllOHQueueItems(maxEntries);
} }

View file

@ -79,7 +79,7 @@ open class AppModule {
@Binds fun bindCommandQueueProvider(commandQueue: CommandQueue): CommandQueueProvider @Binds fun bindCommandQueueProvider(commandQueue: CommandQueue): CommandQueueProvider
@Binds fun bindConfigInterface(config: Config): ConfigInterface @Binds fun bindConfigInterface(config: Config): ConfigInterface
@Binds fun bindConfigBuilderInterface(configBuilderPlugin: ConfigBuilderPlugin): ConfigBuilderInterface @Binds fun bindConfigBuilderInterface(configBuilderPlugin: ConfigBuilderPlugin): ConfigBuilderInterface
@Binds fun bindTreatmentInterface(treatmentsPlugin: TreatmentsPlugin): TreatmentsInterface @Binds fun bindTreatmentsInterface(treatmentsPlugin: TreatmentsPlugin): TreatmentsInterface
@Binds fun bindDatabaseHelperInterface(databaseHelperProvider: DatabaseHelperProvider): DatabaseHelperInterface @Binds fun bindDatabaseHelperInterface(databaseHelperProvider: DatabaseHelperProvider): DatabaseHelperInterface
@Binds fun bindNotificationHolderInterface(notificationHolder: NotificationHolder): NotificationHolderInterface @Binds fun bindNotificationHolderInterface(notificationHolder: NotificationHolder): NotificationHolderInterface
@Binds fun bindImportExportPrefsInterface(importExportPrefs: ImportExportPrefs): ImportExportPrefsInterface @Binds fun bindImportExportPrefsInterface(importExportPrefs: ImportExportPrefs): ImportExportPrefsInterface

View file

@ -17,6 +17,7 @@ abstract class ReceiversModule {
@ContributesAndroidInjector abstract fun contributesChargingStateReceiver(): ChargingStateReceiver @ContributesAndroidInjector abstract fun contributesChargingStateReceiver(): ChargingStateReceiver
@ContributesAndroidInjector abstract fun contributesDataReceiver(): DataReceiver @ContributesAndroidInjector abstract fun contributesDataReceiver(): DataReceiver
@ContributesAndroidInjector abstract fun contributesKeepAliveReceiver(): KeepAliveReceiver @ContributesAndroidInjector abstract fun contributesKeepAliveReceiver(): KeepAliveReceiver
@ContributesAndroidInjector abstract fun contributesKeepAliveWorker(): KeepAliveReceiver.KeepAliveWorker
@ContributesAndroidInjector abstract fun contributesRileyLinkBluetoothStateReceiver(): RileyLinkBluetoothStateReceiver @ContributesAndroidInjector abstract fun contributesRileyLinkBluetoothStateReceiver(): RileyLinkBluetoothStateReceiver
@ContributesAndroidInjector abstract fun contributesSmsReceiver(): SmsReceiver @ContributesAndroidInjector abstract fun contributesSmsReceiver(): SmsReceiver
@ContributesAndroidInjector abstract fun contributesTimeDateOrTZChangeReceiver(): TimeDateOrTZChangeReceiver @ContributesAndroidInjector abstract fun contributesTimeDateOrTZChangeReceiver(): TimeDateOrTZChangeReceiver

View file

@ -9,7 +9,9 @@ import dagger.android.HasAndroidInjector
import info.nightscout.androidaps.Constants import info.nightscout.androidaps.Constants
import info.nightscout.androidaps.R import info.nightscout.androidaps.R
import info.nightscout.androidaps.data.Profile 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.databinding.DialogCalibrationBinding
import info.nightscout.androidaps.interfaces.ProfileFunction import info.nightscout.androidaps.interfaces.ProfileFunction
import info.nightscout.androidaps.logging.UserEntryLogger import info.nightscout.androidaps.logging.UserEntryLogger
@ -79,7 +81,7 @@ class CalibrationDialog : DialogFragmentWithDate() {
if (bg > 0) { if (bg > 0) {
activity?.let { activity -> activity?.let { activity ->
OKDialog.showConfirmation(activity, resourceHelper.gs(R.string.overview_calibration), HtmlHelper.fromHtml(Joiner.on("<br/>").join(actions)), { OKDialog.showConfirmation(activity, resourceHelper.gs(R.string.overview_calibration), HtmlHelper.fromHtml(Joiner.on("<br/>").join(actions)), {
uel.log(Action.CALIBRATION, ValueWithUnit(bg, units)) uel.log(Action.CALIBRATION, Sources.CalibrationDialog, ValueWithUnit.fromGlucoseUnit(bg, units))
xdripCalibrations.sendIntent(bg) xdripCalibrations.sendIntent(bg)
}) })
} }

View file

@ -16,22 +16,22 @@ import info.nightscout.androidaps.data.Profile
import info.nightscout.androidaps.database.AppRepository import info.nightscout.androidaps.database.AppRepository
import info.nightscout.androidaps.database.entities.TemporaryTarget import info.nightscout.androidaps.database.entities.TemporaryTarget
import info.nightscout.androidaps.database.entities.UserEntry.Action import info.nightscout.androidaps.database.entities.UserEntry.Action
import info.nightscout.androidaps.database.entities.UserEntry.Units import info.nightscout.androidaps.database.entities.UserEntry.Sources
import info.nightscout.androidaps.database.entities.UserEntry.ValueWithUnit import info.nightscout.androidaps.database.entities.ValueWithUnit
import info.nightscout.androidaps.database.transactions.InsertTemporaryTargetAndCancelCurrentTransaction import info.nightscout.androidaps.database.transactions.InsertTemporaryTargetAndCancelCurrentTransaction
import info.nightscout.androidaps.databinding.DialogCarbsBinding import info.nightscout.androidaps.databinding.DialogCarbsBinding
import info.nightscout.androidaps.extensions.formatColor
import info.nightscout.androidaps.interfaces.Constraint import info.nightscout.androidaps.interfaces.Constraint
import info.nightscout.androidaps.interfaces.IobCobCalculator
import info.nightscout.androidaps.interfaces.ProfileFunction import info.nightscout.androidaps.interfaces.ProfileFunction
import info.nightscout.androidaps.logging.LTag import info.nightscout.androidaps.logging.LTag
import info.nightscout.androidaps.logging.UserEntryLogger import info.nightscout.androidaps.logging.UserEntryLogger
import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorPlugin
import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin
import info.nightscout.androidaps.queue.Callback import info.nightscout.androidaps.queue.Callback
import info.nightscout.androidaps.queue.CommandQueue import info.nightscout.androidaps.queue.CommandQueue
import info.nightscout.androidaps.utils.* import info.nightscout.androidaps.utils.*
import info.nightscout.androidaps.utils.alertDialogs.OKDialog import info.nightscout.androidaps.utils.alertDialogs.OKDialog
import info.nightscout.androidaps.utils.extensions.formatColor
import info.nightscout.androidaps.utils.resources.ResourceHelper import info.nightscout.androidaps.utils.resources.ResourceHelper
import io.reactivex.disposables.CompositeDisposable import io.reactivex.disposables.CompositeDisposable
import io.reactivex.rxkotlin.plusAssign import io.reactivex.rxkotlin.plusAssign
@ -49,7 +49,7 @@ class CarbsDialog : DialogFragmentWithDate() {
@Inject lateinit var defaultValueHelper: DefaultValueHelper @Inject lateinit var defaultValueHelper: DefaultValueHelper
@Inject lateinit var treatmentsPlugin: TreatmentsPlugin @Inject lateinit var treatmentsPlugin: TreatmentsPlugin
@Inject lateinit var profileFunction: ProfileFunction @Inject lateinit var profileFunction: ProfileFunction
@Inject lateinit var iobCobCalculatorPlugin: IobCobCalculatorPlugin @Inject lateinit var iobCobCalculator: IobCobCalculator
@Inject lateinit var uel: UserEntryLogger @Inject lateinit var uel: UserEntryLogger
@Inject lateinit var carbTimer: CarbTimer @Inject lateinit var carbTimer: CarbTimer
@Inject lateinit var commandQueue: CommandQueue @Inject lateinit var commandQueue: CommandQueue
@ -144,7 +144,7 @@ class CarbsDialog : DialogFragmentWithDate() {
validateInputs() validateInputs()
} }
iobCobCalculatorPlugin.actualBg()?.let { bgReading -> iobCobCalculator.ads.actualBg()?.let { bgReading ->
if (bgReading.value < 72) if (bgReading.value < 72)
binding.hypoTt.isChecked = true binding.hypoTt.isChecked = true
} }
@ -224,7 +224,10 @@ class CarbsDialog : DialogFragmentWithDate() {
OKDialog.showConfirmation(activity, resourceHelper.gs(R.string.carbs), HtmlHelper.fromHtml(Joiner.on("<br/>").join(actions)), { OKDialog.showConfirmation(activity, resourceHelper.gs(R.string.carbs), HtmlHelper.fromHtml(Joiner.on("<br/>").join(actions)), {
when { when {
activitySelected -> { 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( disposable += repository.runTransactionForResult(InsertTemporaryTargetAndCancelCurrentTransaction(
timestamp = System.currentTimeMillis(), timestamp = System.currentTimeMillis(),
duration = TimeUnit.MINUTES.toMillis(activityTTDuration.toLong()), duration = TimeUnit.MINUTES.toMillis(activityTTDuration.toLong()),
@ -240,7 +243,10 @@ class CarbsDialog : DialogFragmentWithDate() {
} }
eatingSoonSelected -> { 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( disposable += repository.runTransactionForResult(InsertTemporaryTargetAndCancelCurrentTransaction(
timestamp = System.currentTimeMillis(), timestamp = System.currentTimeMillis(),
duration = TimeUnit.MINUTES.toMillis(eatingSoonTTDuration.toLong()), duration = TimeUnit.MINUTES.toMillis(eatingSoonTTDuration.toLong()),
@ -256,7 +262,10 @@ class CarbsDialog : DialogFragmentWithDate() {
} }
hypoSelected -> { 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( disposable += repository.runTransactionForResult(InsertTemporaryTargetAndCancelCurrentTransaction(
timestamp = System.currentTimeMillis(), timestamp = System.currentTimeMillis(),
duration = TimeUnit.MINUTES.toMillis(hypoTTDuration.toLong()), duration = TimeUnit.MINUTES.toMillis(hypoTTDuration.toLong()),
@ -279,24 +288,22 @@ class CarbsDialog : DialogFragmentWithDate() {
detailedBolusInfo.notes = notes detailedBolusInfo.notes = notes
detailedBolusInfo.carbsDuration = T.hours(duration.toLong()).msecs() detailedBolusInfo.carbsDuration = T.hours(duration.toLong()).msecs()
detailedBolusInfo.carbsTimestamp = time detailedBolusInfo.carbsTimestamp = time
uel.log(Action.CARBS, detailedBolusInfo.notes, uel.log(if (duration == 0) Action.CARBS else Action.EXTENDED_CARBS, Sources.CarbDialog,
ValueWithUnit(detailedBolusInfo.timestamp, Units.Timestamp), notes,
ValueWithUnit(detailedBolusInfo.carbs, Units.G), ValueWithUnit.Timestamp(eventTime).takeIf { eventTimeChanged },
ValueWithUnit(detailedBolusInfo.carbTime, Units.M, detailedBolusInfo.carbTime != 0), ValueWithUnit.Gram(carbsAfterConstraints),
ValueWithUnit(T.msecs(detailedBolusInfo.carbsDuration).hours(), Units.H, detailedBolusInfo.carbsDuration != 0L) ValueWithUnit.Minute(timeOffset).takeIf { timeOffset != 0 },
) ValueWithUnit.Hour(duration).takeIf { duration != 0 })
commandQueue.bolus(detailedBolusInfo, object : Callback() { commandQueue.bolus(detailedBolusInfo, object : Callback() {
override fun run() { override fun run() {
if (!result.success) { if (!result.success) {
ErrorHelperActivity.runAlarm(ctx, result.comment, resourceHelper.gs(R.string.treatmentdeliveryerror), R.raw.boluserror) ErrorHelperActivity.runAlarm(ctx, result.comment, resourceHelper.gs(R.string.treatmentdeliveryerror), R.raw.boluserror)
} else }
uel.log(Action.BOLUS, notes, ValueWithUnit(carbsAfterConstraints, Units.G))
} }
}) })
} }
if (useAlarm && carbs > 0 && timeOffset > 0) { 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) }, null)
} }

View file

@ -14,10 +14,10 @@ import info.nightscout.androidaps.Constants
import info.nightscout.androidaps.R import info.nightscout.androidaps.R
import info.nightscout.androidaps.data.Profile import info.nightscout.androidaps.data.Profile
import info.nightscout.androidaps.database.AppRepository 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.TherapyEvent
import info.nightscout.androidaps.database.entities.UserEntry.Action import info.nightscout.androidaps.database.entities.UserEntry.Action
import info.nightscout.androidaps.database.entities.UserEntry.Units import info.nightscout.androidaps.database.entities.UserEntry.Sources
import info.nightscout.androidaps.database.entities.UserEntry.ValueWithUnit
import info.nightscout.androidaps.database.transactions.InsertIfNewByTimestampTherapyEventTransaction import info.nightscout.androidaps.database.transactions.InsertIfNewByTimestampTherapyEventTransaction
import info.nightscout.androidaps.databinding.DialogCareBinding import info.nightscout.androidaps.databinding.DialogCareBinding
import info.nightscout.androidaps.interfaces.ProfileFunction import info.nightscout.androidaps.interfaces.ProfileFunction
@ -28,7 +28,7 @@ import info.nightscout.androidaps.utils.HtmlHelper
import info.nightscout.androidaps.utils.T import info.nightscout.androidaps.utils.T
import info.nightscout.androidaps.utils.Translator import info.nightscout.androidaps.utils.Translator
import info.nightscout.androidaps.utils.alertDialogs.OKDialog 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 info.nightscout.androidaps.utils.resources.ResourceHelper
import io.reactivex.disposables.CompositeDisposable import io.reactivex.disposables.CompositeDisposable
import io.reactivex.rxkotlin.plusAssign import io.reactivex.rxkotlin.plusAssign
@ -60,7 +60,8 @@ class CareDialog : DialogFragmentWithDate() {
} }
private var options: EventType = EventType.BGCHECK private var options: EventType = EventType.BGCHECK
private var valuesWithUnit = mutableListOf<ValueWithUnit>() //private var valuesWithUnit = mutableListOf<XXXValueWithUnit?>()
private var valuesWithUnit = mutableListOf<ValueWithUnit?>()
@StringRes @StringRes
private var event: Int = R.string.none private var event: Int = R.string.none
@ -198,17 +199,17 @@ class CareDialog : DialogFragmentWithDate() {
binding.sensor.isChecked -> TherapyEvent.MeterType.SENSOR binding.sensor.isChecked -> TherapyEvent.MeterType.SENSOR
else -> TherapyEvent.MeterType.MANUAL 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)) actions.add(resourceHelper.gs(R.string.treatments_wizard_bg_label) + ": " + Profile.toCurrentUnitsString(profileFunction, binding.bg.value) + " " + resourceHelper.gs(unitResId))
therapyEvent.glucoseType = meterType therapyEvent.glucoseType = meterType
therapyEvent.glucose = binding.bg.value therapyEvent.glucose = binding.bg.value
valuesWithUnit.add(ValueWithUnit(binding.bg.value.toDouble(), profileFunction.getUnits())) valuesWithUnit.add(ValueWithUnit.fromGlucoseUnit(binding.bg.value.toDouble(), profileFunction.getUnits()))
valuesWithUnit.add(ValueWithUnit(meterType.text, Units.TherapyEvent)) valuesWithUnit.add(ValueWithUnit.TherapyEventMeterType(meterType))
} }
if (options == EventType.NOTE || options == EventType.EXERCISE) { 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())) 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() 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() val notes = binding.notesLayout.notes.text.toString()
if (notes.isNotEmpty()) { if (notes.isNotEmpty()) {
@ -220,6 +221,16 @@ class CareDialog : DialogFragmentWithDate() {
therapyEvent.enteredBy = enteredBy 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 -> activity?.let { activity ->
OKDialog.showConfirmation(activity, resourceHelper.gs(event), HtmlHelper.fromHtml(Joiner.on("<br/>").join(actions)), { OKDialog.showConfirmation(activity, resourceHelper.gs(event), HtmlHelper.fromHtml(Joiner.on("<br/>").join(actions)), {
disposable += repository.runTransactionForResult(InsertIfNewByTimestampTherapyEventTransaction(therapyEvent)) disposable += repository.runTransactionForResult(InsertIfNewByTimestampTherapyEventTransaction(therapyEvent))
@ -227,9 +238,9 @@ class CareDialog : DialogFragmentWithDate() {
{ result -> result.inserted.forEach { aapsLogger.debug(LTag.DATABASE, "Inserted therapy event $it") } }, { result -> result.inserted.forEach { aapsLogger.debug(LTag.DATABASE, "Inserted therapy event $it") } },
{ aapsLogger.error(LTag.DATABASE, "Error while saving therapy event", it) } { aapsLogger.error(LTag.DATABASE, "Error while saving therapy event", it) }
) )
valuesWithUnit.add(0, ValueWithUnit(eventTime, Units.Timestamp, eventTimeChanged)) valuesWithUnit.add(0, ValueWithUnit.Timestamp(eventTime).takeIf { eventTimeChanged })
valuesWithUnit.add(1, ValueWithUnit(therapyEvent.type.text, Units.TherapyEvent)) valuesWithUnit.add(1, ValueWithUnit.TherapyEventType(therapyEvent.type))
uel.log(Action.CAREPORTAL, notes, valuesWithUnit) uel.log(Action.CAREPORTAL, source, notes, valuesWithUnit)
}, null) }, null)
} }
return true return true

View file

@ -8,7 +8,9 @@ import android.view.ViewGroup
import com.google.common.base.Joiner import com.google.common.base.Joiner
import info.nightscout.androidaps.R import info.nightscout.androidaps.R
import info.nightscout.androidaps.activities.ErrorHelperActivity 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.databinding.DialogExtendedbolusBinding
import info.nightscout.androidaps.interfaces.ActivePluginProvider import info.nightscout.androidaps.interfaces.ActivePluginProvider
import info.nightscout.androidaps.interfaces.CommandQueueProvider import info.nightscout.androidaps.interfaces.CommandQueueProvider
@ -19,7 +21,7 @@ import info.nightscout.androidaps.queue.Callback
import info.nightscout.androidaps.utils.HtmlHelper import info.nightscout.androidaps.utils.HtmlHelper
import info.nightscout.androidaps.utils.SafeParse import info.nightscout.androidaps.utils.SafeParse
import info.nightscout.androidaps.utils.alertDialogs.OKDialog 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.resources.ResourceHelper
import java.text.DecimalFormat import java.text.DecimalFormat
import java.util.* import java.util.*
@ -88,7 +90,9 @@ class ExtendedBolusDialog : DialogFragmentWithDate() {
activity?.let { activity -> activity?.let { activity ->
OKDialog.showConfirmation(activity, resourceHelper.gs(R.string.extended_bolus), HtmlHelper.fromHtml(Joiner.on("<br/>").join(actions)), { OKDialog.showConfirmation(activity, resourceHelper.gs(R.string.extended_bolus), HtmlHelper.fromHtml(Joiner.on("<br/>").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() { commandQueue.extendedBolus(insulinAfterConstraint, durationInMinutes, object : Callback() {
override fun run() { override fun run() {
if (!result.success) { if (!result.success) {

View file

@ -10,10 +10,10 @@ import info.nightscout.androidaps.R
import info.nightscout.androidaps.activities.ErrorHelperActivity import info.nightscout.androidaps.activities.ErrorHelperActivity
import info.nightscout.androidaps.data.DetailedBolusInfo import info.nightscout.androidaps.data.DetailedBolusInfo
import info.nightscout.androidaps.database.AppRepository 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.TherapyEvent
import info.nightscout.androidaps.database.entities.UserEntry.Action import info.nightscout.androidaps.database.entities.UserEntry.Action
import info.nightscout.androidaps.database.entities.UserEntry.Units import info.nightscout.androidaps.database.entities.UserEntry.Sources
import info.nightscout.androidaps.database.entities.UserEntry.ValueWithUnit
import info.nightscout.androidaps.database.transactions.InsertIfNewByTimestampTherapyEventTransaction import info.nightscout.androidaps.database.transactions.InsertIfNewByTimestampTherapyEventTransaction
import info.nightscout.androidaps.databinding.DialogFillBinding import info.nightscout.androidaps.databinding.DialogFillBinding
import info.nightscout.androidaps.interfaces.ActivePluginProvider import info.nightscout.androidaps.interfaces.ActivePluginProvider
@ -27,7 +27,7 @@ import info.nightscout.androidaps.utils.DecimalFormatter
import info.nightscout.androidaps.utils.HtmlHelper import info.nightscout.androidaps.utils.HtmlHelper
import info.nightscout.androidaps.utils.SafeParse import info.nightscout.androidaps.utils.SafeParse
import info.nightscout.androidaps.utils.alertDialogs.OKDialog 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.resources.ResourceHelper
import io.reactivex.disposables.CompositeDisposable import io.reactivex.disposables.CompositeDisposable
import io.reactivex.rxkotlin.plusAssign import io.reactivex.rxkotlin.plusAssign
@ -123,7 +123,7 @@ class FillDialog : DialogFragmentWithDate() {
val insulinChange = binding.fillCartridgeChange.isChecked val insulinChange = binding.fillCartridgeChange.isChecked
if (insulinChange) if (insulinChange)
actions.add(resourceHelper.gs(R.string.record_insulin_cartridge_change).formatColor(resourceHelper, R.color.actionsConfirm)) 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()) if (notes.isNotEmpty())
actions.add(resourceHelper.gs(R.string.notes_label) + ": " + notes) actions.add(resourceHelper.gs(R.string.notes_label) + ": " + notes)
eventTime -= eventTime % 1000 eventTime -= eventTime % 1000
@ -135,11 +135,16 @@ class FillDialog : DialogFragmentWithDate() {
activity?.let { activity -> activity?.let { activity ->
OKDialog.showConfirmation(activity, resourceHelper.gs(R.string.primefill), HtmlHelper.fromHtml(Joiner.on("<br/>").join(actions)), { OKDialog.showConfirmation(activity, resourceHelper.gs(R.string.primefill), HtmlHelper.fromHtml(Joiner.on("<br/>").join(actions)), {
if (insulinAfterConstraints > 0) { 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) requestPrimeBolus(insulinAfterConstraints, notes)
} }
if (siteChange) { if (siteChange) {
uel.log(Action.CAREPORTAL, notes, ValueWithUnit(TherapyEvent.Type.CANNULA_CHANGE.text, Units.TherapyEvent)) uel.log(Action.SITE_CHANGE, Sources.FillDialog,
notes,
ValueWithUnit.Timestamp(eventTime).takeIf { eventTimeChanged },
ValueWithUnit.TherapyEventType(TherapyEvent.Type.CANNULA_CHANGE))
disposable += repository.runTransactionForResult(InsertIfNewByTimestampTherapyEventTransaction( disposable += repository.runTransactionForResult(InsertIfNewByTimestampTherapyEventTransaction(
timestamp = eventTime, timestamp = eventTime,
type = TherapyEvent.Type.CANNULA_CHANGE, type = TherapyEvent.Type.CANNULA_CHANGE,
@ -152,7 +157,10 @@ class FillDialog : DialogFragmentWithDate() {
} }
if (insulinChange) { if (insulinChange) {
// add a second for case of both checked // add a second for case of both checked
uel.log(Action.CAREPORTAL, notes, ValueWithUnit(TherapyEvent.Type.INSULIN_CHANGE.text, Units.TherapyEvent)) uel.log(Action.RESERVOIR_CHANGE, Sources.FillDialog,
notes,
ValueWithUnit.Timestamp(eventTime).takeIf { eventTimeChanged },
ValueWithUnit.TherapyEventType(TherapyEvent.Type.INSULIN_CHANGE))
disposable += repository.runTransactionForResult(InsertIfNewByTimestampTherapyEventTransaction( disposable += repository.runTransactionForResult(InsertIfNewByTimestampTherapyEventTransaction(
timestamp = eventTime + 1000, timestamp = eventTime + 1000,
type = TherapyEvent.Type.INSULIN_CHANGE, type = TherapyEvent.Type.INSULIN_CHANGE,

View file

@ -15,10 +15,10 @@ import info.nightscout.androidaps.activities.ErrorHelperActivity
import info.nightscout.androidaps.data.DetailedBolusInfo import info.nightscout.androidaps.data.DetailedBolusInfo
import info.nightscout.androidaps.data.Profile import info.nightscout.androidaps.data.Profile
import info.nightscout.androidaps.database.AppRepository 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.TemporaryTarget
import info.nightscout.androidaps.database.entities.UserEntry.Action import info.nightscout.androidaps.database.entities.UserEntry.Action
import info.nightscout.androidaps.database.entities.UserEntry.Units import info.nightscout.androidaps.database.entities.UserEntry.Sources
import info.nightscout.androidaps.database.entities.UserEntry.ValueWithUnit
import info.nightscout.androidaps.database.transactions.InsertTemporaryTargetAndCancelCurrentTransaction import info.nightscout.androidaps.database.transactions.InsertTemporaryTargetAndCancelCurrentTransaction
import info.nightscout.androidaps.databinding.DialogInsulinBinding import info.nightscout.androidaps.databinding.DialogInsulinBinding
import info.nightscout.androidaps.interfaces.ActivePluginProvider import info.nightscout.androidaps.interfaces.ActivePluginProvider
@ -28,13 +28,12 @@ import info.nightscout.androidaps.interfaces.ProfileFunction
import info.nightscout.androidaps.logging.LTag import info.nightscout.androidaps.logging.LTag
import info.nightscout.androidaps.logging.UserEntryLogger import info.nightscout.androidaps.logging.UserEntryLogger
import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker 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.queue.Callback
import info.nightscout.androidaps.utils.* import info.nightscout.androidaps.utils.*
import info.nightscout.androidaps.utils.alertDialogs.OKDialog 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.toSignedString
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.resources.ResourceHelper
import io.reactivex.disposables.CompositeDisposable import io.reactivex.disposables.CompositeDisposable
import io.reactivex.rxkotlin.plusAssign import io.reactivex.rxkotlin.plusAssign
@ -57,7 +56,6 @@ class InsulinDialog : DialogFragmentWithDate() {
@Inject lateinit var repository: AppRepository @Inject lateinit var repository: AppRepository
@Inject lateinit var config: Config @Inject lateinit var config: Config
@Inject lateinit var uel: UserEntryLogger @Inject lateinit var uel: UserEntryLogger
@Inject lateinit var nsUpload: NSUpload
companion object { 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)) 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 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) if (timeOffset != 0)
actions.add(resourceHelper.gs(R.string.time) + ": " + dateUtil.dateAndTimeString(time)) actions.add(resourceHelper.gs(R.string.time) + ": " + dateUtil.dateAndTimeString(time))
@ -189,7 +187,11 @@ class InsulinDialog : DialogFragmentWithDate() {
activity?.let { activity -> activity?.let { activity ->
OKDialog.showConfirmation(activity, resourceHelper.gs(R.string.bolus), HtmlHelper.fromHtml(Joiner.on("<br/>").join(actions)), { OKDialog.showConfirmation(activity, resourceHelper.gs(R.string.bolus), HtmlHelper.fromHtml(Joiner.on("<br/>").join(actions)), {
if (eatingSoonChecked) { 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( disposable += repository.runTransactionForResult(InsertTemporaryTargetAndCancelCurrentTransaction(
timestamp = System.currentTimeMillis(), timestamp = System.currentTimeMillis(),
duration = TimeUnit.MINUTES.toMillis(eatingSoonTTDuration.toLong()), duration = TimeUnit.MINUTES.toMillis(eatingSoonTTDuration.toLong()),
@ -210,25 +212,26 @@ class InsulinDialog : DialogFragmentWithDate() {
detailedBolusInfo.context = context detailedBolusInfo.context = context
detailedBolusInfo.notes = notes detailedBolusInfo.notes = notes
detailedBolusInfo.timestamp = time detailedBolusInfo.timestamp = time
uel.log(Action.BOLUS_RECORD, notes,
ValueWithUnit(detailedBolusInfo.timestamp, Units.Timestamp),
ValueWithUnit(detailedBolusInfo.insulin, Units.U),
ValueWithUnit(timeOffset, Units.M, timeOffset != 0)
)
if (recordOnlyChecked) { if (recordOnlyChecked) {
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()) disposable += repository.runTransactionForResult(detailedBolusInfo.insertBolusTransaction())
.subscribe( .subscribe(
{ result -> result.inserted.forEach { aapsLogger.debug(LTag.DATABASE, "Inserted bolus $it") } }, { result -> result.inserted.forEach { aapsLogger.debug(LTag.DATABASE, "Inserted bolus $it") } },
{ aapsLogger.error(LTag.DATABASE, "Error while saving bolus", it) } { aapsLogger.error(LTag.DATABASE, "Error while saving bolus", it) }
) )
} else { } else {
uel.log(Action.BOLUS, Sources.InsulinDialog,
notes,
ValueWithUnit.Insulin(insulinAfterConstraints))
commandQueue.bolus(detailedBolusInfo, object : Callback() { commandQueue.bolus(detailedBolusInfo, object : Callback() {
override fun run() { override fun run() {
if (!result.success) { if (!result.success) {
ErrorHelperActivity.runAlarm(ctx, result.comment, resourceHelper.gs(R.string.treatmentdeliveryerror), info.nightscout.androidaps.dana.R.raw.boluserror) ErrorHelperActivity.runAlarm(ctx, result.comment, resourceHelper.gs(R.string.treatmentdeliveryerror), info.nightscout.androidaps.dana.R.raw.boluserror)
} else }
uel.log(Action.BOLUS, notes, ValueWithUnit(insulinAfterConstraints, Units.U))
} }
}) })
} }

View file

@ -12,7 +12,9 @@ import androidx.fragment.app.FragmentManager
import dagger.android.support.DaggerDialogFragment import dagger.android.support.DaggerDialogFragment
import info.nightscout.androidaps.R import info.nightscout.androidaps.R
import info.nightscout.androidaps.activities.ErrorHelperActivity 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.databinding.DialogLoopBinding
import info.nightscout.androidaps.events.EventPreferenceChange import info.nightscout.androidaps.events.EventPreferenceChange
import info.nightscout.androidaps.events.EventRefreshOverview import info.nightscout.androidaps.events.EventRefreshOverview
@ -27,7 +29,7 @@ import info.nightscout.androidaps.queue.Callback
import info.nightscout.androidaps.utils.FabricPrivacy import info.nightscout.androidaps.utils.FabricPrivacy
import info.nightscout.androidaps.utils.ToastUtils import info.nightscout.androidaps.utils.ToastUtils
import info.nightscout.androidaps.utils.alertDialogs.OKDialog 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.resources.ResourceHelper
import info.nightscout.androidaps.utils.sharedPreferences.SP import info.nightscout.androidaps.utils.sharedPreferences.SP
import javax.inject.Inject import javax.inject.Inject
@ -239,28 +241,28 @@ class LoopDialog : DaggerDialogFragment() {
val profile = profileFunction.getProfile() ?: return true val profile = profileFunction.getProfile() ?: return true
when (v.id) { when (v.id) {
R.id.overview_closeloop -> { 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") sp.putString(R.string.key_aps_mode, "closed")
rxBus.send(EventPreferenceChange(resourceHelper.gs(R.string.closedloop))) rxBus.send(EventPreferenceChange(resourceHelper.gs(R.string.closedloop)))
return true return true
} }
R.id.overview_lgsloop -> { 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") sp.putString(R.string.key_aps_mode, "lgs")
rxBus.send(EventPreferenceChange(resourceHelper.gs(R.string.lowglucosesuspend))) rxBus.send(EventPreferenceChange(resourceHelper.gs(R.string.lowglucosesuspend)))
return true return true
} }
R.id.overview_openloop -> { 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") sp.putString(R.string.key_aps_mode, "open")
rxBus.send(EventPreferenceChange(resourceHelper.gs(R.string.lowglucosesuspend))) rxBus.send(EventPreferenceChange(resourceHelper.gs(R.string.lowglucosesuspend)))
return true return true
} }
R.id.overview_disable -> { R.id.overview_disable -> {
uel.log(Action.LOOP_DISABLED) uel.log(Action.LOOP_DISABLED, Sources.LoopDialog)
loopPlugin.setPluginEnabled(PluginType.LOOP, false) loopPlugin.setPluginEnabled(PluginType.LOOP, false)
loopPlugin.setFragmentVisible(PluginType.LOOP, false) loopPlugin.setFragmentVisible(PluginType.LOOP, false)
configBuilderPlugin.storeSettings("DisablingLoop") configBuilderPlugin.storeSettings("DisablingLoop")
@ -277,7 +279,7 @@ class LoopDialog : DaggerDialogFragment() {
} }
R.id.overview_enable -> { R.id.overview_enable -> {
uel.log(Action.LOOP_ENABLED) uel.log(Action.LOOP_ENABLED, Sources.LoopDialog)
loopPlugin.setPluginEnabled(PluginType.LOOP, true) loopPlugin.setPluginEnabled(PluginType.LOOP, true)
loopPlugin.setFragmentVisible(PluginType.LOOP, true) loopPlugin.setFragmentVisible(PluginType.LOOP, true)
configBuilderPlugin.storeSettings("EnablingLoop") configBuilderPlugin.storeSettings("EnablingLoop")
@ -287,7 +289,7 @@ class LoopDialog : DaggerDialogFragment() {
} }
R.id.overview_resume, R.id.overview_reconnect -> { 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) loopPlugin.suspendTo(0L)
rxBus.send(EventRefreshOverview("suspendmenu")) rxBus.send(EventRefreshOverview("suspendmenu"))
commandQueue.cancelTempBasal(true, object : Callback() { commandQueue.cancelTempBasal(true, object : Callback() {
@ -303,49 +305,49 @@ class LoopDialog : DaggerDialogFragment() {
} }
R.id.overview_suspend_1h -> { 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) loopPlugin.suspendLoop(60)
rxBus.send(EventRefreshOverview("suspendmenu")) rxBus.send(EventRefreshOverview("suspendmenu"))
return true return true
} }
R.id.overview_suspend_2h -> { 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) loopPlugin.suspendLoop(120)
rxBus.send(EventRefreshOverview("suspendmenu")) rxBus.send(EventRefreshOverview("suspendmenu"))
return true return true
} }
R.id.overview_suspend_3h -> { 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) loopPlugin.suspendLoop(180)
rxBus.send(EventRefreshOverview("suspendmenu")) rxBus.send(EventRefreshOverview("suspendmenu"))
return true return true
} }
R.id.overview_suspend_10h -> { 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) loopPlugin.suspendLoop(600)
rxBus.send(EventRefreshOverview("suspendmenu")) rxBus.send(EventRefreshOverview("suspendmenu"))
return true return true
} }
R.id.overview_disconnect_15m -> { 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) loopPlugin.disconnectPump(15, profile)
rxBus.send(EventRefreshOverview("suspendmenu")) rxBus.send(EventRefreshOverview("suspendmenu"))
return true return true
} }
R.id.overview_disconnect_30m -> { 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) loopPlugin.disconnectPump(30, profile)
rxBus.send(EventRefreshOverview("suspendmenu")) rxBus.send(EventRefreshOverview("suspendmenu"))
return true return true
} }
R.id.overview_disconnect_1h -> { 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) loopPlugin.disconnectPump(60, profile)
sp.putBoolean(R.string.key_objectiveusedisconnect, true) sp.putBoolean(R.string.key_objectiveusedisconnect, true)
rxBus.send(EventRefreshOverview("suspendmenu")) rxBus.send(EventRefreshOverview("suspendmenu"))
@ -353,14 +355,14 @@ class LoopDialog : DaggerDialogFragment() {
} }
R.id.overview_disconnect_2h -> { 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) loopPlugin.disconnectPump(120, profile)
rxBus.send(EventRefreshOverview("suspendmenu")) rxBus.send(EventRefreshOverview("suspendmenu"))
return true return true
} }
R.id.overview_disconnect_3h -> { 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) loopPlugin.disconnectPump(180, profile)
rxBus.send(EventRefreshOverview("suspendmenu")) rxBus.send(EventRefreshOverview("suspendmenu"))
return true return true

View file

@ -8,13 +8,14 @@ import android.widget.ArrayAdapter
import com.google.common.base.Joiner import com.google.common.base.Joiner
import info.nightscout.androidaps.Constants import info.nightscout.androidaps.Constants
import info.nightscout.androidaps.R 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.databinding.DialogProfileswitchBinding
import info.nightscout.androidaps.interfaces.ActivePluginProvider import info.nightscout.androidaps.interfaces.ActivePluginProvider
import info.nightscout.androidaps.interfaces.ProfileFunction import info.nightscout.androidaps.interfaces.ProfileFunction
import info.nightscout.androidaps.logging.UserEntryLogger import info.nightscout.androidaps.logging.UserEntryLogger
import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin
import info.nightscout.androidaps.utils.DateUtil
import info.nightscout.androidaps.utils.HtmlHelper import info.nightscout.androidaps.utils.HtmlHelper
import info.nightscout.androidaps.utils.alertDialogs.OKDialog import info.nightscout.androidaps.utils.alertDialogs.OKDialog
import info.nightscout.androidaps.utils.resources.ResourceHelper import info.nightscout.androidaps.utils.resources.ResourceHelper
@ -81,7 +82,7 @@ class ProfileSwitchDialog : DialogFragmentWithDate() {
binding.profile.setSelection(p) binding.profile.setSelection(p)
} ?: return } ?: return
treatmentsPlugin.getProfileSwitchFromHistory(DateUtil.now())?.let { ps -> treatmentsPlugin.getProfileSwitchFromHistory(dateUtil.now())?.let { ps ->
if (ps.isCPP) { if (ps.isCPP) {
binding.reuselayout.visibility = View.VISIBLE binding.reuselayout.visibility = View.VISIBLE
binding.reusebutton.text = resourceHelper.gs(R.string.reuse_profile_pct_hours, ps.percentage, ps.timeshift) binding.reusebutton.text = resourceHelper.gs(R.string.reuse_profile_pct_hours, ps.percentage, ps.timeshift)
@ -125,7 +126,14 @@ class ProfileSwitchDialog : DialogFragmentWithDate() {
activity?.let { activity -> activity?.let { activity ->
OKDialog.showConfirmation(activity, resourceHelper.gs(R.string.careportal_profileswitch), HtmlHelper.fromHtml(Joiner.on("<br/>").join(actions)), { OKDialog.showConfirmation(activity, resourceHelper.gs(R.string.careportal_profileswitch), HtmlHelper.fromHtml(Joiner.on("<br/>").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) treatmentsPlugin.doProfileSwitch(profileStore, profile, duration, percent, timeShift, eventTime)
}) })
} }

View file

@ -8,20 +8,18 @@ import android.view.ViewGroup
import com.google.common.base.Joiner import com.google.common.base.Joiner
import info.nightscout.androidaps.R import info.nightscout.androidaps.R
import info.nightscout.androidaps.activities.ErrorHelperActivity 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.databinding.DialogTempbasalBinding
import info.nightscout.androidaps.interfaces.ActivePluginProvider import info.nightscout.androidaps.interfaces.*
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.logging.UserEntryLogger import info.nightscout.androidaps.logging.UserEntryLogger
import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker
import info.nightscout.androidaps.queue.Callback import info.nightscout.androidaps.queue.Callback
import info.nightscout.androidaps.utils.HtmlHelper import info.nightscout.androidaps.utils.HtmlHelper
import info.nightscout.androidaps.utils.SafeParse import info.nightscout.androidaps.utils.SafeParse
import info.nightscout.androidaps.utils.alertDialogs.OKDialog 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.resources.ResourceHelper
import java.text.DecimalFormat import java.text.DecimalFormat
import java.util.* import java.util.*
@ -126,11 +124,15 @@ class TempBasalDialog : DialogFragmentWithDate() {
} }
} }
if (isPercentPump) { if (isPercentPump) {
uel.log(Action.TEMP_BASAL, ValueWithUnit(percent, Units.Percent), ValueWithUnit(durationInMinutes, Units.M)) uel.log(Action.TEMP_BASAL, Sources.TempBasalDialog,
commandQueue.tempBasalPercent(percent, durationInMinutes, true, profile, callback) ValueWithUnit.Percent(percent),
ValueWithUnit.Minute(durationInMinutes))
commandQueue.tempBasalPercent(percent, durationInMinutes, true, profile, PumpSync.TemporaryBasalType.NORMAL, callback)
} else { } else {
uel.log(Action.TEMP_BASAL, ValueWithUnit(absolute, Units.U), ValueWithUnit(durationInMinutes, Units.M)) uel.log(Action.TEMP_BASAL, Sources.TempBasalDialog,
commandQueue.tempBasalAbsolute(absolute, durationInMinutes, true, profile, callback) ValueWithUnit.Insulin(absolute),
ValueWithUnit.Minute(durationInMinutes))
commandQueue.tempBasalAbsolute(absolute, durationInMinutes, true, profile, PumpSync.TemporaryBasalType.NORMAL, callback)
} }
}) })
} }

View file

@ -12,8 +12,10 @@ import info.nightscout.androidaps.R
import info.nightscout.androidaps.data.Profile import info.nightscout.androidaps.data.Profile
import info.nightscout.androidaps.database.AppRepository import info.nightscout.androidaps.database.AppRepository
import info.nightscout.androidaps.database.ValueWrapper 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.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.CancelCurrentTemporaryTargetIfAnyTransaction
import info.nightscout.androidaps.database.transactions.InsertTemporaryTargetAndCancelCurrentTransaction import info.nightscout.androidaps.database.transactions.InsertTemporaryTargetAndCancelCurrentTransaction
import info.nightscout.androidaps.databinding.DialogTemptargetBinding import info.nightscout.androidaps.databinding.DialogTemptargetBinding
@ -86,7 +88,7 @@ class TempTargetDialog : DialogFragmentWithDate() {
// temp target // temp target
context?.let { context -> 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 binding.targetCancel.visibility = View.VISIBLE
else else
binding.targetCancel.visibility = View.GONE binding.targetCancel.visibility = View.GONE
@ -179,11 +181,11 @@ class TempTargetDialog : DialogFragmentWithDate() {
OKDialog.showConfirmation(activity, resourceHelper.gs(R.string.careportal_temporarytarget), HtmlHelper.fromHtml(Joiner.on("<br/>").join(actions)), { OKDialog.showConfirmation(activity, resourceHelper.gs(R.string.careportal_temporarytarget), HtmlHelper.fromHtml(Joiner.on("<br/>").join(actions)), {
val units = profileFunction.getUnits() val units = profileFunction.getUnits()
when(reason) { 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.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, ValueWithUnit(eventTime, Units.Timestamp, eventTimeChanged), ValueWithUnit(TemporaryTarget.Reason.ACTIVITY.text, Units.TherapyEvent), ValueWithUnit(target, units), ValueWithUnit(duration, Units.M)) 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, ValueWithUnit(eventTime, Units.Timestamp, eventTimeChanged), ValueWithUnit(TemporaryTarget.Reason.HYPOGLYCEMIA.text, Units.TherapyEvent), ValueWithUnit(target, units), ValueWithUnit(duration, Units.M)) 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, ValueWithUnit(eventTime, Units.Timestamp, eventTimeChanged), ValueWithUnit(TemporaryTarget.Reason.CUSTOM.text, Units.TherapyEvent), ValueWithUnit(target, units), ValueWithUnit(duration, Units.M)) 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, ValueWithUnit(eventTime, Units.Timestamp, eventTimeChanged)) resourceHelper.gs(R.string.stoptemptarget) -> uel.log(Action.CANCEL_TT, Sources.TTDialog, ValueWithUnit.Timestamp(eventTime).takeIf { eventTimeChanged })
} }
if (target == 0.0 || duration == 0) { if (target == 0.0 || duration == 0) {
disposable += repository.runTransactionForResult(CancelCurrentTemporaryTargetIfAnyTransaction(eventTime)) disposable += repository.runTransactionForResult(CancelCurrentTemporaryTargetIfAnyTransaction(eventTime))

View file

@ -13,9 +13,9 @@ import info.nightscout.androidaps.R
import info.nightscout.androidaps.activities.ErrorHelperActivity import info.nightscout.androidaps.activities.ErrorHelperActivity
import info.nightscout.androidaps.data.DetailedBolusInfo import info.nightscout.androidaps.data.DetailedBolusInfo
import info.nightscout.androidaps.database.AppRepository 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.Action
import info.nightscout.androidaps.database.entities.UserEntry.Units import info.nightscout.androidaps.database.entities.UserEntry.Sources
import info.nightscout.androidaps.database.entities.UserEntry.ValueWithUnit
import info.nightscout.androidaps.databinding.DialogTreatmentBinding import info.nightscout.androidaps.databinding.DialogTreatmentBinding
import info.nightscout.androidaps.interfaces.ActivePluginProvider import info.nightscout.androidaps.interfaces.ActivePluginProvider
import info.nightscout.androidaps.interfaces.CommandQueueProvider import info.nightscout.androidaps.interfaces.CommandQueueProvider
@ -23,14 +23,13 @@ import info.nightscout.androidaps.interfaces.Constraint
import info.nightscout.androidaps.logging.LTag import info.nightscout.androidaps.logging.LTag
import info.nightscout.androidaps.logging.UserEntryLogger import info.nightscout.androidaps.logging.UserEntryLogger
import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker 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.queue.Callback
import info.nightscout.androidaps.utils.DecimalFormatter import info.nightscout.androidaps.utils.DecimalFormatter
import info.nightscout.androidaps.utils.HtmlHelper import info.nightscout.androidaps.utils.HtmlHelper
import info.nightscout.androidaps.utils.SafeParse import info.nightscout.androidaps.utils.SafeParse
import info.nightscout.androidaps.utils.ToastUtils import info.nightscout.androidaps.utils.ToastUtils
import info.nightscout.androidaps.utils.alertDialogs.OKDialog 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.resources.ResourceHelper
import io.reactivex.disposables.CompositeDisposable import io.reactivex.disposables.CompositeDisposable
import io.reactivex.rxkotlin.plusAssign import io.reactivex.rxkotlin.plusAssign
@ -48,7 +47,6 @@ class TreatmentDialog : DialogFragmentWithDate() {
@Inject lateinit var ctx: Context @Inject lateinit var ctx: Context
@Inject lateinit var config: Config @Inject lateinit var config: Config
@Inject lateinit var uel: UserEntryLogger @Inject lateinit var uel: UserEntryLogger
@Inject lateinit var nsUpload: NSUpload
@Inject lateinit var repository: AppRepository @Inject lateinit var repository: AppRepository
private val disposable = CompositeDisposable() private val disposable = CompositeDisposable()
@ -139,18 +137,23 @@ class TreatmentDialog : DialogFragmentWithDate() {
if (insulinAfterConstraints > 0 || carbsAfterConstraints > 0) { if (insulinAfterConstraints > 0 || carbsAfterConstraints > 0) {
activity?.let { activity -> activity?.let { activity ->
OKDialog.showConfirmation(activity, resourceHelper.gs(R.string.overview_treatment_label), HtmlHelper.fromHtml(Joiner.on("<br/>").join(actions)), { OKDialog.showConfirmation(activity, resourceHelper.gs(R.string.overview_treatment_label), HtmlHelper.fromHtml(Joiner.on("<br/>").join(actions)), {
val action = when {
insulinAfterConstraints.equals(0.0) -> Action.CARBS
carbsAfterConstraints.equals(0) -> Action.BOLUS
else -> Action.TREATMENT
}
val detailedBolusInfo = DetailedBolusInfo() val detailedBolusInfo = DetailedBolusInfo()
if (insulinAfterConstraints == 0.0) detailedBolusInfo.eventType = DetailedBolusInfo.EventType.CARBS_CORRECTION if (insulinAfterConstraints == 0.0) detailedBolusInfo.eventType = DetailedBolusInfo.EventType.CARBS_CORRECTION
if (carbsAfterConstraints == 0) detailedBolusInfo.eventType = DetailedBolusInfo.EventType.CORRECTION_BOLUS if (carbsAfterConstraints == 0) detailedBolusInfo.eventType = DetailedBolusInfo.EventType.CORRECTION_BOLUS
detailedBolusInfo.insulin = insulinAfterConstraints detailedBolusInfo.insulin = insulinAfterConstraints
detailedBolusInfo.carbs = carbsAfterConstraints.toDouble() detailedBolusInfo.carbs = carbsAfterConstraints.toDouble()
detailedBolusInfo.context = context detailedBolusInfo.context = context
uel.log(Action.TREATMENT,
ValueWithUnit(detailedBolusInfo.timestamp, Units.Timestamp),
ValueWithUnit(insulin, Units.U, insulin != 0.0),
ValueWithUnit(carbs, Units.G, carbs != 0)
)
if (recordOnlyChecked) { 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) if (detailedBolusInfo.insulin > 0)
disposable += repository.runTransactionForResult(detailedBolusInfo.insertBolusTransaction()) disposable += repository.runTransactionForResult(detailedBolusInfo.insertBolusTransaction())
.subscribe( .subscribe(
@ -164,6 +167,10 @@ class TreatmentDialog : DialogFragmentWithDate() {
{ aapsLogger.error(LTag.DATABASE, "Error while saving carbs", it) } { aapsLogger.error(LTag.DATABASE, "Error while saving carbs", it) }
) )
} else { } else {
if (detailedBolusInfo.insulin > 0) {
uel.log(action, Sources.TreatmentDialog,
ValueWithUnit.Insulin(insulinAfterConstraints),
ValueWithUnit.Gram(carbsAfterConstraints).takeIf { carbsAfterConstraints != 0 })
commandQueue.bolus(detailedBolusInfo, object : Callback() { commandQueue.bolus(detailedBolusInfo, object : Callback() {
override fun run() { override fun run() {
if (!result.success) { if (!result.success) {
@ -171,6 +178,9 @@ class TreatmentDialog : DialogFragmentWithDate() {
} }
} }
}) })
} else
uel.log(action, Sources.TreatmentDialog,
ValueWithUnit.Gram(carbsAfterConstraints).takeIf { carbs != 0 })
} }
}) })
} }

View file

@ -27,7 +27,6 @@ import info.nightscout.androidaps.interfaces.ActivePluginProvider
import info.nightscout.androidaps.interfaces.Constraint import info.nightscout.androidaps.interfaces.Constraint
import info.nightscout.androidaps.interfaces.IobCobCalculator import info.nightscout.androidaps.interfaces.IobCobCalculator
import info.nightscout.androidaps.interfaces.ProfileFunction import info.nightscout.androidaps.interfaces.ProfileFunction
import info.nightscout.androidaps.interfaces.TreatmentsInterface
import info.nightscout.androidaps.logging.AAPSLogger import info.nightscout.androidaps.logging.AAPSLogger
import info.nightscout.androidaps.logging.LTag import info.nightscout.androidaps.logging.LTag
import info.nightscout.androidaps.plugins.bus.RxBusWrapper import info.nightscout.androidaps.plugins.bus.RxBusWrapper
@ -37,8 +36,8 @@ import info.nightscout.androidaps.utils.DecimalFormatter
import info.nightscout.androidaps.utils.FabricPrivacy import info.nightscout.androidaps.utils.FabricPrivacy
import info.nightscout.androidaps.utils.SafeParse import info.nightscout.androidaps.utils.SafeParse
import info.nightscout.androidaps.utils.ToastUtils import info.nightscout.androidaps.utils.ToastUtils
import info.nightscout.androidaps.utils.extensions.toVisibility import info.nightscout.androidaps.extensions.toVisibility
import info.nightscout.androidaps.utils.extensions.valueToUnits import info.nightscout.androidaps.extensions.valueToUnits
import info.nightscout.androidaps.utils.resources.ResourceHelper import info.nightscout.androidaps.utils.resources.ResourceHelper
import info.nightscout.androidaps.utils.rx.AapsSchedulers import info.nightscout.androidaps.utils.rx.AapsSchedulers
import info.nightscout.androidaps.utils.sharedPreferences.SP import info.nightscout.androidaps.utils.sharedPreferences.SP
@ -64,7 +63,6 @@ class WizardDialog : DaggerDialogFragment() {
@Inject lateinit var activePlugin: ActivePluginProvider @Inject lateinit var activePlugin: ActivePluginProvider
@Inject lateinit var iobCobCalculator: IobCobCalculator @Inject lateinit var iobCobCalculator: IobCobCalculator
@Inject lateinit var repository: AppRepository @Inject lateinit var repository: AppRepository
@Inject lateinit var treatmentsPlugin: TreatmentsInterface
@Inject lateinit var dateUtil: DateUtil @Inject lateinit var dateUtil: DateUtil
private var wizard: BolusWizard? = null private var wizard: BolusWizard? = null
@ -212,7 +210,7 @@ class WizardDialog : DaggerDialogFragment() {
private fun onCheckedChanged(buttonView: CompoundButton, @Suppress("UNUSED_PARAMETER") state: Boolean) { private fun onCheckedChanged(buttonView: CompoundButton, @Suppress("UNUSED_PARAMETER") state: Boolean) {
saveCheckedStates() 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) if (buttonView.id == binding.cobcheckbox.id)
processCobCheckBox() processCobCheckBox()
calculateInsulin() calculateInsulin()
@ -269,12 +267,12 @@ class WizardDialog : DaggerDialogFragment() {
binding.bgInput.setStep(0.1) binding.bgInput.setStep(0.1)
// Set BG if not old // Set BG if not old
binding.bgInput.value = iobCobCalculator.actualBg()?.valueToUnits(units) ?: 0.0 binding.bgInput.value = iobCobCalculator.ads.actualBg()?.valueToUnits(units) ?: 0.0
binding.ttcheckbox.isEnabled = repository.getTemporaryTargetActiveAt(dateUtil._now()).blockingGet() is ValueWrapper.Existing binding.ttcheckbox.isEnabled = repository.getTemporaryTargetActiveAt(dateUtil.now()).blockingGet() is ValueWrapper.Existing
// IOB calculation // IOB calculation
val bolusIob = iobCobCalculator.calculateIobFromBolus().round() val bolusIob = iobCobCalculator.calculateIobFromBolus().round()
val basalIob = treatmentsPlugin.lastCalculationTempBasals.round() val basalIob = iobCobCalculator.calculateIobFromTempBasalsIncludingConvertedExtended().round()
binding.bolusiobinsulin.text = resourceHelper.gs(R.string.formatinsulinunits, -bolusIob.iob) binding.bolusiobinsulin.text = resourceHelper.gs(R.string.formatinsulinunits, -bolusIob.iob)
binding.basaliobinsulin.text = resourceHelper.gs(R.string.formatinsulinunits, -basalIob.basaliob) binding.basaliobinsulin.text = resourceHelper.gs(R.string.formatinsulinunits, -basalIob.basaliob)
@ -310,7 +308,7 @@ class WizardDialog : DaggerDialogFragment() {
} }
bg = if (binding.bgcheckbox.isChecked) bg else 0.0 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 val tempTarget = if (binding.ttcheckbox.isChecked && dbRecord is ValueWrapper.Existing) dbRecord.value else null
// COB // COB

View file

@ -1,3 +0,0 @@
package info.nightscout.androidaps.events
class EventReloadTempBasalData : Event()

View file

@ -1,3 +0,0 @@
package info.nightscout.androidaps.events
class EventReloadTreatmentData(var next: Event) : Event()

View file

@ -23,7 +23,6 @@ import info.nightscout.androidaps.logging.LTag
import info.nightscout.androidaps.plugins.bus.RxBusWrapper import info.nightscout.androidaps.plugins.bus.RxBusWrapper
import info.nightscout.androidaps.plugins.general.overview.OverviewMenus import info.nightscout.androidaps.plugins.general.overview.OverviewMenus
import info.nightscout.androidaps.plugins.general.overview.graphData.GraphData 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.events.EventAutosensCalculationFinished
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.events.EventIobCalculationProgress import info.nightscout.androidaps.plugins.iob.iobCobCalculator.events.EventIobCalculationProgress
import info.nightscout.androidaps.utils.DateUtil 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.FabricPrivacy
import info.nightscout.androidaps.utils.T import info.nightscout.androidaps.utils.T
import info.nightscout.androidaps.utils.buildHelper.BuildHelper 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.rx.AapsSchedulers
import info.nightscout.androidaps.utils.sharedPreferences.SP import info.nightscout.androidaps.utils.sharedPreferences.SP
import io.reactivex.disposables.CompositeDisposable import io.reactivex.disposables.CompositeDisposable
@ -181,16 +180,6 @@ class HistoryBrowseActivity : NoSplashAppCompatActivity() {
} }
}, fabricPrivacy::logException) }, 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 disposable.add(rxBus
.toObservable(EventIobCalculationProgress::class.java) .toObservable(EventIobCalculationProgress::class.java)
.observeOn(aapsSchedulers.main) .observeOn(aapsSchedulers.main)
@ -306,7 +295,8 @@ class HistoryBrowseActivity : NoSplashAppCompatActivity() {
graphData.addInRangeArea(fromTime, toTime, lowLine, highLine) graphData.addInRangeArea(fromTime, toTime, lowLine, highLine)
// **** BG **** // **** BG ****
graphData.addBgReadings(fromTime, toTime, lowLine, highLine, null) graphData.addBgReadings(fromTime, toTime, highLine, null)
if (buildHelper.isDev()) graphData.addBucketedData(fromTime, toTime)
// add target line // add target line
graphData.addTargetLine(fromTime, toTime, profile, null) graphData.addTargetLine(fromTime, toTime, profile, null)

View file

@ -28,7 +28,6 @@ class IobCobCalculatorPluginHistory @Inject constructor(
resourceHelper: ResourceHelper, resourceHelper: ResourceHelper,
profileFunction: ProfileFunction, profileFunction: ProfileFunction,
activePlugin: ActivePluginProvider, activePlugin: ActivePluginProvider,
treatmentsPluginHistory: TreatmentsPluginHistory,
sensitivityOref1Plugin: SensitivityOref1Plugin, sensitivityOref1Plugin: SensitivityOref1Plugin,
sensitivityAAPSPlugin: SensitivityAAPSPlugin, sensitivityAAPSPlugin: SensitivityAAPSPlugin,
sensitivityWeightedAveragePlugin: SensitivityWeightedAveragePlugin, sensitivityWeightedAveragePlugin: SensitivityWeightedAveragePlugin,
@ -36,7 +35,7 @@ class IobCobCalculatorPluginHistory @Inject constructor(
dateUtil: DateUtil, dateUtil: DateUtil,
repository: AppRepository repository: AppRepository
) : IobCobCalculatorPlugin(injector, aapsLogger, aapsSchedulers, rxBus, sp, resourceHelper, profileFunction, ) : 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 override fun onStart() { // do not attach to rxbus
} }

View file

@ -6,7 +6,6 @@ import info.nightscout.androidaps.database.AppRepository
import info.nightscout.androidaps.interfaces.ActivePluginProvider import info.nightscout.androidaps.interfaces.ActivePluginProvider
import info.nightscout.androidaps.interfaces.DatabaseHelperInterface import info.nightscout.androidaps.interfaces.DatabaseHelperInterface
import info.nightscout.androidaps.interfaces.ProfileFunction import info.nightscout.androidaps.interfaces.ProfileFunction
import info.nightscout.androidaps.interfaces.UploadQueueInterface
import info.nightscout.androidaps.logging.AAPSLogger import info.nightscout.androidaps.logging.AAPSLogger
import info.nightscout.androidaps.plugins.bus.RxBusWrapper import info.nightscout.androidaps.plugins.bus.RxBusWrapper
import info.nightscout.androidaps.plugins.general.nsclient.NSUpload import info.nightscout.androidaps.plugins.general.nsclient.NSUpload
@ -34,10 +33,9 @@ class TreatmentsPluginHistory @Inject constructor(
nsUpload: NSUpload, nsUpload: NSUpload,
fabricPrivacy: FabricPrivacy, fabricPrivacy: FabricPrivacy,
dateUtil: DateUtil, dateUtil: DateUtil,
uploadQueue: UploadQueueInterface,
databaseHelper: DatabaseHelperInterface, databaseHelper: DatabaseHelperInterface,
repository: AppRepository 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 { init {
onStart() onStart()

View file

@ -98,7 +98,6 @@ class LoopFragment : DaggerFragment() {
binding.constraintsprocessed.text = it.constraintsProcessed?.toSpanned() ?: "" binding.constraintsprocessed.text = it.constraintsProcessed?.toSpanned() ?: ""
binding.source.text = it.source ?: "" binding.source.text = it.source ?: ""
binding.lastrun.text = dateUtil.dateAndTimeString(it.lastAPSRun) binding.lastrun.text = dateUtil.dateAndTimeString(it.lastAPSRun)
?: ""
binding.smbrequestTime.text = dateUtil.dateAndTimeAndSecondsString(it.lastSMBRequest) binding.smbrequestTime.text = dateUtil.dateAndTimeAndSecondsString(it.lastSMBRequest)
binding.smbexecutionTime.text = dateUtil.dateAndTimeAndSecondsString(it.lastSMBEnact) binding.smbexecutionTime.text = dateUtil.dateAndTimeAndSecondsString(it.lastSMBEnact)
binding.tbrrequestTime.text = dateUtil.dateAndTimeAndSecondsString(it.lastTBRRequest) binding.tbrrequestTime.text = dateUtil.dateAndTimeAndSecondsString(it.lastTBRRequest)

View file

@ -17,8 +17,11 @@ import info.nightscout.androidaps.data.Profile
import info.nightscout.androidaps.data.PumpEnactResult import info.nightscout.androidaps.data.PumpEnactResult
import info.nightscout.androidaps.database.AppRepository import info.nightscout.androidaps.database.AppRepository
import info.nightscout.androidaps.database.entities.TherapyEvent import info.nightscout.androidaps.database.entities.TherapyEvent
import info.nightscout.androidaps.database.transactions.InsertTherapyEventAnnouncementTransaction 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.InsertIfNewByTimestampTherapyEventTransaction
import info.nightscout.androidaps.database.transactions.InsertTherapyEventAnnouncementTransaction
import info.nightscout.androidaps.events.EventAcceptOpenLoopChange import info.nightscout.androidaps.events.EventAcceptOpenLoopChange
import info.nightscout.androidaps.events.EventAutosensCalculationFinished import info.nightscout.androidaps.events.EventAutosensCalculationFinished
import info.nightscout.androidaps.events.EventNewBG 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.interfaces.LoopInterface.LastRun
import info.nightscout.androidaps.logging.AAPSLogger import info.nightscout.androidaps.logging.AAPSLogger
import info.nightscout.androidaps.logging.LTag 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.EventLoopSetLastRunGui
import info.nightscout.androidaps.plugins.aps.loop.events.EventLoopUpdateGui import info.nightscout.androidaps.plugins.aps.loop.events.EventLoopUpdateGui
import info.nightscout.androidaps.plugins.aps.loop.events.EventNewOpenLoopNotification import info.nightscout.androidaps.plugins.aps.loop.events.EventNewOpenLoopNotification
import info.nightscout.androidaps.plugins.bus.RxBusWrapper import info.nightscout.androidaps.plugins.bus.RxBusWrapper
import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker 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.EventDismissNotification
import info.nightscout.androidaps.plugins.general.overview.events.EventNewNotification import info.nightscout.androidaps.plugins.general.overview.events.EventNewNotification
import info.nightscout.androidaps.plugins.general.overview.notifications.Notification 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.EventWearConfirmAction
import info.nightscout.androidaps.plugins.general.wear.events.EventWearInitiateAction 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.pump.virtual.VirtualPumpPlugin
import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin
import info.nightscout.androidaps.queue.Callback import info.nightscout.androidaps.queue.Callback
import info.nightscout.androidaps.queue.commands.Command import info.nightscout.androidaps.queue.commands.Command
import info.nightscout.androidaps.receivers.ReceiverStatusStore 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.FabricPrivacy
import info.nightscout.androidaps.utils.HardLimits import info.nightscout.androidaps.utils.HardLimits
import info.nightscout.androidaps.utils.T 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.resources.ResourceHelper
import info.nightscout.androidaps.utils.rx.AapsSchedulers import info.nightscout.androidaps.utils.rx.AapsSchedulers
import info.nightscout.androidaps.utils.sharedPreferences.SP import info.nightscout.androidaps.utils.sharedPreferences.SP
@ -71,14 +77,14 @@ open class LoopPlugin @Inject constructor(
private val context: Context, private val context: Context,
private val commandQueue: CommandQueueProvider, private val commandQueue: CommandQueueProvider,
private val activePlugin: ActivePluginProvider, private val activePlugin: ActivePluginProvider,
private val treatmentsPlugin: TreatmentsPlugin,
private val virtualPumpPlugin: VirtualPumpPlugin, private val virtualPumpPlugin: VirtualPumpPlugin,
private val iobCobCalculatorPlugin: IobCobCalculatorPlugin, private val iobCobCalculator: IobCobCalculator,
private val receiverStatusStore: ReceiverStatusStore, private val receiverStatusStore: ReceiverStatusStore,
private val fabricPrivacy: FabricPrivacy, private val fabricPrivacy: FabricPrivacy,
private val nsUpload: NSUpload,
private val dateUtil: DateUtil, private val dateUtil: DateUtil,
private val repository: AppRepository private val uel: UserEntryLogger,
private val repository: AppRepository,
private val runningConfiguration: RunningConfiguration
) : PluginBase(PluginDescription() ) : PluginBase(PluginDescription()
.mainType(PluginType.LOOP) .mainType(PluginType.LOOP)
.fragmentClass(LoopFragment::class.java.name) .fragmentClass(LoopFragment::class.java.name)
@ -96,6 +102,7 @@ open class LoopPlugin @Inject constructor(
private var carbsSuggestionsSuspendedUntil: Long = 0 private var carbsSuggestionsSuspendedUntil: Long = 0
private var prevCarbsreq = 0 private var prevCarbsreq = 0
override var lastRun: LastRun? = null override var lastRun: LastRun? = null
override fun onStart() { override fun onStart() {
createNotificationChannel() createNotificationChannel()
super.onStart() super.onStart()
@ -117,7 +124,7 @@ open class LoopPlugin @Inject constructor(
.subscribe({ event: EventAutosensCalculationFinished -> .subscribe({ event: EventAutosensCalculationFinished ->
// Autosens calculation not triggered by a new BG // Autosens calculation not triggered by a new BG
if (event.cause !is EventNewBG) return@subscribe if (event.cause !is EventNewBG) return@subscribe
val glucoseValue = iobCobCalculatorPlugin.actualBg() ?: return@subscribe val glucoseValue = iobCobCalculator.ads.actualBg() ?: return@subscribe
// BG outdated // BG outdated
// already looped with that value // already looped with that value
if (glucoseValue.timestamp <= lastBgTriggeredRun) return@subscribe if (glucoseValue.timestamp <= lastBgTriggeredRun) return@subscribe
@ -302,21 +309,24 @@ open class LoopPlugin @Inject constructor(
aapsLogger.debug(LTag.APS, "SMB requested but still in 3 min interval") aapsLogger.debug(LTag.APS, "SMB requested but still in 3 min interval")
resultAfterConstraints.smb = 0.0 resultAfterConstraints.smb = 0.0
} }
if (lastRun != null && lastRun!!.constraintsProcessed != null) { prevCarbsreq = lastRun?.constraintsProcessed?.carbsReq ?: prevCarbsreq
prevCarbsreq = lastRun!!.constraintsProcessed!!.carbsReq 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)
} }
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) { if (isSuspended) {
aapsLogger.debug(LTag.APS, resourceHelper.gs(R.string.loopsuspended)) aapsLogger.debug(LTag.APS, resourceHelper.gs(R.string.loopsuspended))
rxBus.send(EventLoopSetLastRunGui(resourceHelper.gs(R.string.loopsuspended))) rxBus.send(EventLoopSetLastRunGui(resourceHelper.gs(R.string.loopsuspended)))
@ -368,6 +378,9 @@ open class LoopPlugin @Inject constructor(
// mId allows you to update the notification later on. // mId allows you to update the notification later on.
mNotificationManager.notify(Constants.notificationID, builder.build()) 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()) rxBus.send(EventNewOpenLoopNotification())
//only send to wear if Native notifications are turned off //only send to wear if Native notifications are turned off
@ -389,24 +402,24 @@ open class LoopPlugin @Inject constructor(
&& !commandQueue.isRunning(Command.CommandType.BOLUS)) { && !commandQueue.isRunning(Command.CommandType.BOLUS)) {
val waiting = PumpEnactResult(injector) val waiting = PumpEnactResult(injector)
waiting.queued = true waiting.queued = true
if (resultAfterConstraints.tempBasalRequested) lastRun!!.tbrSetByPump = waiting if (resultAfterConstraints.tempBasalRequested) lastRun.tbrSetByPump = waiting
if (resultAfterConstraints.bolusRequested) lastRun!!.smbSetByPump = waiting if (resultAfterConstraints.bolusRequested) lastRun.smbSetByPump = waiting
rxBus.send(EventLoopUpdateGui()) rxBus.send(EventLoopUpdateGui())
fabricPrivacy.logCustom("APSRequest") fabricPrivacy.logCustom("APSRequest")
applyTBRRequest(resultAfterConstraints, profile, object : Callback() { applyTBRRequest(resultAfterConstraints, profile, object : Callback() {
override fun run() { override fun run() {
if (result.enacted || result.success) { if (result.enacted || result.success) {
lastRun!!.tbrSetByPump = result lastRun.tbrSetByPump = result
lastRun!!.lastTBRRequest = lastRun!!.lastAPSRun lastRun.lastTBRRequest = lastRun.lastAPSRun
lastRun!!.lastTBREnact = DateUtil.now() lastRun.lastTBREnact = dateUtil.now()
rxBus.send(EventLoopUpdateGui()) rxBus.send(EventLoopUpdateGui())
applySMBRequest(resultAfterConstraints, object : Callback() { applySMBRequest(resultAfterConstraints, object : Callback() {
override fun run() { override fun run() {
// Callback is only called if a bolus was actually requested // Callback is only called if a bolus was actually requested
if (result.enacted || result.success) { if (result.enacted || result.success) {
lastRun!!.smbSetByPump = result lastRun.smbSetByPump = result
lastRun!!.lastSMBRequest = lastRun!!.lastAPSRun lastRun.lastSMBRequest = lastRun.lastAPSRun
lastRun!!.lastSMBEnact = DateUtil.now() lastRun.lastSMBEnact = dateUtil.now()
} else { } else {
Thread { Thread {
SystemClock.sleep(1000) SystemClock.sleep(1000)
@ -417,15 +430,15 @@ open class LoopPlugin @Inject constructor(
} }
}) })
} else { } else {
lastRun!!.tbrSetByPump = result lastRun.tbrSetByPump = result
lastRun!!.lastTBRRequest = lastRun!!.lastAPSRun lastRun.lastTBRRequest = lastRun.lastAPSRun
} }
rxBus.send(EventLoopUpdateGui()) rxBus.send(EventLoopUpdateGui())
} }
}) })
} else { } else {
lastRun!!.tbrSetByPump = null lastRun.tbrSetByPump = null
lastRun!!.smbSetByPump = null lastRun.smbSetByPump = null
} }
} else { } else {
if (resultAfterConstraints.isChangeRequested && allowNotification) { if (resultAfterConstraints.isChangeRequested && allowNotification) {
@ -446,6 +459,7 @@ open class LoopPlugin @Inject constructor(
} }
} }
rxBus.send(EventLoopUpdateGui()) rxBus.send(EventLoopUpdateGui())
}
} finally { } finally {
aapsLogger.debug(LTag.APS, "invoke end") aapsLogger.debug(LTag.APS, "invoke end")
} }
@ -488,21 +502,28 @@ open class LoopPlugin @Inject constructor(
} }
fun acceptChangeRequest() { fun acceptChangeRequest() {
val profile = profileFunction.getProfile() val profile = profileFunction.getProfile() ?: return
val lp = this lastRun?.let { lastRun ->
applyTBRRequest(lastRun!!.constraintsProcessed, profile, object : Callback() { lastRun.constraintsProcessed?.let { constraintsProcessed ->
applyTBRRequest(constraintsProcessed, profile, object : Callback() {
override fun run() { override fun run() {
if (result.enacted) { if (result.enacted) {
lastRun!!.tbrSetByPump = result lastRun.tbrSetByPump = result
lastRun!!.lastTBRRequest = lastRun!!.lastAPSRun lastRun.lastTBRRequest = lastRun.lastAPSRun
lastRun!!.lastTBREnact = DateUtil.now() lastRun.lastTBREnact = dateUtil.now()
lastRun!!.lastOpenModeAccept = DateUtil.now() lastRun.lastOpenModeAccept = dateUtil.now()
nsUpload.uploadDeviceStatus(lp, iobCobCalculatorPlugin, profileFunction, activePlugin.activePump, receiverStatusStore, BuildConfig.VERSION_NAME + "-" + BuildConfig.BUILDVERSION) 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) sp.incInt(R.string.key_ObjectivesmanualEnacts)
} }
rxBus.send(EventAcceptOpenLoopChange()) rxBus.send(EventAcceptOpenLoopChange())
} }
}) })
}
}
fabricPrivacy.logCustom("AcceptTemp") fabricPrivacy.logCustom("AcceptTemp")
} }
@ -510,8 +531,8 @@ open class LoopPlugin @Inject constructor(
* expect absolute request and allow both absolute and percent response based on pump capabilities * expect absolute request and allow both absolute and percent response based on pump capabilities
* TODO: update pump drivers to support APS request in % * TODO: update pump drivers to support APS request in %
*/ */
private fun applyTBRRequest(request: APSResult?, profile: Profile?, callback: Callback?) { private fun applyTBRRequest(request: APSResult, profile: Profile, callback: Callback?) {
if (!request!!.tempBasalRequested) { if (!request.tempBasalRequested) {
callback?.result(PumpEnactResult(injector).enacted(false).success(true).comment(R.string.nochangerequested))?.run() callback?.result(PumpEnactResult(injector).enacted(false).success(true).comment(R.string.nochangerequested))?.run()
return return
} }
@ -528,44 +549,52 @@ open class LoopPlugin @Inject constructor(
} }
aapsLogger.debug(LTag.APS, "applyAPSRequest: $request") aapsLogger.debug(LTag.APS, "applyAPSRequest: $request")
val now = System.currentTimeMillis() val now = System.currentTimeMillis()
val activeTemp = treatmentsPlugin.getTempBasalFromHistory(now) val activeTemp = iobCobCalculator.getTempBasalIncludingConvertedExtended(now)
if (request.usePercent && allowPercentage()) { if (request.usePercent && allowPercentage()) {
if (request.percent == 100 && request.duration == 0) { if (request.percent == 100 && request.duration == 0) {
if (activeTemp != null) { if (activeTemp != null) {
aapsLogger.debug(LTag.APS, "applyAPSRequest: cancelTempBasal()") aapsLogger.debug(LTag.APS, "applyAPSRequest: cancelTempBasal()")
uel.log(Action.CANCEL_TEMP_BASAL, Sources.Loop)
commandQueue.cancelTempBasal(false, callback) commandQueue.cancelTempBasal(false, callback)
} else { } else {
aapsLogger.debug(LTag.APS, "applyAPSRequest: Basal set correctly") aapsLogger.debug(LTag.APS, "applyAPSRequest: Basal set correctly")
callback?.result(PumpEnactResult(injector).percent(request.percent).duration(0) callback?.result(PumpEnactResult(injector).percent(request.percent).duration(0)
.enacted(false).success(true).comment(R.string.basal_set_correctly))?.run() .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") aapsLogger.debug(LTag.APS, "applyAPSRequest: Temp basal set correctly")
callback?.result(PumpEnactResult(injector).percent(request.percent) callback?.result(PumpEnactResult(injector).percent(request.percent)
.enacted(false).success(true).duration(activeTemp.plannedRemainingMinutes) .enacted(false).success(true).duration(activeTemp.plannedRemainingMinutes)
.comment(R.string.let_temp_basal_run))?.run() .comment(R.string.let_temp_basal_run))?.run()
} else { } else {
aapsLogger.debug(LTag.APS, "applyAPSRequest: tempBasalPercent()") 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 { } else {
if (request.rate == 0.0 && request.duration == 0 || abs(request.rate - pump.baseBasalRate) < pump.pumpDescription.basalStep) { if (request.rate == 0.0 && request.duration == 0 || abs(request.rate - pump.baseBasalRate) < pump.pumpDescription.basalStep) {
if (activeTemp != null) { if (activeTemp != null) {
aapsLogger.debug(LTag.APS, "applyAPSRequest: cancelTempBasal()") aapsLogger.debug(LTag.APS, "applyAPSRequest: cancelTempBasal()")
uel.log(Action.CANCEL_TEMP_BASAL, Sources.Loop)
commandQueue.cancelTempBasal(false, callback) commandQueue.cancelTempBasal(false, callback)
} else { } else {
aapsLogger.debug(LTag.APS, "applyAPSRequest: Basal set correctly") aapsLogger.debug(LTag.APS, "applyAPSRequest: Basal set correctly")
callback?.result(PumpEnactResult(injector).absolute(request.rate).duration(0) callback?.result(PumpEnactResult(injector).absolute(request.rate).duration(0)
.enacted(false).success(true).comment(R.string.basal_set_correctly))?.run() .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") 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) .enacted(false).success(true).duration(activeTemp.plannedRemainingMinutes)
.comment(R.string.let_temp_basal_run))?.run() .comment(R.string.let_temp_basal_run))?.run()
} else { } else {
aapsLogger.debug(LTag.APS, "applyAPSRequest: setTempBasalAbsolute()") 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)
} }
} }
} }
@ -603,6 +632,8 @@ open class LoopPlugin @Inject constructor(
detailedBolusInfo.bolusType = DetailedBolusInfo.BolusType.SMB detailedBolusInfo.bolusType = DetailedBolusInfo.BolusType.SMB
detailedBolusInfo.deliverAtTheLatest = request.deliverAt detailedBolusInfo.deliverAtTheLatest = request.deliverAt
aapsLogger.debug(LTag.APS, "applyAPSRequest: bolus()") 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) commandQueue.bolus(detailedBolusInfo, callback)
} }
@ -614,7 +645,7 @@ open class LoopPlugin @Inject constructor(
val pump = activePlugin.activePump val pump = activePlugin.activePump
disconnectTo(System.currentTimeMillis() + durationInMinutes * 60 * 1000L) disconnectTo(System.currentTimeMillis() + durationInMinutes * 60 * 1000L)
if (pump.pumpDescription.tempBasalStyle == PumpDescription.ABSOLUTE) { 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() { override fun run() {
if (!result.success) { if (!result.success) {
ErrorHelperActivity.runAlarm(context, result.comment, resourceHelper.gs(R.string.tempbasaldeliveryerror), info.nightscout.androidaps.dana.R.raw.boluserror) ErrorHelperActivity.runAlarm(context, result.comment, resourceHelper.gs(R.string.tempbasaldeliveryerror), info.nightscout.androidaps.dana.R.raw.boluserror)
@ -622,7 +653,7 @@ open class LoopPlugin @Inject constructor(
} }
}) })
} else { } 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() { override fun run() {
if (!result.success) { if (!result.success) {
ErrorHelperActivity.runAlarm(context, result.comment, resourceHelper.gs(R.string.tempbasaldeliveryerror), info.nightscout.androidaps.dana.R.raw.boluserror) ErrorHelperActivity.runAlarm(context, result.comment, resourceHelper.gs(R.string.tempbasaldeliveryerror), info.nightscout.androidaps.dana.R.raw.boluserror)
@ -630,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() { commandQueue.cancelExtended(object : Callback() {
override fun run() { override fun run() {
if (!result.success) { if (!result.success) {
@ -656,7 +687,7 @@ open class LoopPlugin @Inject constructor(
override fun createOfflineEvent(durationInMinutes: Int) { override fun createOfflineEvent(durationInMinutes: Int) {
disposable += repository.runTransactionForResult(InsertIfNewByTimestampTherapyEventTransaction( disposable += repository.runTransactionForResult(InsertIfNewByTimestampTherapyEventTransaction(
timestamp = dateUtil._now(), timestamp = dateUtil.now(),
type = TherapyEvent.Type.APS_OFFLINE, type = TherapyEvent.Type.APS_OFFLINE,
duration = T.mins(durationInMinutes.toLong()).msecs(), duration = T.mins(durationInMinutes.toLong()).msecs(),
enteredBy = "openaps://" + "AndroidAPS", enteredBy = "openaps://" + "AndroidAPS",

View file

@ -6,6 +6,10 @@ import info.nightscout.androidaps.R
import info.nightscout.androidaps.data.IobTotal import info.nightscout.androidaps.data.IobTotal
import info.nightscout.androidaps.data.MealData import info.nightscout.androidaps.data.MealData
import info.nightscout.androidaps.data.Profile 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.interfaces.ProfileFunction
import info.nightscout.androidaps.logging.AAPSLogger import info.nightscout.androidaps.logging.AAPSLogger
import info.nightscout.androidaps.logging.LTag 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.configBuilder.ConstraintChecker
import info.nightscout.androidaps.plugins.general.openhumans.OpenHumansUploader import info.nightscout.androidaps.plugins.general.openhumans.OpenHumansUploader
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.GlucoseStatus 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 info.nightscout.androidaps.utils.sharedPreferences.SP
import org.json.JSONArray import org.json.JSONArray
import org.json.JSONException import org.json.JSONException
@ -37,7 +39,7 @@ class DetermineBasalAdapterAMAJS internal constructor(scriptReader: ScriptReader
@Inject lateinit var constraintChecker: ConstraintChecker @Inject lateinit var constraintChecker: ConstraintChecker
@Inject lateinit var sp: SP @Inject lateinit var sp: SP
@Inject lateinit var profileFunction: ProfileFunction @Inject lateinit var profileFunction: ProfileFunction
@Inject lateinit var treatmentsPlugin: TreatmentsPlugin @Inject lateinit var iobCobCalculator: IobCobCalculator
@Inject lateinit var openHumansUploader: OpenHumansUploader @Inject lateinit var openHumansUploader: OpenHumansUploader
private val mScriptReader: ScriptReader private val mScriptReader: ScriptReader
@ -183,18 +185,15 @@ class DetermineBasalAdapterAMAJS internal constructor(scriptReader: ScriptReader
this.profile.put("out_units", "mmol/L") this.profile.put("out_units", "mmol/L")
} }
val now = System.currentTimeMillis() val now = System.currentTimeMillis()
val tb = treatmentsPlugin.getTempBasalFromHistory(now) val tb = iobCobCalculator.getTempBasalIncludingConvertedExtended(now)
currentTemp = JSONObject() currentTemp = JSONObject()
currentTemp.put("temp", "absolute") currentTemp.put("temp", "absolute")
currentTemp.put("duration", tb?.plannedRemainingMinutes ?: 0) 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 // as we have non default temps longer than 30 minutes
val tempBasal = treatmentsPlugin.getTempBasalFromHistory(System.currentTimeMillis()) if (tb != null) currentTemp.put("minutesrunning", tb.getPassedDurationToTimeInMinutes(now))
if (tempBasal != null) {
currentTemp.put("minutesrunning", tempBasal.realDuration) iobData = iobCobCalculator.convertToJSONArray(iobArray)
}
iobData = IobCobCalculatorPlugin.convertToJSONArray(iobArray)
this.glucoseStatus = JSONObject() this.glucoseStatus = JSONObject()
this.glucoseStatus.put("glucose", glucoseStatus.glucose) this.glucoseStatus.put("glucose", glucoseStatus.glucose)
if (sp.getBoolean(R.string.key_always_use_shortavg, false)) { if (sp.getBoolean(R.string.key_always_use_shortavg, false)) {

View file

@ -13,7 +13,7 @@ class DetermineBasalResultAMA private constructor(injector: HasAndroidInjector)
private var snoozeBG = 0.0 private var snoozeBG = 0.0
internal constructor(injector: HasAndroidInjector, result: NativeObject, j: JSONObject) : this(injector) { internal constructor(injector: HasAndroidInjector, result: NativeObject, j: JSONObject) : this(injector) {
date = dateUtil._now() date = dateUtil.now()
json = j json = j
if (result.containsKey("error")) { if (result.containsKey("error")) {
reason = result["error"].toString() reason = result["error"].toString()

View file

@ -21,7 +21,7 @@ import info.nightscout.androidaps.utils.FabricPrivacy
import info.nightscout.androidaps.utils.HardLimits import info.nightscout.androidaps.utils.HardLimits
import info.nightscout.androidaps.utils.Profiler import info.nightscout.androidaps.utils.Profiler
import info.nightscout.androidaps.utils.Round 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.resources.ResourceHelper
import org.json.JSONException import org.json.JSONException
import javax.inject.Inject import javax.inject.Inject
@ -37,7 +37,6 @@ open class OpenAPSAMAPlugin @Inject constructor(
private val profileFunction: ProfileFunction, private val profileFunction: ProfileFunction,
private val context: Context, private val context: Context,
private val activePlugin: ActivePluginProvider, private val activePlugin: ActivePluginProvider,
private val treatmentsPlugin: TreatmentsInterface,
private val iobCobCalculator: IobCobCalculator, private val iobCobCalculator: IobCobCalculator,
private val hardLimits: HardLimits, private val hardLimits: HardLimits,
private val profiler: Profiler, private val profiler: Profiler,
@ -108,7 +107,7 @@ open class OpenAPSAMAPlugin @Inject constructor(
val iobArray = iobCobCalculator.calculateIobArrayInDia(profile) val iobArray = iobCobCalculator.calculateIobArrayInDia(profile)
profiler.log(LTag.APS, "calculateIobArrayInDia()", startPart) profiler.log(LTag.APS, "calculateIobArrayInDia()", startPart)
startPart = System.currentTimeMillis() startPart = System.currentTimeMillis()
val mealData = iobCobCalculator.mealData val mealData = iobCobCalculator.getMealDataWithWaitingForCalculationFinish()
profiler.log(LTag.APS, "getMealData()", startPart) profiler.log(LTag.APS, "getMealData()", startPart)
val maxIob = constraintChecker.getMaxIOBAllowed().also { maxIOBAllowedConstraint -> val maxIob = constraintChecker.getMaxIOBAllowed().also { maxIOBAllowedConstraint ->
inputConstraints.copyReasons(maxIOBAllowedConstraint) inputConstraints.copyReasons(maxIOBAllowedConstraint)
@ -117,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 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 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 var isTempTarget = false
val tempTarget = repository.getTemporaryTargetActiveAt(dateUtil._now()).blockingGet() val tempTarget = repository.getTemporaryTargetActiveAt(dateUtil.now()).blockingGet()
if (tempTarget is ValueWrapper.Existing) { if (tempTarget is ValueWrapper.Existing) {
isTempTarget = true 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()) 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())
@ -131,7 +130,7 @@ open class OpenAPSAMAPlugin @Inject constructor(
if (!hardLimits.checkOnlyHardLimits(pump.baseBasalRate, R.string.current_basal_value, 0.01, hardLimits.maxBasal())) return if (!hardLimits.checkOnlyHardLimits(pump.baseBasalRate, R.string.current_basal_value, 0.01, hardLimits.maxBasal())) return
startPart = System.currentTimeMillis() startPart = System.currentTimeMillis()
if (constraintChecker.isAutosensModeEnabled().value()) { if (constraintChecker.isAutosensModeEnabled().value()) {
val autosensData = iobCobCalculator.getLastAutosensDataSynchronized("OpenAPSPlugin") val autosensData = iobCobCalculator.getLastAutosensDataWithWaitForCalculationFinish("OpenAPSPlugin")
if (autosensData == null) { if (autosensData == null) {
rxBus.send(EventOpenAPSUpdateResultGui(resourceHelper.gs(R.string.openaps_noasdata))) rxBus.send(EventOpenAPSUpdateResultGui(resourceHelper.gs(R.string.openaps_noasdata)))
return return
@ -161,10 +160,10 @@ open class OpenAPSAMAPlugin @Inject constructor(
lastAPSResult = null lastAPSResult = null
lastAPSRun = 0 lastAPSRun = 0
} else { } 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] determineBasalResultAMA.iob = iobArray[0]
val now = System.currentTimeMillis() val now = System.currentTimeMillis()
determineBasalResultAMA.json?.put("timestamp", DateUtil.toISOString(now)) determineBasalResultAMA.json?.put("timestamp", dateUtil.toISOString(now))
determineBasalResultAMA.inputConstraints = inputConstraints determineBasalResultAMA.inputConstraints = inputConstraints
lastDetermineBasalAdapterAMAJS = determineBasalAdapterAMAJS lastDetermineBasalAdapterAMAJS = determineBasalAdapterAMAJS
lastAPSResult = determineBasalResultAMA lastAPSResult = determineBasalResultAMA

View file

@ -7,6 +7,7 @@ import info.nightscout.androidaps.data.IobTotal
import info.nightscout.androidaps.data.MealData import info.nightscout.androidaps.data.MealData
import info.nightscout.androidaps.data.Profile import info.nightscout.androidaps.data.Profile
import info.nightscout.androidaps.interfaces.ActivePluginProvider import info.nightscout.androidaps.interfaces.ActivePluginProvider
import info.nightscout.androidaps.interfaces.IobCobCalculator
import info.nightscout.androidaps.interfaces.ProfileFunction import info.nightscout.androidaps.interfaces.ProfileFunction
import info.nightscout.androidaps.logging.AAPSLogger import info.nightscout.androidaps.logging.AAPSLogger
import info.nightscout.androidaps.logging.LTag import info.nightscout.androidaps.logging.LTag
@ -16,8 +17,10 @@ import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker
import info.nightscout.androidaps.plugins.general.openhumans.OpenHumansUploader import info.nightscout.androidaps.plugins.general.openhumans.OpenHumansUploader
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.GlucoseStatus import info.nightscout.androidaps.plugins.iob.iobCobCalculator.GlucoseStatus
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorPlugin 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.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.resources.ResourceHelper
import info.nightscout.androidaps.utils.sharedPreferences.SP import info.nightscout.androidaps.utils.sharedPreferences.SP
import org.json.JSONArray import org.json.JSONArray
@ -37,7 +40,7 @@ class DetermineBasalAdapterSMBJS internal constructor(private val scriptReader:
@Inject lateinit var sp: SP @Inject lateinit var sp: SP
@Inject lateinit var resourceHelper: ResourceHelper @Inject lateinit var resourceHelper: ResourceHelper
@Inject lateinit var profileFunction: ProfileFunction @Inject lateinit var profileFunction: ProfileFunction
@Inject lateinit var treatmentsPlugin: TreatmentsPlugin @Inject lateinit var iobCobCalculator: IobCobCalculator
@Inject lateinit var activePluginProvider: ActivePluginProvider @Inject lateinit var activePluginProvider: ActivePluginProvider
@Inject lateinit var openHumansUploader: OpenHumansUploader @Inject lateinit var openHumansUploader: OpenHumansUploader
@ -227,17 +230,14 @@ class DetermineBasalAdapterSMBJS internal constructor(private val scriptReader:
this.profile.put("out_units", "mmol/L") this.profile.put("out_units", "mmol/L")
} }
val now = System.currentTimeMillis() val now = System.currentTimeMillis()
val tb = treatmentsPlugin.getTempBasalFromHistory(now) val tb = iobCobCalculator.getTempBasalIncludingConvertedExtended(now)
currentTemp.put("temp", "absolute") currentTemp.put("temp", "absolute")
currentTemp.put("duration", tb?.plannedRemainingMinutes ?: 0) 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 // as we have non default temps longer than 30 mintues
val tempBasal = treatmentsPlugin.getTempBasalFromHistory(System.currentTimeMillis()) if (tb != null) currentTemp.put("minutesrunning", tb.getPassedDurationToTimeInMinutes(now))
if (tempBasal != null) {
currentTemp.put("minutesrunning", tempBasal.realDuration) iobData = iobCobCalculator.convertToJSONArray(iobArray)
}
iobData = IobCobCalculatorPlugin.convertToJSONArray(iobArray)
mGlucoseStatus.put("glucose", glucoseStatus.glucose) mGlucoseStatus.put("glucose", glucoseStatus.glucose)
mGlucoseStatus.put("noise", glucoseStatus.noise) mGlucoseStatus.put("noise", glucoseStatus.noise)
if (sp.getBoolean(R.string.key_always_use_shortavg, false)) { if (sp.getBoolean(R.string.key_always_use_shortavg, false)) {

View file

@ -3,7 +3,6 @@ package info.nightscout.androidaps.plugins.aps.openAPSSMB
import dagger.android.HasAndroidInjector import dagger.android.HasAndroidInjector
import info.nightscout.androidaps.logging.LTag import info.nightscout.androidaps.logging.LTag
import info.nightscout.androidaps.plugins.aps.loop.APSResult import info.nightscout.androidaps.plugins.aps.loop.APSResult
import info.nightscout.androidaps.utils.DateUtil
import org.json.JSONException import org.json.JSONException
import org.json.JSONObject import org.json.JSONObject
@ -13,7 +12,7 @@ class DetermineBasalResultSMB private constructor(injector: HasAndroidInjector)
private var snoozeBG = 0.0 private var snoozeBG = 0.0
internal constructor(injector: HasAndroidInjector, result: JSONObject) : this(injector) { internal constructor(injector: HasAndroidInjector, result: JSONObject) : this(injector) {
date = dateUtil._now() date = dateUtil.now()
json = result json = result
try { try {
if (result.has("error")) { if (result.has("error")) {
@ -47,7 +46,7 @@ class DetermineBasalResultSMB private constructor(injector: HasAndroidInjector)
if (result.has("deliverAt")) { if (result.has("deliverAt")) {
val date = result.getString("deliverAt") val date = result.getString("deliverAt")
try { try {
deliverAt = DateUtil.fromISODateString(date).time deliverAt = dateUtil.fromISODateString(date)
} catch (e: Exception) { } catch (e: Exception) {
aapsLogger.error(LTag.APS, "Error parsing 'deliverAt' date: $date", e) aapsLogger.error(LTag.APS, "Error parsing 'deliverAt' date: $date", e)
} }

View file

@ -22,7 +22,7 @@ import info.nightscout.androidaps.utils.DateUtil
import info.nightscout.androidaps.utils.HardLimits import info.nightscout.androidaps.utils.HardLimits
import info.nightscout.androidaps.utils.Profiler import info.nightscout.androidaps.utils.Profiler
import info.nightscout.androidaps.utils.Round 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.resources.ResourceHelper
import info.nightscout.androidaps.utils.sharedPreferences.SP import info.nightscout.androidaps.utils.sharedPreferences.SP
import javax.inject.Inject import javax.inject.Inject
@ -38,7 +38,6 @@ open class OpenAPSSMBPlugin @Inject constructor(
private val profileFunction: ProfileFunction, private val profileFunction: ProfileFunction,
private val context: Context, private val context: Context,
private val activePlugin: ActivePluginProvider, private val activePlugin: ActivePluginProvider,
private val treatmentsPlugin: TreatmentsInterface,
private val iobCobCalculator: IobCobCalculator, private val iobCobCalculator: IobCobCalculator,
private val hardLimits: HardLimits, private val hardLimits: HardLimits,
private val profiler: Profiler, private val profiler: Profiler,
@ -123,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 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 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 var isTempTarget = false
val tempTarget = repository.getTemporaryTargetActiveAt(dateUtil._now()).blockingGet() val tempTarget = repository.getTemporaryTargetActiveAt(dateUtil.now()).blockingGet()
if (tempTarget is ValueWrapper.Existing) { if (tempTarget is ValueWrapper.Existing) {
isTempTarget = true 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()) 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())
@ -137,7 +136,7 @@ open class OpenAPSSMBPlugin @Inject constructor(
if (!hardLimits.checkOnlyHardLimits(pump.baseBasalRate, R.string.current_basal_value, 0.01, hardLimits.maxBasal())) return if (!hardLimits.checkOnlyHardLimits(pump.baseBasalRate, R.string.current_basal_value, 0.01, hardLimits.maxBasal())) return
startPart = System.currentTimeMillis() startPart = System.currentTimeMillis()
if (constraintChecker.isAutosensModeEnabled().value()) { if (constraintChecker.isAutosensModeEnabled().value()) {
val autosensData = iobCobCalculator.getLastAutosensDataSynchronized("OpenAPSPlugin") val autosensData = iobCobCalculator.getLastAutosensDataWithWaitForCalculationFinish("OpenAPSPlugin")
if (autosensData == null) { if (autosensData == null) {
rxBus.send(EventOpenAPSUpdateResultGui(resourceHelper.gs(R.string.openaps_noasdata))) rxBus.send(EventOpenAPSUpdateResultGui(resourceHelper.gs(R.string.openaps_noasdata)))
return return
@ -170,7 +169,7 @@ open class OpenAPSSMBPlugin @Inject constructor(
activePlugin.activePump.baseBasalRate, activePlugin.activePump.baseBasalRate,
iobArray, iobArray,
glucoseStatus, glucoseStatus,
iobCobCalculator.mealData, iobCobCalculator.getMealDataWithWaitingForCalculationFinish(),
lastAutosensResult.ratio, lastAutosensResult.ratio,
isTempTarget, isTempTarget,
smbAllowed.value(), smbAllowed.value(),
@ -188,9 +187,9 @@ open class OpenAPSSMBPlugin @Inject constructor(
} else { } else {
// TODO still needed with oref1? // TODO still needed with oref1?
// Fix bug determine basal // 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.iob = iobArray[0]
determineBasalResultSMB.json?.put("timestamp", DateUtil.toISOString(now)) determineBasalResultSMB.json?.put("timestamp", dateUtil.toISOString(now))
determineBasalResultSMB.inputConstraints = inputConstraints determineBasalResultSMB.inputConstraints = inputConstraints
lastDetermineBasalAdapterSMBJS = determineBasalAdapterSMBJS lastDetermineBasalAdapterSMBJS = determineBasalAdapterSMBJS
lastAPSResult = determineBasalResultSMB lastAPSResult = determineBasalResultSMB

View file

@ -19,7 +19,7 @@ import info.nightscout.androidaps.plugins.bus.RxBusWrapper
import info.nightscout.androidaps.plugins.configBuilder.events.EventConfigBuilderUpdateGui import info.nightscout.androidaps.plugins.configBuilder.events.EventConfigBuilderUpdateGui
import info.nightscout.androidaps.utils.FabricPrivacy import info.nightscout.androidaps.utils.FabricPrivacy
import io.reactivex.rxkotlin.plusAssign 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.protection.ProtectionCheck
import info.nightscout.androidaps.utils.resources.ResourceHelper import info.nightscout.androidaps.utils.resources.ResourceHelper
import info.nightscout.androidaps.utils.rx.AapsSchedulers import info.nightscout.androidaps.utils.rx.AapsSchedulers

View file

@ -3,7 +3,9 @@ package info.nightscout.androidaps.plugins.configBuilder
import androidx.fragment.app.FragmentActivity import androidx.fragment.app.FragmentActivity
import dagger.android.HasAndroidInjector import dagger.android.HasAndroidInjector
import info.nightscout.androidaps.R 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.EventAppInitialized
import info.nightscout.androidaps.events.EventConfigBuilderChange import info.nightscout.androidaps.events.EventConfigBuilderChange
import info.nightscout.androidaps.events.EventRebuildTabs import info.nightscout.androidaps.events.EventRebuildTabs
@ -28,7 +30,8 @@ class ConfigBuilderPlugin @Inject constructor(
private val sp: SP, private val sp: SP,
private val rxBus: RxBusWrapper, private val rxBus: RxBusWrapper,
private val activePlugin: ActivePluginProvider, private val activePlugin: ActivePluginProvider,
private val uel: UserEntryLogger private val uel: UserEntryLogger,
private val pumpSync: PumpSync
) : PluginBase(PluginDescription() ) : PluginBase(PluginDescription()
.mainType(PluginType.GENERAL) .mainType(PluginType.GENERAL)
.fragmentClass(ConfigBuilderFragment::class.java.name) .fragmentClass(ConfigBuilderFragment::class.java.name)
@ -139,13 +142,16 @@ class ConfigBuilderPlugin @Inject constructor(
val allowHardwarePump = sp.getBoolean("allow_hardware_pump", false) val allowHardwarePump = sp.getBoolean("allow_hardware_pump", false)
if (allowHardwarePump || activity == null) { if (allowHardwarePump || activity == null) {
performPluginSwitch(changedPlugin, newState, type) performPluginSwitch(changedPlugin, newState, type)
pumpSync.connectNewPump()
} else { } 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) performPluginSwitch(changedPlugin, newState, type)
pumpSync.connectNewPump()
sp.putBoolean("allow_hardware_pump", true) 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!") aapsLogger.debug(LTag.PUMP, "First time HW pump allowed!")
}, Runnable { }, {
rxBus.send(EventConfigBuilderUpdateGui()) rxBus.send(EventConfigBuilderUpdateGui())
aapsLogger.debug(LTag.PUMP, "User does not allow switching to HW pump!") 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) { 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.setPluginEnabled(type, enabled)
changedPlugin.setFragmentVisible(type, enabled) changedPlugin.setFragmentVisible(type, enabled)
processOnEnabledCategoryChanged(changedPlugin, type) processOnEnabledCategoryChanged(changedPlugin, type)

View file

@ -17,7 +17,9 @@ import androidx.recyclerview.widget.LinearSmoothScroller
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import dagger.android.support.DaggerFragment import dagger.android.support.DaggerFragment
import info.nightscout.androidaps.R 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.ObjectivesFragmentBinding
import info.nightscout.androidaps.databinding.ObjectivesItemBinding import info.nightscout.androidaps.databinding.ObjectivesItemBinding
import info.nightscout.androidaps.dialogs.NtpProgressDialog import info.nightscout.androidaps.dialogs.NtpProgressDialog
@ -235,7 +237,7 @@ class ObjectivesFragment : DaggerFragment() {
holder.binding.verify.setOnClickListener { holder.binding.verify.setOnClickListener {
receiverStatusStore.updateNetworkStatus() receiverStatusStore.updateNetworkStatus()
if (binding.fake.isChecked) { if (binding.fake.isChecked) {
objective.accomplishedOn = DateUtil.now() objective.accomplishedOn = dateUtil.now()
scrollToCurrentObjective() scrollToCurrentObjective()
startUpdateTimer() startUpdateTimer()
rxBus.send(EventObjectivesUpdateGui()) rxBus.send(EventObjectivesUpdateGui())
@ -247,7 +249,7 @@ class ObjectivesFragment : DaggerFragment() {
rxBus.send(EventNtpStatus(resourceHelper.gs(R.string.timedetection), 0)) rxBus.send(EventNtpStatus(resourceHelper.gs(R.string.timedetection), 0))
sntpClient.ntpTime(object : SntpClient.Callback() { sntpClient.ntpTime(object : SntpClient.Callback() {
override fun run() { override fun run() {
aapsLogger.debug("NTP time: $time System time: ${DateUtil.now()}") aapsLogger.debug("NTP time: $time System time: ${dateUtil.now()}")
SystemClock.sleep(300) SystemClock.sleep(300)
if (!networkConnected) { if (!networkConnected) {
rxBus.send(EventNtpStatus(resourceHelper.gs(R.string.notconnected), 99)) rxBus.send(EventNtpStatus(resourceHelper.gs(R.string.notconnected), 99))
@ -274,7 +276,7 @@ class ObjectivesFragment : DaggerFragment() {
holder.binding.start.setOnClickListener { holder.binding.start.setOnClickListener {
receiverStatusStore.updateNetworkStatus() receiverStatusStore.updateNetworkStatus()
if (binding.fake.isChecked) { if (binding.fake.isChecked) {
objective.startedOn = DateUtil.now() objective.startedOn = dateUtil.now()
scrollToCurrentObjective() scrollToCurrentObjective()
startUpdateTimer() startUpdateTimer()
rxBus.send(EventObjectivesUpdateGui()) rxBus.send(EventObjectivesUpdateGui())
@ -286,7 +288,7 @@ class ObjectivesFragment : DaggerFragment() {
rxBus.send(EventNtpStatus(resourceHelper.gs(R.string.timedetection), 0)) rxBus.send(EventNtpStatus(resourceHelper.gs(R.string.timedetection), 0))
sntpClient.ntpTime(object : SntpClient.Callback() { sntpClient.ntpTime(object : SntpClient.Callback() {
override fun run() { override fun run() {
aapsLogger.debug("NTP time: $time System time: ${DateUtil.now()}") aapsLogger.debug("NTP time: $time System time: ${dateUtil.now()}")
SystemClock.sleep(300) SystemClock.sleep(300)
if (!networkConnected) { if (!networkConnected) {
rxBus.send(EventNtpStatus(resourceHelper.gs(R.string.notconnected), 99)) rxBus.send(EventNtpStatus(resourceHelper.gs(R.string.notconnected), 99))
@ -308,7 +310,8 @@ class ObjectivesFragment : DaggerFragment() {
holder.binding.unstart.setOnClickListener { holder.binding.unstart.setOnClickListener {
activity?.let { activity -> activity?.let { activity ->
OKDialog.showConfirmation(activity, resourceHelper.gs(R.string.objectives), resourceHelper.gs(R.string.doyouwantresetstart), Runnable { 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 objective.startedOn = 0
scrollToCurrentObjective() scrollToCurrentObjective()
rxBus.send(EventObjectivesUpdateGui()) rxBus.send(EventObjectivesUpdateGui())

View file

@ -7,7 +7,8 @@ import dagger.android.HasAndroidInjector
import info.nightscout.androidaps.BuildConfig import info.nightscout.androidaps.BuildConfig
import info.nightscout.androidaps.Config import info.nightscout.androidaps.Config
import info.nightscout.androidaps.R 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.interfaces.*
import info.nightscout.androidaps.logging.AAPSLogger import info.nightscout.androidaps.logging.AAPSLogger
import info.nightscout.androidaps.logging.UserEntryLogger import info.nightscout.androidaps.logging.UserEntryLogger
@ -28,6 +29,7 @@ class ObjectivesPlugin @Inject constructor(
private val activePlugin: ActivePluginProvider, private val activePlugin: ActivePluginProvider,
private val sp: SP, private val sp: SP,
config: Config, config: Config,
private val dateUtil: DateUtil,
private val uel: UserEntryLogger private val uel: UserEntryLogger
) : PluginBase(PluginDescription() ) : PluginBase(PluginDescription()
.mainType(PluginType.CONSTRAINTS) .mainType(PluginType.CONSTRAINTS)
@ -125,25 +127,25 @@ class ObjectivesPlugin @Inject constructor(
if (!url.endsWith("/")) url = "$url/" if (!url.endsWith("/")) url = "$url/"
@Suppress("DEPRECATION") val hashNS = Hashing.sha1().hashString(url + BuildConfig.APPLICATION_ID + "/" + requestCode, Charsets.UTF_8).toString() @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)) { if (request.equals(hashNS.substring(0, 10), ignoreCase = true)) {
sp.putLong("Objectives_" + "openloop" + "_started", DateUtil.now()) sp.putLong("Objectives_" + "openloop" + "_started", dateUtil.now())
sp.putLong("Objectives_" + "openloop" + "_accomplished", DateUtil.now()) sp.putLong("Objectives_" + "openloop" + "_accomplished", dateUtil.now())
sp.putLong("Objectives_" + "maxbasal" + "_started", DateUtil.now()) sp.putLong("Objectives_" + "maxbasal" + "_started", dateUtil.now())
sp.putLong("Objectives_" + "maxbasal" + "_accomplished", DateUtil.now()) sp.putLong("Objectives_" + "maxbasal" + "_accomplished", dateUtil.now())
sp.putLong("Objectives_" + "maxiobzero" + "_started", DateUtil.now()) sp.putLong("Objectives_" + "maxiobzero" + "_started", dateUtil.now())
sp.putLong("Objectives_" + "maxiobzero" + "_accomplished", DateUtil.now()) sp.putLong("Objectives_" + "maxiobzero" + "_accomplished", dateUtil.now())
sp.putLong("Objectives_" + "maxiob" + "_started", DateUtil.now()) sp.putLong("Objectives_" + "maxiob" + "_started", dateUtil.now())
sp.putLong("Objectives_" + "maxiob" + "_accomplished", DateUtil.now()) sp.putLong("Objectives_" + "maxiob" + "_accomplished", dateUtil.now())
sp.putLong("Objectives_" + "autosens" + "_started", DateUtil.now()) sp.putLong("Objectives_" + "autosens" + "_started", dateUtil.now())
sp.putLong("Objectives_" + "autosens" + "_accomplished", DateUtil.now()) sp.putLong("Objectives_" + "autosens" + "_accomplished", dateUtil.now())
sp.putLong("Objectives_" + "ama" + "_started", DateUtil.now()) sp.putLong("Objectives_" + "ama" + "_started", dateUtil.now())
sp.putLong("Objectives_" + "ama" + "_accomplished", DateUtil.now()) sp.putLong("Objectives_" + "ama" + "_accomplished", dateUtil.now())
sp.putLong("Objectives_" + "smb" + "_started", DateUtil.now()) sp.putLong("Objectives_" + "smb" + "_started", dateUtil.now())
sp.putLong("Objectives_" + "smb" + "_accomplished", DateUtil.now()) sp.putLong("Objectives_" + "smb" + "_accomplished", dateUtil.now())
sp.putLong("Objectives_" + "auto" + "_started", DateUtil.now()) sp.putLong("Objectives_" + "auto" + "_started", dateUtil.now())
sp.putLong("Objectives_" + "auto" + "_accomplished", DateUtil.now()) sp.putLong("Objectives_" + "auto" + "_accomplished", dateUtil.now())
setupObjectives() setupObjectives()
OKDialog.show(activity, resourceHelper.gs(R.string.objectives), resourceHelper.gs(R.string.codeaccepted)) 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 { } else {
OKDialog.show(activity, resourceHelper.gs(R.string.objectives), resourceHelper.gs(R.string.codeinvalid)) OKDialog.show(activity, resourceHelper.gs(R.string.objectives), resourceHelper.gs(R.string.codeinvalid))
} }

View file

@ -108,7 +108,7 @@ class ObjectivesExamDialog : DaggerDialogFragment() {
} }
task.answered = result task.answered = result
if (!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) ToastUtils.showToastInUiThread(context, R.string.wronganswer)
} else task.disabledTo = 0 } else task.disabledTo = 0
updateGui() updateGui()

View file

@ -21,6 +21,7 @@ abstract class Objective(injector: HasAndroidInjector, spName: String, @StringRe
@Inject lateinit var sp: SP @Inject lateinit var sp: SP
@Inject lateinit var resourceHelper: ResourceHelper @Inject lateinit var resourceHelper: ResourceHelper
@Inject lateinit var dateUtil: DateUtil
private val spName: String private val spName: String
@StringRes val objective: Int @StringRes val objective: Int
@ -55,7 +56,7 @@ abstract class Objective(injector: HasAndroidInjector, spName: String, @StringRe
this.gate = gate this.gate = gate
startedOn = sp.getLong("Objectives_" + spName + "_started", 0L) startedOn = sp.getLong("Objectives_" + spName + "_started", 0L)
accomplishedOn = sp.getLong("Objectives_" + spName + "_accomplished", 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 startedOn = 0
accomplishedOn = 0 accomplishedOn = 0
} }
@ -69,7 +70,7 @@ abstract class Objective(injector: HasAndroidInjector, spName: String, @StringRe
} }
val isAccomplished: Boolean val isAccomplished: Boolean
get() = accomplishedOn != 0L && accomplishedOn < DateUtil.now() get() = accomplishedOn != 0L && accomplishedOn < dateUtil.now()
val isStarted: Boolean val isStarted: Boolean
get() = startedOn != 0L get() = startedOn != 0L
@ -144,7 +145,7 @@ abstract class Objective(injector: HasAndroidInjector, spName: String, @StringRe
override fun isCompleted(): Boolean = answered override fun isCompleted(): Boolean = answered
fun isEnabledAnswer(): Boolean = disabledTo < DateUtil.now() fun isEnabledAnswer(): Boolean = disabledTo < dateUtil.now()
fun option(option: Option): ExamTask { fun option(option: Option): ExamTask {
options.add(option) options.add(option)

View file

@ -3,14 +3,13 @@ package info.nightscout.androidaps.plugins.constraints.objectives.objectives
import dagger.android.HasAndroidInjector import dagger.android.HasAndroidInjector
import info.nightscout.androidaps.R import info.nightscout.androidaps.R
import info.nightscout.androidaps.interfaces.ActivePluginProvider import info.nightscout.androidaps.interfaces.ActivePluginProvider
import info.nightscout.androidaps.interfaces.IobCobCalculator
import info.nightscout.androidaps.interfaces.PluginBase import info.nightscout.androidaps.interfaces.PluginBase
import info.nightscout.androidaps.interfaces.PluginType import info.nightscout.androidaps.interfaces.PluginType
import info.nightscout.androidaps.plugins.aps.loop.LoopPlugin import info.nightscout.androidaps.plugins.aps.loop.LoopPlugin
import info.nightscout.androidaps.plugins.general.nsclient.NSClientPlugin 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.pump.virtual.VirtualPumpPlugin
import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin
import info.nightscout.androidaps.utils.DateUtil
import javax.inject.Inject import javax.inject.Inject
class Objective0(injector: HasAndroidInjector) : Objective(injector, "config", R.string.objectives_0_objective, R.string.objectives_0_gate) { class Objective0(injector: HasAndroidInjector) : Objective(injector, "config", R.string.objectives_0_objective, R.string.objectives_0_gate) {
@ -20,7 +19,7 @@ class Objective0(injector: HasAndroidInjector) : Objective(injector, "config", R
@Inject lateinit var treatmentsPlugin: TreatmentsPlugin @Inject lateinit var treatmentsPlugin: TreatmentsPlugin
@Inject lateinit var loopPlugin: LoopPlugin @Inject lateinit var loopPlugin: LoopPlugin
@Inject lateinit var nsClientPlugin: NSClientPlugin @Inject lateinit var nsClientPlugin: NSClientPlugin
@Inject lateinit var iobCobCalculatorPlugin: IobCobCalculatorPlugin @Inject lateinit var iobCobCalculator: IobCobCalculator
init { init {
tasks.add(object : Task(this, R.string.objectives_bgavailableinns) { 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) { tasks.add(object : Task(this, R.string.hasbgdata) {
override fun isCompleted(): Boolean { override fun isCompleted(): Boolean {
return iobCobCalculatorPlugin.lastBg() != null return iobCobCalculator.ads.lastBg() != null
} }
}) })
tasks.add(object : Task(this, R.string.loopenabled) { 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) { tasks.add(object : Task(this, R.string.activate_profile) {
override fun isCompleted(): Boolean { override fun isCompleted(): Boolean {
return treatmentsPlugin.getProfileSwitchFromHistory(DateUtil.now()) != null return treatmentsPlugin.getProfileSwitchFromHistory(dateUtil.now()) != null
} }
}) })
} }

View file

@ -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.events.EventNewNotification
import info.nightscout.androidaps.plugins.general.overview.notifications.Notification import info.nightscout.androidaps.plugins.general.overview.notifications.Notification
import info.nightscout.androidaps.plugins.sensitivity.SensitivityOref1Plugin import info.nightscout.androidaps.plugins.sensitivity.SensitivityOref1Plugin
import info.nightscout.androidaps.utils.DateUtil
import info.nightscout.androidaps.utils.DecimalFormatter import info.nightscout.androidaps.utils.DecimalFormatter
import info.nightscout.androidaps.utils.HardLimits import info.nightscout.androidaps.utils.HardLimits
import info.nightscout.androidaps.utils.Round import info.nightscout.androidaps.utils.Round
@ -37,8 +38,9 @@ class SafetyPlugin @Inject constructor(
private val activePlugin: ActivePluginProvider, private val activePlugin: ActivePluginProvider,
private val hardLimits: HardLimits, private val hardLimits: HardLimits,
private val buildHelper: BuildHelper, private val buildHelper: BuildHelper,
private val treatmentsPlugin: TreatmentsInterface, private val iobCobCalculator: IobCobCalculator,
private val config: Config private val config: Config,
private val dateUtil: DateUtil
) : PluginBase(PluginDescription() ) : PluginBase(PluginDescription()
.mainType(PluginType.CONSTRAINTS) .mainType(PluginType.CONSTRAINTS)
.neverVisible(true) .neverVisible(true)
@ -68,7 +70,7 @@ class SafetyPlugin @Inject constructor(
value[aapsLogger, false, resourceHelper.gs(R.string.closed_loop_disabled_on_dev_branch)] = this value[aapsLogger, false, resourceHelper.gs(R.string.closed_loop_disabled_on_dev_branch)] = this
} }
val pump = activePlugin.activePump 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 value[aapsLogger, false, resourceHelper.gs(R.string.closed_loop_disabled_with_eb)] = this
} }
return value return value

View file

@ -16,12 +16,19 @@ import info.nightscout.androidaps.Constants
import info.nightscout.androidaps.R import info.nightscout.androidaps.R
import info.nightscout.androidaps.activities.ErrorHelperActivity import info.nightscout.androidaps.activities.ErrorHelperActivity
import info.nightscout.androidaps.activities.TDDStatsActivity 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.dialogs.*
import info.nightscout.androidaps.events.* 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.historyBrowser.HistoryBrowseActivity
import info.nightscout.androidaps.interfaces.ActivePluginProvider import info.nightscout.androidaps.interfaces.ActivePluginProvider
import info.nightscout.androidaps.interfaces.CommandQueueProvider import info.nightscout.androidaps.interfaces.CommandQueueProvider
import info.nightscout.androidaps.interfaces.IobCobCalculator
import info.nightscout.androidaps.interfaces.ProfileFunction import info.nightscout.androidaps.interfaces.ProfileFunction
import info.nightscout.androidaps.logging.AAPSLogger import info.nightscout.androidaps.logging.AAPSLogger
import info.nightscout.androidaps.logging.UserEntryLogger 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.plugins.pump.omnipod.eros.OmnipodErosPumpPlugin
import info.nightscout.androidaps.queue.Callback import info.nightscout.androidaps.queue.Callback
import info.nightscout.androidaps.skins.SkinProvider import info.nightscout.androidaps.skins.SkinProvider
import info.nightscout.androidaps.utils.DateUtil
import info.nightscout.androidaps.utils.FabricPrivacy import info.nightscout.androidaps.utils.FabricPrivacy
import info.nightscout.androidaps.utils.alertDialogs.OKDialog import info.nightscout.androidaps.utils.alertDialogs.OKDialog
import info.nightscout.androidaps.utils.buildHelper.BuildHelper 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.protection.ProtectionCheck
import info.nightscout.androidaps.utils.resources.ResourceHelper import info.nightscout.androidaps.utils.resources.ResourceHelper
import info.nightscout.androidaps.utils.rx.AapsSchedulers import info.nightscout.androidaps.utils.rx.AapsSchedulers
@ -52,18 +59,21 @@ class ActionsFragment : DaggerFragment() {
@Inject lateinit var aapsSchedulers: AapsSchedulers @Inject lateinit var aapsSchedulers: AapsSchedulers
@Inject lateinit var rxBus: RxBusWrapper @Inject lateinit var rxBus: RxBusWrapper
@Inject lateinit var sp: SP @Inject lateinit var sp: SP
@Inject lateinit var dateUtil: DateUtil
@Inject lateinit var profileFunction: ProfileFunction @Inject lateinit var profileFunction: ProfileFunction
@Inject lateinit var ctx: Context @Inject lateinit var ctx: Context
@Inject lateinit var resourceHelper: ResourceHelper @Inject lateinit var resourceHelper: ResourceHelper
@Inject lateinit var statusLightHandler: StatusLightHandler @Inject lateinit var statusLightHandler: StatusLightHandler
@Inject lateinit var fabricPrivacy: FabricPrivacy @Inject lateinit var fabricPrivacy: FabricPrivacy
@Inject lateinit var activePlugin: ActivePluginProvider @Inject lateinit var activePlugin: ActivePluginProvider
@Inject lateinit var iobCobCalculator: IobCobCalculator
@Inject lateinit var commandQueue: CommandQueueProvider @Inject lateinit var commandQueue: CommandQueueProvider
@Inject lateinit var buildHelper: BuildHelper @Inject lateinit var buildHelper: BuildHelper
@Inject lateinit var protectionCheck: ProtectionCheck @Inject lateinit var protectionCheck: ProtectionCheck
@Inject lateinit var skinProvider: SkinProvider @Inject lateinit var skinProvider: SkinProvider
@Inject lateinit var config: Config @Inject lateinit var config: Config
@Inject lateinit var uel: UserEntryLogger @Inject lateinit var uel: UserEntryLogger
@Inject lateinit var repository: AppRepository
private var disposable: CompositeDisposable = CompositeDisposable() private var disposable: CompositeDisposable = CompositeDisposable()
@ -154,8 +164,8 @@ class ActionsFragment : DaggerFragment() {
} }
} }
extendedBolusCancel?.setOnClickListener { extendedBolusCancel?.setOnClickListener {
if (activePlugin.activeTreatments.isInHistoryExtendedBolusInProgress) { if (iobCobCalculator.getExtendedBolus(dateUtil.now()) != null) {
uel.log(Action.CANCEL_EXTENDED_BOLUS) uel.log(Action.CANCEL_EXTENDED_BOLUS, Sources.Actions)
commandQueue.cancelExtended(object : Callback() { commandQueue.cancelExtended(object : Callback() {
override fun run() { override fun run() {
if (!result.success) { if (!result.success) {
@ -169,8 +179,8 @@ class ActionsFragment : DaggerFragment() {
TempBasalDialog().show(childFragmentManager, "Actions") TempBasalDialog().show(childFragmentManager, "Actions")
} }
cancelTempBasal?.setOnClickListener { cancelTempBasal?.setOnClickListener {
if (activePlugin.activeTreatments.isTempBasalInProgress) { if (iobCobCalculator.getTempBasalIncludingConvertedExtended(dateUtil.now()) != null) {
uel.log(Action.CANCEL_TEMP_BASAL) uel.log(Action.CANCEL_TEMP_BASAL, Sources.Actions)
commandQueue.cancelTempBasal(true, object : Callback() { commandQueue.cancelTempBasal(true, object : Callback() {
override fun run() { override fun run() {
if (!result.success) { if (!result.success) {
@ -264,12 +274,12 @@ class ActionsFragment : DaggerFragment() {
extendedBolus?.visibility = View.GONE extendedBolus?.visibility = View.GONE
extendedBolusCancel?.visibility = View.GONE extendedBolusCancel?.visibility = View.GONE
} else { } else {
val activeExtendedBolus = activePlugin.activeTreatments.getExtendedBolusFromHistory(System.currentTimeMillis()) val activeExtendedBolus = repository.getExtendedBolusActiveAt(dateUtil.now()).blockingGet()
if (activeExtendedBolus != null) { if (activeExtendedBolus is ValueWrapper.Existing) {
extendedBolus?.visibility = View.GONE extendedBolus?.visibility = View.GONE
extendedBolusCancel?.visibility = View.VISIBLE extendedBolusCancel?.visibility = View.VISIBLE
@Suppress("SetTextI18n") @Suppress("SetTextI18n")
extendedBolusCancel?.text = resourceHelper.gs(R.string.cancel) + " " + activeExtendedBolus.toStringMedium() extendedBolusCancel?.text = resourceHelper.gs(R.string.cancel) + " " + activeExtendedBolus.value.toStringMedium(dateUtil)
} else { } else {
extendedBolus?.visibility = View.VISIBLE extendedBolus?.visibility = View.VISIBLE
extendedBolusCancel?.visibility = View.GONE extendedBolusCancel?.visibility = View.GONE
@ -280,7 +290,7 @@ class ActionsFragment : DaggerFragment() {
setTempBasal?.visibility = View.GONE setTempBasal?.visibility = View.GONE
cancelTempBasal?.visibility = View.GONE cancelTempBasal?.visibility = View.GONE
} else { } else {
val activeTemp = activePlugin.activeTreatments.getTempBasalFromHistory(System.currentTimeMillis()) val activeTemp = iobCobCalculator.getTempBasalIncludingConvertedExtended(System.currentTimeMillis())
if (activeTemp != null) { if (activeTemp != null) {
setTempBasal?.visibility = View.GONE setTempBasal?.visibility = View.GONE
cancelTempBasal?.visibility = View.VISIBLE cancelTempBasal?.visibility = View.VISIBLE

View file

@ -7,7 +7,6 @@ import android.os.Bundle
import dagger.android.HasAndroidInjector import dagger.android.HasAndroidInjector
import info.nightscout.androidaps.Config import info.nightscout.androidaps.Config
import info.nightscout.androidaps.R import info.nightscout.androidaps.R
import info.nightscout.androidaps.data.IobTotal
import info.nightscout.androidaps.events.* import info.nightscout.androidaps.events.*
import info.nightscout.androidaps.interfaces.* import info.nightscout.androidaps.interfaces.*
import info.nightscout.androidaps.logging.AAPSLogger import info.nightscout.androidaps.logging.AAPSLogger
@ -20,8 +19,11 @@ import info.nightscout.androidaps.plugins.general.overview.events.EventOverviewB
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.GlucoseStatusProvider import info.nightscout.androidaps.plugins.iob.iobCobCalculator.GlucoseStatusProvider
import info.nightscout.androidaps.receivers.ReceiverStatusStore import info.nightscout.androidaps.receivers.ReceiverStatusStore
import info.nightscout.androidaps.services.Intents import info.nightscout.androidaps.services.Intents
import info.nightscout.androidaps.utils.DateUtil
import info.nightscout.androidaps.utils.DefaultValueHelper import info.nightscout.androidaps.utils.DefaultValueHelper
import info.nightscout.androidaps.utils.FabricPrivacy 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.resources.ResourceHelper
import info.nightscout.androidaps.utils.rx.AapsSchedulers import info.nightscout.androidaps.utils.rx.AapsSchedulers
import io.reactivex.disposables.CompositeDisposable import io.reactivex.disposables.CompositeDisposable
@ -35,6 +37,7 @@ class DataBroadcastPlugin @Inject constructor(
resourceHelper: ResourceHelper, resourceHelper: ResourceHelper,
private val aapsSchedulers: AapsSchedulers, private val aapsSchedulers: AapsSchedulers,
private val context: Context, private val context: Context,
private val dateUtil: DateUtil,
private val fabricPrivacy: FabricPrivacy, private val fabricPrivacy: FabricPrivacy,
private val rxBus: RxBusWrapper, private val rxBus: RxBusWrapper,
private val iobCobCalculator: IobCobCalculator, private val iobCobCalculator: IobCobCalculator,
@ -116,7 +119,7 @@ class DataBroadcastPlugin @Inject constructor(
} }
private fun bgStatus(bundle: Bundle) { private fun bgStatus(bundle: Bundle) {
val lastBG = iobCobCalculator.lastBg() ?: return val lastBG = iobCobCalculator.ads.lastBg() ?: return
val glucoseStatus = glucoseStatusProvider.glucoseStatusData ?: return val glucoseStatus = glucoseStatusProvider.glucoseStatusData ?: return
bundle.putDouble("glucoseMgdl", lastBG.value) // last BG in mgdl bundle.putDouble("glucoseMgdl", lastBG.value) // last BG in mgdl
@ -131,8 +134,8 @@ class DataBroadcastPlugin @Inject constructor(
private fun iobCob(bundle: Bundle) { private fun iobCob(bundle: Bundle) {
profileFunction.getProfile() ?: return profileFunction.getProfile() ?: return
val bolusIob: IobTotal = iobCobCalculator.calculateIobFromBolus().round() val bolusIob = iobCobCalculator.calculateIobFromBolus().round()
val basalIob: IobTotal = activePlugin.activeTreatments.lastCalculationTempBasals.round() val basalIob = iobCobCalculator.calculateIobFromTempBasalsIncludingConvertedExtended().round()
bundle.putDouble("bolusIob", bolusIob.iob) bundle.putDouble("bolusIob", bolusIob.iob)
bundle.putDouble("basalIob", basalIob.basaliob) bundle.putDouble("basalIob", basalIob.basaliob)
bundle.putDouble("iob", bolusIob.iob + basalIob.basaliob) // total IOB bundle.putDouble("iob", bolusIob.iob + basalIob.basaliob) // total IOB
@ -174,12 +177,12 @@ class DataBroadcastPlugin @Inject constructor(
bundle.putLong("basalTimeStamp", now) bundle.putLong("basalTimeStamp", now)
bundle.putDouble("baseBasal", profile.basal) bundle.putDouble("baseBasal", profile.basal)
bundle.putString("profile", profileFunction.getProfileName()) bundle.putString("profile", profileFunction.getProfileName())
activePlugin.activeTreatments.getTempBasalFromHistory(now)?.let { iobCobCalculator.getTempBasalIncludingConvertedExtended(now)?.let {
bundle.putLong("tempBasalStart", it.date) bundle.putLong("tempBasalStart", it.timestamp)
bundle.putInt("tempBasalDurationInMinutes", it.durationInMinutes) bundle.putLong("tempBasalDurationInMinutes", it.durationInMinutes)
if (it.isAbsolute) bundle.putDouble("tempBasalAbsolute", it.absoluteRate) // U/h for absolute TBR if (it.isAbsolute) bundle.putDouble("tempBasalAbsolute", it.rate) // U/h for absolute TBR
else bundle.putInt("tempBasalPercent", it.percentRate) // % for percent type TBR else bundle.putInt("tempBasalPercent", it.rate.toInt()) // % for percent type TBR
bundle.putString("tempBasalString", it.toStringFull()) // user friendly string bundle.putString("tempBasalString", it.toStringFull(profile, dateUtil)) // user friendly string
} }
} }

View file

@ -17,6 +17,8 @@ import info.nightscout.androidaps.R
import info.nightscout.androidaps.database.AppRepository import info.nightscout.androidaps.database.AppRepository
import info.nightscout.androidaps.database.entities.Food import info.nightscout.androidaps.database.entities.Food
import info.nightscout.androidaps.database.entities.UserEntry.Action 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.database.transactions.InvalidateFoodTransaction
import info.nightscout.androidaps.databinding.FoodFragmentBinding import info.nightscout.androidaps.databinding.FoodFragmentBinding
import info.nightscout.androidaps.databinding.FoodItemBinding import info.nightscout.androidaps.databinding.FoodItemBinding
@ -28,7 +30,7 @@ import info.nightscout.androidaps.plugins.bus.RxBusWrapper
import info.nightscout.androidaps.plugins.general.nsclient.events.EventNSClientRestart import info.nightscout.androidaps.plugins.general.nsclient.events.EventNSClientRestart
import info.nightscout.androidaps.utils.FabricPrivacy import info.nightscout.androidaps.utils.FabricPrivacy
import info.nightscout.androidaps.utils.alertDialogs.OKDialog 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.resources.ResourceHelper
import info.nightscout.androidaps.utils.rx.AapsSchedulers import info.nightscout.androidaps.utils.rx.AapsSchedulers
import io.reactivex.Completable import io.reactivex.Completable
@ -51,8 +53,8 @@ class FoodFragment : DaggerFragment() {
@Inject lateinit var uel: UserEntryLogger @Inject lateinit var uel: UserEntryLogger
private val disposable = CompositeDisposable() private val disposable = CompositeDisposable()
private lateinit var unfiltered: List<Food> private var unfiltered: List<Food> = arrayListOf()
private lateinit var filtered: MutableList<Food> private var filtered: MutableList<Food> = arrayListOf()
private var _binding: FoodFragmentBinding? = null private var _binding: FoodFragmentBinding? = null
@ -74,7 +76,8 @@ class FoodFragment : DaggerFragment() {
binding.refreshFromNightscout.setOnClickListener { binding.refreshFromNightscout.setOnClickListener {
context?.let { context -> context?.let { context ->
OKDialog.showConfirmation(context, resourceHelper.gs(R.string.refresheventsfromnightscout) + " ?", { 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() } disposable += Completable.fromAction { repository.deleteAllFoods() }
.subscribeOn(aapsSchedulers.io) .subscribeOn(aapsSchedulers.io)
.observeOn(aapsSchedulers.main) .observeOn(aapsSchedulers.main)
@ -250,7 +253,7 @@ class FoodFragment : DaggerFragment() {
val food = v.tag as Food val food = v.tag as Food
activity?.let { activity -> activity?.let { activity ->
OKDialog.showConfirmation(activity, resourceHelper.gs(R.string.removerecord) + "\n" + food.name, { 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)) disposable += repository.runTransactionForResult(InvalidateFoodTransaction(food.id))
.subscribe( .subscribe(
{ aapsLogger.error(LTag.DATABASE, "Invalidated food $it") }, { aapsLogger.error(LTag.DATABASE, "Invalidated food $it") },

View file

@ -3,11 +3,13 @@ package info.nightscout.androidaps.plugins.general.food
import android.content.Context import android.content.Context
import androidx.work.Worker import androidx.work.Worker
import androidx.work.WorkerParameters import androidx.work.WorkerParameters
import androidx.work.workDataOf
import dagger.android.HasAndroidInjector import dagger.android.HasAndroidInjector
import info.nightscout.androidaps.R import info.nightscout.androidaps.R
import info.nightscout.androidaps.database.AppRepository import info.nightscout.androidaps.database.AppRepository
import info.nightscout.androidaps.database.entities.Food import info.nightscout.androidaps.database.entities.Food
import info.nightscout.androidaps.database.transactions.SyncNsFoodTransaction import info.nightscout.androidaps.database.transactions.SyncNsFoodTransaction
import info.nightscout.androidaps.extensions.foodFromJson
import info.nightscout.androidaps.interfaces.PluginBase import info.nightscout.androidaps.interfaces.PluginBase
import info.nightscout.androidaps.interfaces.PluginDescription import info.nightscout.androidaps.interfaces.PluginDescription
import info.nightscout.androidaps.interfaces.PluginType import info.nightscout.androidaps.interfaces.PluginType
@ -15,7 +17,6 @@ import info.nightscout.androidaps.logging.AAPSLogger
import info.nightscout.androidaps.logging.LTag import info.nightscout.androidaps.logging.LTag
import info.nightscout.androidaps.receivers.DataWorker import info.nightscout.androidaps.receivers.DataWorker
import info.nightscout.androidaps.utils.JsonHelper 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.resources.ResourceHelper
import info.nightscout.androidaps.utils.sharedPreferences.SP import info.nightscout.androidaps.utils.sharedPreferences.SP
import org.json.JSONObject import org.json.JSONObject
@ -55,7 +56,7 @@ class FoodPlugin @Inject constructor(
override fun doWork(): Result { override fun doWork(): Result {
val foods = dataWorker.pickupJSONArray(inputData.getLong(DataWorker.STORE_KEY, -1)) val foods = dataWorker.pickupJSONArray(inputData.getLong(DataWorker.STORE_KEY, -1))
?: return Result.failure() ?: return Result.failure(workDataOf("Error" to "missing input data"))
aapsLogger.debug(LTag.DATABASE, "Received Food Data: $foods") aapsLogger.debug(LTag.DATABASE, "Received Food Data: $foods")
var ret = Result.success() var ret = Result.success()
@ -74,10 +75,10 @@ class FoodPlugin @Inject constructor(
isValid = false isValid = false
).also { it.interfaceIDs.nightscoutId = JsonHelper.safeGetString(jsonFood, "_id") } ).also { it.interfaceIDs.nightscoutId = JsonHelper.safeGetString(jsonFood, "_id") }
repository.runTransactionForResult(SyncNsFoodTransaction(delFood)) repository.runTransactionForResult(SyncNsFoodTransaction(delFood, true))
.doOnError { .doOnError {
aapsLogger.error(LTag.DATABASE, "Error while removing food", it) aapsLogger.error(LTag.DATABASE, "Error while removing food", it)
ret = Result.failure() ret = Result.failure(workDataOf("Error" to it))
} }
.blockingGet() .blockingGet()
.also { .also {
@ -88,10 +89,10 @@ class FoodPlugin @Inject constructor(
else -> { else -> {
val food = foodFromJson(jsonFood) val food = foodFromJson(jsonFood)
if (food != null) { if (food != null) {
repository.runTransactionForResult(SyncNsFoodTransaction(food)) repository.runTransactionForResult(SyncNsFoodTransaction(food, false))
.doOnError { .doOnError {
aapsLogger.error(LTag.DATABASE, "Error while adding/updating food", it) aapsLogger.error(LTag.DATABASE, "Error while adding/updating food", it)
ret = Result.failure() ret = Result.failure(workDataOf("Error" to it))
} }
.blockingGet() .blockingGet()
.also { result -> .also { result ->
@ -101,7 +102,7 @@ class FoodPlugin @Inject constructor(
} }
} else { } else {
aapsLogger.error(LTag.DATABASE, "Error parsing food", jsonFood.toString()) aapsLogger.error(LTag.DATABASE, "Error parsing food", jsonFood.toString())
ret = Result.failure() ret = Result.failure(workDataOf("Error" to "Error parsing food"))
} }
} }
} }

View file

@ -16,7 +16,8 @@ import info.nightscout.androidaps.R
import info.nightscout.androidaps.activities.DaggerAppCompatActivityWithResult import info.nightscout.androidaps.activities.DaggerAppCompatActivityWithResult
import info.nightscout.androidaps.activities.PreferencesActivity 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.* 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.events.EventAppExit
import info.nightscout.androidaps.interfaces.ConfigInterface import info.nightscout.androidaps.interfaces.ConfigInterface
import info.nightscout.androidaps.interfaces.ImportExportPrefsInterface import info.nightscout.androidaps.interfaces.ImportExportPrefsInterface
@ -40,7 +41,6 @@ import io.reactivex.Single
import java.io.File import java.io.File
import java.io.FileNotFoundException import java.io.FileNotFoundException
import java.io.IOException import java.io.IOException
import java.util.*
import javax.inject.Inject import javax.inject.Inject
import javax.inject.Singleton import javax.inject.Singleton
import kotlin.system.exitProcess import kotlin.system.exitProcess
@ -62,7 +62,8 @@ class ImportExportPrefs @Inject constructor(
private val classicPrefsFormat: ClassicPrefsFormat, private val classicPrefsFormat: ClassicPrefsFormat,
private val encryptedPrefsFormat: EncryptedPrefsFormat, private val encryptedPrefsFormat: EncryptedPrefsFormat,
private val prefFileList: PrefFileListProvider, private val prefFileList: PrefFileListProvider,
private val uel: UserEntryLogger private val uel: UserEntryLogger,
private val dateUtil: DateUtil
) : ImportExportPrefsInterface { ) : ImportExportPrefsInterface {
override fun prefsFileExists(): Boolean { override fun prefsFileExists(): Boolean {
@ -94,7 +95,7 @@ class ImportExportPrefs @Inject constructor(
val metadata: MutableMap<PrefsMetadataKey, PrefMetadata> = mutableMapOf() val metadata: MutableMap<PrefsMetadataKey, PrefMetadata> = mutableMapOf()
metadata[PrefsMetadataKey.DEVICE_NAME] = PrefMetadata(detectUserName(context), PrefsStatus.OK) 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_VERSION] = PrefMetadata(BuildConfig.VERSION_NAME, PrefsStatus.OK)
metadata[PrefsMetadataKey.AAPS_FLAVOUR] = PrefMetadata(BuildConfig.FLAVOR, PrefsStatus.OK) metadata[PrefsMetadataKey.AAPS_FLAVOUR] = PrefMetadata(BuildConfig.FLAVOR, PrefsStatus.OK)
metadata[PrefsMetadataKey.DEVICE_MODEL] = PrefMetadata(config.currentDeviceModelString, PrefsStatus.OK) metadata[PrefsMetadataKey.DEVICE_MODEL] = PrefMetadata(config.currentDeviceModelString, PrefsStatus.OK)
@ -348,7 +349,7 @@ class ImportExportPrefs @Inject constructor(
private fun restartAppAfterImport(context: Context) { private fun restartAppAfterImport(context: Context) {
sp.putBoolean(R.string.key_setupwizard_processed, true) sp.putBoolean(R.string.key_setupwizard_processed, true)
OKDialog.show(context, resourceHelper.gs(R.string.setting_imported), resourceHelper.gs(R.string.restartingapp)) { 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") log.debug(LTag.CORE, "Exiting")
rxBus.send(EventAppExit()) rxBus.send(EventAppExit())
if (context is AppCompatActivity) { if (context is AppCompatActivity) {

View file

@ -9,15 +9,18 @@ import dagger.android.support.DaggerFragment
import info.nightscout.androidaps.R import info.nightscout.androidaps.R
import info.nightscout.androidaps.database.AppRepository import info.nightscout.androidaps.database.AppRepository
import info.nightscout.androidaps.database.entities.UserEntry.Action 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.databinding.MaintenanceFragmentBinding
import info.nightscout.androidaps.events.EventNewBG import info.nightscout.androidaps.events.EventNewBG
import info.nightscout.androidaps.interfaces.DataSyncSelector import info.nightscout.androidaps.interfaces.DataSyncSelector
import info.nightscout.androidaps.interfaces.DatabaseHelperInterface import info.nightscout.androidaps.interfaces.DatabaseHelperInterface
import info.nightscout.androidaps.interfaces.ImportExportPrefsInterface import info.nightscout.androidaps.interfaces.ImportExportPrefsInterface
import info.nightscout.androidaps.interfaces.PumpSync
import info.nightscout.androidaps.logging.AAPSLogger import info.nightscout.androidaps.logging.AAPSLogger
import info.nightscout.androidaps.logging.UserEntryLogger import info.nightscout.androidaps.logging.UserEntryLogger
import info.nightscout.androidaps.plugins.bus.RxBusWrapper import info.nightscout.androidaps.plugins.bus.RxBusWrapper
import info.nightscout.androidaps.plugins.general.maintenance.activities.LogSettingActivity import info.nightscout.androidaps.plugins.general.maintenance.activities.LogSettingActivity
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.events.EventNewHistoryData
import info.nightscout.androidaps.utils.alertDialogs.OKDialog import info.nightscout.androidaps.utils.alertDialogs.OKDialog
import info.nightscout.androidaps.utils.resources.ResourceHelper import info.nightscout.androidaps.utils.resources.ResourceHelper
import info.nightscout.androidaps.utils.rx.AapsSchedulers import info.nightscout.androidaps.utils.rx.AapsSchedulers
@ -38,6 +41,7 @@ class MaintenanceFragment : DaggerFragment() {
@Inject lateinit var databaseHelper: DatabaseHelperInterface @Inject lateinit var databaseHelper: DatabaseHelperInterface
@Inject lateinit var uel: UserEntryLogger @Inject lateinit var uel: UserEntryLogger
@Inject lateinit var dataSyncSelector: DataSyncSelector @Inject lateinit var dataSyncSelector: DataSyncSelector
@Inject lateinit var pumpSync: PumpSync
private val compositeDisposable = CompositeDisposable() private val compositeDisposable = CompositeDisposable()
@ -56,38 +60,42 @@ class MaintenanceFragment : DaggerFragment() {
super.onViewCreated(view, savedInstanceState) super.onViewCreated(view, savedInstanceState)
binding.logSend.setOnClickListener { maintenancePlugin.sendLogs() } binding.logSend.setOnClickListener { maintenancePlugin.sendLogs() }
binding.logDelete.setOnClickListener { binding.logDelete.setOnClickListener {
uel.log(Action.DELETE_LOGS) uel.log(Action.DELETE_LOGS, Sources.Maintenance)
maintenancePlugin.deleteLogs() maintenancePlugin.deleteLogs()
} }
binding.navResetdb.setOnClickListener { binding.navResetdb.setOnClickListener {
activity?.let { activity -> activity?.let { activity ->
OKDialog.showConfirmation(activity, resourceHelper.gs(R.string.maintenance), resourceHelper.gs(R.string.reset_db_confirm), Runnable { OKDialog.showConfirmation(activity, resourceHelper.gs(R.string.maintenance), resourceHelper.gs(R.string.reset_db_confirm), Runnable {
uel.log(Action.RESET_DATABASES)
compositeDisposable.add( compositeDisposable.add(
fromAction { fromAction {
databaseHelper.resetDatabases() databaseHelper.resetDatabases()
repository.clearDatabases() repository.clearDatabases()
dataSyncSelector.resetToNextFullSync() dataSyncSelector.resetToNextFullSync()
pumpSync.connectNewPump()
} }
.subscribeOn(aapsSchedulers.io) .subscribeOn(aapsSchedulers.io)
.observeOn(aapsSchedulers.main) .observeOn(aapsSchedulers.main)
.subscribeBy( .subscribeBy(
onError = { aapsLogger.error("Error clearing databases", it) }, 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 { binding.navExport.setOnClickListener {
uel.log(Action.EXPORT_SETTINGS) uel.log(Action.EXPORT_SETTINGS, Sources.Maintenance)
// start activity for checking permissions... // start activity for checking permissions...
importExportPrefs.verifyStoragePermissions(this) { importExportPrefs.verifyStoragePermissions(this) {
importExportPrefs.exportSharedPreferences(this) importExportPrefs.exportSharedPreferences(this)
} }
} }
binding.navImport.setOnClickListener { binding.navImport.setOnClickListener {
uel.log(Action.IMPORT_SETTINGS) uel.log(Action.IMPORT_SETTINGS, Sources.Maintenance)
// start activity for checking permissions... // start activity for checking permissions...
importExportPrefs.verifyStoragePermissions(this) { importExportPrefs.verifyStoragePermissions(this) {
importExportPrefs.importSharedPreferences(this) importExportPrefs.importSharedPreferences(this)
@ -97,7 +105,7 @@ class MaintenanceFragment : DaggerFragment() {
binding.exportCsv.setOnClickListener { binding.exportCsv.setOnClickListener {
activity?.let { activity -> activity?.let { activity ->
OKDialog.showConfirmation(activity, resourceHelper.gs(R.string.ue_export_to_csv) + "?") { 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()) importExportPrefs.exportUserEntriesCsv(activity, repository.getAllUserEntries())
} }
} }

View file

@ -2,19 +2,22 @@ package info.nightscout.androidaps.plugins.general.nsclient
import info.nightscout.androidaps.R import info.nightscout.androidaps.R
import info.nightscout.androidaps.database.AppRepository import info.nightscout.androidaps.database.AppRepository
import info.nightscout.androidaps.database.entities.DeviceStatus
import info.nightscout.androidaps.database.entities.* import info.nightscout.androidaps.database.entities.*
import info.nightscout.androidaps.interfaces.ActivePluginProvider import info.nightscout.androidaps.interfaces.ActivePluginProvider
import info.nightscout.androidaps.interfaces.DataSyncSelector import info.nightscout.androidaps.interfaces.DataSyncSelector
import info.nightscout.androidaps.interfaces.ProfileFunction import info.nightscout.androidaps.interfaces.ProfileFunction
import info.nightscout.androidaps.logging.AAPSLogger import info.nightscout.androidaps.logging.AAPSLogger
import info.nightscout.androidaps.logging.LTag import info.nightscout.androidaps.logging.LTag
import info.nightscout.androidaps.utils.extensions.toJson import info.nightscout.androidaps.extensions.toJson
import info.nightscout.androidaps.utils.DateUtil
import info.nightscout.androidaps.utils.sharedPreferences.SP import info.nightscout.androidaps.utils.sharedPreferences.SP
import javax.inject.Inject import javax.inject.Inject
class DataSyncSelectorImplementation @Inject constructor( class DataSyncSelectorImplementation @Inject constructor(
private val sp: SP, private val sp: SP,
private val aapsLogger: AAPSLogger, private val aapsLogger: AAPSLogger,
private val dateUtil: DateUtil,
private val profileFunction: ProfileFunction, private val profileFunction: ProfileFunction,
private val nsClientPlugin: NSClientPlugin, private val nsClientPlugin: NSClientPlugin,
private val activePlugin: ActivePluginProvider, private val activePlugin: ActivePluginProvider,
@ -28,6 +31,10 @@ class DataSyncSelectorImplementation @Inject constructor(
sp.remove(R.string.key_ns_bolus_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_carbs_last_synced_id)
sp.remove(R.string.key_ns_bolus_calculator_result_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) { override fun confirmLastBolusIdIfGreater(lastSynced: Long) {
@ -60,10 +67,10 @@ class DataSyncSelectorImplementation @Inject constructor(
nsClientPlugin.nsClientService?.dbRemove("treatments", bolus.first.interfaceIDs.nightscoutId, DataSyncSelector.PairBolus(bolus.first, bolus.second)) nsClientPlugin.nsClientService?.dbRemove("treatments", bolus.first.interfaceIDs.nightscoutId, DataSyncSelector.PairBolus(bolus.first, bolus.second))
// existing without nsId = create new // existing without nsId = create new
bolus.first.isValid && bolus.first.interfaceIDs.nightscoutId == null -> bolus.first.isValid && bolus.first.interfaceIDs.nightscoutId == null ->
nsClientPlugin.nsClientService?.dbAdd("treatments", bolus.first.toJson(), DataSyncSelector.PairBolus(bolus.first, bolus.second)) nsClientPlugin.nsClientService?.dbAdd("treatments", bolus.first.toJson(dateUtil), DataSyncSelector.PairBolus(bolus.first, bolus.second))
// existing with nsId = update // existing with nsId = update
bolus.first.isValid && bolus.first.interfaceIDs.nightscoutId != null -> bolus.first.isValid && bolus.first.interfaceIDs.nightscoutId != null ->
nsClientPlugin.nsClientService?.dbUpdate("treatments", bolus.first.interfaceIDs.nightscoutId, bolus.first.toJson(), DataSyncSelector.PairBolus(bolus.first, bolus.second)) nsClientPlugin.nsClientService?.dbUpdate("treatments", bolus.first.interfaceIDs.nightscoutId, bolus.first.toJson(dateUtil), DataSyncSelector.PairBolus(bolus.first, bolus.second))
} }
return true return true
} }
@ -97,10 +104,10 @@ class DataSyncSelectorImplementation @Inject constructor(
nsClientPlugin.nsClientService?.dbRemove("treatments", carb.first.interfaceIDs.nightscoutId, DataSyncSelector.PairCarbs(carb.first, carb.second)) nsClientPlugin.nsClientService?.dbRemove("treatments", carb.first.interfaceIDs.nightscoutId, DataSyncSelector.PairCarbs(carb.first, carb.second))
// existing without nsId = create new // existing without nsId = create new
carb.first.isValid && carb.first.interfaceIDs.nightscoutId == null -> carb.first.isValid && carb.first.interfaceIDs.nightscoutId == null ->
nsClientPlugin.nsClientService?.dbAdd("treatments", carb.first.toJson(), DataSyncSelector.PairCarbs(carb.first, carb.second)) nsClientPlugin.nsClientService?.dbAdd("treatments", carb.first.toJson(dateUtil), DataSyncSelector.PairCarbs(carb.first, carb.second))
// existing with nsId = update // existing with nsId = update
carb.first.isValid && carb.first.interfaceIDs.nightscoutId != null -> carb.first.isValid && carb.first.interfaceIDs.nightscoutId != null ->
nsClientPlugin.nsClientService?.dbUpdate("treatments", carb.first.interfaceIDs.nightscoutId, carb.first.toJson(), DataSyncSelector.PairCarbs(carb.first, carb.second)) nsClientPlugin.nsClientService?.dbUpdate("treatments", carb.first.interfaceIDs.nightscoutId, carb.first.toJson(dateUtil), DataSyncSelector.PairCarbs(carb.first, carb.second))
} }
return true return true
} }
@ -134,10 +141,10 @@ class DataSyncSelectorImplementation @Inject constructor(
nsClientPlugin.nsClientService?.dbRemove("treatments", bolusCalculatorResult.first.interfaceIDs.nightscoutId, DataSyncSelector.PairBolusCalculatorResult(bolusCalculatorResult.first, bolusCalculatorResult.second)) nsClientPlugin.nsClientService?.dbRemove("treatments", bolusCalculatorResult.first.interfaceIDs.nightscoutId, DataSyncSelector.PairBolusCalculatorResult(bolusCalculatorResult.first, bolusCalculatorResult.second))
// existing without nsId = create new // existing without nsId = create new
bolusCalculatorResult.first.isValid && bolusCalculatorResult.first.interfaceIDs.nightscoutId == null -> bolusCalculatorResult.first.isValid && bolusCalculatorResult.first.interfaceIDs.nightscoutId == null ->
nsClientPlugin.nsClientService?.dbAdd("treatments", bolusCalculatorResult.first.toJson(), DataSyncSelector.PairBolusCalculatorResult(bolusCalculatorResult.first, bolusCalculatorResult.second)) nsClientPlugin.nsClientService?.dbAdd("treatments", bolusCalculatorResult.first.toJson(dateUtil), DataSyncSelector.PairBolusCalculatorResult(bolusCalculatorResult.first, bolusCalculatorResult.second))
// existing with nsId = update // existing with nsId = update
bolusCalculatorResult.first.isValid && bolusCalculatorResult.first.interfaceIDs.nightscoutId != null -> bolusCalculatorResult.first.isValid && bolusCalculatorResult.first.interfaceIDs.nightscoutId != null ->
nsClientPlugin.nsClientService?.dbUpdate("treatments", bolusCalculatorResult.first.interfaceIDs.nightscoutId, bolusCalculatorResult.first.toJson(), DataSyncSelector.PairBolusCalculatorResult(bolusCalculatorResult.first, bolusCalculatorResult.second)) nsClientPlugin.nsClientService?.dbUpdate("treatments", bolusCalculatorResult.first.interfaceIDs.nightscoutId, bolusCalculatorResult.first.toJson(dateUtil), DataSyncSelector.PairBolusCalculatorResult(bolusCalculatorResult.first, bolusCalculatorResult.second))
} }
return true return true
} }
@ -171,10 +178,10 @@ class DataSyncSelectorImplementation @Inject constructor(
nsClientPlugin.nsClientService?.dbRemove("treatments", tt.first.interfaceIDs.nightscoutId, DataSyncSelector.PairTemporaryTarget(tt.first, tt.second)) nsClientPlugin.nsClientService?.dbRemove("treatments", tt.first.interfaceIDs.nightscoutId, DataSyncSelector.PairTemporaryTarget(tt.first, tt.second))
// existing without nsId = create new // existing without nsId = create new
tt.first.isValid && tt.first.interfaceIDs.nightscoutId == null -> tt.first.isValid && tt.first.interfaceIDs.nightscoutId == null ->
nsClientPlugin.nsClientService?.dbAdd("treatments", tt.first.toJson(profileFunction.getUnits()), DataSyncSelector.PairTemporaryTarget(tt.first, tt.second)) nsClientPlugin.nsClientService?.dbAdd("treatments", tt.first.toJson(profileFunction.getUnits(), dateUtil), DataSyncSelector.PairTemporaryTarget(tt.first, tt.second))
// existing with nsId = update // existing with nsId = update
tt.first.isValid && tt.first.interfaceIDs.nightscoutId != null -> tt.first.isValid && tt.first.interfaceIDs.nightscoutId != null ->
nsClientPlugin.nsClientService?.dbUpdate("treatments", tt.first.interfaceIDs.nightscoutId, tt.first.toJson(profileFunction.getUnits()), DataSyncSelector.PairTemporaryTarget(tt.first, tt.second)) nsClientPlugin.nsClientService?.dbUpdate("treatments", tt.first.interfaceIDs.nightscoutId, tt.first.toJson(profileFunction.getUnits(), dateUtil), DataSyncSelector.PairTemporaryTarget(tt.first, tt.second))
} }
return true return true
} }
@ -246,10 +253,10 @@ class DataSyncSelectorImplementation @Inject constructor(
nsClientPlugin.nsClientService?.dbRemove("entries", gv.first.interfaceIDs.nightscoutId, DataSyncSelector.PairGlucoseValue(gv.first, gv.second)) nsClientPlugin.nsClientService?.dbRemove("entries", gv.first.interfaceIDs.nightscoutId, DataSyncSelector.PairGlucoseValue(gv.first, gv.second))
// existing without nsId = create new // existing without nsId = create new
gv.first.isValid && gv.first.interfaceIDs.nightscoutId == null -> gv.first.isValid && gv.first.interfaceIDs.nightscoutId == null ->
nsClientPlugin.nsClientService?.dbAdd("entries", gv.first.toJson(), DataSyncSelector.PairGlucoseValue(gv.first, gv.second)) nsClientPlugin.nsClientService?.dbAdd("entries", gv.first.toJson(dateUtil), DataSyncSelector.PairGlucoseValue(gv.first, gv.second))
// existing with nsId = update // existing with nsId = update
gv.first.isValid && gv.first.interfaceIDs.nightscoutId != null -> gv.first.isValid && gv.first.interfaceIDs.nightscoutId != null ->
nsClientPlugin.nsClientService?.dbUpdate("entries", gv.first.interfaceIDs.nightscoutId, gv.first.toJson(), DataSyncSelector.PairGlucoseValue(gv.first, gv.second)) nsClientPlugin.nsClientService?.dbUpdate("entries", gv.first.interfaceIDs.nightscoutId, gv.first.toJson(dateUtil), DataSyncSelector.PairGlucoseValue(gv.first, gv.second))
} }
return true return true
} }
@ -294,4 +301,111 @@ class DataSyncSelectorImplementation @Inject constructor(
return false 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<DeviceStatus> {
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<TemporaryBasal> {
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<ExtendedBolus> {
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
}
} }

View file

@ -3,16 +3,17 @@ package info.nightscout.androidaps.plugins.general.nsclient
import android.content.Context import android.content.Context
import androidx.work.Worker import androidx.work.Worker
import androidx.work.WorkerParameters import androidx.work.WorkerParameters
import androidx.work.workDataOf
import dagger.android.HasAndroidInjector import dagger.android.HasAndroidInjector
import info.nightscout.androidaps.Constants
import info.nightscout.androidaps.R import info.nightscout.androidaps.R
import info.nightscout.androidaps.database.AppRepository import info.nightscout.androidaps.database.AppRepository
import info.nightscout.androidaps.database.entities.TherapyEvent 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.ValueWithUnit import info.nightscout.androidaps.database.entities.UserEntry.Sources
import info.nightscout.androidaps.database.transactions.SyncNsBolusTransaction import info.nightscout.androidaps.database.entities.ValueWithUnit
import info.nightscout.androidaps.database.transactions.SyncNsCarbsTransaction import info.nightscout.androidaps.database.transactions.*
import info.nightscout.androidaps.database.transactions.SyncNsTemporaryTargetTransaction import info.nightscout.androidaps.extensions.*
import info.nightscout.androidaps.database.transactions.SyncNsTherapyEventTransaction
import info.nightscout.androidaps.interfaces.ConfigInterface import info.nightscout.androidaps.interfaces.ConfigInterface
import info.nightscout.androidaps.interfaces.DatabaseHelperInterface import info.nightscout.androidaps.interfaces.DatabaseHelperInterface
import info.nightscout.androidaps.logging.AAPSLogger import info.nightscout.androidaps.logging.AAPSLogger
@ -26,11 +27,8 @@ import info.nightscout.androidaps.utils.DateUtil
import info.nightscout.androidaps.utils.JsonHelper import info.nightscout.androidaps.utils.JsonHelper
import info.nightscout.androidaps.utils.JsonHelper.safeGetLong import info.nightscout.androidaps.utils.JsonHelper.safeGetLong
import info.nightscout.androidaps.utils.buildHelper.BuildHelper import info.nightscout.androidaps.utils.buildHelper.BuildHelper
import info.nightscout.androidaps.utils.extensions.bolusFromJson
import info.nightscout.androidaps.utils.extensions.carbsFromJson
import info.nightscout.androidaps.utils.extensions.temporaryTargetFromJson
import info.nightscout.androidaps.utils.extensions.therapyEventFromJson
import info.nightscout.androidaps.utils.sharedPreferences.SP import info.nightscout.androidaps.utils.sharedPreferences.SP
import java.util.concurrent.TimeUnit
import javax.inject.Inject import javax.inject.Inject
class NSClientAddUpdateWorker( class NSClientAddUpdateWorker(
@ -43,7 +41,7 @@ class NSClientAddUpdateWorker(
@Inject lateinit var aapsLogger: AAPSLogger @Inject lateinit var aapsLogger: AAPSLogger
@Inject lateinit var buildHelper: BuildHelper @Inject lateinit var buildHelper: BuildHelper
@Inject lateinit var sp: SP @Inject lateinit var sp: SP
@Inject lateinit var dateutil: DateUtil @Inject lateinit var dateUtil: DateUtil
@Inject lateinit var config: ConfigInterface @Inject lateinit var config: ConfigInterface
@Inject lateinit var repository: AppRepository @Inject lateinit var repository: AppRepository
@Inject lateinit var databaseHelper: DatabaseHelperInterface @Inject lateinit var databaseHelper: DatabaseHelperInterface
@ -52,16 +50,16 @@ class NSClientAddUpdateWorker(
override fun doWork(): Result { override fun doWork(): Result {
val acceptNSData = !sp.getBoolean(R.string.key_ns_upload_only, true) && buildHelper.isEngineeringMode() || config.NSCLIENT 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)) 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 ret = Result.success()
var latestDateInReceivedData = 0L var latestDateInReceivedData = 0L
for (i in 0 until treatments.length()) { for (i in 0 until treatments.length()) {
val json = treatments.getJSONObject(i) var json = treatments.getJSONObject(i)
// new DB model // new DB model
val insulin = JsonHelper.safeGetDouble(json, "insulin") val insulin = JsonHelper.safeGetDouble(json, "insulin")
val carbs = JsonHelper.safeGetDouble(json, "carbs") val carbs = JsonHelper.safeGetDouble(json, "carbs")
@ -73,91 +71,114 @@ class NSClientAddUpdateWorker(
//Find latest date in treatment //Find latest date in treatment
val mills = safeGetLong(json, "mills") val mills = safeGetLong(json, "mills")
if (mills != 0L && mills < dateutil._now()) if (mills != 0L && mills < dateUtil.now())
if (mills > latestDateInReceivedData) latestDateInReceivedData = mills if (mills > latestDateInReceivedData) latestDateInReceivedData = mills
if (insulin > 0) { if (insulin > 0) {
bolusFromJson(json)?.let { bolus -> bolusFromJson(json)?.let { bolus ->
repository.runTransactionForResult(SyncNsBolusTransaction(bolus)) repository.runTransactionForResult(SyncNsBolusTransaction(bolus, invalidateByNsOnly = false))
.doOnError { .doOnError {
aapsLogger.error(LTag.DATABASE, "Error while saving bolus", it) aapsLogger.error(LTag.DATABASE, "Error while saving bolus", it)
ret = Result.failure() ret = Result.failure(workDataOf("Error" to it))
} }
.blockingGet() .blockingGet()
.also { result -> .also { result ->
result.inserted.forEach { result.inserted.forEach {
uel.log(UserEntry.Action.CAREPORTAL_FROM_NS, uel.log(Action.BOLUS, Sources.NSClient,
ValueWithUnit(it.timestamp, UserEntry.Units.Timestamp, true), ValueWithUnit.Timestamp(it.timestamp),
ValueWithUnit(it.amount, UserEntry.Units.U) ValueWithUnit.Insulin(it.amount)
) )
aapsLogger.debug(LTag.DATABASE, "Inserted bolus $it")
} }
result.invalidated.forEach { result.invalidated.forEach {
uel.log(UserEntry.Action.CAREPORTAL_DELETED_FROM_NS, uel.log(Action.BOLUS_REMOVED, Sources.NSClient,
ValueWithUnit(it.timestamp, UserEntry.Units.Timestamp, true), ValueWithUnit.Timestamp(it.timestamp),
ValueWithUnit(it.amount, UserEntry.Units.U) 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") } ?: aapsLogger.error("Error parsing bolus json $json")
} }
if (carbs > 0) { if (carbs > 0) {
carbsFromJson(json)?.let { carb -> carbsFromJson(json)?.let { carb ->
repository.runTransactionForResult(SyncNsCarbsTransaction(carb)) repository.runTransactionForResult(SyncNsCarbsTransaction(carb, invalidateByNsOnly = false))
.doOnError { .doOnError {
aapsLogger.error(LTag.DATABASE, "Error while saving carbs", it) aapsLogger.error(LTag.DATABASE, "Error while saving carbs", it)
ret = Result.failure() ret = Result.failure(workDataOf("Error" to it))
} }
.blockingGet() .blockingGet()
.also { result -> .also { result ->
result.inserted.forEach { result.inserted.forEach {
uel.log(UserEntry.Action.CAREPORTAL_FROM_NS, uel.log(Action.CARBS, Sources.NSClient,
ValueWithUnit(it.timestamp, UserEntry.Units.Timestamp, true), ValueWithUnit.Timestamp(it.timestamp),
ValueWithUnit(it.amount, UserEntry.Units.G) ValueWithUnit.Gram(it.amount.toInt())
) )
aapsLogger.debug(LTag.DATABASE, "Inserted carbs $it")
} }
result.invalidated.forEach { result.invalidated.forEach {
uel.log(UserEntry.Action.CAREPORTAL_DELETED_FROM_NS, uel.log(Action.CARBS_REMOVED, Sources.NSClient,
ValueWithUnit(it.timestamp, UserEntry.Units.Timestamp, true), ValueWithUnit.Timestamp(it.timestamp),
ValueWithUnit(it.amount, UserEntry.Units.G) 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") } ?: 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 { when {
insulin > 0 || carbs > 0 -> Any() insulin > 0 || carbs > 0 -> Any()
eventType == TherapyEvent.Type.TEMPORARY_TARGET.text -> eventType == TherapyEvent.Type.TEMPORARY_TARGET.text ->
temporaryTargetFromJson(json)?.let { temporaryTarget -> temporaryTargetFromJson(json)?.let { temporaryTarget ->
repository.runTransactionForResult(SyncNsTemporaryTargetTransaction(temporaryTarget)) repository.runTransactionForResult(SyncNsTemporaryTargetTransaction(temporaryTarget, invalidateByNsOnly = false))
.doOnError { .doOnError {
aapsLogger.error(LTag.DATABASE, "Error while saving temporary target", it) aapsLogger.error(LTag.DATABASE, "Error while saving temporary target", it)
ret = Result.failure() ret = Result.failure(workDataOf("Error" to it))
} }
.blockingGet() .blockingGet()
.also { result -> .also { result ->
result.inserted.forEach { result.inserted.forEach { tt ->
uel.log(UserEntry.Action.TT_FROM_NS, uel.log(Action.TT, Sources.NSClient,
ValueWithUnit(it.reason.text, UserEntry.Units.TherapyEvent), ValueWithUnit.TherapyEventTTReason(tt.reason),
ValueWithUnit(it.lowTarget, UserEntry.Units.Mg_Dl, true), ValueWithUnit.fromGlucoseUnit(tt.lowTarget, Constants.MGDL),
ValueWithUnit(it.highTarget, UserEntry.Units.Mg_Dl, it.lowTarget != it.highTarget), ValueWithUnit.fromGlucoseUnit(tt.highTarget, Constants.MGDL).takeIf { tt.lowTarget != tt.highTarget },
ValueWithUnit(it.duration.toInt() / 60000, UserEntry.Units.M, true) ValueWithUnit.Minute(TimeUnit.MILLISECONDS.toMinutes(tt.duration).toInt())
) )
aapsLogger.debug(LTag.DATABASE, "Inserted TemporaryTarget $tt")
} }
result.invalidated.forEach { result.invalidated.forEach { tt ->
uel.log(UserEntry.Action.TT_DELETED_FROM_NS, uel.log(Action.TT_REMOVED, Sources.NSClient,
ValueWithUnit(it.reason.text, UserEntry.Units.TherapyEvent), ValueWithUnit.TherapyEventTTReason(tt.reason),
ValueWithUnit(it.lowTarget, UserEntry.Units.Mg_Dl, true), ValueWithUnit.Mgdl(tt.lowTarget),
ValueWithUnit(it.highTarget, UserEntry.Units.Mg_Dl, it.lowTarget != it.highTarget), ValueWithUnit.Mgdl(tt.highTarget).takeIf { tt.lowTarget != tt.highTarget },
ValueWithUnit(it.duration.toInt() / 60000, UserEntry.Units.M, true) ValueWithUnit.Minute(TimeUnit.MILLISECONDS.toMinutes(tt.duration).toInt())
) )
aapsLogger.debug(LTag.DATABASE, "Invalidated TemporaryTarget $tt")
} }
result.ended.forEach { result.ended.forEach { tt ->
uel.log(UserEntry.Action.TT_CANCELED_FROM_NS, uel.log(Action.CANCEL_TT, Sources.NSClient,
ValueWithUnit(it.reason.text, UserEntry.Units.TherapyEvent), ValueWithUnit.TherapyEventTTReason(tt.reason),
ValueWithUnit(it.lowTarget, UserEntry.Units.Mg_Dl, true), ValueWithUnit.Mgdl(tt.lowTarget),
ValueWithUnit(it.highTarget, UserEntry.Units.Mg_Dl, it.lowTarget != it.highTarget), ValueWithUnit.Mgdl(tt.highTarget).takeIf { tt.lowTarget != tt.highTarget },
ValueWithUnit(it.duration.toInt() / 60000, UserEntry.Units.M, true) 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") } ?: aapsLogger.error("Error parsing TT json $json")
@ -172,33 +193,118 @@ class NSClientAddUpdateWorker(
eventType == TherapyEvent.Type.APS_OFFLINE.text || eventType == TherapyEvent.Type.APS_OFFLINE.text ||
eventType == TherapyEvent.Type.PUMP_BATTERY_CHANGE.text -> eventType == TherapyEvent.Type.PUMP_BATTERY_CHANGE.text ->
therapyEventFromJson(json)?.let { therapyEvent -> therapyEventFromJson(json)?.let { therapyEvent ->
repository.runTransactionForResult(SyncNsTherapyEventTransaction(therapyEvent)) repository.runTransactionForResult(SyncNsTherapyEventTransaction(therapyEvent, invalidateByNsOnly = false))
.doOnError { .doOnError {
aapsLogger.error(LTag.DATABASE, "Error while saving therapy event", it) 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() .blockingGet()
.also { result -> .also { result ->
result.inserted.forEach { result.inserted.forEach {
uel.log(UserEntry.Action.CAREPORTAL_FROM_NS, uel.log(Action.EXTENDED_BOLUS, Sources.NSClient,
it.note ?: "", ValueWithUnit.Timestamp(it.timestamp),
ValueWithUnit(it.timestamp, UserEntry.Units.Timestamp, true), ValueWithUnit.Insulin(it.amount),
ValueWithUnit(it.type.text, UserEntry.Units.TherapyEvent) ValueWithUnit.UnitPerHour(it.rate),
ValueWithUnit.Minute(TimeUnit.MILLISECONDS.toMinutes(it.duration).toInt())
) )
aapsLogger.debug(LTag.DATABASE, "Inserted ExtendedBolus $it")
} }
result.invalidated.forEach { result.invalidated.forEach {
uel.log(UserEntry.Action.CAREPORTAL_DELETED_FROM_NS, uel.log(Action.EXTENDED_BOLUS_REMOVED, Sources.NSClient,
it.note ?: "", ValueWithUnit.Timestamp(it.timestamp),
ValueWithUnit(it.timestamp, UserEntry.Units.Timestamp, true), ValueWithUnit.Insulin(it.amount),
ValueWithUnit(it.type.text, UserEntry.Units.TherapyEvent) 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 -> eventType == TherapyEvent.Type.TEMPORARY_BASAL.text ->
databaseHelper.createTempBasalFromJsonIfNotExists(json) temporaryBasalFromJson(json)?.let { temporaryBasal ->
eventType == TherapyEvent.Type.COMBO_BOLUS.text -> repository.runTransactionForResult(SyncNsTemporaryBasalTransaction(temporaryBasal, invalidateByNsOnly = false))
databaseHelper.createExtendedBolusFromJsonIfNotExists(json) .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 -> eventType == TherapyEvent.Type.PROFILE_SWITCH.text ->
databaseHelper.createProfileSwitchFromJsonIfNotExists(json) databaseHelper.createProfileSwitchFromJsonIfNotExists(json)
} }

View file

@ -8,7 +8,8 @@ import android.view.ViewGroup
import android.widget.ScrollView import android.widget.ScrollView
import dagger.android.support.DaggerFragment import dagger.android.support.DaggerFragment
import info.nightscout.androidaps.R 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.NsClientFragmentBinding import info.nightscout.androidaps.databinding.NsClientFragmentBinding
import info.nightscout.androidaps.interfaces.DataSyncSelector import info.nightscout.androidaps.interfaces.DataSyncSelector
import info.nightscout.androidaps.interfaces.UploadQueueAdminInterface import info.nightscout.androidaps.interfaces.UploadQueueAdminInterface
@ -61,7 +62,7 @@ class NSClientFragment : DaggerFragment() {
binding.paused.isChecked = nsClientPlugin.paused binding.paused.isChecked = nsClientPlugin.paused
binding.paused.setOnCheckedChangeListener { _, isChecked -> binding.paused.setOnCheckedChangeListener { _, isChecked ->
uel.log(if (isChecked) UserEntry.Action.NS_PAUSED else UserEntry.Action.NS_RESUME) uel.log(if (isChecked) Action.NS_PAUSED else Action.NS_RESUME, Sources.NSClient)
nsClientPlugin.pause(isChecked) nsClientPlugin.pause(isChecked)
updateGui() updateGui()
} }
@ -74,7 +75,7 @@ class NSClientFragment : DaggerFragment() {
binding.clearQueue.setOnClickListener { binding.clearQueue.setOnClickListener {
context?.let { context -> context?.let { context ->
OKDialog.showConfirmation(context, resourceHelper.gs(R.string.nsclientinternal), resourceHelper.gs(R.string.clearqueueconfirm), Runnable { OKDialog.showConfirmation(context, resourceHelper.gs(R.string.nsclientinternal), resourceHelper.gs(R.string.clearqueueconfirm), Runnable {
uel.log(UserEntry.Action.NS_QUEUE_CLEARED) uel.log(Action.NS_QUEUE_CLEARED, Sources.NSClient)
uploadQueue.clearQueue() uploadQueue.clearQueue()
updateGui() updateGui()
}) })

View file

@ -3,6 +3,7 @@ package info.nightscout.androidaps.plugins.general.nsclient
import android.content.Context import android.content.Context
import androidx.work.Worker import androidx.work.Worker
import androidx.work.WorkerParameters import androidx.work.WorkerParameters
import androidx.work.workDataOf
import dagger.android.HasAndroidInjector import dagger.android.HasAndroidInjector
import info.nightscout.androidaps.R import info.nightscout.androidaps.R
import info.nightscout.androidaps.database.AppRepository import info.nightscout.androidaps.database.AppRepository
@ -13,7 +14,7 @@ import info.nightscout.androidaps.logging.LTag
import info.nightscout.androidaps.plugins.general.nsclient.data.NSMbg import info.nightscout.androidaps.plugins.general.nsclient.data.NSMbg
import info.nightscout.androidaps.receivers.DataWorker import info.nightscout.androidaps.receivers.DataWorker
import info.nightscout.androidaps.utils.buildHelper.BuildHelper 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 info.nightscout.androidaps.utils.sharedPreferences.SP
import javax.inject.Inject import javax.inject.Inject
@ -36,14 +37,14 @@ class NSClientMbgWorker(
if (!acceptNSData) return ret if (!acceptNSData) return ret
val mbgArray = dataWorker.pickupJSONArray(inputData.getLong(DataWorker.STORE_KEY, -1)) 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()) { for (i in 0 until mbgArray.length()) {
val nsMbg = NSMbg(mbgArray.getJSONObject(i)) val nsMbg = NSMbg(mbgArray.getJSONObject(i))
if (!nsMbg.isValid()) continue if (!nsMbg.isValid()) continue
repository.runTransactionForResult(SyncNsTherapyEventTransaction(therapyEventFromNsMbg(nsMbg))) repository.runTransactionForResult(SyncNsTherapyEventTransaction(therapyEventFromNsMbg(nsMbg), false))
.doOnError { .doOnError {
aapsLogger.error("Error while saving therapy event", it) aapsLogger.error("Error while saving therapy event", it)
ret = Result.failure() ret = Result.failure(workDataOf("Error" to it))
} }
.blockingGet() .blockingGet()
.also { .also {

View file

@ -3,15 +3,15 @@ package info.nightscout.androidaps.plugins.general.nsclient
import android.content.Context import android.content.Context
import androidx.work.Worker import androidx.work.Worker
import androidx.work.WorkerParameters import androidx.work.WorkerParameters
import androidx.work.workDataOf
import dagger.android.HasAndroidInjector import dagger.android.HasAndroidInjector
import info.nightscout.androidaps.R import info.nightscout.androidaps.R
import info.nightscout.androidaps.database.AppRepository 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.ValueWithUnit import info.nightscout.androidaps.database.entities.UserEntry.Sources
import info.nightscout.androidaps.database.transactions.SyncNsBolusTransaction import info.nightscout.androidaps.database.entities.ValueWithUnit
import info.nightscout.androidaps.database.transactions.SyncNsCarbsTransaction import info.nightscout.androidaps.database.transactions.*
import info.nightscout.androidaps.database.transactions.SyncNsTemporaryTargetTransaction import info.nightscout.androidaps.extensions.*
import info.nightscout.androidaps.database.transactions.SyncNsTherapyEventTransaction
import info.nightscout.androidaps.interfaces.ConfigInterface import info.nightscout.androidaps.interfaces.ConfigInterface
import info.nightscout.androidaps.interfaces.DatabaseHelperInterface import info.nightscout.androidaps.interfaces.DatabaseHelperInterface
import info.nightscout.androidaps.logging.AAPSLogger import info.nightscout.androidaps.logging.AAPSLogger
@ -21,11 +21,8 @@ import info.nightscout.androidaps.plugins.bus.RxBusWrapper
import info.nightscout.androidaps.receivers.DataWorker import info.nightscout.androidaps.receivers.DataWorker
import info.nightscout.androidaps.utils.JsonHelper import info.nightscout.androidaps.utils.JsonHelper
import info.nightscout.androidaps.utils.buildHelper.BuildHelper import info.nightscout.androidaps.utils.buildHelper.BuildHelper
import info.nightscout.androidaps.utils.extensions.bolusFromNsIdForInvalidating
import info.nightscout.androidaps.utils.extensions.carbsFromNsIdForInvalidating
import info.nightscout.androidaps.utils.extensions.temporaryTargetFromNsIdForInvalidating
import info.nightscout.androidaps.utils.extensions.therapyEventFromNsIdForInvalidating
import info.nightscout.androidaps.utils.sharedPreferences.SP import info.nightscout.androidaps.utils.sharedPreferences.SP
import java.util.concurrent.TimeUnit
import javax.inject.Inject import javax.inject.Inject
// This will not be needed fpr NS v3 // This will not be needed fpr NS v3
@ -48,12 +45,12 @@ class NSClientRemoveWorker(
override fun doWork(): Result { override fun doWork(): Result {
val acceptNSData = !sp.getBoolean(R.string.key_ns_upload_only, true) && buildHelper.isEngineeringMode() || config.NSCLIENT 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() var ret = Result.success()
val treatments = dataWorker.pickupJSONArray(inputData.getLong(DataWorker.STORE_KEY, -1)) 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()) { for (i in 0 until treatments.length()) {
val json = treatments.getJSONObject(i) val json = treatments.getJSONObject(i)
@ -61,78 +58,107 @@ class NSClientRemoveWorker(
// room Temporary target // room Temporary target
val temporaryTarget = temporaryTargetFromNsIdForInvalidating(nsId) val temporaryTarget = temporaryTargetFromNsIdForInvalidating(nsId)
repository.runTransactionForResult(SyncNsTemporaryTargetTransaction(temporaryTarget)) repository.runTransactionForResult(SyncNsTemporaryTargetTransaction(temporaryTarget, invalidateByNsOnly = true))
.doOnError { .doOnError {
aapsLogger.error(LTag.DATABASE, "Error while invalidating temporary target", it) aapsLogger.error(LTag.DATABASE, "Error while invalidating temporary target", it)
ret = Result.failure() ret = Result.failure(workDataOf("Error" to it))
} }
.blockingGet() .blockingGet()
.also { result -> .also { result ->
result.invalidated.forEach { result.invalidated.forEach { tt ->
uel.log( uel.log(
UserEntry.Action.TT_DELETED_FROM_NS, Action.TT_REMOVED, Sources.NSClient,
ValueWithUnit(it.reason.text, UserEntry.Units.TherapyEvent), ValueWithUnit.TherapyEventTTReason(tt.reason),
ValueWithUnit(it.lowTarget, UserEntry.Units.Mg_Dl, true), ValueWithUnit.Mgdl(tt.lowTarget),
ValueWithUnit(it.highTarget, UserEntry.Units.Mg_Dl, it.lowTarget != it.highTarget), ValueWithUnit.Mgdl(tt.highTarget).takeIf { tt.lowTarget != tt.highTarget },
ValueWithUnit(it.duration.toInt() / 60000, UserEntry.Units.M, it.duration != 0L) ValueWithUnit.Minute(TimeUnit.MILLISECONDS.toMinutes(tt.duration).toInt()).takeIf { tt.duration != 0L }
) )
} }
} }
// room Therapy Event // room Therapy Event
val therapyEvent = therapyEventFromNsIdForInvalidating(nsId) val therapyEvent = therapyEventFromNsIdForInvalidating(nsId)
repository.runTransactionForResult(SyncNsTherapyEventTransaction(therapyEvent)) repository.runTransactionForResult(SyncNsTherapyEventTransaction(therapyEvent, invalidateByNsOnly = true))
.doOnError { .doOnError {
aapsLogger.error(LTag.DATABASE, "Error while invalidating therapy event", it) aapsLogger.error(LTag.DATABASE, "Error while invalidating therapy event", it)
ret = Result.failure() ret = Result.failure(workDataOf("Error" to it))
} }
.blockingGet() .blockingGet()
.also { result -> .also { result ->
result.invalidated.forEach { result.invalidated.forEach {
uel.log( uel.log(Action.CAREPORTAL_REMOVED, Sources.NSClient,
UserEntry.Action.CAREPORTAL_DELETED_FROM_NS, (it.note ?: ""), (it.note ?: ""),
ValueWithUnit(it.timestamp, UserEntry.Units.Timestamp, true), ValueWithUnit.Timestamp(it.timestamp),
ValueWithUnit(it.type.text, UserEntry.Units.TherapyEvent)) ValueWithUnit.TherapyEventType(it.type))
} }
} }
// room Bolus // room Bolus
val bolus = bolusFromNsIdForInvalidating(nsId) val bolus = bolusFromNsIdForInvalidating(nsId)
repository.runTransactionForResult(SyncNsBolusTransaction(bolus)) repository.runTransactionForResult(SyncNsBolusTransaction(bolus, invalidateByNsOnly = true))
.doOnError { .doOnError {
aapsLogger.error(LTag.DATABASE, "Error while invalidating bolus", it) aapsLogger.error(LTag.DATABASE, "Error while invalidating bolus", it)
ret = Result.failure() ret = Result.failure(workDataOf("Error" to it))
} }
.blockingGet() .blockingGet()
.also { result -> .also { result ->
result.invalidated.forEach { result.invalidated.forEach {
uel.log( uel.log(Action.CAREPORTAL_REMOVED, Sources.NSClient,
UserEntry.Action.CAREPORTAL_DELETED_FROM_NS, ValueWithUnit.Timestamp(it.timestamp),
ValueWithUnit(it.timestamp, UserEntry.Units.Timestamp, true), ValueWithUnit.Insulin(it.amount))
ValueWithUnit(it.amount, UserEntry.Units.U))
} }
} }
// room Bolus // room Carbs
val carbs = carbsFromNsIdForInvalidating(nsId) val carbs = carbsFromNsIdForInvalidating(nsId)
repository.runTransactionForResult(SyncNsCarbsTransaction(carbs)) repository.runTransactionForResult(SyncNsCarbsTransaction(carbs, invalidateByNsOnly = true))
.doOnError { .doOnError {
aapsLogger.error(LTag.DATABASE, "Error while invalidating carbs", it) aapsLogger.error(LTag.DATABASE, "Error while invalidating carbs", it)
ret = Result.failure() 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() .blockingGet()
.also { result -> .also { result ->
result.invalidated.forEach { result.invalidated.forEach {
uel.log( uel.log(
UserEntry.Action.CAREPORTAL_DELETED_FROM_NS, Action.CAREPORTAL_REMOVED, Sources.NSClient,
ValueWithUnit(it.timestamp, UserEntry.Units.Timestamp, true), ValueWithUnit.Timestamp(it.timestamp),
ValueWithUnit(it.amount, UserEntry.Units.G)) 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))
} }
} }
// old DB model // old DB model
databaseHelper.deleteTempBasalById(nsId)
databaseHelper.deleteExtendedBolusById(nsId)
databaseHelper.deleteProfileSwitchById(nsId) databaseHelper.deleteProfileSwitchById(nsId)
} }

View file

@ -164,11 +164,11 @@ class NSDeviceStatus @Inject constructor(
// test warning level // test warning level
val level = when { val level = when {
pumpData.clock + nsSettingsStatus.extendedPumpSettings("urgentClock") * 60 * 1000L < dateUtil._now() -> Levels.URGENT pumpData.clock + nsSettingsStatus.extendedPumpSettings("urgentClock") * 60 * 1000L < dateUtil.now() -> Levels.URGENT
pumpData.reservoir < nsSettingsStatus.extendedPumpSettings("urgentRes") -> Levels.URGENT pumpData.reservoir < nsSettingsStatus.extendedPumpSettings("urgentRes") -> Levels.URGENT
pumpData.isPercent && pumpData.percent < nsSettingsStatus.extendedPumpSettings("urgentBattP") -> Levels.URGENT pumpData.isPercent && pumpData.percent < nsSettingsStatus.extendedPumpSettings("urgentBattP") -> Levels.URGENT
!pumpData.isPercent && pumpData.voltage < nsSettingsStatus.extendedPumpSettings("urgentBattV") -> Levels.URGENT !pumpData.isPercent && pumpData.voltage < nsSettingsStatus.extendedPumpSettings("urgentBattV") -> Levels.URGENT
pumpData.clock + nsSettingsStatus.extendedPumpSettings("warnClock") * 60 * 1000L < dateUtil._now() -> Levels.WARN pumpData.clock + nsSettingsStatus.extendedPumpSettings("warnClock") * 60 * 1000L < dateUtil.now() -> Levels.WARN
pumpData.reservoir < nsSettingsStatus.extendedPumpSettings("warnRes") -> Levels.WARN pumpData.reservoir < nsSettingsStatus.extendedPumpSettings("warnRes") -> Levels.WARN
pumpData.isPercent && pumpData.percent < nsSettingsStatus.extendedPumpSettings("warnBattP") -> Levels.WARN pumpData.isPercent && pumpData.percent < nsSettingsStatus.extendedPumpSettings("warnBattP") -> Levels.WARN
!pumpData.isPercent && pumpData.voltage < nsSettingsStatus.extendedPumpSettings("warnBattV") -> Levels.WARN !pumpData.isPercent && pumpData.voltage < nsSettingsStatus.extendedPumpSettings("warnBattV") -> Levels.WARN
@ -179,7 +179,7 @@ class NSDeviceStatus @Inject constructor(
if (fields.contains("reservoir")) string.append(pumpData.reservoir.toInt()).append("U ") 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(pumpData.percent).append("% ")
if (fields.contains("battery") && !pumpData.isPercent) string.append(Round.roundTo(pumpData.voltage, 0.001)).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("status")) string.append(pumpData.status).append(" ")
if (fields.contains("device")) string.append(device).append(" ") if (fields.contains("device")) string.append(device).append(" ")
string.append("</span>") // color string.append("</span>") // color
@ -201,7 +201,7 @@ class NSDeviceStatus @Inject constructor(
try { try {
val data = this.data ?: return val data = this.data ?: return
val pump = if (data.has("pump")) data.getJSONObject("pump") else JSONObject() 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 // check if this is new data
if (clock == 0L || deviceStatusPumpData != null && clock < deviceStatusPumpData!!.clock) return 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 openAps = if (jsonObject.has("openaps")) jsonObject.getJSONObject("openaps") else JSONObject()
val suggested = if (openAps.has("suggested")) openAps.getJSONObject("suggested") else JSONObject() val suggested = if (openAps.has("suggested")) openAps.getJSONObject("suggested") else JSONObject()
val enacted = if (openAps.has("enacted")) openAps.getJSONObject("enacted") 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 // check if this is new data
if (clock != 0L && clock > deviceStatusOpenAPSData.clockSuggested) { if (clock != 0L && clock > deviceStatusOpenAPSData.clockSuggested) {
deviceStatusOpenAPSData.suggested = suggested deviceStatusOpenAPSData.suggested = suggested
deviceStatusOpenAPSData.clockSuggested = clock 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 // check if this is new data
if (clock != 0L && clock > deviceStatusOpenAPSData.clockEnacted) { if (clock != 0L && clock > deviceStatusOpenAPSData.clockEnacted) {
deviceStatusOpenAPSData.enacted = enacted deviceStatusOpenAPSData.enacted = enacted
@ -273,12 +273,12 @@ class NSDeviceStatus @Inject constructor(
// test warning level // test warning level
val level = when { 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_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 deviceStatusOpenAPSData.clockSuggested + T.mins(sp.getLong(R.string.key_nsalarm_staledatavalue, 16)).msecs() < dateUtil.now() -> Levels.WARN
else -> Levels.INFO else -> Levels.INFO
} }
string.append("<span style=\"color:${level.toColor()}\">") string.append("<span style=\"color:${level.toColor()}\">")
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("</span>") // color string.append("</span>") // color
return fromHtml(string.toString()) return fromHtml(string.toString())
} }
@ -287,8 +287,8 @@ class NSDeviceStatus @Inject constructor(
get() { get() {
val string = StringBuilder() val string = StringBuilder()
try { try {
if (deviceStatusOpenAPSData.enacted != null && deviceStatusOpenAPSData.clockEnacted != deviceStatusOpenAPSData.clockSuggested) string.append("<b>").append(DateUtil.minAgo(resourceHelper, deviceStatusOpenAPSData.clockEnacted)).append("</b> ").append(deviceStatusOpenAPSData.enacted!!.getString("reason")).append("<br>") if (deviceStatusOpenAPSData.enacted != null && deviceStatusOpenAPSData.clockEnacted != deviceStatusOpenAPSData.clockSuggested) string.append("<b>").append(dateUtil.minAgo(resourceHelper, deviceStatusOpenAPSData.clockEnacted)).append("</b> ").append(deviceStatusOpenAPSData.enacted!!.getString("reason")).append("<br>")
if (deviceStatusOpenAPSData.suggested != null) string.append("<b>").append(DateUtil.minAgo(resourceHelper, deviceStatusOpenAPSData.clockSuggested)).append("</b> ").append(deviceStatusOpenAPSData.suggested!!.getString("reason")).append("<br>") if (deviceStatusOpenAPSData.suggested != null) string.append("<b>").append(dateUtil.minAgo(resourceHelper, deviceStatusOpenAPSData.clockSuggested)).append("</b> ").append(deviceStatusOpenAPSData.suggested!!.getString("reason")).append("<br>")
return fromHtml(string.toString()) return fromHtml(string.toString())
} catch (e: JSONException) { } catch (e: JSONException) {
aapsLogger.error("Unhandled exception", e) aapsLogger.error("Unhandled exception", e)
@ -307,7 +307,7 @@ class NSDeviceStatus @Inject constructor(
val clock = val clock =
when { when {
jsonObject.has("mills") -> jsonObject.getLong("mills") 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 else -> 0L
} }
val device = device val device = device

View file

@ -3,6 +3,7 @@ package info.nightscout.androidaps.plugins.general.nsclient.data
import android.content.Context import android.content.Context
import info.nightscout.androidaps.Config import info.nightscout.androidaps.Config
import info.nightscout.androidaps.R 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.Action
import info.nightscout.androidaps.logging.AAPSLogger import info.nightscout.androidaps.logging.AAPSLogger
import info.nightscout.androidaps.logging.LTag 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("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", "warn")?.let { sp.putDouble(R.string.key_statuslights_bage_warning, it) }
getExtendedWarnValue("bage", "urgent")?.let { sp.putDouble(R.string.key_statuslights_bage_critical, 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) if (context != null) OKDialog.showConfirmation(context, resourceHelper.gs(R.string.statuslights), resourceHelper.gs(R.string.copyexistingvalues), action)

View file

@ -32,12 +32,15 @@ import dagger.android.HasAndroidInjector;
import info.nightscout.androidaps.Config; import info.nightscout.androidaps.Config;
import info.nightscout.androidaps.R; import info.nightscout.androidaps.R;
import info.nightscout.androidaps.database.AppRepository; import info.nightscout.androidaps.database.AppRepository;
import info.nightscout.androidaps.database.entities.Carbs; import info.nightscout.androidaps.database.entities.DeviceStatus;
import info.nightscout.androidaps.database.transactions.UpdateNsIdBolusCalculatorResultTransaction; import info.nightscout.androidaps.database.transactions.UpdateNsIdBolusCalculatorResultTransaction;
import info.nightscout.androidaps.database.transactions.UpdateNsIdBolusTransaction; import info.nightscout.androidaps.database.transactions.UpdateNsIdBolusTransaction;
import info.nightscout.androidaps.database.transactions.UpdateNsIdCarbsTransaction; import info.nightscout.androidaps.database.transactions.UpdateNsIdCarbsTransaction;
import info.nightscout.androidaps.database.transactions.UpdateNsIdDeviceStatusTransaction;
import info.nightscout.androidaps.database.transactions.UpdateNsIdExtendedBolusTransaction;
import info.nightscout.androidaps.database.transactions.UpdateNsIdFoodTransaction; import info.nightscout.androidaps.database.transactions.UpdateNsIdFoodTransaction;
import info.nightscout.androidaps.database.transactions.UpdateNsIdGlucoseValueTransaction; import info.nightscout.androidaps.database.transactions.UpdateNsIdGlucoseValueTransaction;
import info.nightscout.androidaps.database.transactions.UpdateNsIdTemporaryBasalTransaction;
import info.nightscout.androidaps.database.transactions.UpdateNsIdTemporaryTargetTransaction; import info.nightscout.androidaps.database.transactions.UpdateNsIdTemporaryTargetTransaction;
import info.nightscout.androidaps.database.transactions.UpdateNsIdTherapyEventTransaction; import info.nightscout.androidaps.database.transactions.UpdateNsIdTherapyEventTransaction;
import info.nightscout.androidaps.db.DbRequest; import info.nightscout.androidaps.db.DbRequest;
@ -138,7 +141,7 @@ public class NSClientService extends DaggerService {
private final ArrayList<Long> reconnections = new ArrayList<>(); private final ArrayList<Long> reconnections = new ArrayList<>();
private final int WATCHDOG_INTERVAL_MINUTES = 2; private final int WATCHDOG_INTERVAL_MINUTES = 2;
private final int WATCHDOG_RECONNECT_IN = 15; private final int WATCHDOG_RECONNECT_IN = 15;
private final int WATCHDOG_MAXCONNECTIONS = 5; private final int WATCHDOG_MAX_CONNECTIONS = 5;
public NSClientService() { public NSClientService() {
super(); super();
@ -225,7 +228,7 @@ public class NSClientService extends DaggerService {
} }
public void processAddAck(NSAddAck ack) { public void processAddAck(NSAddAck ack) {
lastAckTime = dateUtil._now(); lastAckTime = dateUtil.now();
// new room way // new room way
if (ack.getOriginalObject() instanceof DataSyncSelector.PairTemporaryTarget) { if (ack.getOriginalObject() instanceof DataSyncSelector.PairTemporaryTarget) {
DataSyncSelector.PairTemporaryTarget pair = (DataSyncSelector.PairTemporaryTarget) ack.getOriginalObject(); DataSyncSelector.PairTemporaryTarget pair = (DataSyncSelector.PairTemporaryTarget) ack.getOriginalObject();
@ -339,6 +342,54 @@ public class NSClientService extends DaggerService {
dataSyncSelector.processChangedBolusCalculatorResultsCompat(); dataSyncSelector.processChangedBolusCalculatorResultsCompat();
return; return;
} }
if (ack.getOriginalObject() instanceof DataSyncSelector.PairTemporaryBasal) {
DataSyncSelector.PairTemporaryBasal pair = (DataSyncSelector.PairTemporaryBasal) ack.getOriginalObject();
pair.getValue().getInterfaceIDs().setNightscoutId(ack.getId());
disposable.add(repository.runTransactionForResult(new UpdateNsIdTemporaryBasalTransaction(pair.getValue()))
.observeOn(aapsSchedulers.getIo())
.subscribe(
result -> aapsLogger.debug(LTag.DATABASE, "Updated ns id of TemporaryBasal " + pair.getValue()),
error -> aapsLogger.error(LTag.DATABASE, "Updated ns id of TemporaryBasal failed", error)
));
dataSyncSelector.confirmLastTemporaryBasalIdIfGreater(pair.getUpdateRecordId());
rxBus.send(new EventNSClientNewLog("DBADD", "Acked TemporaryBasal" + pair.getValue().getInterfaceIDs().getNightscoutId()));
// Send new if waiting
dataSyncSelector.processChangedTemporaryBasalsCompat();
return;
}
if (ack.getOriginalObject() instanceof DataSyncSelector.PairExtendedBolus) {
DataSyncSelector.PairExtendedBolus pair = (DataSyncSelector.PairExtendedBolus) ack.getOriginalObject();
pair.getValue().getInterfaceIDs().setNightscoutId(ack.getId());
disposable.add(repository.runTransactionForResult(new UpdateNsIdExtendedBolusTransaction(pair.getValue()))
.observeOn(aapsSchedulers.getIo())
.subscribe(
result -> aapsLogger.debug(LTag.DATABASE, "Updated ns id of ExtendedBolus " + pair.getValue()),
error -> aapsLogger.error(LTag.DATABASE, "Updated ns id of ExtendedBolus failed", error)
));
dataSyncSelector.confirmLastExtendedBolusIdIfGreater(pair.getUpdateRecordId());
rxBus.send(new EventNSClientNewLog("DBADD", "Acked ExtendedBolus" + pair.getValue().getInterfaceIDs().getNightscoutId()));
// Send new if waiting
dataSyncSelector.processChangedTemporaryBasalsCompat();
return;
}
if (ack.getOriginalObject() instanceof DeviceStatus) {
DeviceStatus deviceStatus = (DeviceStatus) ack.getOriginalObject();
deviceStatus.getInterfaceIDs().setNightscoutId(ack.getId());
disposable.add(repository.runTransactionForResult(new UpdateNsIdDeviceStatusTransaction(deviceStatus))
.observeOn(aapsSchedulers.getIo())
.subscribe(
result -> aapsLogger.debug(LTag.DATABASE, "Updated ns id of DeviceStatus " + deviceStatus),
error -> aapsLogger.error(LTag.DATABASE, "Updated ns id of DeviceStatus failed", error)
));
dataSyncSelector.confirmLastDeviceStatusIdIfGreater(deviceStatus.getId());
rxBus.send(new EventNSClientNewLog("DBADD", "Acked DeviceStatus" + deviceStatus.getInterfaceIDs().getNightscoutId()));
// Send new if waiting
dataSyncSelector.processChangedBolusCalculatorResultsCompat();
return;
}
// old way // old way
if (ack.nsClientID != null) { if (ack.nsClientID != null) {
uploadQueue.removeByNsClientIdIfExists(ack.json); uploadQueue.removeByNsClientIdIfExists(ack.json);
@ -349,7 +400,7 @@ public class NSClientService extends DaggerService {
} }
public void processUpdateAck(NSUpdateAck ack) { public void processUpdateAck(NSUpdateAck ack) {
lastAckTime = dateUtil._now(); lastAckTime = dateUtil.now();
// new room way // new room way
if (ack.getOriginalObject() instanceof DataSyncSelector.PairTemporaryTarget) { if (ack.getOriginalObject() instanceof DataSyncSelector.PairTemporaryTarget) {
DataSyncSelector.PairTemporaryTarget pair = (DataSyncSelector.PairTemporaryTarget) ack.getOriginalObject(); DataSyncSelector.PairTemporaryTarget pair = (DataSyncSelector.PairTemporaryTarget) ack.getOriginalObject();
@ -407,6 +458,22 @@ public class NSClientService extends DaggerService {
dataSyncSelector.processChangedBolusCalculatorResultsCompat(); dataSyncSelector.processChangedBolusCalculatorResultsCompat();
return; return;
} }
if (ack.getOriginalObject() instanceof DataSyncSelector.PairTemporaryBasal) {
DataSyncSelector.PairTemporaryBasal pair = (DataSyncSelector.PairTemporaryBasal) ack.getOriginalObject();
dataSyncSelector.confirmLastTemporaryBasalIdIfGreater(pair.getUpdateRecordId());
rxBus.send(new EventNSClientNewLog("DBUPDATE/DBREMOVE", "Acked TemporaryBasal " + ack.get_id()));
// Send new if waiting
dataSyncSelector.processChangedTemporaryBasalsCompat();
return;
}
if (ack.getOriginalObject() instanceof DataSyncSelector.PairExtendedBolus) {
DataSyncSelector.PairExtendedBolus pair = (DataSyncSelector.PairExtendedBolus) ack.getOriginalObject();
dataSyncSelector.confirmLastExtendedBolusIdIfGreater(pair.getUpdateRecordId());
rxBus.send(new EventNSClientNewLog("DBUPDATE/DBREMOVE", "Acked ExtendedBolus " + ack.get_id()));
// Send new if waiting
dataSyncSelector.processChangedExtendedBolusesCompat();
return;
}
// old way // old way
if (ack.getResult()) { if (ack.getResult()) {
uploadQueue.removeByMongoId(ack.getAction(), ack.get_id()); uploadQueue.removeByMongoId(ack.getAction(), ack.get_id());
@ -524,7 +591,7 @@ public class NSClientService extends DaggerService {
void watchdog() { void watchdog() {
synchronized (reconnections) { synchronized (reconnections) {
long now = DateUtil.now(); long now = dateUtil.now();
reconnections.add(now); reconnections.add(now);
for (int i = 0; i < reconnections.size(); i++) { for (int i = 0; i < reconnections.size(); i++) {
Long r = reconnections.get(i); Long r = reconnections.get(i);
@ -532,8 +599,8 @@ public class NSClientService extends DaggerService {
reconnections.remove(r); reconnections.remove(r);
} }
} }
rxBus.send(new EventNSClientNewLog("WATCHDOG", "connections in last " + WATCHDOG_INTERVAL_MINUTES + " mins: " + 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_MAXCONNECTIONS) { if (reconnections.size() >= WATCHDOG_MAX_CONNECTIONS) {
Notification n = new Notification(Notification.NS_MALFUNCTION, resourceHelper.gs(R.string.nsmalfunction), Notification.URGENT); Notification n = new Notification(Notification.NS_MALFUNCTION, resourceHelper.gs(R.string.nsmalfunction), Notification.URGENT);
rxBus.send(new EventNewNotification(n)); rxBus.send(new EventNewNotification(n));
rxBus.send(new EventNSClientNewLog("WATCHDOG", "pausing for " + WATCHDOG_RECONNECT_IN + " mins")); rxBus.send(new EventNSClientNewLog("WATCHDOG", "pausing for " + WATCHDOG_RECONNECT_IN + " mins"));
@ -766,7 +833,7 @@ public class NSClientService extends DaggerService {
if (action == null) addedOrUpdatedTreatments.put(jsonTreatment); if (action == null) addedOrUpdatedTreatments.put(jsonTreatment);
else if (action.equals("update")) else if (action.equals("update"))
addedOrUpdatedTreatments.put(jsonTreatment); 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); removedTreatments.put(jsonTreatment);
} }
if (removedTreatments.length() > 0) { if (removedTreatments.length() > 0) {
@ -973,10 +1040,13 @@ public class NSClientService extends DaggerService {
dataSyncSelector.processChangedBolusesCompat(); dataSyncSelector.processChangedBolusesCompat();
dataSyncSelector.processChangedCarbsCompat(); dataSyncSelector.processChangedCarbsCompat();
dataSyncSelector.processChangedBolusCalculatorResultsCompat(); dataSyncSelector.processChangedBolusCalculatorResultsCompat();
dataSyncSelector.processChangedTemporaryBasalsCompat();
dataSyncSelector.processChangedExtendedBolusesCompat();
dataSyncSelector.processChangedGlucoseValuesCompat(); dataSyncSelector.processChangedGlucoseValuesCompat();
dataSyncSelector.processChangedTempTargetsCompat(); dataSyncSelector.processChangedTempTargetsCompat();
dataSyncSelector.processChangedFoodsCompat(); dataSyncSelector.processChangedFoodsCompat();
dataSyncSelector.processChangedTherapyEventsCompat(); dataSyncSelector.processChangedTherapyEventsCompat();
dataSyncSelector.processChangedDeviceStatusesCompat();
if (uploadQueue.size() == 0) if (uploadQueue.size() == 0)
return; return;

View file

@ -28,7 +28,7 @@ import info.nightscout.androidaps.interfaces.PluginType
import info.nightscout.androidaps.logging.AAPSLogger import info.nightscout.androidaps.logging.AAPSLogger
import info.nightscout.androidaps.logging.LTag import info.nightscout.androidaps.logging.LTag
import info.nightscout.androidaps.plugins.bus.RxBusWrapper import info.nightscout.androidaps.plugins.bus.RxBusWrapper
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.resources.ResourceHelper
import info.nightscout.androidaps.utils.rx.AapsSchedulers import info.nightscout.androidaps.utils.rx.AapsSchedulers
import info.nightscout.androidaps.utils.sharedPreferences.SP import info.nightscout.androidaps.utils.sharedPreferences.SP
@ -365,18 +365,18 @@ class OpenHumansUploader @Inject constructor(
.andThen(Observable.defer { Observable.fromIterable(repository.compatGetTherapyEventDataFromTime(0, true).blockingGet()) }) .andThen(Observable.defer { Observable.fromIterable(repository.compatGetTherapyEventDataFromTime(0, true).blockingGet()) })
.map { enqueueTherapyEvent(it); increaseCounter() } .map { enqueueTherapyEvent(it); increaseCounter() }
.ignoreElements() .ignoreElements()
.andThen(Observable.defer { Observable.fromIterable(databaseHelper.getAllExtendedBoluses()) }) // .andThen(Observable.defer { Observable.fromIterable(databaseHelper.getAllExtendedBoluses()) })
.map { enqueueExtendedBolus(it); increaseCounter() } // .map { enqueueExtendedBolus(it); increaseCounter() }
.ignoreElements() // .ignoreElements()
.andThen(Observable.defer { Observable.fromIterable(databaseHelper.getAllProfileSwitches()) }) .andThen(Observable.defer { Observable.fromIterable(databaseHelper.getAllProfileSwitches()) })
.map { enqueueProfileSwitch(it); increaseCounter() } .map { enqueueProfileSwitch(it); increaseCounter() }
.ignoreElements() .ignoreElements()
.andThen(Observable.defer { Observable.fromIterable(databaseHelper.getAllTDDs()) }) .andThen(Observable.defer { Observable.fromIterable(databaseHelper.getAllTDDs()) })
.map { enqueueTotalDailyDose(it); increaseCounter() } .map { enqueueTotalDailyDose(it); increaseCounter() }
.ignoreElements() .ignoreElements()
.andThen(Observable.defer { Observable.fromIterable(databaseHelper.getAllTemporaryBasals()) }) // .andThen(Observable.defer { Observable.fromIterable(databaseHelper.getAllTemporaryBasals()) })
.map { enqueueTemporaryBasal(it); increaseCounter() } // .map { enqueueTemporaryBasal(it); increaseCounter() }
.ignoreElements() // .ignoreElements()
.andThen(Observable.defer { Observable.fromIterable(repository.compatGetTemporaryTargetData().blockingGet()) }) .andThen(Observable.defer { Observable.fromIterable(repository.compatGetTemporaryTargetData().blockingGet()) })
.map { enqueueTempTarget(it); increaseCounter() } .map { enqueueTempTarget(it); increaseCounter() }
.ignoreElements() .ignoreElements()

View file

@ -31,11 +31,13 @@ import info.nightscout.androidaps.data.Profile
import info.nightscout.androidaps.database.AppRepository import info.nightscout.androidaps.database.AppRepository
import info.nightscout.androidaps.database.ValueWrapper import info.nightscout.androidaps.database.ValueWrapper
import info.nightscout.androidaps.database.entities.TemporaryTarget 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.interfaces.end
import info.nightscout.androidaps.databinding.OverviewFragmentBinding import info.nightscout.androidaps.databinding.OverviewFragmentBinding
import info.nightscout.androidaps.dialogs.* import info.nightscout.androidaps.dialogs.*
import info.nightscout.androidaps.events.* import info.nightscout.androidaps.events.*
import info.nightscout.androidaps.extensions.*
import info.nightscout.androidaps.interfaces.* import info.nightscout.androidaps.interfaces.*
import info.nightscout.androidaps.logging.AAPSLogger import info.nightscout.androidaps.logging.AAPSLogger
import info.nightscout.androidaps.logging.UserEntryLogger import info.nightscout.androidaps.logging.UserEntryLogger
@ -61,10 +63,7 @@ import info.nightscout.androidaps.skins.SkinProvider
import info.nightscout.androidaps.utils.* import info.nightscout.androidaps.utils.*
import info.nightscout.androidaps.utils.alertDialogs.OKDialog import info.nightscout.androidaps.utils.alertDialogs.OKDialog
import info.nightscout.androidaps.utils.buildHelper.BuildHelper import info.nightscout.androidaps.utils.buildHelper.BuildHelper
import info.nightscout.androidaps.utils.extensions.directionToIcon import info.nightscout.androidaps.utils.extensions.*
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.protection.ProtectionCheck import info.nightscout.androidaps.utils.protection.ProtectionCheck
import info.nightscout.androidaps.utils.resources.ResourceHelper import info.nightscout.androidaps.utils.resources.ResourceHelper
import info.nightscout.androidaps.utils.rx.AapsSchedulers import info.nightscout.androidaps.utils.rx.AapsSchedulers
@ -100,7 +99,7 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
@Inject lateinit var configBuilderPlugin: ConfigBuilderPlugin @Inject lateinit var configBuilderPlugin: ConfigBuilderPlugin
@Inject lateinit var activePlugin: ActivePluginProvider @Inject lateinit var activePlugin: ActivePluginProvider
@Inject lateinit var treatmentsPlugin: TreatmentsPlugin @Inject lateinit var treatmentsPlugin: TreatmentsPlugin
@Inject lateinit var iobCobCalculatorPlugin: IobCobCalculator @Inject lateinit var iobCobCalculator: IobCobCalculator
@Inject lateinit var dexcomPlugin: DexcomPlugin @Inject lateinit var dexcomPlugin: DexcomPlugin
@Inject lateinit var dexcomMediator: DexcomPlugin.DexcomMediator @Inject lateinit var dexcomMediator: DexcomPlugin.DexcomMediator
@Inject lateinit var xdripPlugin: XdripPlugin @Inject lateinit var xdripPlugin: XdripPlugin
@ -310,7 +309,7 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
R.id.active_profile -> { R.id.active_profile -> {
ProfileViewerDialog().also { pvd -> ProfileViewerDialog().also { pvd ->
pvd.arguments = Bundle().also { pvd.arguments = Bundle().also {
it.putLong("time", DateUtil.now()) it.putLong("time", dateUtil.now())
it.putInt("mode", ProfileViewerDialog.Mode.RUNNING_PROFILE.ordinal) it.putInt("mode", ProfileViewerDialog.Mode.RUNNING_PROFILE.ordinal)
} }
}.show(childFragmentManager, "ProfileViewDialog") }.show(childFragmentManager, "ProfileViewDialog")
@ -351,7 +350,7 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
protectionCheck.queryProtection(activity, ProtectionCheck.Protection.BOLUS, UIRunnable { protectionCheck.queryProtection(activity, ProtectionCheck.Protection.BOLUS, UIRunnable {
OKDialog.showConfirmation(activity, resourceHelper.gs(R.string.tempbasal_label), lastRun.constraintsProcessed?.toSpanned() OKDialog.showConfirmation(activity, resourceHelper.gs(R.string.tempbasal_label), lastRun.constraintsProcessed?.toSpanned()
?: "".toSpanned(), { ?: "".toSpanned(), {
uel.log(Action.ACCEPTS_TEMP_BASAL) uel.log(Action.ACCEPTS_TEMP_BASAL, Sources.Overview)
binding.buttonsLayout.acceptTempButton.visibility = View.GONE binding.buttonsLayout.acceptTempButton.visibility = View.GONE
(context?.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager).cancel(Constants.notificationID) (context?.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager).cancel(Constants.notificationID)
rxBus.send(EventWearInitiateAction("cancelChangeRequest")) rxBus.send(EventWearInitiateAction("cancelChangeRequest"))
@ -412,7 +411,7 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
} }
private fun onClickQuickWizard() { private fun onClickQuickWizard() {
val actualBg = iobCobCalculatorPlugin.actualBg() val actualBg = iobCobCalculator.ads.actualBg()
val profile = profileFunction.getProfile() val profile = profileFunction.getProfile()
val profileName = profileFunction.getProfileName() val profileName = profileFunction.getProfileName()
val pump = activePlugin.activePump val pump = activePlugin.activePump
@ -447,11 +446,11 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
@SuppressLint("SetTextI18n") @SuppressLint("SetTextI18n")
private fun processButtonsVisibility() { private fun processButtonsVisibility() {
val lastBG = iobCobCalculatorPlugin.lastBg() val lastBG = iobCobCalculator.ads.lastBg()
val pump = activePlugin.activePump val pump = activePlugin.activePump
val profile = profileFunction.getProfile() val profile = profileFunction.getProfile()
val profileName = profileFunction.getProfileName() val profileName = profileFunction.getProfileName()
val actualBG = iobCobCalculatorPlugin.actualBg() val actualBG = iobCobCalculator.ads.actualBg()
// QuickWizard button // QuickWizard button
val quickWizardEntry = quickWizard.getActive() val quickWizardEntry = quickWizard.getActive()
@ -550,7 +549,7 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
if (_binding == null) return if (_binding == null) return
aapsLogger.debug("UpdateGUI from $from") aapsLogger.debug("UpdateGUI from $from")
binding.infoLayout.time.text = dateUtil.timeString(Date()) binding.infoLayout.time.text = dateUtil.timeString(dateUtil.now())
if (!profileFunction.isProfileValid("Overview")) { if (!profileFunction.isProfileValid("Overview")) {
binding.loopPumpStatusLayout.pumpStatus.setText(R.string.noprofileset) binding.loopPumpStatusLayout.pumpStatus.setText(R.string.noprofileset)
@ -563,8 +562,8 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
binding.loopPumpStatusLayout.loopLayout.visibility = View.VISIBLE binding.loopPumpStatusLayout.loopLayout.visibility = View.VISIBLE
val profile = profileFunction.getProfile() ?: return val profile = profileFunction.getProfile() ?: return
val actualBG = iobCobCalculatorPlugin.actualBg() val actualBG = iobCobCalculator.ads.actualBg()
val lastBG = iobCobCalculatorPlugin.lastBg() val lastBG = iobCobCalculator.ads.lastBg()
val pump = activePlugin.activePump val pump = activePlugin.activePump
val units = profileFunction.getUnits() val units = profileFunction.getUnits()
val lowLine = defaultValueHelper.determineLowLine() val lowLine = defaultValueHelper.determineLowLine()
@ -613,8 +612,8 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
} else flag and Paint.STRIKE_THRU_TEXT_FLAG.inv() } else flag and Paint.STRIKE_THRU_TEXT_FLAG.inv()
overview_bg.paintFlags = flag overview_bg.paintFlags = flag
} }
binding.infoLayout.timeAgo.text = DateUtil.minAgo(resourceHelper, lastBG.timestamp) binding.infoLayout.timeAgo.text = dateUtil.minAgo(resourceHelper, lastBG.timestamp)
binding.infoLayout.timeAgoShort.text = "(" + DateUtil.minAgoShort(lastBG.timestamp) + ")" binding.infoLayout.timeAgoShort.text = "(" + dateUtil.minAgoShort(lastBG.timestamp) + ")"
} }
val closedLoopEnabled = constraintChecker.isClosedLoopAllowed() val closedLoopEnabled = constraintChecker.isClosedLoopAllowed()
@ -626,19 +625,19 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
when { when {
loopPlugin.isEnabled() && loopPlugin.isSuperBolus -> { loopPlugin.isEnabled() && loopPlugin.isSuperBolus -> {
binding.infoLayout.apsMode.setImageResource(R.drawable.ic_loop_superbolus) 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 binding.infoLayout.apsModeText.visibility = View.VISIBLE
} }
loopPlugin.isDisconnected -> { loopPlugin.isDisconnected -> {
binding.infoLayout.apsMode.setImageResource(R.drawable.ic_loop_disconnected) 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 binding.infoLayout.apsModeText.visibility = View.VISIBLE
} }
loopPlugin.isEnabled() && loopPlugin.isSuspended -> { loopPlugin.isEnabled() && loopPlugin.isSuspended -> {
binding.infoLayout.apsMode.setImageResource(R.drawable.ic_loop_paused) 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 binding.infoLayout.apsModeText.visibility = View.VISIBLE
} }
@ -681,11 +680,11 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
} }
// temp target // temp target
val tempTarget: ValueWrapper<TemporaryTarget> = repository.getTemporaryTargetActiveAt(dateUtil._now()).blockingGet() val tempTarget: ValueWrapper<TemporaryTarget> = repository.getTemporaryTargetActiveAt(dateUtil.now()).blockingGet()
if (tempTarget is ValueWrapper.Existing) { if (tempTarget is ValueWrapper.Existing) {
binding.loopPumpStatusLayout.tempTarget.setTextColor(resourceHelper.gc(R.color.ribbonTextWarning)) binding.loopPumpStatusLayout.tempTarget.setTextColor(resourceHelper.gc(R.color.ribbonTextWarning))
binding.loopPumpStatusLayout.tempTarget.setBackgroundColor(resourceHelper.gc(R.color.ribbonWarning)) 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 { } else {
// If the target is not the same as set in the profile then oref has overridden it // If the target is not the same as set in the profile then oref has overridden it
val targetUsed = lastRun?.constraintsProcessed?.targetBG ?: 0.0 val targetUsed = lastRun?.constraintsProcessed?.targetBG ?: 0.0
@ -703,13 +702,13 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
} }
// Basal, TBR // Basal, TBR
val activeTemp = treatmentsPlugin.getTempBasalFromHistory(System.currentTimeMillis()) val activeTemp = iobCobCalculator.getTempBasalIncludingConvertedExtended(System.currentTimeMillis())
binding.infoLayout.baseBasal.text = activeTemp?.let { "T:" + activeTemp.toStringVeryShort() } binding.infoLayout.baseBasal.text = activeTemp?.let { "T:" + activeTemp.toStringShort() }
?: resourceHelper.gs(R.string.pump_basebasalrate, profile.basal) ?: resourceHelper.gs(R.string.pump_basebasalrate, profile.basal)
binding.infoLayout.basalLayout.setOnClickListener { binding.infoLayout.basalLayout.setOnClickListener {
var fullText = "${resourceHelper.gs(R.string.basebasalrate_label)}: ${resourceHelper.gs(R.string.pump_basebasalrate, profile.basal)}" var fullText = "${resourceHelper.gs(R.string.basebasalrate_label)}: ${resourceHelper.gs(R.string.pump_basebasalrate, profile.basal)}"
if (activeTemp != null) 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 { activity?.let {
OKDialog.show(it, resourceHelper.gs(R.string.basal), fullText) OKDialog.show(it, resourceHelper.gs(R.string.basal), fullText)
} }
@ -718,23 +717,23 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
?: resourceHelper.gc(R.color.defaulttextcolor)) ?: resourceHelper.gc(R.color.defaulttextcolor))
binding.infoLayout.baseBasalIcon.setImageResource(R.drawable.ic_cp_basal_no_tbr) 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 ?: 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_high)
if (percentRate < 100) binding.infoLayout.baseBasalIcon.setImageResource(R.drawable.ic_cp_basal_tbr_low) if (percentRate < 100) binding.infoLayout.baseBasalIcon.setImageResource(R.drawable.ic_cp_basal_tbr_low)
// Extended bolus // Extended bolus
val extendedBolus = treatmentsPlugin.getExtendedBolusFromHistory(System.currentTimeMillis()) val extendedBolus = repository.getExtendedBolusActiveAt(dateUtil.now()).blockingGet()
binding.infoLayout.extendedBolus.text = binding.infoLayout.extendedBolus.text =
if (extendedBolus != null && !pump.isFakingTempsByExtendedBoluses) if (extendedBolus is ValueWrapper.Existing && !pump.isFakingTempsByExtendedBoluses)
resourceHelper.gs(R.string.pump_basebasalrate, extendedBolus.absoluteRate()) resourceHelper.gs(R.string.pump_basebasalrate, extendedBolus.value.rate)
else "" else ""
binding.infoLayout.extendedBolus.setOnClickListener { binding.infoLayout.extendedBolus.setOnClickListener {
if (extendedBolus != null) activity?.let { if (extendedBolus is ValueWrapper.Existing) activity?.let {
OKDialog.show(it, resourceHelper.gs(R.string.extended_bolus), extendedBolus.toString()) 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 // Active profile
binding.loopPumpStatusLayout.activeProfile.text = profileFunction.getProfileNameWithDuration() binding.loopPumpStatusLayout.activeProfile.text = profileFunction.getProfileNameWithDuration()
@ -749,8 +748,8 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
processButtonsVisibility() processButtonsVisibility()
// iob // iob
val bolusIob = iobCobCalculatorPlugin.calculateIobFromBolus().round() val bolusIob = iobCobCalculator.calculateIobFromBolus().round()
val basalIob = treatmentsPlugin.lastCalculationTempBasals.round() val basalIob = iobCobCalculator.calculateIobFromTempBasalsIncludingConvertedExtended().round()
binding.infoLayout.iob.text = resourceHelper.gs(R.string.formatinsulinunits, bolusIob.iob + basalIob.basaliob) binding.infoLayout.iob.text = resourceHelper.gs(R.string.formatinsulinunits, bolusIob.iob + basalIob.basaliob)
binding.infoLayout.iobLayout.setOnClickListener { binding.infoLayout.iobLayout.setOnClickListener {
@ -769,7 +768,7 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
// cob // cob
var cobText: String = resourceHelper.gs(R.string.value_unavailable_short) 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) { if (cobInfo.displayCob != null) {
cobText = resourceHelper.gs(R.string.format_carbs, cobInfo.displayCob!!.toInt()) cobText = resourceHelper.gs(R.string.format_carbs, cobInfo.displayCob!!.toInt())
if (cobInfo.futureCarbs > 0) cobText += "(" + DecimalFormatter.to0Decimal(cobInfo.futureCarbs) + ")" if (cobInfo.futureCarbs > 0) cobText += "(" + DecimalFormatter.to0Decimal(cobInfo.futureCarbs) + ")"
@ -813,7 +812,7 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
} }
binding.infoLayout.sensitivity.text = 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) String.format(Locale.ENGLISH, "%.0f%%", autosensData.autosensResult.ratio * 100)
} ?: "" } ?: ""
} }
@ -823,7 +822,7 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
if (_binding == null) return@launch if (_binding == null) return@launch
val menuChartSettings = overviewMenus.setting val menuChartSettings = overviewMenus.setting
prepareGraphsIfNeeded(menuChartSettings.size) prepareGraphsIfNeeded(menuChartSettings.size)
val graphData = GraphData(injector, binding.graphsLayout.bgGraph, iobCobCalculatorPlugin, treatmentsPlugin) val graphData = GraphData(injector, binding.graphsLayout.bgGraph, iobCobCalculator, treatmentsPlugin)
val secondaryGraphsData: ArrayList<GraphData> = ArrayList() val secondaryGraphsData: ArrayList<GraphData> = ArrayList()
// do preparation in different thread // do preparation in different thread
@ -863,8 +862,9 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
// **** BG **** // **** BG ****
if (predictionsAvailable && menuChartSettings[0][OverviewMenus.CharType.PRE.ordinal]) if (predictionsAvailable && menuChartSettings[0][OverviewMenus.CharType.PRE.ordinal])
graphData.addBgReadings(fromTime, toTime, lowLine, highLine, apsResult?.predictions?.map { bg-> GlucoseValueDataPoint(bg, defaultValueHelper, profileFunction, resourceHelper) }?.toMutableList()) graphData.addBgReadings(fromTime, toTime, highLine, apsResult?.predictions?.map { bg-> GlucoseValueDataPoint(bg, defaultValueHelper, profileFunction, resourceHelper) }?.toMutableList())
else graphData.addBgReadings(fromTime, toTime, lowLine, highLine, null) else graphData.addBgReadings(fromTime, toTime, highLine, null)
if (buildHelper.isDev()) graphData.addBucketedData(fromTime, toTime)
// Treatments // Treatments
graphData.addTreatments(fromTime, endTime) graphData.addTreatments(fromTime, endTime)
@ -890,7 +890,7 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
// ------------------ 2nd graph // ------------------ 2nd graph
synchronized(graphLock) { synchronized(graphLock) {
for (g in 0 until min(secondaryGraphs.size, menuChartSettings.size + 1)) { 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 useABSForScale = false
var useIobForScale = false var useIobForScale = false
var useCobForScale = false var useCobForScale = false

View file

@ -6,6 +6,7 @@ import dagger.android.HasAndroidInjector
import info.nightscout.androidaps.Config import info.nightscout.androidaps.Config
import info.nightscout.androidaps.R import info.nightscout.androidaps.R
import info.nightscout.androidaps.events.EventRefreshOverview import info.nightscout.androidaps.events.EventRefreshOverview
import info.nightscout.androidaps.extensions.*
import info.nightscout.androidaps.interfaces.OverviewInterface import info.nightscout.androidaps.interfaces.OverviewInterface
import info.nightscout.androidaps.interfaces.PluginBase import info.nightscout.androidaps.interfaces.PluginBase
import info.nightscout.androidaps.interfaces.PluginDescription import info.nightscout.androidaps.interfaces.PluginDescription

View file

@ -14,7 +14,8 @@ import info.nightscout.androidaps.plugins.pump.omnipod.eros.OmnipodErosPumpPlugi
import info.nightscout.androidaps.plugins.pump.omnipod.eros.driver.definition.OmnipodConstants import info.nightscout.androidaps.plugins.pump.omnipod.eros.driver.definition.OmnipodConstants
import info.nightscout.androidaps.utils.DecimalFormatter import info.nightscout.androidaps.utils.DecimalFormatter
import info.nightscout.androidaps.utils.WarnColors 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.resources.ResourceHelper
import info.nightscout.androidaps.utils.sharedPreferences.SP import info.nightscout.androidaps.utils.sharedPreferences.SP
import javax.inject.Inject import javax.inject.Inject
@ -24,6 +25,7 @@ import javax.inject.Singleton
class StatusLightHandler @Inject constructor( class StatusLightHandler @Inject constructor(
private val resourceHelper: ResourceHelper, private val resourceHelper: ResourceHelper,
private val sp: SP, private val sp: SP,
private val dateUtil: DateUtil,
private val activePlugin: ActivePluginProvider, private val activePlugin: ActivePluginProvider,
private val warnColors: WarnColors, private val warnColors: WarnColors,
private val config: Config, private val config: Config,
@ -75,7 +77,7 @@ class StatusLightHandler @Inject constructor(
val therapyEvent = repository.getLastTherapyRecord(type).blockingGet() val therapyEvent = repository.getLastTherapyRecord(type).blockingGet()
if (therapyEvent is ValueWrapper.Existing) { if (therapyEvent is ValueWrapper.Existing) {
warnColors.setColorByAge(view, therapyEvent.value, warn, urgent) 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 { } else {
view?.text = if (resourceHelper.shortTextMode()) "-" else resourceHelper.gs(R.string.notavailable) view?.text = if (resourceHelper.shortTextMode()) "-" else resourceHelper.gs(R.string.notavailable)
} }

View file

@ -83,7 +83,7 @@ class EditQuickWizardDialog : DaggerDialogFragment(), View.OnClickListener {
// create an OnTimeSetListener // create an OnTimeSetListener
val fromTimeSetListener = TimePickerDialog.OnTimeSetListener { _, hour, minute -> val fromTimeSetListener = TimePickerDialog.OnTimeSetListener { _, hour, minute ->
fromSeconds = (T.hours(hour.toLong()).secs() + T.mins(minute.toLong()).secs()).toInt() 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 { binding.from.setOnClickListener {
@ -96,11 +96,11 @@ class EditQuickWizardDialog : DaggerDialogFragment(), View.OnClickListener {
} }
} }
fromSeconds = entry.validFrom() 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 -> val toTimeSetListener = TimePickerDialog.OnTimeSetListener { _, hour, minute ->
toSeconds = (T.hours(hour.toLong()).secs() + T.mins(minute.toLong()).secs()).toInt() 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 { binding.to.setOnClickListener {
@ -113,7 +113,7 @@ class EditQuickWizardDialog : DaggerDialogFragment(), View.OnClickListener {
} }
} }
toSeconds = entry.validFrom() 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.buttonEdit.setText(entry.buttonText())
binding.carbsEdit.setText(entry.carbs().toString()) binding.carbsEdit.setText(entry.carbs().toString())

View file

@ -24,7 +24,7 @@ import info.nightscout.androidaps.plugins.aps.openAPSSMB.SMBDefaults
import info.nightscout.androidaps.plugins.general.overview.graphExtensions.* import info.nightscout.androidaps.plugins.general.overview.graphExtensions.*
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.AutosensResult import info.nightscout.androidaps.plugins.iob.iobCobCalculator.AutosensResult
import info.nightscout.androidaps.utils.* import info.nightscout.androidaps.utils.*
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.resources.ResourceHelper
import java.util.* import java.util.*
import javax.inject.Inject import javax.inject.Inject
@ -61,10 +61,23 @@ class GraphData(
units = profileFunction.getUnits() units = profileFunction.getUnits()
} }
@Suppress("UNUSED_PARAMETER") fun addBucketedData(fromTime: Long, toTime: Long) {
fun addBgReadings(fromTime: Long, toTime: Long, lowLine: Double, highLine: Double, predictions: MutableList<GlucoseValueDataPoint>?) { val bucketedData = iobCobCalculator.ads.getBucketedDataTableCopy() ?: return
if (bucketedData.isEmpty()) {
aapsLogger.debug("No bucketed data.")
return
}
val bucketedListArray: MutableList<DataPointWithLabelInterface> = 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<GlucoseValueDataPoint>?) {
var maxBgValue = Double.MIN_VALUE var maxBgValue = Double.MIN_VALUE
bgReadingsArray = iobCobCalculator.bgReadings bgReadingsArray = repository.compatGetBgReadingsDataFromTime(fromTime, toTime, false).blockingGet()
if (bgReadingsArray?.isEmpty() != false) { if (bgReadingsArray?.isEmpty() != false) {
aapsLogger.debug("No BG data.") aapsLogger.debug("No BG data.")
maxY = if (units == Constants.MGDL) 180.0 else 10.0 maxY = if (units == Constants.MGDL) 180.0 else 10.0
@ -259,8 +272,8 @@ class GraphData(
// Extended bolus // Extended bolus
if (!activePlugin.activePump.isFakingTempsByExtendedBoluses) { if (!activePlugin.activePump.isFakingTempsByExtendedBoluses) {
treatmentsPlugin.extendedBolusesFromHistory.list repository.getExtendedBolusDataFromTimeToTime(fromTime, endTime, true).blockingGet()
.filterTimeframe(fromTime, endTime) .map { ExtendedBolusDataPoint(it) }
.filter { it.duration != 0L } .filter { it.duration != 0L }
.forEach { .forEach {
it.y = getNearestBg(it.x.toLong()) it.y = getNearestBg(it.x.toLong())
@ -289,8 +302,7 @@ class GraphData(
private fun getNearestBg(date: Long): Double { private fun getNearestBg(date: Long): Double {
bgReadingsArray?.let { bgReadingsArray -> bgReadingsArray?.let { bgReadingsArray ->
for (r in bgReadingsArray.indices) { for (reading in bgReadingsArray) {
val reading = bgReadingsArray[r]
if (reading.timestamp > date) continue if (reading.timestamp > date) continue
return Profile.fromMgdlToUnits(reading.value, units) return Profile.fromMgdlToUnits(reading.value, units)
} }
@ -312,7 +324,7 @@ class GraphData(
time += 5 * 60 * 1000L time += 5 * 60 * 1000L
continue continue
} }
total = iobCobCalculator.calculateFromTreatmentsAndTempsSynchronized(time, profile) total = iobCobCalculator.calculateFromTreatmentsAndTemps(time, profile)
val act: Double = total.activity val act: Double = total.activity
if (time <= now) actArrayHist.add(ScaledDataPoint(time, act, actScale)) else actArrayPrediction.add(ScaledDataPoint(time, act, actScale)) if (time <= now) actArrayHist.add(ScaledDataPoint(time, act, actScale)) else actArrayPrediction.add(ScaledDataPoint(time, act, actScale))
maxIAValue = max(maxIAValue, abs(act)) maxIAValue = max(maxIAValue, abs(act))
@ -353,10 +365,10 @@ class GraphData(
time += 5 * 60 * 1000L time += 5 * 60 * 1000L
continue continue
} }
val deviation = if (devBgiScale) iobCobCalculator.getAutosensData(time)?.deviation val deviation = if (devBgiScale) iobCobCalculator.ads.getAutosensDataAtTime(time)?.deviation
?: 0.0 else 0.0 ?: 0.0 else 0.0
total = iobCobCalculator.calculateFromTreatmentsAndTempsSynchronized(time, profile) total = iobCobCalculator.calculateFromTreatmentsAndTemps(time, profile)
val bgi: Double = total.activity * profile.getIsfMgdl(time) * 5.0 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)) if (time <= now) bgiArrayHist.add(ScaledDataPoint(time, bgi, bgiScale)) else bgiArrayPrediction.add(ScaledDataPoint(time, bgi, bgiScale))
maxBGIValue = max(maxBGIValue, max(abs(bgi), deviation)) maxBGIValue = max(maxBGIValue, max(abs(bgi), deviation))
@ -395,8 +407,8 @@ class GraphData(
var iob = 0.0 var iob = 0.0
var absIob = 0.0 var absIob = 0.0
if (profile != null) { if (profile != null) {
iob = iobCobCalculator.calculateFromTreatmentsAndTempsSynchronized(time, profile).iob iob = iobCobCalculator.calculateFromTreatmentsAndTemps(time, profile).iob
if (absScale) absIob = iobCobCalculator.calculateAbsInsulinFromTreatmentsAndTempsSynchronized(time).iob if (absScale) absIob = iobCobCalculator.calculateAbsInsulinFromTreatmentsAndTemps(time).iob
} }
if (abs(lastIob - iob) > 0.02) { if (abs(lastIob - iob) > 0.02) {
if (abs(lastIob - iob) > 0.2) iobArray.add(ScaledDataPoint(time, lastIob, iobScale)) if (abs(lastIob - iob) > 0.2) iobArray.add(ScaledDataPoint(time, lastIob, iobScale))
@ -413,9 +425,9 @@ class GraphData(
it.thickness = 3 it.thickness = 3
} }
if (showPrediction) { if (showPrediction) {
val autosensData = iobCobCalculator.getLastAutosensDataSynchronized("GraphData") val autosensData = iobCobCalculator.getLastAutosensDataWithWaitForCalculationFinish("GraphData")
val lastAutosensResult = autosensData?.autosensResult ?: AutosensResult() 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<DataPointWithLabelInterface> = ArrayList() val iobPrediction: MutableList<DataPointWithLabelInterface> = ArrayList()
val iobPredictionArray = iobCobCalculator.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) { for (i in iobPredictionArray) {
@ -452,7 +464,7 @@ class GraphData(
while (time <= toTime) { while (time <= toTime) {
val profile = profileFunction.getProfile(time) val profile = profileFunction.getProfile(time)
var iob = 0.0 var iob = 0.0
if (profile != null) iob = iobCobCalculator.calculateAbsInsulinFromTreatmentsAndTempsSynchronized(time).iob if (profile != null) iob = iobCobCalculator.calculateAbsInsulinFromTreatmentsAndTemps(time).iob
if (abs(lastIob - iob) > 0.02) { if (abs(lastIob - iob) > 0.02) {
if (abs(lastIob - iob) > 0.2) iobArray.add(ScaledDataPoint(time, lastIob, iobScale)) if (abs(lastIob - iob) > 0.2) iobArray.add(ScaledDataPoint(time, lastIob, iobScale))
iobArray.add(ScaledDataPoint(time, iob, iobScale)) iobArray.add(ScaledDataPoint(time, iob, iobScale))
@ -484,7 +496,7 @@ class GraphData(
val cobScale = Scale() val cobScale = Scale()
var time = fromTime var time = fromTime
while (time <= toTime) { while (time <= toTime) {
iobCobCalculator.getAutosensData(time)?.let { autosensData -> iobCobCalculator.ads.getAutosensDataAtTime(time)?.let { autosensData ->
val cob = autosensData.cob.toInt() val cob = autosensData.cob.toInt()
if (cob != lastCob) { if (cob != lastCob) {
if (autosensData.carbsFromBolus > 0) cobArray.add(ScaledDataPoint(time, lastCob.toDouble(), cobScale)) if (autosensData.carbsFromBolus > 0) cobArray.add(ScaledDataPoint(time, lastCob.toDouble(), cobScale))
@ -529,12 +541,12 @@ class GraphData(
while (time <= toTime) { while (time <= toTime) {
// if align Dev Scale with BGI scale, then calculate BGI value, else bgi = 0.0 // if align Dev Scale with BGI scale, then calculate BGI value, else bgi = 0.0
val bgi: Double = if (devBgiScale) { val bgi: Double = if (devBgiScale) {
val profile = profileFunction.getProfile(time) val profile = profileFunction.getProfile(time) ?: continue
total = iobCobCalculator.calculateFromTreatmentsAndTempsSynchronized(time, profile) total = iobCobCalculator.calculateFromTreatmentsAndTemps(time, profile)
total.activity * (profile?.getIsfMgdl(time) ?: 0.0) * 5.0 total.activity * profile.getIsfMgdl(time) * 5.0
} else 0.0 } else 0.0
iobCobCalculator.getAutosensData(time)?.let { autosensData -> iobCobCalculator.ads.getAutosensDataAtTime(time)?.let { autosensData ->
var color = resourceHelper.gc(R.color.deviationblack) // "=" var color = resourceHelper.gc(R.color.deviationblack) // "="
if (autosensData.type == "" || autosensData.type == "non-meal") { if (autosensData.type == "" || autosensData.type == "non-meal") {
if (autosensData.pastSensitivity == "C") color = resourceHelper.gc(R.color.deviationgrey) if (autosensData.pastSensitivity == "C") color = resourceHelper.gc(R.color.deviationgrey)
@ -570,7 +582,7 @@ class GraphData(
val ratioScale = Scale() val ratioScale = Scale()
var time = fromTime var time = fromTime
while (time <= toTime) { while (time <= toTime) {
iobCobCalculator.getAutosensData(time)?.let { autosensData -> iobCobCalculator.ads.getAutosensDataAtTime(time)?.let { autosensData ->
ratioArray.add(ScaledDataPoint(time, autosensData.autosensResult.ratio - 1, ratioScale)) ratioArray.add(ScaledDataPoint(time, autosensData.autosensResult.ratio - 1, ratioScale))
maxRatioValueFound = max(maxRatioValueFound, autosensData.autosensResult.ratio - 1) maxRatioValueFound = max(maxRatioValueFound, autosensData.autosensResult.ratio - 1)
minRatioValueFound = min(minRatioValueFound, autosensData.autosensResult.ratio - 1) minRatioValueFound = min(minRatioValueFound, autosensData.autosensResult.ratio - 1)
@ -600,7 +612,7 @@ class GraphData(
val dsMinScale = Scale() val dsMinScale = Scale()
var time = fromTime var time = fromTime
while (time <= toTime) { while (time <= toTime) {
iobCobCalculator.getAutosensData(time)?.let { autosensData -> iobCobCalculator.ads.getAutosensDataAtTime(time)?.let { autosensData ->
dsMaxArray.add(ScaledDataPoint(time, autosensData.slopeFromMaxDeviation, dsMaxScale)) dsMaxArray.add(ScaledDataPoint(time, autosensData.slopeFromMaxDeviation, dsMaxScale))
dsMinArray.add(ScaledDataPoint(time, autosensData.slopeFromMinDeviation, dsMinScale)) dsMinArray.add(ScaledDataPoint(time, autosensData.slopeFromMinDeviation, dsMinScale))
maxFromMaxValueFound = max(maxFromMaxValueFound, abs(autosensData.slopeFromMaxDeviation)) maxFromMaxValueFound = max(maxFromMaxValueFound, abs(autosensData.slopeFromMaxDeviation))

View file

@ -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
}
}

View file

@ -52,7 +52,7 @@ class GlucoseValueDataPoint @Inject constructor(
return when (data.sourceSensor) { return when (data.sourceSensor) {
GlucoseValue.SourceSensor.IOB_PREDICTION -> resourceHelper.gc(R.color.iob) GlucoseValue.SourceSensor.IOB_PREDICTION -> resourceHelper.gc(R.color.iob)
GlucoseValue.SourceSensor.COB_PREDICTION -> resourceHelper.gc(R.color.cob) GlucoseValue.SourceSensor.COB_PREDICTION -> resourceHelper.gc(R.color.cob)
GlucoseValue.SourceSensor.aCOB_PREDICTION -> -0x7f000001 and 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.UAM_PREDICTION -> resourceHelper.gc(R.color.uam)
GlucoseValue.SourceSensor.ZT_PREDICTION -> resourceHelper.gc(R.color.zt) GlucoseValue.SourceSensor.ZT_PREDICTION -> resourceHelper.gc(R.color.zt)
else -> R.color.white else -> R.color.white
@ -62,7 +62,7 @@ class GlucoseValueDataPoint @Inject constructor(
private val isPrediction: Boolean private val isPrediction: Boolean
get() = data.sourceSensor == GlucoseValue.SourceSensor.IOB_PREDICTION || get() = data.sourceSensor == GlucoseValue.SourceSensor.IOB_PREDICTION ||
data.sourceSensor == GlucoseValue.SourceSensor.COB_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.UAM_PREDICTION ||
data.sourceSensor == GlucoseValue.SourceSensor.ZT_PREDICTION data.sourceSensor == GlucoseValue.SourceSensor.ZT_PREDICTION

View file

@ -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)
}

View file

@ -49,7 +49,7 @@ class TherapyEventDataPoint @Inject constructor(
override fun getLabel(): String? = override fun getLabel(): String? =
if (data.note != null) data.note 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 getDuration(): Long = end() - start()
override fun getShape(): PointsWithLabelGraphSeries.Shape = override fun getShape(): PointsWithLabelGraphSeries.Shape =

View file

@ -15,15 +15,14 @@ import info.nightscout.androidaps.events.*
import info.nightscout.androidaps.interfaces.* import info.nightscout.androidaps.interfaces.*
import info.nightscout.androidaps.logging.AAPSLogger import info.nightscout.androidaps.logging.AAPSLogger
import info.nightscout.androidaps.plugins.bus.RxBusWrapper 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.GlucoseStatusProvider
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorPlugin
import info.nightscout.androidaps.utils.DecimalFormatter import info.nightscout.androidaps.utils.DecimalFormatter
import info.nightscout.androidaps.utils.FabricPrivacy import info.nightscout.androidaps.utils.FabricPrivacy
import info.nightscout.androidaps.extensions.toStringShort
import info.nightscout.androidaps.utils.resources.IconsProvider import info.nightscout.androidaps.utils.resources.IconsProvider
import info.nightscout.androidaps.utils.resources.ResourceHelper import info.nightscout.androidaps.utils.resources.ResourceHelper
import info.nightscout.androidaps.utils.rx.AapsSchedulers 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 io.reactivex.disposables.CompositeDisposable
import javax.inject.Inject import javax.inject.Inject
import javax.inject.Singleton import javax.inject.Singleton
@ -131,7 +130,7 @@ class PersistentNotificationPlugin @Inject constructor(
if (profileFunction.isProfileValid("Notification")) { if (profileFunction.isProfileValid("Notification")) {
var line1aa: String var line1aa: String
val units = profileFunction.getUnits() val units = profileFunction.getUnits()
val lastBG = iobCobCalculator.lastBg() val lastBG = iobCobCalculator.ads.lastBg()
val glucoseStatus = glucoseStatusProvider.glucoseStatusData val glucoseStatus = glucoseStatusProvider.glucoseStatusData
if (lastBG != null) { if (lastBG != null) {
line1aa = lastBG.valueToUnitsString(units) line1aa = lastBG.valueToUnitsString(units)
@ -150,14 +149,14 @@ class PersistentNotificationPlugin @Inject constructor(
line1aa = resourceHelper.gs(R.string.missed_bg_readings) line1aa = resourceHelper.gs(R.string.missed_bg_readings)
line1 = line1aa line1 = line1aa
} }
val activeTemp = activePlugins.activeTreatments.getTempBasalFromHistory(System.currentTimeMillis()) val activeTemp = iobCobCalculator.getTempBasalIncludingConvertedExtended(System.currentTimeMillis())
if (activeTemp != null) { if (activeTemp != null) {
line1 += " " + activeTemp.toStringShort() line1 += " " + activeTemp.toStringShort()
line1aa += " " + activeTemp.toStringShort() + "." line1aa += " " + activeTemp.toStringShort() + "."
} }
//IOB //IOB
val bolusIob = iobCobCalculator.calculateIobFromBolus().round() val bolusIob = iobCobCalculator.calculateIobFromBolus().round()
val basalIob = activePlugins.activeTreatments.lastCalculationTempBasals.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() 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() + "." 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" line3 = DecimalFormatter.to2Decimal(pump.baseBasalRate) + " U/h"

View file

@ -22,12 +22,14 @@ class AuthRequest internal constructor(
@Inject lateinit var smsCommunicatorPlugin: SmsCommunicatorPlugin @Inject lateinit var smsCommunicatorPlugin: SmsCommunicatorPlugin
@Inject lateinit var resourceHelper: ResourceHelper @Inject lateinit var resourceHelper: ResourceHelper
@Inject lateinit var otp: OneTimePassword @Inject lateinit var otp: OneTimePassword
@Inject lateinit var dateUtil: DateUtil
private val date = DateUtil.now() private var date = 0L
private var processed = false private var processed = false
init { init {
injector.androidInjector().inject(this) injector.androidInjector().inject(this)
date = dateUtil.now()
smsCommunicatorPlugin.sendSMS(Sms(requester.phoneNumber, requestText)) 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))) smsCommunicatorPlugin.sendSMS(Sms(requester.phoneNumber, resourceHelper.gs(R.string.sms_wrongcode)))
return return
} }
if (DateUtil.now() - date < Constants.SMS_CONFIRM_TIMEOUT) { if (dateUtil.now() - date < Constants.SMS_CONFIRM_TIMEOUT) {
processed = true processed = true
aapsLogger.debug(LTag.SMS, "Processing confirmed SMS: " + requester.text) aapsLogger.debug(LTag.SMS, "Processing confirmed SMS: " + requester.text)
action.run() action.run()

View file

@ -1,10 +1,9 @@
package info.nightscout.androidaps.plugins.general.smsCommunicator package info.nightscout.androidaps.plugins.general.smsCommunicator
import android.telephony.SmsMessage import android.telephony.SmsMessage
import info.nightscout.androidaps.MainApp
import info.nightscout.androidaps.utils.DateUtil
class Sms { class Sms {
var phoneNumber: String var phoneNumber: String
var text: String var text: String
var date: Long var date: Long
@ -23,7 +22,7 @@ class Sms {
internal constructor(phoneNumber: String, text: String) { internal constructor(phoneNumber: String, text: String) {
this.phoneNumber = phoneNumber this.phoneNumber = phoneNumber
this.text = text this.text = text
date = DateUtil.now() date = System.currentTimeMillis()
sent = true sent = true
} }

View file

@ -9,6 +9,7 @@ import androidx.preference.Preference
import androidx.preference.PreferenceFragmentCompat import androidx.preference.PreferenceFragmentCompat
import androidx.work.Worker import androidx.work.Worker
import androidx.work.WorkerParameters import androidx.work.WorkerParameters
import androidx.work.workDataOf
import dagger.android.HasAndroidInjector import dagger.android.HasAndroidInjector
import info.nightscout.androidaps.Config import info.nightscout.androidaps.Config
import info.nightscout.androidaps.Constants import info.nightscout.androidaps.Constants
@ -16,10 +17,10 @@ import info.nightscout.androidaps.R
import info.nightscout.androidaps.data.DetailedBolusInfo import info.nightscout.androidaps.data.DetailedBolusInfo
import info.nightscout.androidaps.data.Profile import info.nightscout.androidaps.data.Profile
import info.nightscout.androidaps.database.AppRepository 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.TemporaryTarget
import info.nightscout.androidaps.database.entities.UserEntry.Action import info.nightscout.androidaps.database.entities.UserEntry.Action
import info.nightscout.androidaps.database.entities.UserEntry.Units import info.nightscout.androidaps.database.entities.UserEntry.Sources
import info.nightscout.androidaps.database.entities.UserEntry.ValueWithUnit
import info.nightscout.androidaps.database.transactions.CancelCurrentTemporaryTargetIfAnyTransaction import info.nightscout.androidaps.database.transactions.CancelCurrentTemporaryTargetIfAnyTransaction
import info.nightscout.androidaps.database.transactions.InsertTemporaryTargetAndCancelCurrentTransaction import info.nightscout.androidaps.database.transactions.InsertTemporaryTargetAndCancelCurrentTransaction
import info.nightscout.androidaps.events.EventPreferenceChange import info.nightscout.androidaps.events.EventPreferenceChange
@ -40,7 +41,7 @@ import info.nightscout.androidaps.plugins.iob.iobCobCalculator.GlucoseStatusProv
import info.nightscout.androidaps.queue.Callback import info.nightscout.androidaps.queue.Callback
import info.nightscout.androidaps.receivers.DataWorker import info.nightscout.androidaps.receivers.DataWorker
import info.nightscout.androidaps.utils.* 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.resources.ResourceHelper
import info.nightscout.androidaps.utils.rx.AapsSchedulers import info.nightscout.androidaps.utils.rx.AapsSchedulers
import info.nightscout.androidaps.utils.sharedPreferences.SP import info.nightscout.androidaps.utils.sharedPreferences.SP
@ -48,9 +49,11 @@ import info.nightscout.androidaps.utils.textValidator.ValidatingEditTextPreferen
import io.reactivex.disposables.CompositeDisposable import io.reactivex.disposables.CompositeDisposable
import io.reactivex.rxkotlin.plusAssign import io.reactivex.rxkotlin.plusAssign
import org.apache.commons.lang3.StringUtils import org.apache.commons.lang3.StringUtils
import org.joda.time.DateTime
import java.text.Normalizer import java.text.Normalizer
import java.util.* import java.util.*
import java.util.concurrent.TimeUnit import java.util.concurrent.TimeUnit
import java.util.regex.Pattern
import javax.inject.Inject import javax.inject.Inject
import javax.inject.Singleton import javax.inject.Singleton
import kotlin.math.max import kotlin.math.max
@ -180,8 +183,9 @@ class SmsCommunicatorPlugin @Inject constructor(
@Suppress("SpellCheckingInspection") @Suppress("SpellCheckingInspection")
override fun doWork(): Result { override fun doWork(): Result {
val bundle = dataWorker.pickupBundle(inputData.getLong(DataWorker.STORE_KEY, -1)) val bundle = dataWorker.pickupBundle(inputData.getLong(DataWorker.STORE_KEY, -1))
?: return Result.failure() ?: return Result.failure(workDataOf("Error" to "missing input data"))
val format = bundle.getString("format") ?: return Result.failure() val format = bundle.getString("format")
?: return Result.failure(workDataOf("Error" to "missing format in input data"))
val pdus = bundle["pdus"] as Array<*> val pdus = bundle["pdus"] as Array<*>
for (pdu in pdus) { for (pdu in pdus) {
val message = SmsMessage.createFromPdu(pdu as ByteArray, format) val message = SmsMessage.createFromPdu(pdu as ByteArray, format)
@ -272,7 +276,7 @@ class SmsCommunicatorPlugin @Inject constructor(
else sendSMS(Sms(receivedSms.phoneNumber, resourceHelper.gs(R.string.wrongformat))) else sendSMS(Sms(receivedSms.phoneNumber, resourceHelper.gs(R.string.wrongformat)))
"BOLUS" -> "BOLUS" ->
if (!remoteCommandsAllowed) sendSMS(Sms(receivedSms.phoneNumber, resourceHelper.gs(R.string.smscommunicator_remotecommandnotallowed))) 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 && pump.isSuspended()) sendSMS(Sms(receivedSms.phoneNumber, resourceHelper.gs(R.string.pumpsuspended)))
else if (divided.size == 2 || divided.size == 3) processBOLUS(divided, receivedSms) else if (divided.size == 2 || divided.size == 3) processBOLUS(divided, receivedSms)
else sendSMS(Sms(receivedSms.phoneNumber, resourceHelper.gs(R.string.wrongformat))) else sendSMS(Sms(receivedSms.phoneNumber, resourceHelper.gs(R.string.wrongformat)))
@ -306,21 +310,21 @@ class SmsCommunicatorPlugin @Inject constructor(
} }
private fun processBG(receivedSms: Sms) { private fun processBG(receivedSms: Sms) {
val actualBG = iobCobCalculator.actualBg() val actualBG = iobCobCalculator.ads.actualBg()
val lastBG = iobCobCalculator.lastBg() val lastBG = iobCobCalculator.ads.lastBg()
var reply = "" var reply = ""
val units = profileFunction.getUnits() val units = profileFunction.getUnits()
if (actualBG != null) { if (actualBG != null) {
reply = resourceHelper.gs(R.string.sms_actualbg) + " " + actualBG.valueToUnitsString(units) + ", " reply = resourceHelper.gs(R.string.sms_actualbg) + " " + actualBG.valueToUnitsString(units) + ", "
} else if (lastBG != null) { } else if (lastBG != null) {
val agoMilliseconds = System.currentTimeMillis() - lastBG.timestamp val agoMilliseconds = dateUtil.now() - lastBG.timestamp
val agoMin = (agoMilliseconds / 60.0 / 1000.0).toInt() 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) + ", " reply = resourceHelper.gs(R.string.sms_lastbg) + " " + lastBG.valueToUnitsString(units) + " " + String.format(resourceHelper.gs(R.string.sms_minago), agoMin) + ", "
} }
val glucoseStatus = glucoseStatusProvider.glucoseStatusData 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 + ", " if (glucoseStatus != null) reply += resourceHelper.gs(R.string.sms_delta) + " " + Profile.toUnitsString(glucoseStatus.delta, glucoseStatus.delta * Constants.MGDL_TO_MMOLL, units) + " " + units + ", "
val bolusIob = iobCobCalculator.calculateIobFromBolus().round() val bolusIob = iobCobCalculator.calculateIobFromBolus().round()
val basalIob = activePlugin.activeTreatments.lastCalculationTempBasals.round() val basalIob = iobCobCalculator.calculateIobFromTempBasalsIncludingConvertedExtended().round()
val cobInfo = iobCobCalculator.getCobInfo(false, "SMS COB") val cobInfo = iobCobCalculator.getCobInfo(false, "SMS COB")
reply += (resourceHelper.gs(R.string.sms_iob) + " " + DecimalFormatter.to2Decimal(bolusIob.iob + basalIob.basaliob) + "U (" 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_bolus) + " " + DecimalFormatter.to2Decimal(bolusIob.iob) + "U "
@ -339,7 +343,7 @@ class SmsCommunicatorPlugin @Inject constructor(
receivedSms.processed = true receivedSms.processed = true
messageToConfirm = AuthRequest(injector, receivedSms, reply, passCode, object : SmsAction() { messageToConfirm = AuthRequest(injector, receivedSms, reply, passCode, object : SmsAction() {
override fun run() { override fun run() {
uel.log(Action.SMS_LOOP_DISABLED) uel.log(Action.LOOP_DISABLED, Sources.SMS)
loopPlugin.setPluginEnabled(PluginType.LOOP, false) loopPlugin.setPluginEnabled(PluginType.LOOP, false)
commandQueue.cancelTempBasal(true, object : Callback() { commandQueue.cancelTempBasal(true, object : Callback() {
override fun run() { override fun run() {
@ -363,7 +367,7 @@ class SmsCommunicatorPlugin @Inject constructor(
receivedSms.processed = true receivedSms.processed = true
messageToConfirm = AuthRequest(injector, receivedSms, reply, passCode, object : SmsAction() { messageToConfirm = AuthRequest(injector, receivedSms, reply, passCode, object : SmsAction() {
override fun run() { override fun run() {
uel.log(Action.SMS_LOOP_ENABLED) uel.log(Action.LOOP_ENABLED, Sources.SMS)
loopPlugin.setPluginEnabled(PluginType.LOOP, true) loopPlugin.setPluginEnabled(PluginType.LOOP, true)
sendSMS(Sms(receivedSms.phoneNumber, resourceHelper.gs(R.string.smscommunicator_loophasbeenenabled))) sendSMS(Sms(receivedSms.phoneNumber, resourceHelper.gs(R.string.smscommunicator_loophasbeenenabled)))
rxBus.send(EventRefreshOverview("SMS_LOOP_START")) rxBus.send(EventRefreshOverview("SMS_LOOP_START"))
@ -390,7 +394,7 @@ class SmsCommunicatorPlugin @Inject constructor(
receivedSms.processed = true receivedSms.processed = true
messageToConfirm = AuthRequest(injector, receivedSms, reply, passCode, object : SmsAction() { messageToConfirm = AuthRequest(injector, receivedSms, reply, passCode, object : SmsAction() {
override fun run() { override fun run() {
uel.log(Action.SMS_LOOP_RESUME) uel.log(Action.RESUME, Sources.SMS)
loopPlugin.suspendTo(0L) loopPlugin.suspendTo(0L)
rxBus.send(EventRefreshOverview("SMS_LOOP_RESUME")) rxBus.send(EventRefreshOverview("SMS_LOOP_RESUME"))
commandQueue.cancelTempBasal(true, object : Callback() { commandQueue.cancelTempBasal(true, object : Callback() {
@ -423,11 +427,11 @@ class SmsCommunicatorPlugin @Inject constructor(
receivedSms.processed = true receivedSms.processed = true
messageToConfirm = AuthRequest(injector, receivedSms, reply, passCode, object : SmsAction(duration) { messageToConfirm = AuthRequest(injector, receivedSms, reply, passCode, object : SmsAction(duration) {
override fun run() { override fun run() {
uel.log(Action.SMS_LOOP_SUSPEND) uel.log(Action.SUSPEND, Sources.SMS)
commandQueue.cancelTempBasal(true, object : Callback() { commandQueue.cancelTempBasal(true, object : Callback() {
override fun run() { override fun run() {
if (result.success) { if (result.success) {
loopPlugin.suspendTo(System.currentTimeMillis() + anInteger() * 60L * 1000) loopPlugin.suspendTo(dateUtil.now() + anInteger() * 60L * 1000)
loopPlugin.createOfflineEvent(anInteger() * 60) loopPlugin.createOfflineEvent(anInteger() * 60)
rxBus.send(EventRefreshOverview("SMS_LOOP_SUSPENDED")) rxBus.send(EventRefreshOverview("SMS_LOOP_SUSPENDED"))
val replyText = resourceHelper.gs(R.string.smscommunicator_loopsuspended) + " " + val replyText = resourceHelper.gs(R.string.smscommunicator_loopsuspended) + " " +
@ -497,7 +501,7 @@ class SmsCommunicatorPlugin @Inject constructor(
receivedSms.processed = true receivedSms.processed = true
messageToConfirm = AuthRequest(injector, receivedSms, reply, passCode, object : SmsAction() { messageToConfirm = AuthRequest(injector, receivedSms, reply, passCode, object : SmsAction() {
override fun run() { override fun run() {
uel.log(Action.SMS_PUMP_CONNECT) uel.log(Action.RECONNECT, Sources.SMS)
commandQueue.cancelTempBasal(true, object : Callback() { commandQueue.cancelTempBasal(true, object : Callback() {
override fun run() { override fun run() {
if (!result.success) { if (!result.success) {
@ -526,7 +530,7 @@ class SmsCommunicatorPlugin @Inject constructor(
receivedSms.processed = true receivedSms.processed = true
messageToConfirm = AuthRequest(injector, receivedSms, reply, passCode, object : SmsAction() { messageToConfirm = AuthRequest(injector, receivedSms, reply, passCode, object : SmsAction() {
override fun run() { override fun run() {
uel.log(Action.SMS_PUMP_DISCONNECT) uel.log(Action.DISCONNECT, Sources.SMS)
val profile = profileFunction.getProfile() val profile = profileFunction.getProfile()
loopPlugin.disconnectPump(duration, profile) loopPlugin.disconnectPump(duration, profile)
rxBus.send(EventRefreshOverview("SMS_PUMP_DISCONNECT")) rxBus.send(EventRefreshOverview("SMS_PUMP_DISCONNECT"))
@ -580,10 +584,11 @@ class SmsCommunicatorPlugin @Inject constructor(
val finalPercentage = percentage val finalPercentage = percentage
messageToConfirm = AuthRequest(injector, receivedSms, reply, passCode, object : SmsAction(list[pIndex - 1] as String, finalPercentage) { messageToConfirm = AuthRequest(injector, receivedSms, reply, passCode, object : SmsAction(list[pIndex - 1] as String, finalPercentage) {
override fun run() { 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) val replyText = resourceHelper.gs(R.string.profileswitchcreated)
sendSMS(Sms(receivedSms.phoneNumber, replyText)) 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)))
} }
}) })
} }
@ -605,12 +610,14 @@ class SmsCommunicatorPlugin @Inject constructor(
var replyText = resourceHelper.gs(R.string.smscommunicator_tempbasalcanceled) var replyText = resourceHelper.gs(R.string.smscommunicator_tempbasalcanceled)
replyText += "\n" + activePlugin.activePump.shortStatus(true) replyText += "\n" + activePlugin.activePump.shortStatus(true)
sendSMSToAllNumbers(Sms(receivedSms.phoneNumber, replyText)) 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 { } else {
var replyText = resourceHelper.gs(R.string.smscommunicator_tempbasalcancelfailed) var replyText = resourceHelper.gs(R.string.smscommunicator_tempbasalcancelfailed)
replyText += "\n" + activePlugin.activePump.shortStatus(true) replyText += "\n" + activePlugin.activePump.shortStatus(true)
sendSMS(Sms(receivedSms.phoneNumber, replyText)) 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)))
} }
} }
}) })
@ -632,21 +639,28 @@ class SmsCommunicatorPlugin @Inject constructor(
receivedSms.processed = true receivedSms.processed = true
messageToConfirm = AuthRequest(injector, receivedSms, reply, passCode, object : SmsAction(tempBasalPct, duration) { messageToConfirm = AuthRequest(injector, receivedSms, reply, passCode, object : SmsAction(tempBasalPct, duration) {
override fun run() { 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() { override fun run() {
if (result.success) { 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) 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) replyText += "\n" + activePlugin.activePump.shortStatus(true)
sendSMSToAllNumbers(Sms(receivedSms.phoneNumber, replyText)) sendSMSToAllNumbers(Sms(receivedSms.phoneNumber, replyText))
if (result.isPercent) 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 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 { } else {
var replyText = resourceHelper.gs(R.string.smscommunicator_tempbasalfailed) var replyText = resourceHelper.gs(R.string.smscommunicator_tempbasalfailed)
replyText += "\n" + activePlugin.activePump.shortStatus(true) replyText += "\n" + activePlugin.activePump.shortStatus(true)
sendSMS(Sms(receivedSms.phoneNumber, replyText)) 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)))
} }
} }
}) })
@ -669,7 +683,7 @@ class SmsCommunicatorPlugin @Inject constructor(
receivedSms.processed = true receivedSms.processed = true
messageToConfirm = AuthRequest(injector, receivedSms, reply, passCode, object : SmsAction(tempBasal, duration) { messageToConfirm = AuthRequest(injector, receivedSms, reply, passCode, object : SmsAction(tempBasal, duration) {
override fun run() { 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() { override fun run() {
if (result.success) { if (result.success) {
var replyText = if (result.isPercent) String.format(resourceHelper.gs(R.string.smscommunicator_tempbasalset_percent), result.percent, result.duration) var replyText = if (result.isPercent) String.format(resourceHelper.gs(R.string.smscommunicator_tempbasalset_percent), result.percent, result.duration)
@ -677,14 +691,19 @@ class SmsCommunicatorPlugin @Inject constructor(
replyText += "\n" + activePlugin.activePump.shortStatus(true) replyText += "\n" + activePlugin.activePump.shortStatus(true)
sendSMSToAllNumbers(Sms(receivedSms.phoneNumber, replyText)) sendSMSToAllNumbers(Sms(receivedSms.phoneNumber, replyText))
if (result.isPercent) 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 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 { } else {
var replyText = resourceHelper.gs(R.string.smscommunicator_tempbasalfailed) var replyText = resourceHelper.gs(R.string.smscommunicator_tempbasalfailed)
replyText += "\n" + activePlugin.activePump.shortStatus(true) replyText += "\n" + activePlugin.activePump.shortStatus(true)
sendSMS(Sms(receivedSms.phoneNumber, replyText)) 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)))
} }
} }
}) })
@ -711,7 +730,8 @@ class SmsCommunicatorPlugin @Inject constructor(
var replyText = resourceHelper.gs(R.string.smscommunicator_extendedcancelfailed) var replyText = resourceHelper.gs(R.string.smscommunicator_extendedcancelfailed)
replyText += "\n" + activePlugin.activePump.shortStatus(true) replyText += "\n" + activePlugin.activePump.shortStatus(true)
sendSMS(Sms(receivedSms.phoneNumber, replyText)) 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)))
} }
} }
}) })
@ -738,16 +758,20 @@ class SmsCommunicatorPlugin @Inject constructor(
replyText += "\n" + activePlugin.activePump.shortStatus(true) replyText += "\n" + activePlugin.activePump.shortStatus(true)
sendSMSToAllNumbers(Sms(receivedSms.phoneNumber, replyText)) sendSMSToAllNumbers(Sms(receivedSms.phoneNumber, replyText))
if (config.APS) if (config.APS)
uel.log(Action.SMS_EXTENDED_BOLUS, activePlugin.activePump.shortStatus(true), ValueWithUnit(R.string.smscommunicator_extendedset, 2), ValueWithUnit(aDouble 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),
?: 0.0, Units.U), ValueWithUnit(duration, Units.M), ValueWithUnit(R.string.loopsuspended, Units.R_String)) ValueWithUnit.Insulin(aDouble ?: 0.0),
ValueWithUnit.Minute(duration),
ValueWithUnit.SimpleString(resourceHelper.gsNotLocalised(R.string.loopsuspended)))
else else
uel.log(Action.SMS_EXTENDED_BOLUS, activePlugin.activePump.shortStatus(true), ValueWithUnit(R.string.smscommunicator_extendedset, 2), ValueWithUnit(aDouble uel.log(Action.EXTENDED_BOLUS, Sources.SMS, activePlugin.activePump.shortStatus(true) + "\n" + resourceHelper.gs(R.string.smscommunicator_extendedset, aDouble, duration),
?: 0.0, Units.U), ValueWithUnit(duration, Units.M)) ValueWithUnit.Insulin(aDouble ?: 0.0),
ValueWithUnit.Minute(duration))
} else { } else {
var replyText = resourceHelper.gs(R.string.smscommunicator_extendedfailed) var replyText = resourceHelper.gs(R.string.smscommunicator_extendedfailed)
replyText += "\n" + activePlugin.activePump.shortStatus(true) replyText += "\n" + activePlugin.activePump.shortStatus(true)
sendSMS(Sms(receivedSms.phoneNumber, replyText)) 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)))
} }
} }
}) })
@ -786,7 +810,7 @@ class SmsCommunicatorPlugin @Inject constructor(
else else
String.format(resourceHelper.gs(R.string.smscommunicator_bolusdelivered), resultBolusDelivered) String.format(resourceHelper.gs(R.string.smscommunicator_bolusdelivered), resultBolusDelivered)
replyText += "\n" + activePlugin.activePump.shortStatus(true) replyText += "\n" + activePlugin.activePump.shortStatus(true)
lastRemoteBolusTime = DateUtil.now() lastRemoteBolusTime = dateUtil.now()
if (isMeal) { if (isMeal) {
profileFunction.getProfile()?.let { currentProfile -> profileFunction.getProfile()?.let { currentProfile ->
var eatingSoonTTDuration = sp.getInt(R.string.key_eatingsoon_duration, Constants.defaultEatingSoonTTDuration) var eatingSoonTTDuration = sp.getInt(R.string.key_eatingsoon_duration, Constants.defaultEatingSoonTTDuration)
@ -801,7 +825,7 @@ class SmsCommunicatorPlugin @Inject constructor(
else -> Constants.defaultEatingSoonTTmgdl else -> Constants.defaultEatingSoonTTmgdl
} }
disposable += repository.runTransactionForResult(InsertTemporaryTargetAndCancelCurrentTransaction( disposable += repository.runTransactionForResult(InsertTemporaryTargetAndCancelCurrentTransaction(
timestamp = System.currentTimeMillis(), timestamp = dateUtil.now(),
duration = TimeUnit.MINUTES.toMillis(eatingSoonTTDuration.toLong()), duration = TimeUnit.MINUTES.toMillis(eatingSoonTTDuration.toLong()),
reason = TemporaryTarget.Reason.EATING_SOON, reason = TemporaryTarget.Reason.EATING_SOON,
lowTarget = Profile.toMgdl(eatingSoonTT, profileFunction.getUnits()), lowTarget = Profile.toMgdl(eatingSoonTT, profileFunction.getUnits()),
@ -819,12 +843,13 @@ class SmsCommunicatorPlugin @Inject constructor(
} }
} }
sendSMSToAllNumbers(Sms(receivedSms.phoneNumber, replyText)) sendSMSToAllNumbers(Sms(receivedSms.phoneNumber, replyText))
uel.log(Action.SMS_BOLUS, replyText) uel.log(Action.BOLUS, Sources.SMS, replyText)
} else { } else {
var replyText = resourceHelper.gs(R.string.smscommunicator_bolusfailed) var replyText = resourceHelper.gs(R.string.smscommunicator_bolusfailed)
replyText += "\n" + activePlugin.activePump.shortStatus(true) replyText += "\n" + activePlugin.activePump.shortStatus(true)
sendSMS(Sms(receivedSms.phoneNumber, replyText)) 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)))
} }
} }
}) })
@ -835,11 +860,30 @@ class SmsCommunicatorPlugin @Inject constructor(
} else sendSMS(Sms(receivedSms.phoneNumber, resourceHelper.gs(R.string.wrongformat))) } 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<String>, receivedSms: Sms) { private fun processCARBS(divided: Array<String>, receivedSms: Sms) {
var grams = SafeParse.stringToInt(divided[1]) var grams = SafeParse.stringToInt(divided[1])
var time = DateUtil.now() var time = dateUtil.now()
if (divided.size > 2) { if (divided.size > 2) {
time = DateUtil.toTodayTime(divided[2].toUpperCase(Locale.getDefault())) time = toTodayTime(divided[2].toUpperCase(Locale.getDefault()))
if (time == 0L) { if (time == 0L) {
sendSMS(Sms(receivedSms.phoneNumber, resourceHelper.gs(R.string.wrongformat))) sendSMS(Sms(receivedSms.phoneNumber, resourceHelper.gs(R.string.wrongformat)))
return return
@ -862,14 +906,14 @@ class SmsCommunicatorPlugin @Inject constructor(
var replyText = String.format(resourceHelper.gs(R.string.smscommunicator_carbsset), anInteger) var replyText = String.format(resourceHelper.gs(R.string.smscommunicator_carbsset), anInteger)
replyText += "\n" + activePlugin.activePump.shortStatus(true) replyText += "\n" + activePlugin.activePump.shortStatus(true)
sendSMSToAllNumbers(Sms(receivedSms.phoneNumber, replyText)) sendSMSToAllNumbers(Sms(receivedSms.phoneNumber, replyText))
uel.log(Action.SMS_CARBS, activePlugin.activePump.shortStatus(true), ValueWithUnit(R.string.smscommunicator_carbsset, 1), ValueWithUnit(anInteger uel.log(Action.CARBS, Sources.SMS, activePlugin.activePump.shortStatus(true) + ": " + resourceHelper.gs(R.string.smscommunicator_carbsset, anInteger),
?: 0, Units.G)) ValueWithUnit.Gram(anInteger ?: 0))
} else { } else {
var replyText = resourceHelper.gs(R.string.smscommunicator_carbsfailed, anInteger) var replyText = resourceHelper.gs(R.string.smscommunicator_carbsfailed, anInteger)
replyText += "\n" + activePlugin.activePump.shortStatus(true) replyText += "\n" + activePlugin.activePump.shortStatus(true)
sendSMS(Sms(receivedSms.phoneNumber, replyText)) sendSMS(Sms(receivedSms.phoneNumber, replyText))
uel.log(Action.SMS_CARBS, activePlugin.activePump.shortStatus(true), ValueWithUnit(R.string.smscommunicator_carbsfailed, 1), ValueWithUnit(anInteger uel.log(Action.CARBS, Sources.SMS, activePlugin.activePump.shortStatus(true) + ": " + resourceHelper.gs(R.string.smscommunicator_carbsfailed, anInteger),
?: 0, Units.G)) ValueWithUnit.Gram(anInteger ?: 0))
} }
} }
}) })
@ -926,7 +970,7 @@ class SmsCommunicatorPlugin @Inject constructor(
tt = Profile.toCurrentUnits(profileFunction, tt) tt = Profile.toCurrentUnits(profileFunction, tt)
tt = if (tt > 0) tt else if (units == Constants.MMOL) defaultTargetMMOL else defaultTargetMGDL tt = if (tt > 0) tt else if (units == Constants.MMOL) defaultTargetMMOL else defaultTargetMGDL
disposable += repository.runTransactionForResult(InsertTemporaryTargetAndCancelCurrentTransaction( disposable += repository.runTransactionForResult(InsertTemporaryTargetAndCancelCurrentTransaction(
timestamp = System.currentTimeMillis(), timestamp = dateUtil.now(),
duration = TimeUnit.MINUTES.toMillis(ttDuration.toLong()), duration = TimeUnit.MINUTES.toMillis(ttDuration.toLong()),
reason = TemporaryTarget.Reason.EATING_SOON, reason = TemporaryTarget.Reason.EATING_SOON,
lowTarget = Profile.toMgdl(tt, profileFunction.getUnits()), lowTarget = Profile.toMgdl(tt, profileFunction.getUnits()),
@ -940,8 +984,9 @@ class SmsCommunicatorPlugin @Inject constructor(
val ttString = if (units == Constants.MMOL) DecimalFormatter.to1Decimal(tt) else DecimalFormatter.to0Decimal(tt) 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) val replyText = String.format(resourceHelper.gs(R.string.smscommunicator_tt_set), ttString, ttDuration)
sendSMSToAllNumbers(Sms(receivedSms.phoneNumber, replyText)) 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.TT, Sources.SMS,
uel.log(Action.SMS_TT, ValueWithUnit(tt, units), ValueWithUnit(ttDuration, Units.M)) ValueWithUnit.fromGlucoseUnit(tt, units),
ValueWithUnit.Minute(ttDuration))
} }
}) })
} else if (isStop) { } else if (isStop) {
@ -950,7 +995,7 @@ class SmsCommunicatorPlugin @Inject constructor(
receivedSms.processed = true receivedSms.processed = true
messageToConfirm = AuthRequest(injector, receivedSms, reply, passCode, object : SmsAction() { messageToConfirm = AuthRequest(injector, receivedSms, reply, passCode, object : SmsAction() {
override fun run() { override fun run() {
disposable += repository.runTransactionForResult(CancelCurrentTemporaryTargetIfAnyTransaction(dateUtil._now())) disposable += repository.runTransactionForResult(CancelCurrentTemporaryTargetIfAnyTransaction(dateUtil.now()))
.subscribe({ result -> .subscribe({ result ->
result.updated.forEach { aapsLogger.debug(LTag.DATABASE, "Updated temp target $it") } result.updated.forEach { aapsLogger.debug(LTag.DATABASE, "Updated temp target $it") }
}, { }, {
@ -958,7 +1003,8 @@ class SmsCommunicatorPlugin @Inject constructor(
}) })
val replyText = String.format(resourceHelper.gs(R.string.smscommunicator_tt_canceled)) val replyText = String.format(resourceHelper.gs(R.string.smscommunicator_tt_canceled))
sendSMSToAllNumbers(Sms(receivedSms.phoneNumber, replyText)) 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 } else
@ -977,7 +1023,8 @@ class SmsCommunicatorPlugin @Inject constructor(
sp.putBoolean(R.string.key_smscommunicator_remotecommandsallowed, false) sp.putBoolean(R.string.key_smscommunicator_remotecommandsallowed, false)
val replyText = String.format(resourceHelper.gs(R.string.smscommunicator_stoppedsms)) val replyText = String.format(resourceHelper.gs(R.string.smscommunicator_stoppedsms))
sendSMSToAllNumbers(Sms(receivedSms.phoneNumber, replyText)) 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))) } else sendSMS(Sms(receivedSms.phoneNumber, resourceHelper.gs(R.string.wrongformat)))
@ -996,9 +1043,11 @@ class SmsCommunicatorPlugin @Inject constructor(
if (result) resourceHelper.gs(R.string.smscommunicator_calibrationsent) else resourceHelper.gs(R.string.smscommunicator_calibrationfailed) if (result) resourceHelper.gs(R.string.smscommunicator_calibrationsent) else resourceHelper.gs(R.string.smscommunicator_calibrationfailed)
sendSMSToAllNumbers(Sms(receivedSms.phoneNumber, replyText)) sendSMSToAllNumbers(Sms(receivedSms.phoneNumber, replyText))
if (result) 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 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))) } else sendSMS(Sms(receivedSms.phoneNumber, resourceHelper.gs(R.string.wrongformat)))

View file

@ -14,7 +14,8 @@ import com.google.common.primitives.Ints.min
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel
import info.nightscout.androidaps.R import info.nightscout.androidaps.R
import info.nightscout.androidaps.activities.NoSplashAppCompatActivity 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.databinding.ActivitySmscommunicatorOtpBinding
import info.nightscout.androidaps.logging.UserEntryLogger import info.nightscout.androidaps.logging.UserEntryLogger
import info.nightscout.androidaps.plugins.bus.RxBusWrapper 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_title),
resourceHelper.gs(R.string.smscommunicator_otp_reset_prompt), resourceHelper.gs(R.string.smscommunicator_otp_reset_prompt),
Runnable { Runnable {
uel.log(Action.OTP_RESET) uel.log(Action.OTP_RESET, Sources.SMS)
otp.ensureKey(true) otp.ensureKey(true)
updateGui() updateGui()
ToastUtils.Long.infoToast(this, resourceHelper.gs(R.string.smscommunicator_otp_reset_successful)) 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()) val clip = ClipData.newPlainText("OTP Secret", otp.provisioningSecret())
clipboard.primaryClip = clip clipboard.primaryClip = clip
ToastUtils.Long.infoToast(this, resourceHelper.gs(R.string.smscommunicator_otp_export_successful)) 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 true

View file

@ -18,7 +18,8 @@ import javax.inject.Singleton
@Singleton @Singleton
class OneTimePassword @Inject constructor( class OneTimePassword @Inject constructor(
private val sp: SP, private val sp: SP,
private val resourceHelper: ResourceHelper private val resourceHelper: ResourceHelper,
private val dateUtil: DateUtil
) { ) {
private var key: SecretKey? = null private var key: SecretKey? = null
@ -85,7 +86,7 @@ class OneTimePassword @Inject constructor(
return OneTimePasswordValidationResult.ERROR_WRONG_PIN return OneTimePasswordValidationResult.ERROR_WRONG_PIN
} }
val counter: Long = DateUtil.now() / 30000L val counter: Long = dateUtil.now() / 30000L
val acceptableTokens: MutableList<String> = mutableListOf(generateOneTimePassword(counter)) val acceptableTokens: MutableList<String> = mutableListOf(generateOneTimePassword(counter))
for (i in 0 until Constants.OTP_ACCEPT_OLD_TOKENS_COUNT) { for (i in 0 until Constants.OTP_ACCEPT_OLD_TOKENS_COUNT) {

View file

@ -151,7 +151,7 @@ class TidepoolUploader @Inject constructor(
if (session.datasetReply == null) { if (session.datasetReply == null) {
rxBus.send(EventTidepoolStatus(("Creating new dataset"))) rxBus.send(EventTidepoolStatus(("Creating new dataset")))
val call = session.service.openDataSet(session.token!!, session.authReply!!.userid!!, val call = session.service.openDataSet(session.token!!, session.authReply!!.userid!!,
OpenDatasetRequestMessage(activePlugin.activePump.serialNumber()).getBody()) OpenDatasetRequestMessage(activePlugin.activePump.serialNumber(), dateUtil).getBody())
call.enqueue(TidepoolCallback<DatasetReplyMessage>(aapsLogger, rxBus, session, "Open New Dataset", { call.enqueue(TidepoolCallback<DatasetReplyMessage>(aapsLogger, rxBus, session, "Open New Dataset", {
connectionStatus = ConnectionStatus.CONNECTED connectionStatus = ConnectionStatus.CONNECTED
rxBus.send(EventTidepoolStatus(("New dataset OK"))) rxBus.send(EventTidepoolStatus(("New dataset OK")))
@ -232,7 +232,7 @@ class TidepoolUploader @Inject constructor(
} }
private fun uploadNext() { private fun uploadNext() {
if (uploadChunk.getLastEnd() < DateUtil.now() - T.mins(1).msecs()) { if (uploadChunk.getLastEnd() < dateUtil.now() - T.mins(1).msecs()) {
SystemClock.sleep(3000) SystemClock.sleep(3000)
aapsLogger.debug(LTag.TIDEPOOL, "Restarting doUpload. Last: " + dateUtil.dateAndTimeString(uploadChunk.getLastEnd())) aapsLogger.debug(LTag.TIDEPOOL, "Restarting doUpload. Last: " + dateUtil.dateAndTimeString(uploadChunk.getLastEnd()))
doUpload() doUpload()

View file

@ -1,10 +1,9 @@
package info.nightscout.androidaps.plugins.general.tidepool.comm package info.nightscout.androidaps.plugins.general.tidepool.comm
import info.nightscout.androidaps.R import info.nightscout.androidaps.R
import info.nightscout.androidaps.data.Intervals
import info.nightscout.androidaps.database.AppRepository import info.nightscout.androidaps.database.AppRepository
import info.nightscout.androidaps.database.entities.TemporaryBasal
import info.nightscout.androidaps.db.ProfileSwitch import info.nightscout.androidaps.db.ProfileSwitch
import info.nightscout.androidaps.db.TemporaryBasal
import info.nightscout.androidaps.interfaces.ActivePluginProvider import info.nightscout.androidaps.interfaces.ActivePluginProvider
import info.nightscout.androidaps.interfaces.DatabaseHelperInterface import info.nightscout.androidaps.interfaces.DatabaseHelperInterface
import info.nightscout.androidaps.interfaces.ProfileFunction import info.nightscout.androidaps.interfaces.ProfileFunction
@ -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.elements.*
import info.nightscout.androidaps.plugins.general.tidepool.events.EventTidepoolStatus import info.nightscout.androidaps.plugins.general.tidepool.events.EventTidepoolStatus
import info.nightscout.androidaps.plugins.general.tidepool.utils.GsonInstance 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.DateUtil
import info.nightscout.androidaps.utils.T import info.nightscout.androidaps.utils.T
import info.nightscout.androidaps.utils.sharedPreferences.SP import info.nightscout.androidaps.utils.sharedPreferences.SP
@ -30,7 +28,6 @@ class UploadChunk @Inject constructor(
private val rxBus: RxBusWrapper, private val rxBus: RxBusWrapper,
private val aapsLogger: AAPSLogger, private val aapsLogger: AAPSLogger,
private val profileFunction: ProfileFunction, private val profileFunction: ProfileFunction,
private val treatmentsPlugin: TreatmentsPlugin,
private val activePlugin: ActivePluginProvider, private val activePlugin: ActivePluginProvider,
private val databaseHelper: DatabaseHelperInterface, private val databaseHelper: DatabaseHelperInterface,
private val repository: AppRepository, private val repository: AppRepository,
@ -44,7 +41,7 @@ class UploadChunk @Inject constructor(
return null return null
session.start = getLastEnd() 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) val result = get(session.start, session.end)
if (result.length < 3) { if (result.length < 3) {
@ -84,7 +81,7 @@ class UploadChunk @Inject constructor(
fun getLastEnd(): Long { fun getLastEnd(): Long {
val result = sp.getLong(R.string.key_tidepool_last_end, 0) 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) { 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 // TODO we could make sure we include records older than the first bg record for completeness
val start: Long = 0 val start: Long = 0
val end = DateUtil.now() val end = dateUtil.now()
val bgReadingList = repository.compatGetBgReadingsDataFromTime(start, end, true) val bgReadingList = repository.compatGetBgReadingsDataFromTime(start, end, true)
.blockingGet() .blockingGet()
@ -118,19 +115,19 @@ class UploadChunk @Inject constructor(
repository.getBolusesDataFromTimeToTime(start, end, true) repository.getBolusesDataFromTimeToTime(start, end, true)
.blockingGet() .blockingGet()
.forEach { bolus -> .forEach { bolus ->
result.add(BolusElement(bolus)) result.add(BolusElement(bolus, dateUtil))
} }
repository.getCarbsDataFromTimeToTimeExpanded(start, end, true) repository.getCarbsDataFromTimeToTimeExpanded(start, end, true)
.blockingGet() .blockingGet()
.forEach { carb -> .forEach { carb ->
result.add(WizardElement(carb)) result.add(WizardElement(carb, dateUtil))
} }
return result return result
} }
private fun getBloodTests(start: Long, end: Long): List<BloodGlucoseElement> { private fun getBloodTests(start: Long, end: Long): List<BloodGlucoseElement> {
val readings = repository.compatGetTherapyEventDataFromToTime(start, end).blockingGet() val readings = repository.compatGetTherapyEventDataFromToTime(start, end).blockingGet()
val selection = BloodGlucoseElement.fromCareportalEvents(readings) val selection = BloodGlucoseElement.fromCareportalEvents(readings, dateUtil)
if (selection.isNotEmpty()) if (selection.isNotEmpty())
rxBus.send(EventTidepoolStatus("${selection.size} BGs selected for upload")) rxBus.send(EventTidepoolStatus("${selection.size} BGs selected for upload"))
return selection return selection
@ -140,24 +137,25 @@ class UploadChunk @Inject constructor(
private fun getBgReadings(start: Long, end: Long): List<SensorGlucoseElement> { private fun getBgReadings(start: Long, end: Long): List<SensorGlucoseElement> {
val readings = repository.compatGetBgReadingsDataFromTime(start, end, true) val readings = repository.compatGetBgReadingsDataFromTime(start, end, true)
.blockingGet() .blockingGet()
val selection = SensorGlucoseElement.fromBgReadings(readings) val selection = SensorGlucoseElement.fromBgReadings(readings, dateUtil)
if (selection.isNotEmpty()) if (selection.isNotEmpty())
rxBus.send(EventTidepoolStatus("${selection.size} CGMs selected for upload")) rxBus.send(EventTidepoolStatus("${selection.size} CGMs selected for upload"))
return selection return selection
} }
private fun fromTemporaryBasals(tbrList: Intervals<TemporaryBasal>, start: Long, end: Long): List<BasalElement> { private fun fromTemporaryBasals(tbrList: List<TemporaryBasal>, start: Long, end: Long): List<BasalElement> {
val results = LinkedList<BasalElement>() val results = LinkedList<BasalElement>()
for (tbr in tbrList.list) { for (tbr in tbrList) {
if (tbr.date in start..end && tbr.durationInMinutes != 0) if (tbr.timestamp in start..end)
results.add(BasalElement(tbr, profileFunction)) profileFunction.getProfile(tbr.timestamp)?.let {
results.add(BasalElement(tbr, it, dateUtil))
}
} }
return results return results
} }
private fun getBasals(start: Long, end: Long): List<BasalElement> { private fun getBasals(start: Long, end: Long): List<BasalElement> {
val temporaryBasals = treatmentsPlugin.temporaryBasalsFromHistory val temporaryBasals = repository.getTemporaryBasalsDataFromTimeToTime(start, end, true).blockingGet()
temporaryBasals.merge()
val selection = fromTemporaryBasals(temporaryBasals, start, end) // TODO do not upload running TBR val selection = fromTemporaryBasals(temporaryBasals, start, end) // TODO do not upload running TBR
if (selection.isNotEmpty()) if (selection.isNotEmpty())
rxBus.send(EventTidepoolStatus("${selection.size} TBRs selected for upload")) rxBus.send(EventTidepoolStatus("${selection.size} TBRs selected for upload"))
@ -165,7 +163,7 @@ class UploadChunk @Inject constructor(
} }
private fun newInstanceOrNull(ps: ProfileSwitch): ProfileElement? = try { private fun newInstanceOrNull(ps: ProfileSwitch): ProfileElement? = try {
ProfileElement(ps, activePlugin.activePump.serialNumber()) ProfileElement(ps, activePlugin.activePump.serialNumber(), dateUtil)
} catch (e: Throwable) { } catch (e: Throwable) {
null null
} }

View file

@ -1,32 +1,39 @@
package info.nightscout.androidaps.plugins.general.tidepool.elements package info.nightscout.androidaps.plugins.general.tidepool.elements
import com.google.gson.annotations.Expose import com.google.gson.annotations.Expose
import info.nightscout.androidaps.db.TemporaryBasal import info.nightscout.androidaps.data.Profile
import info.nightscout.androidaps.interfaces.ProfileFunction import info.nightscout.androidaps.database.entities.TemporaryBasal
import info.nightscout.androidaps.extensions.convertedToAbsolute
import info.nightscout.androidaps.utils.DateUtil
import java.util.* import java.util.*
class BasalElement(tbr: TemporaryBasal, private val profileFunction: ProfileFunction) class BasalElement(tbr: TemporaryBasal, private val profile: Profile, dateUtil: DateUtil)
: BaseElement(tbr.date, UUID.nameUUIDFromBytes(("AAPS-basal" + tbr.date).toByteArray()).toString()) { : BaseElement(tbr.timestamp, UUID.nameUUIDFromBytes(("AAPS-basal" + tbr.timestamp).toByteArray()).toString(), dateUtil) {
internal var timestamp: Long = 0 // not exposed internal var timestamp: Long = 0 // not exposed
@Expose @Expose
internal var deliveryType = "automated" internal var deliveryType = "automated"
@Expose @Expose
internal var duration: Long = 0 internal var duration: Long = 0
@Expose @Expose
internal var rate = -1.0 internal var rate = -1.0
@Expose @Expose
internal var scheduleName = "AAPS" internal var scheduleName = "AAPS"
@Expose @Expose
internal var clockDriftOffset: Long = 0 internal var clockDriftOffset: Long = 0
@Expose @Expose
internal var conversionOffset: Long = 0 internal var conversionOffset: Long = 0
init { init {
type = "basal" type = "basal"
timestamp = tbr.date timestamp = tbr.timestamp
rate = tbr.tempBasalConvertedToAbsolute(tbr.date, profileFunction.getProfile(tbr.date)) rate = tbr.convertedToAbsolute(tbr.timestamp, profile)
duration = tbr.end() - tbr.start() duration = tbr.duration
} }
} }

View file

@ -3,7 +3,7 @@ package info.nightscout.androidaps.plugins.general.tidepool.elements
import com.google.gson.annotations.Expose import com.google.gson.annotations.Expose
import info.nightscout.androidaps.utils.DateUtil import info.nightscout.androidaps.utils.DateUtil
open class BaseElement(timestamp: Long, uuid: String) { open class BaseElement(timestamp: Long, uuid: String, dateUtil: DateUtil) {
@Expose @Expose
var deviceTime: String = "" var deviceTime: String = ""
@Expose @Expose
@ -16,9 +16,9 @@ open class BaseElement(timestamp: Long, uuid: String) {
var origin: Origin? = null var origin: Origin? = null
init { init {
deviceTime = DateUtil.toISONoZone(timestamp) deviceTime = dateUtil.toISONoZone(timestamp)
time = DateUtil.toISOAsUTC(timestamp) time = dateUtil.toISOAsUTC(timestamp)
timezoneOffset = DateUtil.getTimeZoneOffsetMinutes(timestamp) // TODO timezoneOffset = dateUtil.getTimeZoneOffsetMinutes(timestamp) // TODO
origin = Origin(uuid) origin = Origin(uuid)
} }

View file

@ -3,11 +3,12 @@ package info.nightscout.androidaps.plugins.general.tidepool.elements
import com.google.gson.annotations.Expose import com.google.gson.annotations.Expose
import info.nightscout.androidaps.data.Profile import info.nightscout.androidaps.data.Profile
import info.nightscout.androidaps.database.entities.TherapyEvent 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.* import java.util.*
class BloodGlucoseElement(therapyEvent: TherapyEvent) class BloodGlucoseElement(therapyEvent: TherapyEvent, dateUtil: DateUtil)
: BaseElement(therapyEvent.timestamp, UUID.nameUUIDFromBytes(("AAPS-bg" + therapyEvent.timestamp).toByteArray()).toString()) { : BaseElement(therapyEvent.timestamp, UUID.nameUUIDFromBytes(("AAPS-bg" + therapyEvent.timestamp).toByteArray()).toString(), dateUtil) {
@Expose @Expose
var subType: String = "manual" var subType: String = "manual"
@ -28,13 +29,13 @@ class BloodGlucoseElement(therapyEvent: TherapyEvent)
companion object { companion object {
fun fromCareportalEvents(careportalList: List<TherapyEvent>): List<BloodGlucoseElement> { fun fromCareportalEvents(careportalList: List<TherapyEvent>, dateUtil: DateUtil): List<BloodGlucoseElement> {
val results = LinkedList<BloodGlucoseElement>() val results = LinkedList<BloodGlucoseElement>()
for (bt in careportalList) { for (bt in careportalList) {
if (bt.type == TherapyEvent.Type.NS_MBG || bt.type == TherapyEvent.Type.FINGER_STICK_BG_VALUE) { 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) if (bge.value > 0)
results.add(BloodGlucoseElement(bt)) results.add(BloodGlucoseElement(bt, dateUtil))
} }
} }
return results return results

View file

@ -2,10 +2,11 @@ package info.nightscout.androidaps.plugins.general.tidepool.elements
import com.google.gson.annotations.Expose import com.google.gson.annotations.Expose
import info.nightscout.androidaps.database.entities.Bolus import info.nightscout.androidaps.database.entities.Bolus
import info.nightscout.androidaps.utils.DateUtil
import java.util.* import java.util.*
class BolusElement(bolus: Bolus) class BolusElement(bolus: Bolus, dateUtil: DateUtil)
: BaseElement(bolus.timestamp, UUID.nameUUIDFromBytes(("AAPS-bolus" + bolus.timestamp).toByteArray()).toString()) { : BaseElement(bolus.timestamp, UUID.nameUUIDFromBytes(("AAPS-bolus" + bolus.timestamp).toByteArray()).toString(), dateUtil) {
@Expose var subType = "normal" @Expose var subType = "normal"
@Expose var normal: Double = 0.0 @Expose var normal: Double = 0.0

View file

@ -4,11 +4,12 @@ import com.google.gson.annotations.Expose
import info.nightscout.androidaps.data.Profile import info.nightscout.androidaps.data.Profile
import info.nightscout.androidaps.db.ProfileSwitch import info.nightscout.androidaps.db.ProfileSwitch
import info.nightscout.androidaps.plugins.general.tidepool.comm.TidepoolUploader import info.nightscout.androidaps.plugins.general.tidepool.comm.TidepoolUploader
import info.nightscout.androidaps.utils.DateUtil
import java.util.* import java.util.*
import kotlin.collections.ArrayList import kotlin.collections.ArrayList
class ProfileElement(ps: ProfileSwitch, serialNumber: String) class ProfileElement(ps: ProfileSwitch, serialNumber: String, dateUtil: DateUtil)
: BaseElement(ps.date, UUID.nameUUIDFromBytes(("AAPS-profile" + ps.date).toByteArray()).toString()) { : BaseElement(ps.date, UUID.nameUUIDFromBytes(("AAPS-profile" + ps.date).toByteArray()).toString(), dateUtil) {
@Expose @Expose
internal var activeSchedule = "Normal" internal var activeSchedule = "Normal"

View file

@ -2,10 +2,11 @@ package info.nightscout.androidaps.plugins.general.tidepool.elements
import com.google.gson.annotations.Expose import com.google.gson.annotations.Expose
import info.nightscout.androidaps.database.entities.GlucoseValue import info.nightscout.androidaps.database.entities.GlucoseValue
import info.nightscout.androidaps.utils.DateUtil
import java.util.* import java.util.*
class SensorGlucoseElement(bgReading: GlucoseValue) class SensorGlucoseElement(bgReading: GlucoseValue, private val dateUtil: DateUtil)
: BaseElement(bgReading.timestamp, UUID.nameUUIDFromBytes(("AAPS-cgm" + bgReading.timestamp).toByteArray()).toString()) { : BaseElement(bgReading.timestamp, UUID.nameUUIDFromBytes(("AAPS-cgm" + bgReading.timestamp).toByteArray()).toString(), dateUtil) {
@Expose @Expose
internal var units: String = "mg/dL" internal var units: String = "mg/dL"
@ -20,10 +21,10 @@ class SensorGlucoseElement(bgReading: GlucoseValue)
companion object { companion object {
internal fun fromBgReadings(bgReadingList: List<GlucoseValue>): List<SensorGlucoseElement> { internal fun fromBgReadings(bgReadingList: List<GlucoseValue>, dateUtil: DateUtil): List<SensorGlucoseElement> {
val results = LinkedList<SensorGlucoseElement>() val results = LinkedList<SensorGlucoseElement>()
for (bgReading in bgReadingList) { for (bgReading in bgReadingList) {
results.add(SensorGlucoseElement(bgReading)) results.add(SensorGlucoseElement(bgReading, dateUtil))
} }
return results return results
} }

View file

@ -3,10 +3,11 @@ package info.nightscout.androidaps.plugins.general.tidepool.elements
import com.google.gson.annotations.Expose import com.google.gson.annotations.Expose
import info.nightscout.androidaps.database.entities.Bolus import info.nightscout.androidaps.database.entities.Bolus
import info.nightscout.androidaps.database.entities.Carbs import info.nightscout.androidaps.database.entities.Carbs
import info.nightscout.androidaps.utils.DateUtil
import java.util.* import java.util.*
class WizardElement(carbs: Carbs) class WizardElement(carbs: Carbs, dateUtil: DateUtil)
: BaseElement(carbs.timestamp, UUID.nameUUIDFromBytes(("AAPS-wizard" + carbs.timestamp).toByteArray()).toString()) { : BaseElement(carbs.timestamp, UUID.nameUUIDFromBytes(("AAPS-wizard" + carbs.timestamp).toByteArray()).toString(), dateUtil) {
@Expose var units = "mg/dL" @Expose var units = "mg/dL"
@Expose var carbInput: Double = 0.toDouble() @Expose var carbInput: Double = 0.toDouble()
@ -19,10 +20,9 @@ class WizardElement(carbs: Carbs)
val fake = Bolus( val fake = Bolus(
amount = 0.0001, amount = 0.0001,
timestamp = carbs.timestamp, timestamp = carbs.timestamp,
type = Bolus.Type.NORMAL, type = Bolus.Type.NORMAL
isBasalInsulin = false
) )
bolus = BolusElement(fake) // fake insulin record bolus = BolusElement(fake, dateUtil) // fake insulin record
} }
} }

View file

@ -1,12 +1,12 @@
package info.nightscout.androidaps.plugins.general.tidepool.events package info.nightscout.androidaps.plugins.general.tidepool.events
import info.nightscout.androidaps.events.Event import info.nightscout.androidaps.events.Event
import info.nightscout.androidaps.utils.DateUtil
import java.text.SimpleDateFormat import java.text.SimpleDateFormat
import java.util.* import java.util.*
class EventTidepoolStatus(val status: String) : Event() { 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()) private var timeFormat = SimpleDateFormat("HH:mm:ss", Locale.getDefault())

View file

@ -7,46 +7,62 @@ import info.nightscout.androidaps.utils.DateUtil
import info.nightscout.androidaps.utils.T import info.nightscout.androidaps.utils.T
import java.util.* import java.util.*
class OpenDatasetRequestMessage (val serialNumber : String): BaseMessage() { class OpenDatasetRequestMessage(serialNumber: String, dateUtil: DateUtil) : BaseMessage() {
@Expose @Expose
var deviceId: String = TidepoolUploader.PUMP_TYPE + ":" + serialNumber var deviceId: String = TidepoolUploader.PUMP_TYPE + ":" + serialNumber
@Expose @Expose
var time: String = DateUtil.toISOAsUTC(DateUtil.now()) var time: String = dateUtil.toISOAsUTC(System.currentTimeMillis())
@Expose @Expose
var timezoneOffset = (DateUtil.getTimeZoneOffsetMs() / T.mins(1).msecs()).toInt() var timezoneOffset = (dateUtil.getTimeZoneOffsetMs() / T.mins(1).msecs()).toInt()
@Expose @Expose
var type = "upload" var type = "upload"
//public String byUser; //public String byUser;
@Expose @Expose
var client = ClientInfo() var client = ClientInfo()
@Expose @Expose
var computerTime: String = DateUtil.toISONoZone(DateUtil.now()) var computerTime: String = dateUtil.toISONoZone(System.currentTimeMillis())
@Expose @Expose
var dataSetType = "continuous" var dataSetType = "continuous"
@Expose @Expose
var deviceManufacturers = arrayOf(TidepoolUploader.PUMP_TYPE) var deviceManufacturers = arrayOf(TidepoolUploader.PUMP_TYPE)
@Expose @Expose
var deviceModel = TidepoolUploader.PUMP_TYPE var deviceModel = TidepoolUploader.PUMP_TYPE
@Expose @Expose
var deviceTags = arrayOf("bgm", "cgm", "insulin-pump") var deviceTags = arrayOf("bgm", "cgm", "insulin-pump")
@Expose @Expose
var deduplicator = Deduplicator() var deduplicator = Deduplicator()
@Expose @Expose
var timeProcessing = "none" var timeProcessing = "none"
@Expose @Expose
var timezone: String = TimeZone.getDefault().id var timezone: String = TimeZone.getDefault().id
@Expose @Expose
var version = BuildConfig.VERSION_NAME var version = BuildConfig.VERSION_NAME
inner class ClientInfo { inner class ClientInfo {
@Expose @Expose
val name = BuildConfig.APPLICATION_ID val name = BuildConfig.APPLICATION_ID
@Expose @Expose
val version = TidepoolUploader.VERSION val version = TidepoolUploader.VERSION
} }
inner class Deduplicator { inner class Deduplicator {
@Expose @Expose
val name = "org.tidepool.deduplicator.dataset.delete.origin" val name = "org.tidepool.deduplicator.dataset.delete.origin"
} }

View file

@ -21,13 +21,13 @@ class RateLimit @Inject constructor(
fun rateLimit(name: String, seconds: Int): Boolean { fun rateLimit(name: String, seconds: Int): Boolean {
// check if over limit // check if over limit
rateLimits[name]?.let { 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") aapsLogger.debug(LTag.TIDEPOOL, "$name rate limited: $seconds seconds")
return false return false
} }
} }
// not over limit // not over limit
rateLimits[name] = dateUtil._now() rateLimits[name] = dateUtil.now()
return true return true
} }
} }

View file

@ -16,24 +16,27 @@ import info.nightscout.androidaps.data.Profile
import info.nightscout.androidaps.database.AppRepository import info.nightscout.androidaps.database.AppRepository
import info.nightscout.androidaps.database.ValueWrapper import info.nightscout.androidaps.database.ValueWrapper
import info.nightscout.androidaps.database.entities.TemporaryTarget import info.nightscout.androidaps.database.entities.TemporaryTarget
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.interfaces.end
import info.nightscout.androidaps.database.transactions.CancelCurrentTemporaryTargetIfAnyTransaction import info.nightscout.androidaps.database.transactions.CancelCurrentTemporaryTargetIfAnyTransaction
import info.nightscout.androidaps.database.transactions.InsertTemporaryTargetAndCancelCurrentTransaction import info.nightscout.androidaps.database.transactions.InsertTemporaryTargetAndCancelCurrentTransaction
import info.nightscout.androidaps.db.TDD import info.nightscout.androidaps.db.TDD
import info.nightscout.androidaps.extensions.valueToUnits
import info.nightscout.androidaps.interfaces.* import info.nightscout.androidaps.interfaces.*
import info.nightscout.androidaps.logging.AAPSLogger import info.nightscout.androidaps.logging.AAPSLogger
import info.nightscout.androidaps.logging.LTag 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.aps.loop.LoopPlugin
import info.nightscout.androidaps.plugins.bus.RxBusWrapper import info.nightscout.androidaps.plugins.bus.RxBusWrapper
import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker
import info.nightscout.androidaps.plugins.general.overview.events.EventDismissNotification 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.EventWearConfirmAction
import info.nightscout.androidaps.plugins.general.wear.events.EventWearInitiateAction 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.pump.insight.LocalInsightPlugin
import info.nightscout.androidaps.queue.Callback import info.nightscout.androidaps.queue.Callback
import info.nightscout.androidaps.utils.* import info.nightscout.androidaps.utils.*
import info.nightscout.androidaps.utils.extensions.valueToUnits
import info.nightscout.androidaps.utils.resources.ResourceHelper import info.nightscout.androidaps.utils.resources.ResourceHelper
import info.nightscout.androidaps.utils.rx.AapsSchedulers import info.nightscout.androidaps.utils.rx.AapsSchedulers
import info.nightscout.androidaps.utils.sharedPreferences.SP import info.nightscout.androidaps.utils.sharedPreferences.SP
@ -67,7 +70,7 @@ class ActionStringHandler @Inject constructor(
private val fabricPrivacy: FabricPrivacy, private val fabricPrivacy: FabricPrivacy,
private val commandQueue: CommandQueueProvider, private val commandQueue: CommandQueueProvider,
private val activePlugin: ActivePluginProvider, private val activePlugin: ActivePluginProvider,
private val iobCobCalculatorPlugin: IobCobCalculatorPlugin, private val iobCobCalculator: IobCobCalculator,
private val localInsightPlugin: LocalInsightPlugin, private val localInsightPlugin: LocalInsightPlugin,
private val danaRPlugin: DanaRPlugin, private val danaRPlugin: DanaRPlugin,
private val danaRKoreanPlugin: DanaRKoreanPlugin, private val danaRKoreanPlugin: DanaRKoreanPlugin,
@ -77,7 +80,8 @@ class ActionStringHandler @Inject constructor(
private val dateUtil: DateUtil, private val dateUtil: DateUtil,
private val config: Config, private val config: Config,
private val databaseHelper: DatabaseHelperInterface, private val databaseHelper: DatabaseHelperInterface,
private val repository: AppRepository private val repository: AppRepository,
private val uel: UserEntryLogger
) { ) {
private val timeout = 65 * 1000 private val timeout = 65 * 1000
@ -203,19 +207,19 @@ class ActionStringHandler @Inject constructor(
sendError("No profile found!") sendError("No profile found!")
return return
} }
val bgReading = iobCobCalculatorPlugin.actualBg() val bgReading = iobCobCalculator.ads.actualBg()
if (bgReading == null) { if (bgReading == null) {
sendError("No recent BG to base calculation on!") sendError("No recent BG to base calculation on!")
return return
} }
val cobInfo = iobCobCalculatorPlugin.getCobInfo(false, "Wizard wear") val cobInfo = iobCobCalculator.getCobInfo(false, "Wizard wear")
if (cobInfo.displayCob == null) { if (cobInfo.displayCob == null) {
sendError("Unknown COB! BG reading missing or recent app restart?") sendError("Unknown COB! BG reading missing or recent app restart?")
return return
} }
val format = DecimalFormat("0.00") val format = DecimalFormat("0.00")
val formatInt = DecimalFormat("0") 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 tempTarget = if (dbRecord is ValueWrapper.Existing) dbRecord.value else null
val bolusWizard = BolusWizard(injector).doCalc(profile, profileName, tempTarget, val bolusWizard = BolusWizard(injector).doCalc(profile, profileName, tempTarget,
@ -452,7 +456,7 @@ class ActionStringHandler @Inject constructor(
} }
val profile = profileFunction.getProfile() ?: return "No profile set :(" val profile = profileFunction.getProfile() ?: return "No profile set :("
//Check for Temp-Target: //Check for Temp-Target:
val tempTarget = repository.getTemporaryTargetActiveAt(dateUtil._now()).blockingGet() val tempTarget = repository.getTemporaryTargetActiveAt(dateUtil.now()).blockingGet()
if (tempTarget is ValueWrapper.Existing) { if (tempTarget is ValueWrapper.Existing) {
ret += "Temp Target: " + Profile.toTargetRangeString(tempTarget.value.lowTarget, tempTarget.value.lowTarget, Constants.MGDL, profileFunction.getUnits()) ret += "Temp Target: " + Profile.toTargetRangeString(tempTarget.value.lowTarget, tempTarget.value.lowTarget, Constants.MGDL, profileFunction.getUnits())
ret += "\nuntil: " + dateUtil.timeString(tempTarget.value.end) ret += "\nuntil: " + dateUtil.timeString(tempTarget.value.end)
@ -564,11 +568,14 @@ class ActionStringHandler @Inject constructor(
return return
} }
//send profile to pump //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) activePlugin.activeTreatments.doProfileSwitch(0, percentage, timeshift)
} }
private fun generateTempTarget(duration: Int, low: Double, high: Double) { private fun generateTempTarget(duration: Int, low: Double, high: Double) {
if (duration != 0) if (duration != 0) {
disposable += repository.runTransactionForResult(InsertTemporaryTargetAndCancelCurrentTransaction( disposable += repository.runTransactionForResult(InsertTemporaryTargetAndCancelCurrentTransaction(
timestamp = System.currentTimeMillis(), timestamp = System.currentTimeMillis(),
duration = TimeUnit.MINUTES.toMillis(duration.toLong()), duration = TimeUnit.MINUTES.toMillis(duration.toLong()),
@ -581,19 +588,29 @@ class ActionStringHandler @Inject constructor(
}, { }, {
aapsLogger.error(LTag.DATABASE, "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())) disposable += repository.runTransactionForResult(CancelCurrentTemporaryTargetIfAnyTransaction(System.currentTimeMillis()))
.subscribe({ result -> .subscribe({ result ->
result.updated.forEach { aapsLogger.debug(LTag.DATABASE, "Updated temp target $it") } result.updated.forEach { aapsLogger.debug(LTag.DATABASE, "Updated temp target $it") }
}, { }, {
aapsLogger.error(LTag.DATABASE, "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) { private fun doFillBolus(amount: Double) {
val detailedBolusInfo = DetailedBolusInfo() val detailedBolusInfo = DetailedBolusInfo()
detailedBolusInfo.insulin = amount detailedBolusInfo.insulin = amount
detailedBolusInfo.bolusType = DetailedBolusInfo.BolusType.PRIMING detailedBolusInfo.bolusType = DetailedBolusInfo.BolusType.PRIMING
uel.log(Action.PRIME_BOLUS, Sources.Wear,
ValueWithUnit.Insulin(amount).takeIf { amount != 0.0 })
commandQueue.bolus(detailedBolusInfo, object : Callback() { commandQueue.bolus(detailedBolusInfo, object : Callback() {
override fun run() { override fun run() {
if (!result.success) { if (!result.success) {
@ -606,6 +623,10 @@ class ActionStringHandler @Inject constructor(
} }
private fun doECarbs(carbs: Int, time: Long, duration: 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) doBolus(0.0, carbs, time, duration)
} }
@ -617,6 +638,16 @@ class ActionStringHandler @Inject constructor(
detailedBolusInfo.carbsTimestamp = carbsTime detailedBolusInfo.carbsTimestamp = carbsTime
detailedBolusInfo.carbsDuration = T.hours(carbsDuration.toLong()).msecs() detailedBolusInfo.carbsDuration = T.hours(carbsDuration.toLong()).msecs()
if (detailedBolusInfo.insulin > 0 || detailedBolusInfo.carbs > 0) { 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() { commandQueue.bolus(detailedBolusInfo, object : Callback() {
override fun run() { override fun run() {
if (!result.success) { if (!result.success) {

View file

@ -32,13 +32,14 @@ import dagger.android.AndroidInjection;
import info.nightscout.androidaps.Config; import info.nightscout.androidaps.Config;
import info.nightscout.androidaps.Constants; import info.nightscout.androidaps.Constants;
import info.nightscout.androidaps.R; import info.nightscout.androidaps.R;
import info.nightscout.androidaps.plugins.general.overview.graphExtensions.GlucoseValueDataPoint;
import info.nightscout.androidaps.data.IobTotal; import info.nightscout.androidaps.data.IobTotal;
import info.nightscout.androidaps.data.Profile; import info.nightscout.androidaps.data.Profile;
import info.nightscout.androidaps.database.AppRepository; import info.nightscout.androidaps.database.AppRepository;
import info.nightscout.androidaps.database.entities.Bolus; import info.nightscout.androidaps.database.entities.Bolus;
import info.nightscout.androidaps.database.entities.GlucoseValue; import info.nightscout.androidaps.database.entities.GlucoseValue;
import info.nightscout.androidaps.db.TemporaryBasal; import info.nightscout.androidaps.database.entities.TemporaryBasal;
import info.nightscout.androidaps.extensions.GlucoseValueExtensionKt;
import info.nightscout.androidaps.extensions.TemporaryBasalExtensionKt;
import info.nightscout.androidaps.interfaces.ActivePluginProvider; import info.nightscout.androidaps.interfaces.ActivePluginProvider;
import info.nightscout.androidaps.interfaces.IobCobCalculator; import info.nightscout.androidaps.interfaces.IobCobCalculator;
import info.nightscout.androidaps.interfaces.PluginType; import info.nightscout.androidaps.interfaces.PluginType;
@ -48,17 +49,16 @@ import info.nightscout.androidaps.logging.LTag;
import info.nightscout.androidaps.plugins.aps.loop.LoopPlugin; import info.nightscout.androidaps.plugins.aps.loop.LoopPlugin;
import info.nightscout.androidaps.plugins.bus.RxBusWrapper; import info.nightscout.androidaps.plugins.bus.RxBusWrapper;
import info.nightscout.androidaps.plugins.general.nsclient.data.NSDeviceStatus; 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.WearPlugin;
import info.nightscout.androidaps.plugins.general.wear.events.EventWearConfirmAction; import info.nightscout.androidaps.plugins.general.wear.events.EventWearConfirmAction;
import info.nightscout.androidaps.plugins.general.wear.events.EventWearInitiateAction; import info.nightscout.androidaps.plugins.general.wear.events.EventWearInitiateAction;
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.GlucoseStatus; import info.nightscout.androidaps.plugins.iob.iobCobCalculator.GlucoseStatus;
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.GlucoseStatusProvider; import info.nightscout.androidaps.plugins.iob.iobCobCalculator.GlucoseStatusProvider;
import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin;
import info.nightscout.androidaps.receivers.ReceiverStatusStore; import info.nightscout.androidaps.receivers.ReceiverStatusStore;
import info.nightscout.androidaps.utils.DecimalFormatter; import info.nightscout.androidaps.utils.DecimalFormatter;
import info.nightscout.androidaps.utils.DefaultValueHelper; import info.nightscout.androidaps.utils.DefaultValueHelper;
import info.nightscout.androidaps.utils.ToastUtils; import info.nightscout.androidaps.utils.ToastUtils;
import info.nightscout.androidaps.utils.extensions.GlucoseValueExtensionKt;
import info.nightscout.androidaps.utils.resources.ResourceHelper; import info.nightscout.androidaps.utils.resources.ResourceHelper;
import info.nightscout.androidaps.utils.sharedPreferences.SP; import info.nightscout.androidaps.utils.sharedPreferences.SP;
@ -75,7 +75,6 @@ public class WatchUpdaterService extends WearableListenerService implements Goog
@Inject public ActivePluginProvider activePlugin; @Inject public ActivePluginProvider activePlugin;
@Inject public LoopPlugin loopPlugin; @Inject public LoopPlugin loopPlugin;
@Inject public IobCobCalculator iobCobCalculator; @Inject public IobCobCalculator iobCobCalculator;
@Inject public TreatmentsPlugin treatmentsPlugin;
@Inject public AppRepository repository; @Inject public AppRepository repository;
@Inject ReceiverStatusStore receiverStatusStore; @Inject ReceiverStatusStore receiverStatusStore;
@Inject Config config; @Inject Config config;
@ -280,7 +279,7 @@ public class WatchUpdaterService extends WearableListenerService implements Goog
private void sendData() { private void sendData() {
GlucoseValue lastBG = iobCobCalculator.lastBg(); GlucoseValue lastBG = iobCobCalculator.getAds().lastBg();
// Log.d(TAG, logPrefix + "LastBg=" + lastBG); // Log.d(TAG, logPrefix + "LastBg=" + lastBG);
if (lastBG != null) { if (lastBG != null) {
GlucoseStatus glucoseStatus = glucoseStatusProvider.getGlucoseStatusData(); GlucoseStatus glucoseStatus = glucoseStatusProvider.getGlucoseStatusData();
@ -382,7 +381,7 @@ public class WatchUpdaterService extends WearableListenerService implements Goog
googleApiConnect(); googleApiConnect();
} }
long startTime = System.currentTimeMillis() - (long) (60000 * 60 * 5.5); long startTime = System.currentTimeMillis() - (long) (60000 * 60 * 5.5);
GlucoseValue last_bg = iobCobCalculator.lastBg(); GlucoseValue last_bg = iobCobCalculator.getAds().lastBg();
if (last_bg == null) return; if (last_bg == null) return;
@ -437,8 +436,8 @@ public class WatchUpdaterService extends WearableListenerService implements Goog
double beginBasalValue = profile.getBasal(beginBasalSegmentTime); double beginBasalValue = profile.getBasal(beginBasalSegmentTime);
double endBasalValue = beginBasalValue; double endBasalValue = beginBasalValue;
TemporaryBasal tb1 = treatmentsPlugin.getTempBasalFromHistory(runningTime); TemporaryBasal tb1 = iobCobCalculator.getTempBasalIncludingConvertedExtended(runningTime);
TemporaryBasal tb2 = treatmentsPlugin.getTempBasalFromHistory(runningTime); //TODO for Adrian ... what's the meaning? TemporaryBasal tb2 = iobCobCalculator.getTempBasalIncludingConvertedExtended(runningTime); //TODO for Adrian ... what's the meaning?
double tb_before = beginBasalValue; double tb_before = beginBasalValue;
double tb_amount = beginBasalValue; double tb_amount = beginBasalValue;
long tb_start = runningTime; long tb_start = runningTime;
@ -447,7 +446,7 @@ public class WatchUpdaterService extends WearableListenerService implements Goog
tb_before = beginBasalValue; tb_before = beginBasalValue;
Profile profileTB = profileFunction.getProfile(runningTime); Profile profileTB = profileFunction.getProfile(runningTime);
if (profileTB != null) { if (profileTB != null) {
tb_amount = tb1.tempBasalConvertedToAbsolute(runningTime, profileTB); tb_amount = TemporaryBasalExtensionKt.convertedToAbsolute(tb1, runningTime, profileTB);
tb_start = runningTime; tb_start = runningTime;
} }
} }
@ -469,7 +468,7 @@ public class WatchUpdaterService extends WearableListenerService implements Goog
} }
//temps //temps
tb2 = treatmentsPlugin.getTempBasalFromHistory(runningTime); tb2 = iobCobCalculator.getTempBasalIncludingConvertedExtended(runningTime);
if (tb1 == null && tb2 == null) { if (tb1 == null && tb2 == null) {
//no temp stays no temp //no temp stays no temp
@ -484,10 +483,10 @@ public class WatchUpdaterService extends WearableListenerService implements Goog
tb1 = tb2; tb1 = tb2;
tb_start = runningTime; tb_start = runningTime;
tb_before = endBasalValue; tb_before = endBasalValue;
tb_amount = tb1.tempBasalConvertedToAbsolute(runningTime, profileTB); tb_amount = TemporaryBasalExtensionKt.convertedToAbsolute(tb1, runningTime, profileTB);
} else if (tb1 != null && tb2 != null) { } else if (tb1 != null && tb2 != null) {
double currentAmount = tb2.tempBasalConvertedToAbsolute(runningTime, profileTB); double currentAmount = TemporaryBasalExtensionKt.convertedToAbsolute(tb2, runningTime, profileTB);
if (currentAmount != tb_amount) { if (currentAmount != tb_amount) {
temps.add(tempDatamap(tb_start, tb_before, runningTime, currentAmount, tb_amount)); temps.add(tempDatamap(tb_start, tb_before, runningTime, currentAmount, tb_amount));
tb_start = runningTime; tb_start = runningTime;
@ -502,14 +501,14 @@ public class WatchUpdaterService extends WearableListenerService implements Goog
basals.add(basalMap(beginBasalSegmentTime, runningTime, beginBasalValue)); basals.add(basalMap(beginBasalSegmentTime, runningTime, beginBasalValue));
} }
if (tb1 != null) { 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) { if (tb2 == null) {
//express the cancelled temp by painting it down one minute early //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)); temps.add(tempDatamap(tb_start, tb_before, now - 1 * 60 * 1000, endBasalValue, tb_amount));
} else { } else {
//express currently running temp by painting it a bit into the future //express currently running temp by painting it a bit into the future
Profile profileNow = profileFunction.getProfile(now); Profile profileNow = profileFunction.getProfile(now);
double currentAmount = tb2.tempBasalConvertedToAbsolute(now, profileNow); double currentAmount = TemporaryBasalExtensionKt.convertedToAbsolute(tb2, now, profileNow);
if (currentAmount != tb_amount) { if (currentAmount != tb_amount) {
temps.add(tempDatamap(tb_start, tb_before, now, tb_amount, 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)); temps.add(tempDatamap(now, tb_amount, runningTime + 5 * 60 * 1000, currentAmount, currentAmount));
@ -518,11 +517,11 @@ public class WatchUpdaterService extends WearableListenerService implements Goog
} }
} }
} else { } else {
tb2 = treatmentsPlugin.getTempBasalFromHistory(now); //use "now" to express current situation tb2 = iobCobCalculator.getTempBasalIncludingConvertedExtended(now); //use "now" to express current situation
if (tb2 != null) { if (tb2 != null) {
//onset at the end //onset at the end
Profile profileTB = profileFunction.getProfile(runningTime); 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)); temps.add(tempDatamap(now - 1 * 60 * 1000, endBasalValue, runningTime + 5 * 60 * 1000, currentAmount, currentAmount));
} }
} }
@ -688,7 +687,7 @@ public class WatchUpdaterService extends WearableListenerService implements Goog
iobSum = iobDetail = cobString = currentBasal = bgiString = ""; iobSum = iobDetail = cobString = currentBasal = bgiString = "";
if (profile != null) { if (profile != null) {
IobTotal bolusIob = iobCobCalculator.calculateIobFromBolus().round(); IobTotal bolusIob = iobCobCalculator.calculateIobFromBolus().round();
IobTotal basalIob = treatmentsPlugin.getLastCalculationTempBasals().round(); IobTotal basalIob = iobCobCalculator.calculateIobFromTempBasalsIncludingConvertedExtended().round();
iobSum = DecimalFormatter.INSTANCE.to2Decimal(bolusIob.iob + basalIob.basaliob); iobSum = DecimalFormatter.INSTANCE.to2Decimal(bolusIob.iob + basalIob.basaliob);
iobDetail = "(" + DecimalFormatter.INSTANCE.to2Decimal(bolusIob.iob) + "|" + DecimalFormatter.INSTANCE.to2Decimal(basalIob.basaliob) + ")"; iobDetail = "(" + DecimalFormatter.INSTANCE.to2Decimal(bolusIob.iob) + "|" + DecimalFormatter.INSTANCE.to2Decimal(basalIob.basaliob) + ")";
@ -798,16 +797,12 @@ public class WatchUpdaterService extends WearableListenerService implements Goog
if (profile == null) if (profile == null)
return ""; return "";
TemporaryBasal activeTemp = treatmentsPlugin.getTempBasalFromHistory(System.currentTimeMillis()); TemporaryBasal activeTemp = iobCobCalculator.getTempBasalIncludingConvertedExtended(System.currentTimeMillis());
if (activeTemp != null) { if (activeTemp != null) {
basalStringResult = activeTemp.toStringShort(); basalStringResult = TemporaryBasalExtensionKt.toStringShort(activeTemp);
} else {
if (sp.getBoolean(R.string.key_danar_visualizeextendedaspercentage, false)) {
basalStringResult = "100%";
} else { } else {
basalStringResult = DecimalFormatter.INSTANCE.to2Decimal(profile.getBasal()) + "U/h"; basalStringResult = DecimalFormatter.INSTANCE.to2Decimal(profile.getBasal()) + "U/h";
} }
}
return basalStringResult; return basalStringResult;
} }

View file

@ -13,6 +13,7 @@ import info.nightscout.androidaps.plugins.aps.loop.LoopPlugin
import info.nightscout.androidaps.plugins.bus.RxBusWrapper import info.nightscout.androidaps.plugins.bus.RxBusWrapper
import info.nightscout.androidaps.utils.DecimalFormatter import info.nightscout.androidaps.utils.DecimalFormatter
import info.nightscout.androidaps.utils.FabricPrivacy import info.nightscout.androidaps.utils.FabricPrivacy
import info.nightscout.androidaps.extensions.toStringShort
import info.nightscout.androidaps.utils.resources.ResourceHelper import info.nightscout.androidaps.utils.resources.ResourceHelper
import info.nightscout.androidaps.utils.rx.AapsSchedulers import info.nightscout.androidaps.utils.rx.AapsSchedulers
import info.nightscout.androidaps.utils.sharedPreferences.SP import info.nightscout.androidaps.utils.sharedPreferences.SP
@ -121,13 +122,13 @@ class StatusLinePlugin @Inject constructor(
lastLoopStatus = true lastLoopStatus = true
} }
//Temp basal //Temp basal
val activeTemp = activePlugin.activeTreatments.getTempBasalFromHistory(System.currentTimeMillis()) val activeTemp = iobCobCalculator.getTempBasalIncludingConvertedExtended(System.currentTimeMillis())
if (activeTemp != null) { if (activeTemp != null) {
status += activeTemp.toStringShort() + " " status += activeTemp.toStringShort() + " "
} }
//IOB //IOB
val bolusIob = iobCobCalculator.calculateIobFromBolus().round() val bolusIob = iobCobCalculator.calculateIobFromBolus().round()
val basalIob = activePlugin.activeTreatments.lastCalculationTempBasals.round() val basalIob = iobCobCalculator.calculateIobFromTempBasalsIncludingConvertedExtended().round()
status += DecimalFormatter.to2Decimal(bolusIob.iob + basalIob.basaliob) + "U" status += DecimalFormatter.to2Decimal(bolusIob.iob + basalIob.basaliob) + "U"
if (sp.getBoolean(R.string.key_xdripstatus_detailediob, true)) { if (sp.getBoolean(R.string.key_xdripstatus_detailediob, true)) {
status += ("(" status += ("("

View file

@ -25,8 +25,7 @@ class ActivityGraph : GraphView {
val bolus = Bolus( val bolus = Bolus(
timestamp = 0, timestamp = 0,
amount = 1.0, amount = 1.0,
type = Bolus.Type.NORMAL, type = Bolus.Type.NORMAL
isBasalInsulin = false
) )
val activityArray: MutableList<DataPoint> = ArrayList() val activityArray: MutableList<DataPoint> = ArrayList()
val iobArray: MutableList<DataPoint> = ArrayList() val iobArray: MutableList<DataPoint> = ArrayList()

View file

@ -6,8 +6,8 @@ import info.nightscout.androidaps.interfaces.InsulinInterface
import info.nightscout.androidaps.interfaces.ProfileFunction import info.nightscout.androidaps.interfaces.ProfileFunction
import info.nightscout.androidaps.logging.AAPSLogger import info.nightscout.androidaps.logging.AAPSLogger
import info.nightscout.androidaps.plugins.bus.RxBusWrapper import info.nightscout.androidaps.plugins.bus.RxBusWrapper
import info.nightscout.androidaps.utils.extensions.storeInt import info.nightscout.androidaps.extensions.storeInt
import info.nightscout.androidaps.utils.extensions.putInt import info.nightscout.androidaps.extensions.putInt
import info.nightscout.androidaps.utils.resources.ResourceHelper import info.nightscout.androidaps.utils.resources.ResourceHelper
import info.nightscout.androidaps.utils.sharedPreferences.SP import info.nightscout.androidaps.utils.sharedPreferences.SP
import org.json.JSONObject import org.json.JSONObject

View file

@ -1,9 +1,2 @@
package info.nightscout.androidaps.plugins.iob.iobCobCalculator 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
}

View file

@ -9,38 +9,39 @@ import info.nightscout.androidaps.data.IobTotal
import info.nightscout.androidaps.data.MealData import info.nightscout.androidaps.data.MealData
import info.nightscout.androidaps.data.Profile import info.nightscout.androidaps.data.Profile
import info.nightscout.androidaps.database.AppRepository 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.Bolus
import info.nightscout.androidaps.database.entities.GlucoseValue import info.nightscout.androidaps.database.entities.ExtendedBolus
import info.nightscout.androidaps.db.TemporaryBasal import info.nightscout.androidaps.database.entities.TemporaryBasal
import info.nightscout.androidaps.database.interfaces.end
import info.nightscout.androidaps.events.* 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.interfaces.*
import info.nightscout.androidaps.logging.AAPSLogger import info.nightscout.androidaps.logging.AAPSLogger
import info.nightscout.androidaps.logging.LTag import info.nightscout.androidaps.logging.LTag
import info.nightscout.androidaps.plugins.bus.RxBusWrapper import info.nightscout.androidaps.plugins.bus.RxBusWrapper
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.data.AutosensData 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.iob.iobCobCalculator.events.EventNewHistoryData
import info.nightscout.androidaps.plugins.sensitivity.SensitivityAAPSPlugin import info.nightscout.androidaps.plugins.sensitivity.SensitivityAAPSPlugin
import info.nightscout.androidaps.plugins.sensitivity.SensitivityOref1Plugin import info.nightscout.androidaps.plugins.sensitivity.SensitivityOref1Plugin
import info.nightscout.androidaps.plugins.sensitivity.SensitivityWeightedAveragePlugin 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.DateUtil
import info.nightscout.androidaps.utils.DecimalFormatter import info.nightscout.androidaps.utils.DecimalFormatter
import info.nightscout.androidaps.utils.FabricPrivacy import info.nightscout.androidaps.utils.FabricPrivacy
import info.nightscout.androidaps.utils.T import info.nightscout.androidaps.utils.T
import info.nightscout.androidaps.utils.extensions.iobCalc
import info.nightscout.androidaps.utils.resources.ResourceHelper import info.nightscout.androidaps.utils.resources.ResourceHelper
import info.nightscout.androidaps.utils.rx.AapsSchedulers import info.nightscout.androidaps.utils.rx.AapsSchedulers
import info.nightscout.androidaps.utils.sharedPreferences.SP import info.nightscout.androidaps.utils.sharedPreferences.SP
import io.reactivex.disposables.CompositeDisposable import io.reactivex.disposables.CompositeDisposable
import io.reactivex.rxkotlin.plusAssign
import org.json.JSONArray import org.json.JSONArray
import java.util.concurrent.TimeUnit
import javax.inject.Inject import javax.inject.Inject
import javax.inject.Singleton import javax.inject.Singleton
import kotlin.math.abs
import kotlin.math.floor import kotlin.math.floor
import kotlin.math.max import kotlin.math.max
import kotlin.math.roundToLong import kotlin.math.min
@Singleton @Singleton
open class IobCobCalculatorPlugin @Inject constructor( open class IobCobCalculatorPlugin @Inject constructor(
@ -52,7 +53,6 @@ open class IobCobCalculatorPlugin @Inject constructor(
resourceHelper: ResourceHelper, resourceHelper: ResourceHelper,
private val profileFunction: ProfileFunction, private val profileFunction: ProfileFunction,
private val activePlugin: ActivePluginProvider, private val activePlugin: ActivePluginProvider,
private val treatmentsPlugin: TreatmentsPlugin,
private val sensitivityOref1Plugin: SensitivityOref1Plugin, private val sensitivityOref1Plugin: SensitivityOref1Plugin,
private val sensitivityAAPSPlugin: SensitivityAAPSPlugin, private val sensitivityAAPSPlugin: SensitivityAAPSPlugin,
private val sensitivityWeightedAveragePlugin: SensitivityWeightedAveragePlugin, private val sensitivityWeightedAveragePlugin: SensitivityWeightedAveragePlugin,
@ -69,61 +69,31 @@ open class IobCobCalculatorPlugin @Inject constructor(
), IobCobCalculator { ), IobCobCalculator {
private val disposable = CompositeDisposable() private val disposable = CompositeDisposable()
private var iobTable = LongSparseArray<IobTotal?>() // oldest at index 0
private var absIobTable = LongSparseArray<IobTotal?>() // oldest at index 0, absolute insulin in the body
private var autosensDataTable = LongSparseArray<AutosensData>() // oldest at index 0
private var basalDataTable = LongSparseArray<BasalData>() // oldest at index 0
@Volatile override var bgReadings: List<GlucoseValue> = listOf() // newest at index 0
@Volatile var bucketedData: MutableList<InMemoryGlucoseValue>? = null
// we need to make sure that bucketed_data will always have the same timestamp for correct use of cached values private var iobTable = LongSparseArray<IobTotal>() // oldest at index 0
// once referenceTime != null all bucketed data should be (x * 5min) from referenceTime private var absIobTable = LongSparseArray<IobTotal>() // oldest at index 0, absolute insulin in the body
var referenceTime: Long = -1 private var basalDataTable = LongSparseArray<BasalData>() // oldest at index 0
private var lastUsed5minCalculation: Boolean? = null // true if used 5min bucketed data
override val dataLock = Any() override var ads: AutosensDataStore = AutosensDataStore()
private val dataLock = Any()
var stopCalculationTrigger = false var stopCalculationTrigger = false
private var thread: Thread? = null private var thread: Thread? = null
override fun onStart() { override fun onStart() {
super.onStart() super.onStart()
// EventConfigBuilderChange // EventConfigBuilderChange
disposable.add(rxBus disposable += rxBus
.toObservable(EventConfigBuilderChange::class.java) .toObservable(EventConfigBuilderChange::class.java)
.observeOn(aapsSchedulers.io) .observeOn(aapsSchedulers.io)
.subscribe({ event -> .subscribe({ event -> resetDataAndRunCalculation("onEventConfigBuilderChange", event) }, fabricPrivacy::logException)
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)
)
// EventNewBasalProfile // EventNewBasalProfile
disposable.add(rxBus disposable += rxBus
.toObservable(EventNewBasalProfile::class.java) .toObservable(EventNewBasalProfile::class.java)
.observeOn(aapsSchedulers.io) .observeOn(aapsSchedulers.io)
.subscribe({ event -> .subscribe({ event -> resetDataAndRunCalculation("onNewProfile", event) }, fabricPrivacy::logException)
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)
)
// EventPreferenceChange // EventPreferenceChange
disposable.add(rxBus disposable += rxBus
.toObservable(EventPreferenceChange::class.java) .toObservable(EventPreferenceChange::class.java)
.observeOn(aapsSchedulers.io) .observeOn(aapsSchedulers.io)
.subscribe({ event -> .subscribe({ event ->
@ -135,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_max) ||
event.isChanged(resourceHelper, R.string.key_openapsama_autosens_min) || event.isChanged(resourceHelper, R.string.key_openapsama_autosens_min) ||
event.isChanged(resourceHelper, R.string.key_insulin_oref_peak)) { event.isChanged(resourceHelper, R.string.key_insulin_oref_peak)) {
stopCalculation("onEventPreferenceChange") resetDataAndRunCalculation("onEventPreferenceChange", event)
synchronized(dataLock) {
aapsLogger.debug(LTag.AUTOSENS, "Invalidating cached data because of preference change.")
resetData()
}
runCalculation("onEventPreferenceChange", System.currentTimeMillis(), bgDataReload = false, limitDataToOldestAvailable = true, cause = event)
} }
}, fabricPrivacy::logException) }, fabricPrivacy::logException)
)
// EventAppInitialized // EventAppInitialized
disposable.add(rxBus disposable += rxBus
.toObservable(EventAppInitialized::class.java) .toObservable(EventAppInitialized::class.java)
.observeOn(aapsSchedulers.io) .observeOn(aapsSchedulers.io)
.subscribe({ event -> runCalculation("onEventAppInitialized", System.currentTimeMillis(), bgDataReload = true, limitDataToOldestAvailable = true, cause = event) }, fabricPrivacy::logException) .subscribe({ event -> runCalculation("onEventAppInitialized", System.currentTimeMillis(), bgDataReload = true, limitDataToOldestAvailable = true, cause = event) }, fabricPrivacy::logException)
)
// EventNewHistoryData // EventNewHistoryData
disposable.add(rxBus disposable += rxBus
.toObservable(EventNewHistoryData::class.java) .toObservable(EventNewHistoryData::class.java)
.observeOn(aapsSchedulers.io) .observeOn(aapsSchedulers.io)
.subscribe({ event -> newHistoryData(event, false) }, fabricPrivacy::logException) .subscribe({ event -> newHistoryData(event.oldDataTimestamp, event.reloadBgData, if (event.newestGlucoseValue != null) EventNewBG(event.newestGlucoseValue) else event) }, fabricPrivacy::logException)
)
// EventNewHistoryBgData
disposable.add(rxBus
.toObservable(EventNewHistoryBgData::class.java)
.observeOn(aapsSchedulers.io)
.subscribe({ event -> newHistoryData(EventNewHistoryData(event.timestamp), true) }, fabricPrivacy::logException)
)
} }
override fun onStop() { override fun onStop() {
@ -169,219 +125,40 @@ open class IobCobCalculatorPlugin @Inject constructor(
super.onStop() super.onStop()
} }
override fun getAutosensDataTable(): LongSparseArray<AutosensData> { private fun resetDataAndRunCalculation(reason: String, event: Event?) {
return autosensDataTable stopCalculation(reason)
clearCache()
ads.reset()
runCalculation(reason, System.currentTimeMillis(), bgDataReload = false, limitDataToOldestAvailable = true, cause = event)
} }
fun adjustToReferenceTime(someTime: Long): Long { fun clearCache() {
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() {
synchronized(dataLock) { synchronized(dataLock) {
aapsLogger.debug(LTag.AUTOSENS, "Clearing cached data.")
iobTable = LongSparseArray() iobTable = LongSparseArray()
autosensDataTable = LongSparseArray()
basalDataTable = LongSparseArray() basalDataTable = LongSparseArray()
absIobTable = LongSparseArray()
} }
} }
fun createBucketedData() { private fun oldestDataAvailable(): Long {
val fiveMinData = isAbout5minData var oldestTime = System.currentTimeMillis()
if (lastUsed5minCalculation != null && lastUsed5minCalculation != fiveMinData) { val oldestTempBasal = repository.getOldestTemporaryBasalRecord()
// changing mode => clear cache if (oldestTempBasal != null) oldestTime = min(oldestTime, oldestTempBasal.timestamp)
aapsLogger.debug("Invalidating cached data because of changed mode.") val oldestExtendedBolus = repository.getOldestExtendedBolusRecord()
resetData() if (oldestExtendedBolus != null) oldestTime = min(oldestTime, oldestExtendedBolus.timestamp)
} val oldestBolus = repository.getOldestBolusRecord()
lastUsed5minCalculation = fiveMinData if (oldestBolus != null) oldestTime = min(oldestTime, oldestBolus.timestamp)
if (isAbout5minData) createBucketedData5min() else createBucketedDataRecalculated() val oldestCarbs = repository.getOldestCarbsRecord()
} if (oldestCarbs != null) oldestTime = min(oldestTime, oldestCarbs.timestamp)
oldestTime -= 15 * 60 * 1000L // allow 15 min before
fun findNewer(time: Long): GlucoseValue? { return oldestTime
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<InMemoryGlucoseValue> = 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
} }
fun calculateDetectionStart(from: Long, limitDataToOldestAvailable: Boolean): Long { fun calculateDetectionStart(from: Long, limitDataToOldestAvailable: Boolean): Long {
val profile = profileFunction.getProfile(from) val profile = profileFunction.getProfile(from)
var dia = Constants.defaultDIA var dia = Constants.defaultDIA
if (profile != null) dia = profile.dia if (profile != null) dia = profile.dia
val oldestDataAvailable = treatmentsPlugin.oldestDataAvailable() val oldestDataAvailable = oldestDataAvailable()
val getBGDataFrom: Long val getBGDataFrom: Long
if (limitDataToOldestAvailable) { if (limitDataToOldestAvailable) {
getBGDataFrom = max(oldestDataAvailable, (from - T.hours(1).msecs() * (24 + dia)).toLong()) getBGDataFrom = max(oldestDataAvailable, (from - T.hours(1).msecs() * (24 + dia)).toLong())
@ -390,33 +167,27 @@ open class IobCobCalculatorPlugin @Inject constructor(
return getBGDataFrom return getBGDataFrom
} }
override fun calculateFromTreatmentsAndTempsSynchronized(time: Long, profile: Profile?): IobTotal { override fun calculateFromTreatmentsAndTemps(fromTime: 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 {
val now = System.currentTimeMillis() val now = System.currentTimeMillis()
val time = roundUpTime(fromTime) val time = ads.roundUpTime(fromTime)
val cacheHit = iobTable[time] val cacheHit = iobTable[time]
if (time < now && cacheHit != null) { if (time < now && cacheHit != null) {
//og.debug(">>> calculateFromTreatmentsAndTemps Cache hit " + new Date(time).toLocaleString()); //og.debug(">>> calculateFromTreatmentsAndTemps Cache hit " + new Date(time).toLocaleString());
return cacheHit return cacheHit
} // else log.debug(">>> calculateFromTreatmentsAndTemps Cache miss " + new Date(time).toLocaleString()); } // else log.debug(">>> calculateFromTreatmentsAndTemps Cache miss " + new Date(time).toLocaleString());
val bolusIob = calculateIobFromBolusToTime(time).round() val bolusIob = calculateIobFromBolusToTime(time).round()
val basalIob = treatmentsPlugin.getCalculationToTimeTempBasals(time, true, now).round() val basalIob = calculateIobToTimeFromTempBasalsIncludingConvertedExtended(time).round()
// OpenAPSSMB only // OpenAPSSMB only
// Add expected zero temp basal for next 240 minutes // Add expected zero temp basal for next 240 minutes
val basalIobWithZeroTemp = basalIob.copy() val basalIobWithZeroTemp = basalIob.copy()
val t = TemporaryBasal(injector) val t = TemporaryBasal(
.date(now + 60 * 1000L) timestamp = now + 60 * 1000L,
.duration(240) duration = 240,
.absolute(0.0) rate = 0.0,
if (t.date < time) { isAbsolute = true,
val calc = t.iobCalc(time, profile) type = TemporaryBasal.Type.NORMAL)
if (t.timestamp < time) {
val calc = t.iobCalc(time, profile, activePlugin.activeInsulin)
basalIobWithZeroTemp.plus(calc) basalIobWithZeroTemp.plus(calc)
} }
basalIob.iobWithZeroTemp = IobTotal.combine(bolusIob, basalIobWithZeroTemp).round() basalIob.iobWithZeroTemp = IobTotal.combine(bolusIob, basalIobWithZeroTemp).round()
@ -427,17 +198,17 @@ open class IobCobCalculatorPlugin @Inject constructor(
return iobTotal return iobTotal
} }
override fun calculateAbsInsulinFromTreatmentsAndTempsSynchronized(fromTime: Long): IobTotal { override fun calculateAbsInsulinFromTreatmentsAndTemps(fromTime: Long): IobTotal {
synchronized(dataLock) { synchronized(dataLock) {
val now = System.currentTimeMillis() val now = System.currentTimeMillis()
val time = roundUpTime(fromTime) val time = ads.roundUpTime(fromTime)
val cacheHit = absIobTable[time] val cacheHit = absIobTable[time]
if (time < now && cacheHit != null) { if (time < now && cacheHit != null) {
//log.debug(">>> calculateFromTreatmentsAndTemps Cache hit " + new Date(time).toLocaleString()); //log.debug(">>> calculateFromTreatmentsAndTemps Cache hit " + new Date(time).toLocaleString());
return cacheHit return cacheHit
} // else log.debug(">>> calculateFromTreatmentsAndTemps Cache miss " + new Date(time).toLocaleString()); } // else log.debug(">>> calculateFromTreatmentsAndTemps Cache miss " + new Date(time).toLocaleString());
val bolusIob = calculateIobFromBolusToTime(time).round() val bolusIob = calculateIobFromBolusToTime(time).round()
val basalIob = treatmentsPlugin.getAbsoluteIOBTempBasals(time).round() val basalIob = calculateAbsoluteIobTempBasals(time).round()
val iobTotal = IobTotal.combine(bolusIob, basalIob).round() val iobTotal = IobTotal.combine(bolusIob, basalIob).round()
if (time < System.currentTimeMillis()) { if (time < System.currentTimeMillis()) {
absIobTable.put(time, iobTotal) absIobTable.put(time, iobTotal)
@ -447,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 { private fun calculateFromTreatmentsAndTemps(time: Long, lastAutosensResult: AutosensResult, exercise_mode: Boolean, half_basal_exercise_target: Int, isTempTarget: Boolean): IobTotal {
val now = DateUtil.now() val now = dateUtil.now()
val bolusIob = calculateIobFromBolusToTime(time).round() val bolusIob = calculateIobFromBolusToTime(time).round()
val basalIob = treatmentsPlugin.getCalculationToTimeTempBasals(time, now, lastAutosensResult, exercise_mode, half_basal_exercise_target, isTempTarget).round() val basalIob = getCalculationToTimeTempBasals(time, lastAutosensResult, exercise_mode, half_basal_exercise_target, isTempTarget).round()
// OpenAPSSMB only // OpenAPSSMB only
// Add expected zero temp basal for next 240 minutes // Add expected zero temp basal for next 240 minutes
val basalIobWithZeroTemp = basalIob.copy() val basalIobWithZeroTemp = basalIob.copy()
val t = TemporaryBasal(injector) val t = TemporaryBasal(
.date(now + 60 * 1000L) timestamp = now + 60 * 1000L,
.duration(240) duration = 240,
.absolute(0.0) rate = 0.0,
if (t.date < time) { isAbsolute = true,
val profile = profileFunction.getProfile(t.date) type = TemporaryBasal.Type.NORMAL)
if (t.timestamp < time) {
val profile = profileFunction.getProfile(t.timestamp)
if (profile != null) { 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) basalIobWithZeroTemp.plus(calc)
} }
} }
@ -468,27 +241,19 @@ open class IobCobCalculatorPlugin @Inject constructor(
return IobTotal.combine(bolusIob, basalIob).round() 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
}
override fun getBasalData(profile: Profile, fromTime: Long): BasalData { override fun getBasalData(profile: Profile, fromTime: Long): BasalData {
synchronized(dataLock) { synchronized(dataLock) {
val now = System.currentTimeMillis() val now = System.currentTimeMillis()
val time = roundUpTime(fromTime) val time = ads.roundUpTime(fromTime)
var retVal = basalDataTable[time] var retVal = basalDataTable[time]
if (retVal == null) { if (retVal == null) {
//log.debug(">>> getBasalData Cache miss " + new Date(time).toLocaleString()); //log.debug(">>> getBasalData Cache miss " + new Date(time).toLocaleString());
retVal = BasalData() retVal = BasalData()
val tb = treatmentsPlugin.getTempBasalFromHistory(time) val tb = getTempBasalIncludingConvertedExtended(time)
retVal.basal = profile.getBasal(time) retVal.basal = profile.getBasal(time)
if (tb != null) { if (tb != null) {
retVal.isTempBasalRunning = true retVal.isTempBasalRunning = true
retVal.tempBasalAbsolute = tb.tempBasalConvertedToAbsolute(time, profile) retVal.tempBasalAbsolute = tb.convertedToAbsolute(time, profile)
} else { } else {
retVal.isTempBasalRunning = false retVal.isTempBasalRunning = false
retVal.tempBasalAbsolute = retVal.basal retVal.tempBasalAbsolute = retVal.basal
@ -501,20 +266,7 @@ open class IobCobCalculatorPlugin @Inject constructor(
} }
} }
override fun getAutosensData(fromTime: Long): AutosensData? { override fun getLastAutosensDataWithWaitForCalculationFinish(reason: String): 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]
}
}
override fun getLastAutosensDataSynchronized(reason: String): AutosensData? {
if (thread?.isAlive == true) { if (thread?.isAlive == true) {
aapsLogger.debug(LTag.AUTOSENS, "AUTOSENSDATA is waiting for calculation thread: $reason") aapsLogger.debug(LTag.AUTOSENS, "AUTOSENSDATA is waiting for calculation thread: $reason")
try { try {
@ -523,19 +275,21 @@ open class IobCobCalculatorPlugin @Inject constructor(
} }
aapsLogger.debug(LTag.AUTOSENS, "AUTOSENSDATA finished waiting for calculation thread: $reason") 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 { override fun getCobInfo(waitForCalculationFinish: Boolean, reason: String): CobInfo {
val autosensData = if (_synchronized) getLastAutosensDataSynchronized(reason) else getLastAutosensData(reason) val autosensData =
if (waitForCalculationFinish) getLastAutosensDataWithWaitForCalculationFinish(reason)
else ads.getLastAutosensData(reason, aapsLogger, dateUtil)
var displayCob: Double? = null var displayCob: Double? = null
var futureCarbs = 0.0 var futureCarbs = 0.0
val now = DateUtil.now() val now = dateUtil.now()
val carbs = repository.getCarbsDataFromTimeExpanded(now, true).blockingGet() val carbs = repository.getCarbsDataFromTimeExpanded(now, true).blockingGet()
if (autosensData != null) { if (autosensData != null) {
displayCob = autosensData.cob displayCob = autosensData.cob
carbs.forEach { carb -> carbs.forEach { carb ->
if (roundUpTime(carb.timestamp) > roundUpTime(autosensData.time) && carb.timestamp <= now) { if (ads.roundUpTime(carb.timestamp) > ads.roundUpTime(autosensData.time) && carb.timestamp <= now) {
displayCob += carb.amount displayCob += carb.amount
} }
} }
@ -545,54 +299,7 @@ open class IobCobCalculatorPlugin @Inject constructor(
return CobInfo(displayCob, futureCarbs) return CobInfo(displayCob, futureCarbs)
} }
override fun slowAbsorptionPercentage(timeInMinutes: Int): Double { override fun getMealDataWithWaitingForCalculationFinish(): MealData {
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
} else {
aapsLogger.debug(LTag.AUTOSENS, "AUTOSENSDATA ($reason) $data")
data
}
}
override fun lastDataTime(): String {
return if (autosensDataTable.size() > 0) dateUtil.dateAndTimeAndSecondsString(autosensDataTable.valueAt(autosensDataTable.size() - 1).time) else "autosensDataTable empty"
}
override val mealData: MealData
get() {
val result = MealData() val result = MealData()
val now = System.currentTimeMillis() val now = System.currentTimeMillis()
val maxAbsorptionHours: Double = if (sensitivityAAPSPlugin.isEnabled() || sensitivityWeightedAveragePlugin.isEnabled()) { val maxAbsorptionHours: Double = if (sensitivityAAPSPlugin.isEnabled() || sensitivityWeightedAveragePlugin.isEnabled()) {
@ -609,26 +316,27 @@ open class IobCobCalculatorPlugin @Inject constructor(
if (it.timestamp > result.lastCarbTime) result.lastCarbTime = it.timestamp if (it.timestamp > result.lastCarbTime) result.lastCarbTime = it.timestamp
} }
} }
val autosensData = getLastAutosensDataSynchronized("getMealData()") val autosensData = getLastAutosensDataWithWaitForCalculationFinish("getMealData()")
if (autosensData != null) { if (autosensData != null) {
result.mealCOB = autosensData.cob result.mealCOB = autosensData.cob
result.slopeFromMinDeviation = autosensData.slopeFromMinDeviation result.slopeFromMinDeviation = autosensData.slopeFromMinDeviation
result.slopeFromMaxDeviation = autosensData.slopeFromMaxDeviation result.slopeFromMaxDeviation = autosensData.slopeFromMaxDeviation
result.usedMinCarbsImpact = autosensData.usedMinCarbsImpact result.usedMinCarbsImpact = autosensData.usedMinCarbsImpact
} }
result.lastBolusTime = repository.getLastBolusRecord()?.timestamp ?: 0L val lastBolus = repository.getLastBolusRecordWrapped().blockingGet()
result.lastBolusTime = if (lastBolus is ValueWrapper.Existing) lastBolus.value.timestamp else 0L
return result return result
} }
override fun calculateIobArrayInDia(profile: Profile): Array<IobTotal> { override fun calculateIobArrayInDia(profile: Profile): Array<IobTotal> {
// predict IOB out to DIA plus 30m // predict IOB out to DIA plus 30m
var time = System.currentTimeMillis() var time = System.currentTimeMillis()
time = roundUpTime(time) time = ads.roundUpTime(time)
val len = ((profile.dia * 60 + 30) / 5).toInt() val len = ((profile.dia * 60 + 30) / 5).toInt()
val array = Array(len) { IobTotal(0) } val array = Array(len) { IobTotal(0) }
for ((pos, i) in (0 until len).withIndex()) { for ((pos, i) in (0 until len).withIndex()) {
val t = time + i * 5 * 60000 val t = time + i * 5 * 60000
val iob = calculateFromTreatmentsAndTempsSynchronized(t, profile) val iob = calculateFromTreatmentsAndTemps(t, profile)
array[pos] = iob array[pos] = iob
} }
return array return array
@ -636,12 +344,12 @@ open class IobCobCalculatorPlugin @Inject constructor(
override fun calculateIobArrayForSMB(lastAutosensResult: AutosensResult, exercise_mode: Boolean, half_basal_exercise_target: Int, isTempTarget: Boolean): Array<IobTotal> { override fun calculateIobArrayForSMB(lastAutosensResult: AutosensResult, exercise_mode: Boolean, half_basal_exercise_target: Int, isTempTarget: Boolean): Array<IobTotal> {
// predict IOB out to DIA plus 30m // predict IOB out to DIA plus 30m
val now = DateUtil.now() val now = dateUtil.now()
val len = 4 * 60 / 5 val len = 4 * 60 / 5
val array = Array(len) { IobTotal(0) } val array = Array(len) { IobTotal(0) }
for ((pos, i) in (0 until len).withIndex()) { for ((pos, i) in (0 until len).withIndex()) {
val t = now + i * 5 * 60000 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 array[pos] = iob
} }
return array return array
@ -658,37 +366,35 @@ open class IobCobCalculatorPlugin @Inject constructor(
return sb.toString() return sb.toString()
} }
fun detectSensitivityWithLock(fromTime: Long, toTime: Long): AutosensResult {
synchronized(dataLock) { return activePlugin.activeSensitivity.detectSensitivity(this, fromTime, toTime) }
}
fun stopCalculation(from: String) { fun stopCalculation(from: String) {
if (thread?.state != Thread.State.TERMINATED) { if (thread?.state != Thread.State.TERMINATED) {
stopCalculationTrigger = true stopCalculationTrigger = true
aapsLogger.debug(LTag.AUTOSENS, "Stopping calculation thread: $from") 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) SystemClock.sleep(100)
} }
aapsLogger.debug(LTag.AUTOSENS, "Calculation thread stopped: $from") 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)) aapsLogger.debug(LTag.AUTOSENS, "Starting calculation thread: " + from + " to " + dateUtil.dateAndTimeAndSecondsString(end))
if (thread == null || thread?.state == Thread.State.TERMINATED) { if (thread == null || thread?.state == Thread.State.TERMINATED) {
thread = if (sensitivityOref1Plugin.isEnabled()) IobCobOref1Thread(injector, this, from, end, bgDataReload, limitDataToOldestAvailable, cause) else IobCobThread(injector, this, 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() thread?.start()
} }
} }
// When historical data is changed (coming from NS etc) finished calculations after this date must be invalidated // 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"); //log.debug("Locking onNewHistoryData");
stopCalculation("onEventNewHistoryData") stopCalculation("onEventNewHistoryData")
synchronized(dataLock) { synchronized(dataLock) {
// clear up 5 min back for proper COB calculation // 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)) aapsLogger.debug(LTag.AUTOSENS, "Invalidating cached data to: " + dateUtil.dateAndTimeAndSecondsString(time))
for (index in iobTable.size() - 1 downTo 0) { for (index in iobTable.size() - 1 downTo 0) {
if (iobTable.keyAt(index) > time) { if (iobTable.keyAt(index) > time) {
@ -706,14 +412,6 @@ open class IobCobCalculatorPlugin @Inject constructor(
break 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) { for (index in basalDataTable.size() - 1 downTo 0) {
if (basalDataTable.keyAt(index) > time) { if (basalDataTable.keyAt(index) > time) {
aapsLogger.debug(LTag.AUTOSENS, "Removing from basalDataTable: " + dateUtil.dateAndTimeAndSecondsString(basalDataTable.keyAt(index))) aapsLogger.debug(LTag.AUTOSENS, "Removing from basalDataTable: " + dateUtil.dateAndTimeAndSecondsString(basalDataTable.keyAt(index)))
@ -722,49 +420,22 @@ open class IobCobCalculatorPlugin @Inject constructor(
break break
} }
} }
ads.newHistoryData(time, aapsLogger, dateUtil)
} }
runCalculation("onEventNewHistoryData", System.currentTimeMillis(), bgDataReload, true, ev) runCalculation("onEventNewHistoryData", System.currentTimeMillis(), bgDataReload, true, event)
//log.debug("Releasing onNewHistoryData"); //log.debug("Releasing onNewHistoryData");
} }
fun clearCache() { override fun convertToJSONArray(iobArray: Array<IobTotal>): JSONArray {
synchronized(dataLock) {
aapsLogger.debug(LTag.AUTOSENS, "Clearing cached data.")
iobTable = LongSparseArray()
autosensDataTable = LongSparseArray()
basalDataTable = LongSparseArray()
}
}
/*
* Return last BgReading from database or null if db is empty
*/
override fun lastBg(): GlucoseValue? {
val bgList = bgReadings
for (i in bgList.indices) if (bgList[i].value >= 39) return bgList[i]
return null
}
override fun actualBg(): GlucoseValue? {
val lastBg = lastBg() ?: return null
return if (lastBg.timestamp > System.currentTimeMillis() - T.mins(9).msecs()) lastBg else null
}
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<IobTotal>): JSONArray {
val array = JSONArray() val array = JSONArray()
for (i in iobArray.indices) { for (i in iobArray.indices) {
array.put(iobArray[i].determineBasalJson()) array.put(iobArray[i].determineBasalJson(dateUtil))
} }
return array return array
} }
companion object {
// From https://gist.github.com/IceCreamYou/6ffa1b18c4c8f6aeaad2 // From https://gist.github.com/IceCreamYou/6ffa1b18c4c8f6aeaad2
// Returns the value at a given percentile in a sorted numeric array. // Returns the value at a given percentile in a sorted numeric array.
// "Linear interpolation between closest ranks" method // "Linear interpolation between closest ranks" method
@ -784,31 +455,38 @@ open class IobCobCalculatorPlugin @Inject constructor(
* Time range to the past for IOB calculation * Time range to the past for IOB calculation
* @return milliseconds * @return milliseconds
*/ */
fun range(): Long { fun range(): Long = ((profileFunction.getProfile()?.dia
val dia = profileFunction.getProfile()?.dia ?: Constants.defaultDIA ?: Constants.defaultDIA) * 60 * 60 * 1000).toLong()
return (60 * 60 * 1000L * (24 + dia)).toLong()
}
override fun calculateIobFromBolus(): IobTotal = calculateIobFromBolusToTime(dateUtil._now()) override fun calculateIobFromBolus(): IobTotal = calculateIobFromBolusToTime(dateUtil.now())
override fun calculateIobFromBolusToTime(timestamp: Long): IobTotal { /**
val total = IobTotal(timestamp) * 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 profile = profileFunction.getProfile() ?: return total
val dia = profile.dia val dia = profile.dia
val divisor = sp.getDouble(R.string.key_openapsama_bolussnooze_dia_divisor, 2.0) val divisor = sp.getDouble(R.string.key_openapsama_bolussnooze_dia_divisor, 2.0)
val boluses = repository.getBolusesDataFromTime(timestamp - range(), true).blockingGet() val boluses = repository.getBolusesDataFromTime(toTime - range(), true).blockingGet()
boluses.forEach { t -> boluses.forEach { t ->
if (t.isValid && t.timestamp < timestamp) { if (t.isValid && t.timestamp < toTime) {
val tIOB = t.iobCalc(activePlugin, timestamp, dia) val tIOB = t.iobCalc(activePlugin, toTime, dia)
total.iob += tIOB.iobContrib total.iob += tIOB.iobContrib
total.activity += tIOB.activityContrib total.activity += tIOB.activityContrib
if (t.amount > 0 && t.timestamp > total.lastBolusTime) total.lastBolusTime = t.timestamp if (t.amount > 0 && t.timestamp > total.lastBolusTime) total.lastBolusTime = t.timestamp
if (t.type != Bolus.Type.SMB) { if (t.type != Bolus.Type.SMB) {
// instead of dividing the DIA that only worked on the bilinear curves, // instead of dividing the DIA that only worked on the bilinear curves,
// multiply the time the treatment is seen active. // multiply the time the treatment is seen active.
val timeSinceTreatment = timestamp - t.timestamp val timeSinceTreatment = toTime - t.timestamp
val snoozeTime = t.timestamp + (timeSinceTreatment * divisor).toLong() val snoozeTime = t.timestamp + (timeSinceTreatment * divisor).toLong()
val bIOB = t.iobCalc(activePlugin, snoozeTime, dia) val bIOB = t.iobCalc(activePlugin, snoozeTime, dia)
total.bolussnooze += bIOB.iobContrib total.bolussnooze += bIOB.iobContrib
@ -816,8 +494,146 @@ open class IobCobCalculatorPlugin @Inject constructor(
} }
} }
total.plus(treatmentsPlugin.getCalculationToTimeExtendedBoluses(timestamp)) total.plus(calculateIobToTimeFromExtendedBoluses(toTime))
return total 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
}
} }

View file

@ -10,6 +10,8 @@ import info.nightscout.androidaps.database.AppRepository
import info.nightscout.androidaps.database.ValueWrapper import info.nightscout.androidaps.database.ValueWrapper
import info.nightscout.androidaps.events.Event import info.nightscout.androidaps.events.Event
import info.nightscout.androidaps.events.EventAutosensCalculationFinished import info.nightscout.androidaps.events.EventAutosensCalculationFinished
import info.nightscout.androidaps.extensions.target
import info.nightscout.androidaps.interfaces.ActivePluginProvider
import info.nightscout.androidaps.interfaces.ProfileFunction import info.nightscout.androidaps.interfaces.ProfileFunction
import info.nightscout.androidaps.logging.AAPSLogger import info.nightscout.androidaps.logging.AAPSLogger
import info.nightscout.androidaps.logging.LTag import info.nightscout.androidaps.logging.LTag
@ -17,15 +19,16 @@ import info.nightscout.androidaps.plugins.aps.openAPSSMB.SMBDefaults
import info.nightscout.androidaps.plugins.bus.RxBusWrapper import info.nightscout.androidaps.plugins.bus.RxBusWrapper
import info.nightscout.androidaps.plugins.general.overview.events.EventNewNotification import info.nightscout.androidaps.plugins.general.overview.events.EventNewNotification
import info.nightscout.androidaps.plugins.general.overview.notifications.Notification 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.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.iob.iobCobCalculator.events.EventIobCalculationProgress
import info.nightscout.androidaps.plugins.sensitivity.SensitivityAAPSPlugin import info.nightscout.androidaps.plugins.sensitivity.SensitivityAAPSPlugin
import info.nightscout.androidaps.plugins.sensitivity.SensitivityWeightedAveragePlugin import info.nightscout.androidaps.plugins.sensitivity.SensitivityWeightedAveragePlugin
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.buildHelper.BuildHelper
import info.nightscout.androidaps.utils.extensions.target
import info.nightscout.androidaps.utils.resources.ResourceHelper import info.nightscout.androidaps.utils.resources.ResourceHelper
import info.nightscout.androidaps.utils.sharedPreferences.SP import info.nightscout.androidaps.utils.sharedPreferences.SP
import java.util.* import java.util.*
@ -42,7 +45,7 @@ class IobCobOref1Thread internal constructor(
private val end: Long, private val end: Long,
private val bgDataReload: Boolean, private val bgDataReload: Boolean,
private val limitDataToOldestAvailable: Boolean, private val limitDataToOldestAvailable: Boolean,
private val cause: Event private val cause: Event?
) : Thread() { ) : Thread() {
@Inject lateinit var aapsLogger: AAPSLogger @Inject lateinit var aapsLogger: AAPSLogger
@ -53,6 +56,7 @@ class IobCobOref1Thread internal constructor(
@Inject lateinit var context: Context @Inject lateinit var context: Context
@Inject lateinit var sensitivityAAPSPlugin: SensitivityAAPSPlugin @Inject lateinit var sensitivityAAPSPlugin: SensitivityAAPSPlugin
@Inject lateinit var sensitivityWeightedAveragePlugin: SensitivityWeightedAveragePlugin @Inject lateinit var sensitivityWeightedAveragePlugin: SensitivityWeightedAveragePlugin
@Inject lateinit var activePlugin: ActivePluginProvider
@Inject lateinit var buildHelper: BuildHelper @Inject lateinit var buildHelper: BuildHelper
@Inject lateinit var profiler: Profiler @Inject lateinit var profiler: Profiler
@Inject lateinit var fabricPrivacy: FabricPrivacy @Inject lateinit var fabricPrivacy: FabricPrivacy
@ -67,7 +71,7 @@ class IobCobOref1Thread internal constructor(
} }
override fun run() { override fun run() {
val start = DateUtil.now() val start = dateUtil.now()
mWakeLock?.acquire(T.mins(10).msecs()) mWakeLock?.acquire(T.mins(10).msecs())
try { try {
aapsLogger.debug(LTag.AUTOSENS, "AUTOSENSDATA thread started: $from") aapsLogger.debug(LTag.AUTOSENS, "AUTOSENSDATA thread started: $from")
@ -77,19 +81,19 @@ class IobCobOref1Thread internal constructor(
} }
//log.debug("Locking calculateSensitivityData"); //log.debug("Locking calculateSensitivityData");
val oldestTimeWithData = iobCobCalculatorPlugin.calculateDetectionStart(end, limitDataToOldestAvailable) val oldestTimeWithData = iobCobCalculatorPlugin.calculateDetectionStart(end, limitDataToOldestAvailable)
synchronized(iobCobCalculatorPlugin.dataLock) {
if (bgDataReload) { if (bgDataReload) {
iobCobCalculatorPlugin.loadBgData(end) iobCobCalculatorPlugin.ads.loadBgData(end, repository, aapsLogger, dateUtil)
iobCobCalculatorPlugin.createBucketedData() iobCobCalculatorPlugin.clearCache()
rxBus.send(EventAutosensBgLoaded(cause))
} }
val bucketedData = iobCobCalculatorPlugin.bucketedData // work on local copy and set back when finished
val autosensDataTable = iobCobCalculatorPlugin.getAutosensDataTable() val ads = iobCobCalculatorPlugin.ads.clone()
val bucketedData = ads.bucketedData
val autosensDataTable = ads.autosensDataTable
if (bucketedData == null || bucketedData.size < 3) { if (bucketedData == null || bucketedData.size < 3) {
aapsLogger.debug(LTag.AUTOSENS, "Aborting calculation thread (No bucketed data available): $from") aapsLogger.debug(LTag.AUTOSENS, "Aborting calculation thread (No bucketed data available): $from")
return return
} }
val prevDataTime = roundUpTime(bucketedData[bucketedData.size - 3].timestamp) val prevDataTime = ads.roundUpTime(bucketedData[bucketedData.size - 3].timestamp)
aapsLogger.debug(LTag.AUTOSENS, "Prev data time: " + dateUtil.dateAndTimeString(prevDataTime)) aapsLogger.debug(LTag.AUTOSENS, "Prev data time: " + dateUtil.dateAndTimeString(prevDataTime))
var previous = autosensDataTable[prevDataTime] var previous = autosensDataTable[prevDataTime]
// start from oldest to be able sub cob // start from oldest to be able sub cob
@ -103,8 +107,8 @@ class IobCobOref1Thread internal constructor(
} }
// check if data already exists // check if data already exists
var bgTime = bucketedData[i].timestamp var bgTime = bucketedData[i].timestamp
bgTime = roundUpTime(bgTime) bgTime = ads.roundUpTime(bgTime)
if (bgTime > roundUpTime(DateUtil.now())) continue if (bgTime > ads.roundUpTime(dateUtil.now())) continue
var existing: AutosensData? var existing: AutosensData?
if (autosensDataTable[bgTime].also { existing = it } != null) { if (autosensDataTable[bgTime].also { existing = it } != null) {
previous = existing previous = existing
@ -144,7 +148,7 @@ class IobCobOref1Thread internal constructor(
@Suppress("UNUSED_VARIABLE") var maxDeviation = 0.0 @Suppress("UNUSED_VARIABLE") var maxDeviation = 0.0
@Suppress("UNUSED_VARIABLE") var minDeviation = 999.0 @Suppress("UNUSED_VARIABLE") var minDeviation = 999.0
val hourAgo = bgTime + 10 * 1000 - 60 * 60 * 1000L val hourAgo = bgTime + 10 * 1000 - 60 * 60 * 1000L
val hourAgoData = iobCobCalculatorPlugin.getAutosensData(hourAgo) val hourAgoData = ads.getAutosensDataAtTime(hourAgo)
if (hourAgoData != null) { if (hourAgoData != null) {
val initialIndex = autosensDataTable.indexOfKey(hourAgoData.time) val initialIndex = autosensDataTable.indexOfKey(hourAgoData.time)
aapsLogger.debug(LTag.AUTOSENS, ">>>>> bucketed_data.size()=" + bucketedData.size + " i=" + i + " hourAgoData=" + hourAgoData.toString()) aapsLogger.debug(LTag.AUTOSENS, ">>>>> bucketed_data.size()=" + bucketedData.size + " i=" + i + " hourAgoData=" + hourAgoData.toString())
@ -156,7 +160,7 @@ class IobCobOref1Thread internal constructor(
if (ad == null) { if (ad == null) {
aapsLogger.debug(LTag.AUTOSENS, autosensDataTable.toString()) aapsLogger.debug(LTag.AUTOSENS, autosensDataTable.toString())
aapsLogger.debug(LTag.AUTOSENS, bucketedData.toString()) aapsLogger.debug(LTag.AUTOSENS, bucketedData.toString())
aapsLogger.debug(LTag.AUTOSENS, iobCobCalculatorPlugin.bgReadings.toString()) //aapsLogger.debug(LTag.AUTOSENS, iobCobCalculatorPlugin.getBgReadingsDataTable().toString())
val notification = Notification(Notification.SEND_LOGFILES, resourceHelper.gs(R.string.sendlogfiles), Notification.LOW) val notification = Notification(Notification.SEND_LOGFILES, resourceHelper.gs(R.string.sendlogfiles), Notification.LOW)
rxBus.send(EventNewNotification(notification)) rxBus.send(EventNewNotification(notification))
sp.putBoolean("log_AUTOSENS", true) sp.putBoolean("log_AUTOSENS", true)
@ -179,7 +183,7 @@ class IobCobOref1Thread internal constructor(
fabricPrivacy.logException(e) fabricPrivacy.logException(e)
aapsLogger.debug(autosensDataTable.toString()) aapsLogger.debug(autosensDataTable.toString())
aapsLogger.debug(bucketedData.toString()) aapsLogger.debug(bucketedData.toString())
aapsLogger.debug(iobCobCalculatorPlugin.bgReadings.toString()) //aapsLogger.debug(iobCobCalculatorPlugin.getBgReadingsDataTable().toString())
val notification = Notification(Notification.SEND_LOGFILES, resourceHelper.gs(R.string.sendlogfiles), Notification.LOW) val notification = Notification(Notification.SEND_LOGFILES, resourceHelper.gs(R.string.sendlogfiles), Notification.LOW)
rxBus.send(EventNewNotification(notification)) rxBus.send(EventNewNotification(notification))
sp.putBoolean("log_AUTOSENS", true) sp.putBoolean("log_AUTOSENS", true)
@ -294,7 +298,7 @@ class IobCobOref1Thread internal constructor(
// TODO AS-FIX // TODO AS-FIX
@Suppress("SimplifyBooleanWithConstants") @Suppress("SimplifyBooleanWithConstants")
if (false && sp.getBoolean(R.string.key_high_temptarget_raises_sensitivity, SMBDefaults.high_temptarget_raises_sensitivity)) { if (false && sp.getBoolean(R.string.key_high_temptarget_raises_sensitivity, SMBDefaults.high_temptarget_raises_sensitivity)) {
val tempTarget = repository.getTemporaryTargetActiveAt(dateUtil._now()).blockingGet() val tempTarget = repository.getTemporaryTargetActiveAt(dateUtil.now()).blockingGet()
if (tempTarget is ValueWrapper.Existing && tempTarget.value.target() >= 100) { if (tempTarget is ValueWrapper.Existing && tempTarget.value.target() >= 100) {
autosensData.extraDeviation.add(-(tempTarget.value.target() - 100) / 20) autosensData.extraDeviation.add(-(tempTarget.value.target() - 100) / 20)
} }
@ -307,14 +311,14 @@ class IobCobOref1Thread internal constructor(
val hours = calendar[Calendar.HOUR_OF_DAY] val hours = calendar[Calendar.HOUR_OF_DAY]
if (min in 0..4 && hours % 2 == 0) autosensData.extraDeviation.add(0.0) if (min in 0..4 && hours % 2 == 0) autosensData.extraDeviation.add(0.0)
previous = autosensData previous = autosensData
if (bgTime < DateUtil.now()) autosensDataTable.put(bgTime, 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()) aapsLogger.debug(LTag.AUTOSENS, "Running detectSensitivity from: " + dateUtil.dateAndTimeString(oldestTimeWithData) + " to: " + dateUtil.dateAndTimeString(bgTime) + " lastDataTime:" + ads.lastDataTime(dateUtil))
val sensitivity = iobCobCalculatorPlugin.detectSensitivityWithLock(oldestTimeWithData, bgTime) val sensitivity = activePlugin.activeSensitivity.detectSensitivity(ads, oldestTimeWithData, bgTime)
aapsLogger.debug(LTag.AUTOSENS, "Sensitivity result: $sensitivity") aapsLogger.debug(LTag.AUTOSENS, "Sensitivity result: $sensitivity")
autosensData.autosensResult = sensitivity autosensData.autosensResult = sensitivity
aapsLogger.debug(LTag.AUTOSENS, autosensData.toString()) aapsLogger.debug(LTag.AUTOSENS, autosensData.toString())
} }
} iobCobCalculatorPlugin.ads = ads
Thread { Thread {
SystemClock.sleep(1000) SystemClock.sleep(1000)
rxBus.send(EventAutosensCalculationFinished(cause)) rxBus.send(EventAutosensCalculationFinished(cause))
@ -323,7 +327,6 @@ class IobCobOref1Thread internal constructor(
mWakeLock?.release() mWakeLock?.release()
rxBus.send(EventIobCalculationProgress("")) rxBus.send(EventIobCalculationProgress(""))
aapsLogger.debug(LTag.AUTOSENS, "AUTOSENSDATA thread ended: $from") aapsLogger.debug(LTag.AUTOSENS, "AUTOSENSDATA thread ended: $from")
aapsLogger.debug(LTag.AUTOSENS, "Midnights: " + MidnightTime.log())
profiler.log(LTag.AUTOSENS, "IobCobOref1Thread", start) profiler.log(LTag.AUTOSENS, "IobCobOref1Thread", start)
} }
} }

View file

@ -9,6 +9,7 @@ import info.nightscout.androidaps.R
import info.nightscout.androidaps.database.AppRepository import info.nightscout.androidaps.database.AppRepository
import info.nightscout.androidaps.events.Event import info.nightscout.androidaps.events.Event
import info.nightscout.androidaps.events.EventAutosensCalculationFinished import info.nightscout.androidaps.events.EventAutosensCalculationFinished
import info.nightscout.androidaps.interfaces.ActivePluginProvider
import info.nightscout.androidaps.interfaces.PluginType import info.nightscout.androidaps.interfaces.PluginType
import info.nightscout.androidaps.interfaces.ProfileFunction import info.nightscout.androidaps.interfaces.ProfileFunction
import info.nightscout.androidaps.logging.AAPSLogger import info.nightscout.androidaps.logging.AAPSLogger
@ -17,13 +18,15 @@ import info.nightscout.androidaps.plugins.aps.openAPSSMB.SMBDefaults
import info.nightscout.androidaps.plugins.bus.RxBusWrapper import info.nightscout.androidaps.plugins.bus.RxBusWrapper
import info.nightscout.androidaps.plugins.general.overview.events.EventNewNotification import info.nightscout.androidaps.plugins.general.overview.events.EventNewNotification
import info.nightscout.androidaps.plugins.general.overview.notifications.Notification 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.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.iob.iobCobCalculator.events.EventIobCalculationProgress
import info.nightscout.androidaps.plugins.sensitivity.SensitivityAAPSPlugin import info.nightscout.androidaps.plugins.sensitivity.SensitivityAAPSPlugin
import info.nightscout.androidaps.plugins.sensitivity.SensitivityWeightedAveragePlugin import info.nightscout.androidaps.plugins.sensitivity.SensitivityWeightedAveragePlugin
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.buildHelper.BuildHelper
import info.nightscout.androidaps.utils.resources.ResourceHelper import info.nightscout.androidaps.utils.resources.ResourceHelper
import info.nightscout.androidaps.utils.sharedPreferences.SP import info.nightscout.androidaps.utils.sharedPreferences.SP
@ -41,7 +44,7 @@ class IobCobThread @Inject internal constructor(
private val end: Long, private val end: Long,
private val bgDataReload: Boolean, private val bgDataReload: Boolean,
private val limitDataToOldestAvailable: Boolean, private val limitDataToOldestAvailable: Boolean,
private val cause: Event private val cause: Event?
) : Thread() { ) : Thread() {
@Inject lateinit var aapsLogger: AAPSLogger @Inject lateinit var aapsLogger: AAPSLogger
@ -52,6 +55,7 @@ class IobCobThread @Inject internal constructor(
@Inject lateinit var context: Context @Inject lateinit var context: Context
@Inject lateinit var sensitivityAAPSPlugin: SensitivityAAPSPlugin @Inject lateinit var sensitivityAAPSPlugin: SensitivityAAPSPlugin
@Inject lateinit var sensitivityWeightedAveragePlugin: SensitivityWeightedAveragePlugin @Inject lateinit var sensitivityWeightedAveragePlugin: SensitivityWeightedAveragePlugin
@Inject lateinit var activePlugin: ActivePluginProvider
@Inject lateinit var buildHelper: BuildHelper @Inject lateinit var buildHelper: BuildHelper
@Inject lateinit var profiler: Profiler @Inject lateinit var profiler: Profiler
@Inject lateinit var fabricPrivacy: FabricPrivacy @Inject lateinit var fabricPrivacy: FabricPrivacy
@ -66,7 +70,7 @@ class IobCobThread @Inject internal constructor(
} }
override fun run() { override fun run() {
val start = DateUtil.now() val start = dateUtil.now()
mWakeLock?.acquire(T.mins(10).msecs()) mWakeLock?.acquire(T.mins(10).msecs())
try { try {
aapsLogger.debug(LTag.AUTOSENS, "AUTOSENSDATA thread started: $from") aapsLogger.debug(LTag.AUTOSENS, "AUTOSENSDATA thread started: $from")
@ -76,19 +80,19 @@ class IobCobThread @Inject internal constructor(
} }
//log.debug("Locking calculateSensitivityData"); //log.debug("Locking calculateSensitivityData");
val oldestTimeWithData = iobCobCalculatorPlugin.calculateDetectionStart(end, limitDataToOldestAvailable) val oldestTimeWithData = iobCobCalculatorPlugin.calculateDetectionStart(end, limitDataToOldestAvailable)
synchronized(iobCobCalculatorPlugin.dataLock) {
if (bgDataReload) { if (bgDataReload) {
iobCobCalculatorPlugin.loadBgData(end) iobCobCalculatorPlugin.ads.loadBgData(end, repository, aapsLogger, dateUtil)
iobCobCalculatorPlugin.createBucketedData() iobCobCalculatorPlugin.clearCache()
rxBus.send(EventAutosensBgLoaded(cause))
} }
val bucketedData = iobCobCalculatorPlugin.bucketedData // work on local copy and set back when finished
val autosensDataTable = iobCobCalculatorPlugin.getAutosensDataTable() val ads = iobCobCalculatorPlugin.ads.clone()
val bucketedData = ads.bucketedData
val autosensDataTable = ads.autosensDataTable
if (bucketedData == null || bucketedData.size < 3) { if (bucketedData == null || bucketedData.size < 3) {
aapsLogger.debug(LTag.AUTOSENS, "Aborting calculation thread (No bucketed data available): $from") aapsLogger.debug(LTag.AUTOSENS, "Aborting calculation thread (No bucketed data available): $from")
return return
} }
val prevDataTime = roundUpTime(bucketedData[bucketedData.size - 3].timestamp) val prevDataTime = ads.roundUpTime(bucketedData[bucketedData.size - 3].timestamp)
aapsLogger.debug(LTag.AUTOSENS, "Prev data time: " + dateUtil.dateAndTimeString(prevDataTime)) aapsLogger.debug(LTag.AUTOSENS, "Prev data time: " + dateUtil.dateAndTimeString(prevDataTime))
var previous = autosensDataTable[prevDataTime] var previous = autosensDataTable[prevDataTime]
// start from oldest to be able sub cob // start from oldest to be able sub cob
@ -102,8 +106,8 @@ class IobCobThread @Inject internal constructor(
} }
// check if data already exists // check if data already exists
var bgTime = bucketedData[i].timestamp var bgTime = bucketedData[i].timestamp
bgTime = roundUpTime(bgTime) bgTime = ads.roundUpTime(bgTime)
if (bgTime > roundUpTime(DateUtil.now())) continue if (bgTime > ads.roundUpTime(dateUtil.now())) continue
var existing: AutosensData? var existing: AutosensData?
if (autosensDataTable[bgTime].also { existing = it } != null) { if (autosensDataTable[bgTime].also { existing = it } != null) {
previous = existing previous = existing
@ -143,7 +147,7 @@ class IobCobThread @Inject internal constructor(
@Suppress("UNUSED_VARIABLE") var maxDeviation = 0.0 @Suppress("UNUSED_VARIABLE") var maxDeviation = 0.0
@Suppress("UNUSED_VARIABLE") var minDeviation = 999.0 @Suppress("UNUSED_VARIABLE") var minDeviation = 999.0
val hourAgo = bgTime + 10 * 1000 - 60 * 60 * 1000L val hourAgo = bgTime + 10 * 1000 - 60 * 60 * 1000L
val hourAgoData = iobCobCalculatorPlugin.getAutosensData(hourAgo) val hourAgoData = ads.getAutosensDataAtTime(hourAgo)
if (hourAgoData != null) { if (hourAgoData != null) {
val initialIndex = autosensDataTable.indexOfKey(hourAgoData.time) val initialIndex = autosensDataTable.indexOfKey(hourAgoData.time)
aapsLogger.debug(LTag.AUTOSENS, ">>>>> bucketed_data.size()=" + bucketedData.size + " i=" + i + " hourAgoData=" + hourAgoData.toString()) aapsLogger.debug(LTag.AUTOSENS, ">>>>> bucketed_data.size()=" + bucketedData.size + " i=" + i + " hourAgoData=" + hourAgoData.toString())
@ -155,7 +159,7 @@ class IobCobThread @Inject internal constructor(
if (ad == null) { if (ad == null) {
aapsLogger.debug(LTag.AUTOSENS, autosensDataTable.toString()) aapsLogger.debug(LTag.AUTOSENS, autosensDataTable.toString())
aapsLogger.debug(LTag.AUTOSENS, bucketedData.toString()) aapsLogger.debug(LTag.AUTOSENS, bucketedData.toString())
aapsLogger.debug(LTag.AUTOSENS, iobCobCalculatorPlugin.bgReadings.toString()) //aapsLogger.debug(LTag.AUTOSENS, iobCobCalculatorPlugin.getBgReadingsDataTable().toString())
val notification = Notification(Notification.SEND_LOGFILES, resourceHelper.gs(R.string.sendlogfiles), Notification.LOW) val notification = Notification(Notification.SEND_LOGFILES, resourceHelper.gs(R.string.sendlogfiles), Notification.LOW)
rxBus.send(EventNewNotification(notification)) rxBus.send(EventNewNotification(notification))
sp.putBoolean("log_AUTOSENS", true) sp.putBoolean("log_AUTOSENS", true)
@ -178,7 +182,7 @@ class IobCobThread @Inject internal constructor(
fabricPrivacy.logException(e) fabricPrivacy.logException(e)
aapsLogger.debug(autosensDataTable.toString()) aapsLogger.debug(autosensDataTable.toString())
aapsLogger.debug(bucketedData.toString()) aapsLogger.debug(bucketedData.toString())
aapsLogger.debug(iobCobCalculatorPlugin.bgReadings.toString()) //aapsLogger.debug(iobCobCalculatorPlugin.getBgReadingsDataTable().toString())
val notification = Notification(Notification.SEND_LOGFILES, resourceHelper.gs(R.string.sendlogfiles), Notification.LOW) val notification = Notification(Notification.SEND_LOGFILES, resourceHelper.gs(R.string.sendlogfiles), Notification.LOW)
rxBus.send(EventNewNotification(notification)) rxBus.send(EventNewNotification(notification))
sp.putBoolean("log_AUTOSENS", true) sp.putBoolean("log_AUTOSENS", true)
@ -254,14 +258,14 @@ class IobCobThread @Inject internal constructor(
autosensData.pastSensitivity += "C" autosensData.pastSensitivity += "C"
} }
previous = autosensData previous = autosensData
if (bgTime < DateUtil.now()) autosensDataTable.put(bgTime, 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()) aapsLogger.debug(LTag.AUTOSENS, "Running detectSensitivity from: " + dateUtil.dateAndTimeString(oldestTimeWithData) + " to: " + dateUtil.dateAndTimeString(bgTime) + " lastDataTime:" + ads.lastDataTime(dateUtil))
val sensitivity = iobCobCalculatorPlugin.detectSensitivityWithLock(oldestTimeWithData, bgTime) val sensitivity = activePlugin.activeSensitivity.detectSensitivity(ads, oldestTimeWithData, bgTime)
aapsLogger.debug(LTag.AUTOSENS, "Sensitivity result: $sensitivity") aapsLogger.debug(LTag.AUTOSENS, "Sensitivity result: $sensitivity")
autosensData.autosensResult = sensitivity autosensData.autosensResult = sensitivity
aapsLogger.debug(LTag.AUTOSENS, autosensData.toString()) aapsLogger.debug(LTag.AUTOSENS, autosensData.toString())
} }
} iobCobCalculatorPlugin.ads = ads
Thread { Thread {
SystemClock.sleep(1000) SystemClock.sleep(1000)
rxBus.send(EventAutosensCalculationFinished(cause)) rxBus.send(EventAutosensCalculationFinished(cause))
@ -270,7 +274,6 @@ class IobCobThread @Inject internal constructor(
mWakeLock?.release() mWakeLock?.release()
rxBus.send(EventIobCalculationProgress("")) rxBus.send(EventIobCalculationProgress(""))
aapsLogger.debug(LTag.AUTOSENS, "AUTOSENSDATA thread ended: $from") aapsLogger.debug(LTag.AUTOSENS, "AUTOSENSDATA thread ended: $from")
aapsLogger.debug(LTag.AUTOSENS, "Midnights: " + MidnightTime.log())
profiler.log(LTag.AUTOSENS, "IobCobThread", start) profiler.log(LTag.AUTOSENS, "IobCobThread", start)
} }
} }

View file

@ -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()

View file

@ -1,5 +0,0 @@
package info.nightscout.androidaps.plugins.iob.iobCobCalculator.events
import info.nightscout.androidaps.events.Event
class EventNewHistoryBgData(val timestamp: Long) : Event()

Some files were not shown because too many files have changed in this diff Show more