NSClient v3 initial work, NS v1 improvements

* NSCv3 initial work

* Allow only 1 NSC

* read sgv

* NSv3: Read Bolus, Carbs

* NSCv3: more work

* fix build

* loading working

* work on TT

* TT working

* TBR processing

* EPS working

* PS Sync

* Process entries at once. Share code v1,v3

* BolusCalculatorWizard working

* TherapyEvent working

* process bg at once

* improve sync

* sdk -> ns-sdk

* handle status per version

* OffileEvents working

* EB working

* RemoteDeviceStatus

* fix build

* cleanup
This commit is contained in:
Milos Kozak 2022-11-08 09:23:46 +01:00 committed by GitHub
parent 7ae9ad1105
commit 774ed51e1b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
275 changed files with 7493 additions and 3433 deletions

View file

@ -1,9 +1,11 @@
apply plugin: 'com.android.library'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-kapt'
apply plugin: 'kotlin-allopen'
apply plugin: 'com.hiya.jacoco-android'
apply plugin: 'kotlinx-serialization'
plugins {
id 'com.android.library'
id 'kotlin-android'
id 'kotlin-kapt'
id 'kotlin-allopen'
id 'com.hiya.jacoco-android'
id 'kotlinx-serialization'
}
apply from: "${project.rootDir}/core/android_dependencies.gradle"
apply from: "${project.rootDir}/core/android_module_dependencies.gradle"

View file

@ -1,9 +1,11 @@
apply plugin: 'com.android.library'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-kapt'
apply plugin: 'kotlin-allopen'
apply plugin: 'com.hiya.jacoco-android'
apply plugin: 'kotlinx-serialization'
plugins {
id 'com.android.library'
id 'kotlin-android'
id 'kotlin-kapt'
id 'kotlin-allopen'
id 'com.hiya.jacoco-android'
id 'kotlinx-serialization'
}
apply from: "${project.rootDir}/core/android_dependencies.gradle"
apply from: "${project.rootDir}/core/android_module_dependencies.gradle"

View file

@ -1,12 +1,15 @@
apply plugin: 'com.android.library'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-kapt'
apply plugin: 'kotlin-allopen'
apply plugin: 'com.hiya.jacoco-android'
apply plugin: 'kotlinx-serialization'
plugins {
id 'com.android.library'
id 'kotlin-android'
id 'kotlin-kapt'
id 'kotlinx-serialization'
id 'kotlin-allopen'
id 'com.hiya.jacoco-android'
}
apply from: "${project.rootDir}/core/android_dependencies.gradle"
apply from: "${project.rootDir}/core/android_module_dependencies.gradle"
apply from: "${project.rootDir}/core/allopen_dependencies.gradle"
apply from: "${project.rootDir}/core/test_dependencies.gradle"
apply from: "${project.rootDir}/core/jacoco_global.gradle"
@ -31,7 +34,7 @@ dependencies {
api 'org.slf4j:slf4j-api:1.7.36' // 2.0.x breaks logging. Code change needed
api 'com.github.tony19:logback-android:2.0.0'
api "org.jetbrains.kotlinx:kotlinx-serialization-json:1.4.1"
api "org.jetbrains.kotlinx:kotlinx-serialization-json:$serialization_version"
api "org.apache.commons:commons-lang3:$commonslang3_version"
//RxBus

View file

@ -1,10 +1,13 @@
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-kapt'
apply plugin: 'kotlin-allopen'
apply plugin: 'com.google.gms.google-services'
apply plugin: 'com.hiya.jacoco-android'
apply plugin: 'com.google.firebase.crashlytics'
plugins {
id 'com.android.application'
id 'kotlin-android'
id 'kotlin-kapt'
id 'kotlin-allopen'
id 'com.hiya.jacoco-android'
id 'kotlinx-serialization'
id 'com.google.gms.google-services'
id 'com.google.firebase.crashlytics'
}
apply from: "${project.rootDir}/core/android_dependencies.gradle"
apply from: "${project.rootDir}/core/jacoco_global.gradle"
@ -105,7 +108,7 @@ android {
defaultConfig {
multiDexEnabled true
versionCode 1500
version "3.1.0.3-dev-c"
version "3.1.0.3-dev-c-nscv3"
buildConfigField "String", "VERSION", '"' + version + '"'
buildConfigField "String", "BUILDVERSION", '"' + generateGitBuild() + '-' + generateDate() + '"'
buildConfigField "String", "REMOTE", '"' + generateGitRemote() + '"'
@ -178,6 +181,7 @@ dependencies {
// https://github.com/nightscout/iconify.git
implementation project(':graphview')
implementation project(':libraries')
implementation project(':ns-sdk')
implementation project(':app-wear-shared:rx')
implementation project(':app-wear-shared:shared')
implementation project(':app-wear-shared:shared-impl')

View file

@ -77,7 +77,7 @@ class RealPumpTest {
configBuilderPlugin.performPluginSwitch(loopPlugin, true, PluginType.LOOP)
// Enable common
configBuilderPlugin.performPluginSwitch(actionsPlugin, true, PluginType.GENERAL)
configBuilderPlugin.performPluginSwitch(actionsPlugin, true, )
// Disable unneeded
MainApp.getPluginsList().remove(objectivesPlugin)

View file

@ -169,7 +169,7 @@ adb shell settings put global animator_duration_scale 0 &
Assert.assertEquals(1.1, p.getBasalTimeFromMidnight(0), 0.0001)
Assert.assertEquals(6.0 * Constants.MMOLL_TO_MGDL, p.targetLowMgdl, 0.0001)
Assert.assertTrue(VirtualPumpPlugin.getPlugin().isEnabled(PluginType.PUMP))
Assert.assertTrue(OpenAPSSMBPlugin.getPlugin().isEnabled(PluginType.APS))
Assert.assertTrue(OpenAPSSMBPlugin.getPlugin().isEnabled())
Assert.assertTrue(LoopPlugin.getPlugin().isEnabled(PluginType.LOOP))
Assert.assertTrue(SensitivityOref1Plugin.getPlugin().isEnabled(PluginType.SENSITIVITY))
Assert.assertTrue(ObjectivesPlugin.objectives[0].isStarted)

View file

@ -172,7 +172,7 @@
</intent-filter>
</service>
<service
android:name=".plugins.general.nsclient.services.NSClientService"
android:name=".plugins.sync.nsclient.services.NSClientService"
android:enabled="true"
android:exported="true" />
<service

View file

@ -51,7 +51,7 @@ import info.nightscout.androidaps.interfaces.ProfileFunction
import info.nightscout.interfaces.SmsCommunicator
import info.nightscout.androidaps.logging.UserEntryLogger
import info.nightscout.androidaps.plugins.constraints.versionChecker.VersionCheckerUtils
import info.nightscout.androidaps.plugins.general.nsclient.data.NSSettingsStatus
import info.nightscout.androidaps.plugins.sync.nsclient.data.NSSettingsStatus
import info.nightscout.androidaps.setupwizard.SetupWizardActivity
import info.nightscout.androidaps.utils.FabricPrivacy
import info.nightscout.androidaps.utils.alertDialogs.OKDialog

View file

@ -214,6 +214,8 @@ class MainApp : DaggerApplication() {
}
sp.remove("ns_charginonly")
}
if (!sp.contains(R.string.key_ns_logappstartedevent))
sp.putBoolean(R.string.key_ns_logappstartedevent, config.APS)
}
override fun applicationInjector(): AndroidInjector<out DaggerApplication> {

View file

@ -36,9 +36,6 @@ import info.nightscout.androidaps.plugins.aps.openAPSSMBDynamicISF.OpenAPSSMBDyn
import info.nightscout.androidaps.plugins.configBuilder.PluginStore
import info.nightscout.androidaps.plugins.constraints.safety.SafetyPlugin
import info.nightscout.androidaps.plugins.general.maintenance.MaintenancePlugin
import info.nightscout.androidaps.plugins.general.nsclient.NSClientPlugin
import info.nightscout.androidaps.plugins.general.nsclient.data.NSSettingsStatus
import info.nightscout.androidaps.plugins.general.tidepool.TidepoolPlugin
import info.nightscout.androidaps.plugins.general.wear.WearPlugin
import info.nightscout.androidaps.plugins.pump.combo.ComboPlugin
import info.nightscout.androidaps.plugins.pump.eopatch.EopatchPumpPlugin
@ -56,6 +53,10 @@ import info.nightscout.androidaps.plugins.source.GlunovoPlugin
import info.nightscout.androidaps.plugins.source.IntelligoPlugin
import info.nightscout.androidaps.plugins.source.PoctechPlugin
import info.nightscout.androidaps.plugins.source.TomatoPlugin
import info.nightscout.androidaps.plugins.sync.nsclient.NSClientPlugin
import info.nightscout.androidaps.plugins.sync.nsclient.data.NSSettingsStatus
import info.nightscout.androidaps.plugins.sync.nsclientV3.NSClientV3Plugin
import info.nightscout.androidaps.plugins.sync.tidepool.TidepoolPlugin
import info.nightscout.androidaps.utils.alertDialogs.OKDialog.show
import info.nightscout.androidaps.utils.protection.PasswordCheck
import info.nightscout.androidaps.utils.protection.ProtectionCheck.ProtectionType.BIOMETRIC
@ -97,6 +98,7 @@ class MyPreferenceFragment : PreferenceFragmentCompat(), OnSharedPreferenceChang
@Inject lateinit var localInsightPlugin: LocalInsightPlugin
@Inject lateinit var medtronicPumpPlugin: MedtronicPumpPlugin
@Inject lateinit var nsClientPlugin: NSClientPlugin
@Inject lateinit var nsClientV3Plugin: NSClientV3Plugin
@Inject lateinit var openAPSAMAPlugin: OpenAPSAMAPlugin
@Inject lateinit var openAPSSMBPlugin: OpenAPSSMBPlugin
@Inject lateinit var openAPSSMBDynamicISFPlugin: OpenAPSSMBDynamicISFPlugin
@ -212,6 +214,7 @@ class MyPreferenceFragment : PreferenceFragmentCompat(), OnSharedPreferenceChang
addPreferencesFromResourceIfEnabled(virtualPumpPlugin, rootKey)
addPreferencesFromResourceIfEnabled(insulinOrefFreePeakPlugin, rootKey)
addPreferencesFromResourceIfEnabled(nsClientPlugin, rootKey)
addPreferencesFromResourceIfEnabled(nsClientV3Plugin, rootKey)
addPreferencesFromResourceIfEnabled(tidepoolPlugin, rootKey)
addPreferencesFromResourceIfEnabled(smsCommunicatorPlugin, rootKey)
addPreferencesFromResourceIfEnabled(automationPlugin, rootKey)
@ -328,13 +331,11 @@ class MyPreferenceFragment : PreferenceFragmentCompat(), OnSharedPreferenceChang
var visible = false
if (p is PreferenceGroup) {
for (i in 0 until p.preferenceCount) {
for (i in 0 until p.preferenceCount)
visible = updateFilterVisibility(filter, p.getPreference(i)) || visible
}
if (visible && p is PreferenceCategory) {
p.initialExpandedChildrenCount = Int.MAX_VALUE
}
if (visible && p is PreferenceCategory) p.initialExpandedChildrenCount = Int.MAX_VALUE
} else {
@Suppress("KotlinConstantConditions")
visible = visible || p.key?.contains(filter, true) == true
visible = visible || p.title?.contains(filter, true) == true
visible = visible || p.summary?.contains(filter, true) == true

View file

@ -43,10 +43,10 @@ import info.nightscout.androidaps.plugins.configBuilder.PluginStore
import info.nightscout.androidaps.plugins.configBuilder.ProfileFunctionImpl
import info.nightscout.androidaps.plugins.general.maintenance.ImportExportPrefsImpl
import info.nightscout.androidaps.plugins.general.maintenance.PrefFileListProvider
import info.nightscout.androidaps.plugins.general.nsclient.DataSyncSelectorImplementation
import info.nightscout.androidaps.plugins.general.nsclient.data.DeviceStatusData
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorPlugin
import info.nightscout.androidaps.plugins.pump.PumpSyncImplementation
import info.nightscout.androidaps.plugins.sync.nsclient.DataSyncSelectorImplementation
import info.nightscout.androidaps.plugins.sync.nsclient.data.ProcessedDeviceStatusData
import info.nightscout.androidaps.utils.DateUtil
import info.nightscout.androidaps.utils.FabricPrivacy
import info.nightscout.androidaps.utils.HardLimits
@ -115,11 +115,11 @@ open class AppModule {
aapsLogger: AAPSLogger, sp: SP, rxBus: RxBus, rh:
ResourceHelper, activePlugin:
ActivePlugin, repository: AppRepository, dateUtil: DateUtil, config: Config, hardLimits: HardLimits,
aapsSchedulers: AapsSchedulers, fabricPrivacy: FabricPrivacy, deviceStatusData: DeviceStatusData
aapsSchedulers: AapsSchedulers, fabricPrivacy: FabricPrivacy, processedDeviceStatusData: ProcessedDeviceStatusData
): ProfileFunction =
ProfileFunctionImpl(
aapsLogger, sp, rxBus, rh, activePlugin, repository, dateUtil,
config, hardLimits, aapsSchedulers, fabricPrivacy, deviceStatusData
config, hardLimits, aapsSchedulers, fabricPrivacy, processedDeviceStatusData
)
@Provides

View file

@ -20,13 +20,13 @@ import info.nightscout.androidaps.plugins.constraints.objectives.ObjectivesFragm
import info.nightscout.androidaps.plugins.constraints.objectives.activities.ObjectivesExamDialog
import info.nightscout.androidaps.plugins.general.actions.ActionsFragment
import info.nightscout.androidaps.plugins.general.maintenance.MaintenanceFragment
import info.nightscout.androidaps.plugins.general.nsclient.NSClientFragment
import info.nightscout.androidaps.plugins.general.overview.OverviewFragment
import info.nightscout.androidaps.plugins.general.overview.dialogs.EditQuickWizardDialog
import info.nightscout.androidaps.plugins.general.tidepool.TidepoolFragment
import info.nightscout.androidaps.plugins.general.wear.WearFragment
import info.nightscout.androidaps.plugins.pump.virtual.VirtualPumpFragment
import info.nightscout.androidaps.plugins.source.BGSourceFragment
import info.nightscout.androidaps.plugins.sync.nsShared.NSClientFragment
import info.nightscout.androidaps.plugins.sync.tidepool.TidepoolFragment
import info.nightscout.androidaps.utils.protection.PasswordCheck
import info.nightscout.plugins.general.autotune.AutotuneFragment

View file

@ -21,10 +21,8 @@ import info.nightscout.androidaps.plugins.constraints.safety.SafetyPlugin
import info.nightscout.androidaps.plugins.general.actions.ActionsPlugin
import info.nightscout.androidaps.plugins.general.dataBroadcaster.DataBroadcastPlugin
import info.nightscout.androidaps.plugins.general.maintenance.MaintenancePlugin
import info.nightscout.androidaps.plugins.general.nsclient.NSClientPlugin
import info.nightscout.androidaps.plugins.general.overview.OverviewPlugin
import info.nightscout.androidaps.plugins.general.persistentNotification.PersistentNotificationPlugin
import info.nightscout.androidaps.plugins.general.tidepool.TidepoolPlugin
import info.nightscout.androidaps.plugins.general.wear.WearPlugin
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorPlugin
import info.nightscout.androidaps.plugins.pump.combo.ComboPlugin
@ -48,6 +46,9 @@ import info.nightscout.androidaps.plugins.source.PoctechPlugin
import info.nightscout.androidaps.plugins.source.RandomBgPlugin
import info.nightscout.androidaps.plugins.source.TomatoPlugin
import info.nightscout.androidaps.plugins.source.XdripPlugin
import info.nightscout.androidaps.plugins.sync.nsclient.NSClientPlugin
import info.nightscout.androidaps.plugins.sync.nsclientV3.NSClientV3Plugin
import info.nightscout.androidaps.plugins.sync.tidepool.TidepoolPlugin
import info.nightscout.automation.AutomationPlugin
import info.nightscout.plugins.constraints.bgQualityCheck.BgQualityCheckPlugin
import info.nightscout.plugins.constraints.dstHelper.DstHelperPlugin
@ -316,6 +317,12 @@ abstract class PluginsListModule {
@IntKey(368)
abstract fun bindTidepoolPlugin(plugin: TidepoolPlugin): PluginBase
@Binds
@Unfinished
@IntoMap
@IntKey(362)
abstract fun bindNSClientV3Plugin(plugin: NSClientV3Plugin): PluginBase
@Binds
@AllConfigs
@IntoMap

View file

@ -2,7 +2,7 @@ package info.nightscout.androidaps.di
import dagger.Module
import dagger.android.ContributesAndroidInjector
import info.nightscout.androidaps.plugins.general.nsclient.services.NSClientService
import info.nightscout.androidaps.plugins.sync.nsclient.services.NSClientService
import info.nightscout.androidaps.plugins.general.overview.notifications.DismissNotificationService
import info.nightscout.androidaps.plugins.general.persistentNotification.DummyService
import info.nightscout.androidaps.plugins.general.wear.wearintegration.DataLayerListenerServiceMobile

View file

@ -3,11 +3,6 @@ package info.nightscout.androidaps.di
import dagger.Module
import dagger.android.ContributesAndroidInjector
import info.nightscout.androidaps.plugins.general.maintenance.ImportExportPrefsImpl
import info.nightscout.androidaps.plugins.general.nsclient.NSClientAddAckWorker
import info.nightscout.androidaps.plugins.general.nsclient.NSClientAddUpdateWorker
import info.nightscout.androidaps.plugins.general.nsclient.NSClientMbgWorker
import info.nightscout.androidaps.plugins.general.nsclient.NSClientUpdateRemoveAckWorker
import info.nightscout.plugins.profile.ProfilePlugin
import info.nightscout.androidaps.plugins.source.AidexPlugin
import info.nightscout.androidaps.plugins.source.DexcomPlugin
import info.nightscout.androidaps.plugins.source.EversensePlugin
@ -17,6 +12,18 @@ import info.nightscout.androidaps.plugins.source.NSClientSourcePlugin
import info.nightscout.androidaps.plugins.source.PoctechPlugin
import info.nightscout.androidaps.plugins.source.TomatoPlugin
import info.nightscout.androidaps.plugins.source.XdripPlugin
import info.nightscout.androidaps.plugins.sync.nsShared.StoreDataForDb
import info.nightscout.androidaps.plugins.sync.nsclient.NSClientAddAckWorker
import info.nightscout.androidaps.plugins.sync.nsclient.NSClientAddUpdateWorker
import info.nightscout.androidaps.plugins.sync.nsclient.NSClientMbgWorker
import info.nightscout.androidaps.plugins.sync.nsclient.NSClientUpdateRemoveAckWorker
import info.nightscout.androidaps.plugins.sync.nsclientV3.workers.LoadBgWorker
import info.nightscout.androidaps.plugins.sync.nsclientV3.workers.LoadDeviceStatusWorker
import info.nightscout.androidaps.plugins.sync.nsclientV3.workers.LoadLastModificationWorker
import info.nightscout.androidaps.plugins.sync.nsclientV3.workers.LoadStatusWorker
import info.nightscout.androidaps.plugins.sync.nsclientV3.workers.LoadTreatmentsWorker
import info.nightscout.androidaps.plugins.sync.nsclientV3.workers.ProcessTreatmentsWorker
import info.nightscout.plugins.profile.ProfilePlugin
@Module
@Suppress("unused")
@ -37,4 +44,11 @@ abstract class WorkersModule {
@ContributesAndroidInjector abstract fun contributesNSClientMbgWorker(): NSClientMbgWorker
@ContributesAndroidInjector abstract fun contributesCsvExportWorker(): ImportExportPrefsImpl.CsvExportWorker
@ContributesAndroidInjector abstract fun contributesAidexWorker(): AidexPlugin.AidexWorker
@ContributesAndroidInjector abstract fun contributesLoadStatusWorker(): LoadStatusWorker
@ContributesAndroidInjector abstract fun contributesLoadLastModificationWorker(): LoadLastModificationWorker
@ContributesAndroidInjector abstract fun contributesLoadBgWorker(): LoadBgWorker
@ContributesAndroidInjector abstract fun contributesStoreBgWorker(): StoreDataForDb.StoreBgWorker
@ContributesAndroidInjector abstract fun contributesTreatmentWorker(): LoadTreatmentsWorker
@ContributesAndroidInjector abstract fun contributesProcessTreatmentsWorker(): ProcessTreatmentsWorker
@ContributesAndroidInjector abstract fun contributesLoadDeviceStatusWorker(): LoadDeviceStatusWorker
}

View file

@ -13,7 +13,6 @@ import android.os.SystemClock
import androidx.core.app.NotificationCompat
import dagger.android.HasAndroidInjector
import info.nightscout.androidaps.BuildConfig
import info.nightscout.interfaces.Constants
import info.nightscout.androidaps.MainActivity
import info.nightscout.androidaps.R
import info.nightscout.androidaps.annotations.OpenForTesting
@ -27,22 +26,17 @@ import info.nightscout.androidaps.database.entities.UserEntry.Sources
import info.nightscout.androidaps.database.entities.ValueWithUnit
import info.nightscout.androidaps.database.transactions.InsertAndCancelCurrentOfflineEventTransaction
import info.nightscout.androidaps.database.transactions.InsertTherapyEventAnnouncementTransaction
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.interfaces.ActivePlugin
import info.nightscout.interfaces.ActivityNames
import info.nightscout.androidaps.interfaces.CommandQueue
import info.nightscout.interfaces.Config
import info.nightscout.androidaps.interfaces.Constraint
import info.nightscout.androidaps.interfaces.Constraints
import info.nightscout.androidaps.interfaces.IobCobCalculator
import info.nightscout.androidaps.interfaces.Loop
import info.nightscout.androidaps.interfaces.Loop.LastRun
import info.nightscout.androidaps.interfaces.PluginBase
import info.nightscout.interfaces.PluginDescription
import info.nightscout.interfaces.PluginType
import info.nightscout.androidaps.interfaces.Profile
import info.nightscout.androidaps.interfaces.ProfileFunction
import info.nightscout.androidaps.interfaces.PumpDescription
@ -55,14 +49,20 @@ import info.nightscout.androidaps.plugins.aps.loop.events.EventNewOpenLoopNotifi
import info.nightscout.androidaps.plugins.configBuilder.RunningConfiguration
import info.nightscout.androidaps.plugins.general.overview.events.EventDismissNotification
import info.nightscout.androidaps.plugins.general.overview.events.EventNewNotification
import info.nightscout.interfaces.notifications.Notification
import info.nightscout.androidaps.plugins.pump.virtual.VirtualPumpPlugin
import info.nightscout.interfaces.queue.Callback
import info.nightscout.androidaps.receivers.ReceiverStatusStore
import info.nightscout.androidaps.utils.DateUtil
import info.nightscout.androidaps.utils.FabricPrivacy
import info.nightscout.androidaps.utils.HardLimits
import info.nightscout.androidaps.utils.T
import info.nightscout.androidaps.utils.extensions.buildDeviceStatus
import info.nightscout.interfaces.ActivityNames
import info.nightscout.interfaces.Config
import info.nightscout.interfaces.Constants
import info.nightscout.interfaces.PluginDescription
import info.nightscout.interfaces.PluginType
import info.nightscout.interfaces.notifications.Notification
import info.nightscout.interfaces.queue.Callback
import info.nightscout.rx.AapsSchedulers
import info.nightscout.rx.bus.RxBus
import info.nightscout.rx.events.EventAcceptOpenLoopChange

View file

@ -100,7 +100,7 @@ class OpenAPSAMAPlugin @Inject constructor(
aapsLogger.debug(LTag.APS, rh.gs(R.string.noprofileset))
return
}
if (!isEnabled(PluginType.APS)) {
if (!isEnabled()) {
rxBus.send(EventOpenAPSUpdateResultGui(rh.gs(R.string.openapsma_disabled)))
aapsLogger.debug(LTag.APS, rh.gs(R.string.openapsma_disabled))
return

View file

@ -109,7 +109,7 @@ class OpenAPSSMBPlugin @Inject constructor(
aapsLogger.debug(LTag.APS, rh.gs(R.string.noprofileset))
return
}
if (!isEnabled(PluginType.APS)) {
if (!isEnabled()) {
rxBus.send(EventOpenAPSUpdateResultGui(rh.gs(R.string.openapsma_disabled)))
aapsLogger.debug(LTag.APS, rh.gs(R.string.openapsma_disabled))
return

View file

@ -114,6 +114,7 @@ class ConfigBuilderFragment : DaggerFragment() {
createViewsForPlugins(R.string.configbuilder_loop, R.string.configbuilder_loop_description, PluginType.LOOP, activePlugin.getSpecificPluginsVisibleInList(PluginType.LOOP))
createViewsForPlugins(R.string.constraints, R.string.configbuilder_constraints_description, PluginType.CONSTRAINTS, activePlugin.getSpecificPluginsVisibleInList(PluginType.CONSTRAINTS))
}
createViewsForPlugins(R.string.configbuilder_sync, R.string.configbuilder_sync_description, PluginType.SYNC, activePlugin.getSpecificPluginsVisibleInList(PluginType.SYNC))
createViewsForPlugins(R.string.configbuilder_general, R.string.configbuilder_general_description, PluginType.GENERAL, activePlugin.getSpecificPluginsVisibleInList(PluginType.GENERAL))
}
@ -208,7 +209,7 @@ class ConfigBuilderFragment : DaggerFragment() {
}
private fun areMultipleSelectionsAllowed(type: PluginType): Boolean {
return type == PluginType.GENERAL || type == PluginType.CONSTRAINTS || type == PluginType.LOOP
return type == PluginType.GENERAL || type == PluginType.CONSTRAINTS || type == PluginType.LOOP || type == PluginType.SYNC
}
}

View file

@ -11,9 +11,8 @@ import info.nightscout.androidaps.interfaces.ActivePlugin
import info.nightscout.androidaps.interfaces.BgSource
import info.nightscout.androidaps.interfaces.ConfigBuilder
import info.nightscout.androidaps.interfaces.Insulin
import info.nightscout.androidaps.interfaces.NsClient
import info.nightscout.androidaps.interfaces.PluginBase
import info.nightscout.interfaces.PluginDescription
import info.nightscout.interfaces.PluginType
import info.nightscout.androidaps.interfaces.ProfileSource
import info.nightscout.androidaps.interfaces.Pump
import info.nightscout.androidaps.interfaces.PumpSync
@ -22,6 +21,8 @@ import info.nightscout.androidaps.interfaces.Sensitivity
import info.nightscout.androidaps.logging.UserEntryLogger
import info.nightscout.androidaps.plugins.configBuilder.events.EventConfigBuilderUpdateGui
import info.nightscout.androidaps.utils.alertDialogs.OKDialog
import info.nightscout.interfaces.PluginDescription
import info.nightscout.interfaces.PluginType
import info.nightscout.rx.bus.RxBus
import info.nightscout.rx.events.EventAppInitialized
import info.nightscout.rx.events.EventConfigBuilderChange
@ -44,15 +45,15 @@ class ConfigBuilderPlugin @Inject constructor(
private val pumpSync: PumpSync
) : PluginBase(
PluginDescription()
.mainType(PluginType.GENERAL)
.fragmentClass(ConfigBuilderFragment::class.java.name)
.showInList(true)
.alwaysEnabled(true)
.alwaysVisible(false)
.pluginIcon(R.drawable.ic_cogs)
.pluginName(R.string.configbuilder)
.shortName(R.string.configbuilder_shortname)
.description(R.string.description_config_builder),
.mainType(PluginType.GENERAL)
.fragmentClass(ConfigBuilderFragment::class.java.name)
.showInList(true)
.alwaysEnabled(true)
.alwaysVisible(false)
.pluginIcon(R.drawable.ic_cogs)
.pluginName(R.string.configbuilder)
.shortName(R.string.configbuilder_shortname)
.description(R.string.description_config_builder),
aapsLogger, rh, injector
), ConfigBuilder {
@ -77,58 +78,60 @@ class ConfigBuilderPlugin @Inject constructor(
val type = p.getType()
if (p.pluginDescription.alwaysEnabled && p.pluginDescription.alwaysVisible) continue
if (p.pluginDescription.alwaysEnabled && p.pluginDescription.neverVisible) continue
savePref(p, type, true)
savePref(p, type)
}
}
private fun savePref(p: PluginBase, type: PluginType, storeVisible: Boolean) {
private fun savePref(p: PluginBase, type: PluginType) {
val settingEnabled = "ConfigBuilder_" + type.name + "_" + p.javaClass.simpleName + "_Enabled"
sp.putBoolean(settingEnabled, p.isEnabled())
aapsLogger.debug(LTag.CONFIGBUILDER, "Storing: " + settingEnabled + ":" + p.isEnabled())
if (storeVisible) {
val settingVisible = "ConfigBuilder_" + type.name + "_" + p.javaClass.simpleName + "_Visible"
sp.putBoolean(settingVisible, p.isFragmentVisible())
aapsLogger.debug(LTag.CONFIGBUILDER, "Storing: " + settingVisible + ":" + p.isFragmentVisible())
}
val settingVisible = "ConfigBuilder_" + type.name + "_" + p.javaClass.simpleName + "_Visible"
sp.putBoolean(settingVisible, p.isFragmentVisible())
aapsLogger.debug(LTag.CONFIGBUILDER, "Storing: " + settingVisible + ":" + p.isFragmentVisible())
}
private fun loadSettings() {
aapsLogger.debug(LTag.CONFIGBUILDER, "Loading stored settings")
for (p in activePlugin.getPluginsList()) {
val type = p.getType()
loadPref(p, type, true)
loadPref(p, type)
}
activePlugin.verifySelectionInCategories()
}
private fun loadPref(p: PluginBase, type: PluginType, loadVisible: Boolean) {
private fun loadPref(p: PluginBase, type: PluginType) {
val settingEnabled = "ConfigBuilder_" + type.name + "_" + p.javaClass.simpleName + "_Enabled"
if (sp.contains(settingEnabled)) p.setPluginEnabled(type, sp.getBoolean(settingEnabled, false)) else if (p.getType() == type && (p.pluginDescription.enableByDefault || p.pluginDescription.alwaysEnabled)) {
if (sp.contains(settingEnabled)) p.setPluginEnabled(
type,
sp.getBoolean(settingEnabled, false)
) else if (p.getType() == type && (p.pluginDescription.enableByDefault || p.pluginDescription.alwaysEnabled)) {
p.setPluginEnabled(type, true)
}
aapsLogger.debug(LTag.CONFIGBUILDER, "Loaded: " + settingEnabled + ":" + p.isEnabled(type))
if (loadVisible) {
val settingVisible = "ConfigBuilder_" + type.name + "_" + p.javaClass.simpleName + "_Visible"
if (sp.contains(settingVisible)) p.setFragmentVisible(type, sp.getBoolean(settingVisible, false) && sp.getBoolean(settingEnabled, false)) else if (p.getType() == type && p.pluginDescription.visibleByDefault) {
p.setFragmentVisible(type, true)
}
aapsLogger.debug(LTag.CONFIGBUILDER, "Loaded: " + settingVisible + ":" + p.isFragmentVisible())
val settingVisible = "ConfigBuilder_" + type.name + "_" + p.javaClass.simpleName + "_Visible"
if (sp.contains(settingVisible)) p.setFragmentVisible(
type,
sp.getBoolean(settingVisible, false) && sp.getBoolean(settingEnabled, false)
) else if (p.getType() == type && p.pluginDescription.visibleByDefault) {
p.setFragmentVisible(type, true)
}
aapsLogger.debug(LTag.CONFIGBUILDER, "Loaded: " + settingVisible + ":" + p.isFragmentVisible())
}
fun logPluginStatus() {
for (p in activePlugin.getPluginsList()) {
aapsLogger.debug(
LTag.CONFIGBUILDER, p.name + ":" +
(if (p.isEnabled(PluginType.GENERAL)) " GENERAL" else "") +
(if (p.isEnabled(PluginType.SENSITIVITY)) " SENSITIVITY" else "") +
(if (p.isEnabled(PluginType.PROFILE)) " PROFILE" else "") +
(if (p.isEnabled(PluginType.APS)) " APS" else "") +
(if (p.isEnabled(PluginType.PUMP)) " PUMP" else "") +
(if (p.isEnabled(PluginType.CONSTRAINTS)) " CONSTRAINTS" else "") +
(if (p.isEnabled(PluginType.LOOP)) " LOOP" else "") +
(if (p.isEnabled(PluginType.BGSOURCE)) " BGSOURCE" else "") +
if (p.isEnabled(PluginType.INSULIN)) " INSULIN" else ""
(if (p.isEnabled(PluginType.GENERAL)) " GENERAL" else "") +
(if (p.isEnabled(PluginType.SENSITIVITY)) " SENSITIVITY" else "") +
(if (p.isEnabled(PluginType.PROFILE)) " PROFILE" else "") +
(if (p.isEnabled(PluginType.APS)) " APS" else "") +
(if (p.isEnabled(PluginType.PUMP)) " PUMP" else "") +
(if (p.isEnabled(PluginType.CONSTRAINTS)) " CONSTRAINTS" else "") +
(if (p.isEnabled(PluginType.LOOP)) " LOOP" else "") +
(if (p.isEnabled(PluginType.BGSOURCE)) " BGSOURCE" else "") +
if (p.isEnabled(PluginType.INSULIN)) " INSULIN" else ""
)
}
}
@ -153,36 +156,41 @@ class ConfigBuilderPlugin @Inject constructor(
performPluginSwitch(changedPlugin, newState, type)
pumpSync.connectNewPump()
sp.putBoolean("allow_hardware_pump", true)
uel.log(Action.HW_PUMP_ALLOWED, Sources.ConfigBuilder, rh.gs(changedPlugin.pluginDescription.pluginName),
ValueWithUnit.SimpleString(rh.gsNotLocalised(changedPlugin.pluginDescription.pluginName)))
uel.log(
Action.HW_PUMP_ALLOWED, Sources.ConfigBuilder, rh.gs(changedPlugin.pluginDescription.pluginName),
ValueWithUnit.SimpleString(rh.gsNotLocalised(changedPlugin.pluginDescription.pluginName))
)
aapsLogger.debug(LTag.PUMP, "First time HW pump allowed!")
}, {
rxBus.send(EventConfigBuilderUpdateGui())
aapsLogger.debug(LTag.PUMP, "User does not allow switching to HW pump!")
})
rxBus.send(EventConfigBuilderUpdateGui())
aapsLogger.debug(LTag.PUMP, "User does not allow switching to HW pump!")
})
}
}
override fun performPluginSwitch(changedPlugin: PluginBase, enabled: Boolean, type: PluginType) {
if(enabled && !changedPlugin.isEnabled()) {
uel.log(Action.PLUGIN_ENABLED, Sources.ConfigBuilder, rh.gs(changedPlugin.pluginDescription.pluginName),
ValueWithUnit.SimpleString(rh.gsNotLocalised(changedPlugin.pluginDescription.pluginName)))
}
else if(!enabled) {
uel.log(Action.PLUGIN_DISABLED, Sources.ConfigBuilder, rh.gs(changedPlugin.pluginDescription.pluginName),
ValueWithUnit.SimpleString(rh.gsNotLocalised(changedPlugin.pluginDescription.pluginName)))
if (enabled && !changedPlugin.isEnabled()) {
uel.log(
Action.PLUGIN_ENABLED, Sources.ConfigBuilder, rh.gs(changedPlugin.pluginDescription.pluginName),
ValueWithUnit.SimpleString(rh.gsNotLocalised(changedPlugin.pluginDescription.pluginName))
)
} else if (!enabled) {
uel.log(
Action.PLUGIN_DISABLED, Sources.ConfigBuilder, rh.gs(changedPlugin.pluginDescription.pluginName),
ValueWithUnit.SimpleString(rh.gsNotLocalised(changedPlugin.pluginDescription.pluginName))
)
}
changedPlugin.setPluginEnabled(type, enabled)
changedPlugin.setFragmentVisible(type, enabled)
processOnEnabledCategoryChanged(changedPlugin, type)
storeSettings("CheckedCheckboxEnabled")
storeSettings("RemoteConfiguration")
rxBus.send(EventRebuildTabs())
rxBus.send(EventConfigBuilderChange())
rxBus.send(EventConfigBuilderUpdateGui())
logPluginStatus()
}
fun processOnEnabledCategoryChanged(changedPlugin: PluginBase, type: PluginType?) {
fun processOnEnabledCategoryChanged(changedPlugin: PluginBase, type: PluginType) {
var pluginsInCategory: ArrayList<PluginBase>? = null
when (type) {
PluginType.INSULIN -> pluginsInCategory = activePlugin.getSpecificPluginsListByInterface(Insulin::class.java)
@ -191,12 +199,14 @@ class ConfigBuilderPlugin @Inject constructor(
PluginType.PROFILE -> pluginsInCategory = activePlugin.getSpecificPluginsListByInterface(ProfileSource::class.java)
PluginType.BGSOURCE -> pluginsInCategory = activePlugin.getSpecificPluginsListByInterface(BgSource::class.java)
PluginType.PUMP -> pluginsInCategory = activePlugin.getSpecificPluginsListByInterface(Pump::class.java)
// Process only NSClients
PluginType.SYNC -> pluginsInCategory = activePlugin.getSpecificPluginsListByInterface(NsClient::class.java)
else -> {
}
}
if (pluginsInCategory != null) {
val newSelection = changedPlugin.isEnabled(type!!)
val newSelection = changedPlugin.isEnabled(type)
if (newSelection) { // new plugin selected -> disable others
for (p in pluginsInCategory) {
if (p.name == changedPlugin.name) {
@ -206,7 +216,9 @@ class ConfigBuilderPlugin @Inject constructor(
p.setFragmentVisible(type, false)
}
}
} else { // enable first plugin in list
} else if (type != PluginType.SYNC) {
// enable first plugin in list
// NSC must not be selected
pluginsInCategory[0].setPluginEnabled(type, true)
}
}

View file

@ -3,16 +3,18 @@ package info.nightscout.androidaps.plugins.configBuilder
import info.nightscout.androidaps.interfaces.APS
import info.nightscout.androidaps.interfaces.ActivePlugin
import info.nightscout.androidaps.interfaces.BgSource
import info.nightscout.interfaces.Config
import info.nightscout.androidaps.interfaces.Insulin
import info.nightscout.androidaps.interfaces.IobCobCalculator
import info.nightscout.androidaps.interfaces.NsClient
import info.nightscout.androidaps.interfaces.Overview
import info.nightscout.androidaps.interfaces.PluginBase
import info.nightscout.interfaces.PluginType
import info.nightscout.androidaps.interfaces.ProfileSource
import info.nightscout.androidaps.interfaces.Pump
import info.nightscout.interfaces.Safety
import info.nightscout.androidaps.interfaces.Sensitivity
import info.nightscout.androidaps.interfaces.Sync
import info.nightscout.interfaces.Config
import info.nightscout.interfaces.PluginType
import info.nightscout.interfaces.Safety
import info.nightscout.rx.logging.AAPSLogger
import info.nightscout.rx.logging.LTag
import javax.inject.Inject
@ -133,8 +135,9 @@ class PluginStore @Inject constructor(
setFragmentVisibilities((activePumpStore as PluginBase).name, pluginsInCategory, PluginType.PUMP)
}
private fun setFragmentVisibilities(activePluginName: String, pluginsInCategory: ArrayList<PluginBase>,
pluginType: PluginType
private fun setFragmentVisibilities(
activePluginName: String, pluginsInCategory: ArrayList<PluginBase>,
pluginType: PluginType
) {
aapsLogger.debug(LTag.CONFIGBUILDER, "Selected interface: $activePluginName")
for (p in pluginsInCategory)
@ -185,6 +188,17 @@ class PluginStore @Inject constructor(
override val activeIobCobCalculator: IobCobCalculator
get() = getSpecificPluginsListByInterface(IobCobCalculator::class.java).first() as IobCobCalculator
override val activeNsClient: NsClient?
get() = getTheOneEnabledInArray(getSpecificPluginsListByInterface(NsClient::class.java), PluginType.SYNC) as NsClient?
@Suppress("UNCHECKED_CAST")
override val firstActiveSync: Sync?
get() = (getSpecificPluginsList(PluginType.SYNC) as ArrayList<Sync>).firstOrNull { it.connected }
@Suppress("UNCHECKED_CAST")
override val activeSyncs: ArrayList<Sync>
get() = getSpecificPluginsList(PluginType.SYNC) as ArrayList<Sync>
override fun getPluginsList(): ArrayList<PluginBase> = ArrayList(plugins)
}

View file

@ -1,6 +1,5 @@
package info.nightscout.androidaps.plugins.configBuilder
import info.nightscout.interfaces.Constants
import info.nightscout.androidaps.core.R
import info.nightscout.androidaps.data.ProfileSealed
import info.nightscout.androidaps.database.AppRepository
@ -8,19 +7,20 @@ import info.nightscout.androidaps.database.ValueWrapper
import info.nightscout.androidaps.database.entities.ProfileSwitch
import info.nightscout.androidaps.database.transactions.InsertOrUpdateProfileSwitch
import info.nightscout.androidaps.events.EventEffectiveProfileSwitchChanged
import info.nightscout.androidaps.extensions.fromConstant
import info.nightscout.androidaps.interfaces.ActivePlugin
import info.nightscout.interfaces.Config
import info.nightscout.androidaps.interfaces.GlucoseUnit
import info.nightscout.androidaps.interfaces.Profile
import info.nightscout.androidaps.interfaces.ProfileFunction
import info.nightscout.androidaps.interfaces.ProfileStore
import info.nightscout.androidaps.interfaces.ResourceHelper
import info.nightscout.androidaps.plugins.general.nsclient.data.DeviceStatusData
import info.nightscout.androidaps.plugins.sync.nsclient.data.ProcessedDeviceStatusData
import info.nightscout.androidaps.utils.DateUtil
import info.nightscout.androidaps.utils.FabricPrivacy
import info.nightscout.androidaps.utils.HardLimits
import info.nightscout.androidaps.utils.T
import info.nightscout.androidaps.utils.extensions.fromConstant
import info.nightscout.interfaces.Config
import info.nightscout.interfaces.Constants
import info.nightscout.rx.AapsSchedulers
import info.nightscout.rx.bus.RxBus
import info.nightscout.rx.logging.AAPSLogger
@ -45,7 +45,7 @@ class ProfileFunctionImpl @Inject constructor(
private val hardLimits: HardLimits,
aapsSchedulers: AapsSchedulers,
private val fabricPrivacy: FabricPrivacy,
private val deviceStatusData: DeviceStatusData
private val processedDeviceStatusData: ProcessedDeviceStatusData
) : ProfileFunction {
private var cache = ConcurrentHashMap<Long, Profile?>()
@ -117,7 +117,7 @@ class ProfileFunctionImpl @Inject constructor(
// Try to get it from device status
// Remove this code after switch to api v3
if (config.NSCLIENT && ps is ValueWrapper.Absent) {
deviceStatusData.pumpData?.activeProfileName?.let { activeProfile ->
processedDeviceStatusData.pumpData?.activeProfileName?.let { activeProfile ->
activePlugin.activeProfileSource.profile?.getSpecificProfile(activeProfile)?.let { ap ->
val sealed = ProfileSealed.Pure(ap)
synchronized(cache) {
@ -183,7 +183,7 @@ class ProfileFunctionImpl @Inject constructor(
val profileStore = activePlugin.activeProfileSource.profile ?: return false
val ps = buildProfileSwitch(profileStore, profile.profileName, durationInMinutes, percentage, 0, dateUtil.now()) ?: return false
val validity = ProfileSealed.PS(ps).isValid(
rh.gs(info.nightscout.automation.R.string.careportal_profileswitch),
rh.gs(R.string.careportal_profileswitch),
activePlugin.activePump,
config,
rh,

View file

@ -2,21 +2,22 @@ package info.nightscout.androidaps.plugins.configBuilder
import info.nightscout.androidaps.core.R
import info.nightscout.androidaps.interfaces.ActivePlugin
import info.nightscout.interfaces.Config
import info.nightscout.androidaps.interfaces.ConfigBuilder
import info.nightscout.androidaps.interfaces.Insulin
import info.nightscout.interfaces.PluginType
import info.nightscout.androidaps.interfaces.NsClient
import info.nightscout.androidaps.interfaces.PumpSync
import info.nightscout.androidaps.interfaces.ResourceHelper
import info.nightscout.androidaps.interfaces.Sensitivity
import info.nightscout.androidaps.plugins.general.nsclient.events.EventNSClientNewLog
import info.nightscout.androidaps.plugins.general.overview.events.EventNewNotification
import info.nightscout.interfaces.notifications.Notification
import info.nightscout.androidaps.plugins.pump.common.defs.PumpType
import info.nightscout.interfaces.utils.JsonHelper
import info.nightscout.androidaps.plugins.sync.nsShared.events.EventNSClientNewLog
import info.nightscout.interfaces.Config
import info.nightscout.interfaces.PluginType
import info.nightscout.interfaces.notifications.Notification
import info.nightscout.rx.bus.RxBus
import info.nightscout.rx.logging.AAPSLogger
import info.nightscout.rx.logging.LTag
import info.nightscout.sdk.remotemodel.RemoteDeviceStatus
import info.nightscout.shared.sharedPreferences.SP
import org.json.JSONException
import org.json.JSONObject
@ -66,17 +67,16 @@ class RunningConfiguration @Inject constructor(
}
// called in NSClient mode only
fun apply(configuration: JSONObject) {
fun apply(configuration: RemoteDeviceStatus.Configuration, version: NsClient.Version) {
assert(config.NSCLIENT)
if (configuration.has("version")) {
rxBus.send(EventNSClientNewLog("VERSION", "Received AndroidAPS version ${configuration.getString("version")}"))
if (config.VERSION_NAME.startsWith(configuration.getString("version")).not()) {
configuration.version?.let {
rxBus.send(EventNSClientNewLog("VERSION", "Received AndroidAPS version $it", version))
if (config.VERSION_NAME.startsWith(it).not())
rxBus.send(EventNewNotification(Notification(Notification.NSCLIENT_VERSION_DOES_NOT_MATCH, rh.gs(R.string.nsclient_version_does_not_match), Notification.NORMAL)))
}
}
if (configuration.has("insulin")) {
val insulin = Insulin.InsulinType.fromInt(JsonHelper.safeGetInt(configuration, "insulin", Insulin.InsulinType.UNKNOWN.value))
configuration.insulin?.let {
val insulin = Insulin.InsulinType.fromInt(it)
for (p in activePlugin.getSpecificPluginsListByInterface(Insulin::class.java)) {
val insulinPlugin = p as Insulin
if (insulinPlugin.id == insulin) {
@ -84,13 +84,13 @@ class RunningConfiguration @Inject constructor(
aapsLogger.debug(LTag.CORE, "Changing insulin plugin to ${insulin.name}")
configBuilder.performPluginSwitch(p, true, PluginType.INSULIN)
}
insulinPlugin.applyConfiguration(configuration.getJSONObject("insulinConfiguration"))
configuration.insulinConfiguration?.let { ic -> insulinPlugin.applyConfiguration(ic) }
}
}
}
if (configuration.has("sensitivity")) {
val sensitivity = Sensitivity.SensitivityType.fromInt(JsonHelper.safeGetInt(configuration, "sensitivity", Sensitivity.SensitivityType.UNKNOWN.value))
configuration.sensitivity?.let {
val sensitivity = Sensitivity.SensitivityType.fromInt(it)
for (p in activePlugin.getSpecificPluginsListByInterface(Sensitivity::class.java)) {
val sensitivityPlugin = p as Sensitivity
if (sensitivityPlugin.id == sensitivity) {
@ -98,25 +98,26 @@ class RunningConfiguration @Inject constructor(
aapsLogger.debug(LTag.CORE, "Changing sensitivity plugin to ${sensitivity.name}")
configBuilder.performPluginSwitch(p, true, PluginType.SENSITIVITY)
}
sensitivityPlugin.applyConfiguration(configuration.getJSONObject("sensitivityConfiguration"))
configuration.sensitivityConfiguration?.let { sc -> sensitivityPlugin.applyConfiguration(sc) }
}
}
}
if (configuration.has("pump")) {
val pumpType = JsonHelper.safeGetString(configuration, "pump", PumpType.GENERIC_AAPS.description)
if (sp.getString(R.string.key_virtualpump_type, "fake") != pumpType) {
sp.putString(R.string.key_virtualpump_type, pumpType)
activePlugin.activePump.pumpDescription.fillFor(PumpType.getByDescription(pumpType))
configuration.pump?.let {
if (sp.getString(R.string.key_virtualpump_type, "fake") != it) {
sp.putString(R.string.key_virtualpump_type, it)
activePlugin.activePump.pumpDescription.fillFor(PumpType.getByDescription(it))
pumpSync.connectNewPump(endRunning = false) // do not end running TBRs, we call this only to accept data properly
aapsLogger.debug(LTag.CORE, "Changing pump type to $pumpType")
aapsLogger.debug(LTag.CORE, "Changing pump type to $it")
}
}
if (configuration.has("overviewConfiguration"))
activePlugin.activeOverview.applyConfiguration(configuration.getJSONObject("overviewConfiguration"))
configuration.overviewConfiguration?.let {
activePlugin.activeOverview.applyConfiguration(it)
}
if (configuration.has("safetyConfiguration"))
activePlugin.activeSafety.applyConfiguration(configuration.getJSONObject("safetyConfiguration"))
configuration.safetyConfiguration?.let {
activePlugin.activeSafety.applyConfiguration(it)
}
}
}

View file

@ -1,22 +1,12 @@
package info.nightscout.androidaps.plugins.constraints.objectives
import androidx.fragment.app.FragmentActivity
import com.google.common.base.Charsets
import com.google.common.hash.Hashing
import dagger.android.HasAndroidInjector
import info.nightscout.androidaps.BuildConfig
import info.nightscout.androidaps.R
import info.nightscout.androidaps.database.entities.UserEntry.Action
import info.nightscout.androidaps.database.entities.UserEntry.Sources
import info.nightscout.androidaps.interfaces.ActivePlugin
import info.nightscout.interfaces.Config
import info.nightscout.androidaps.interfaces.Constraint
import info.nightscout.androidaps.interfaces.Constraints
import info.nightscout.androidaps.interfaces.PluginBase
import info.nightscout.interfaces.PluginDescription
import info.nightscout.interfaces.PluginType
import info.nightscout.androidaps.interfaces.ResourceHelper
import info.nightscout.androidaps.logging.UserEntryLogger
import info.nightscout.androidaps.plugins.constraints.objectives.objectives.Objective
import info.nightscout.androidaps.plugins.constraints.objectives.objectives.Objective0
import info.nightscout.androidaps.plugins.constraints.objectives.objectives.Objective1
@ -28,11 +18,11 @@ import info.nightscout.androidaps.plugins.constraints.objectives.objectives.Obje
import info.nightscout.androidaps.plugins.constraints.objectives.objectives.Objective6
import info.nightscout.androidaps.plugins.constraints.objectives.objectives.Objective7
import info.nightscout.androidaps.plugins.constraints.objectives.objectives.Objective9
import info.nightscout.androidaps.utils.DateUtil
import info.nightscout.androidaps.utils.alertDialogs.OKDialog
import info.nightscout.interfaces.Config
import info.nightscout.interfaces.PluginDescription
import info.nightscout.interfaces.PluginType
import info.nightscout.rx.logging.AAPSLogger
import info.nightscout.shared.sharedPreferences.SP
import java.util.Locale
import javax.inject.Inject
import javax.inject.Singleton
@ -43,19 +33,17 @@ class ObjectivesPlugin @Inject constructor(
rh: ResourceHelper,
private val activePlugin: ActivePlugin,
private val sp: SP,
config: Config,
private val dateUtil: DateUtil,
private val uel: UserEntryLogger
config: Config
) : PluginBase(
PluginDescription()
.mainType(PluginType.CONSTRAINTS)
.fragmentClass(ObjectivesFragment::class.qualifiedName)
.alwaysEnabled(config.APS)
.showInList(config.APS)
.pluginIcon(R.drawable.ic_graduation)
.pluginName(R.string.objectives)
.shortName(R.string.objectives_shortname)
.description(R.string.description_objectives),
.mainType(PluginType.CONSTRAINTS)
.fragmentClass(ObjectivesFragment::class.qualifiedName)
.alwaysEnabled(config.APS)
.showInList(config.APS)
.pluginIcon(R.drawable.ic_graduation)
.pluginName(R.string.objectives)
.shortName(R.string.objectives_shortname)
.description(R.string.description_objectives),
aapsLogger, rh, injector
), Constraints {
@ -115,34 +103,6 @@ class ObjectivesPlugin @Inject constructor(
sp.putBoolean(R.string.key_objectiveusescale, false)
}
fun completeObjectives(activity: FragmentActivity, request: String) {
val requestCode = sp.getString(R.string.key_objectives_request_code, "")
var url = sp.getString(R.string.key_nsclientinternal_url, "").lowercase(Locale.getDefault())
if (!url.endsWith("/")) url = "$url/"
@Suppress("DEPRECATION", "UnstableApiUsage") val hashNS = Hashing.sha1().hashString(url + BuildConfig.APPLICATION_ID + "/" + requestCode, Charsets.UTF_8).toString()
if (request.equals(hashNS.substring(0, 10), ignoreCase = true)) {
sp.putLong("Objectives_" + "openloop" + "_started", dateUtil.now())
sp.putLong("Objectives_" + "openloop" + "_accomplished", dateUtil.now())
sp.putLong("Objectives_" + "maxbasal" + "_started", dateUtil.now())
sp.putLong("Objectives_" + "maxbasal" + "_accomplished", dateUtil.now())
sp.putLong("Objectives_" + "maxiobzero" + "_started", dateUtil.now())
sp.putLong("Objectives_" + "maxiobzero" + "_accomplished", dateUtil.now())
sp.putLong("Objectives_" + "maxiob" + "_started", dateUtil.now())
sp.putLong("Objectives_" + "maxiob" + "_accomplished", dateUtil.now())
sp.putLong("Objectives_" + "autosens" + "_started", dateUtil.now())
sp.putLong("Objectives_" + "autosens" + "_accomplished", dateUtil.now())
sp.putLong("Objectives_" + "smb" + "_started", dateUtil.now())
sp.putLong("Objectives_" + "smb" + "_accomplished", dateUtil.now())
sp.putLong("Objectives_" + "auto" + "_started", dateUtil.now())
sp.putLong("Objectives_" + "auto" + "_accomplished", dateUtil.now())
setupObjectives()
OKDialog.show(activity, rh.gs(R.string.objectives), rh.gs(R.string.codeaccepted))
uel.log(Action.OBJECTIVES_SKIPPED, Sources.Objectives)
} else {
OKDialog.show(activity, rh.gs(R.string.objectives), rh.gs(R.string.codeinvalid))
}
}
fun allPriorAccomplished(position: Int): Boolean {
var accomplished = true
for (i in 0 until position) {

View file

@ -8,7 +8,6 @@ import info.nightscout.androidaps.interfaces.ActivePlugin
import info.nightscout.androidaps.interfaces.IobCobCalculator
import info.nightscout.androidaps.interfaces.Loop
import info.nightscout.androidaps.interfaces.PluginBase
import info.nightscout.androidaps.plugins.general.nsclient.NSClientPlugin
import info.nightscout.androidaps.plugins.pump.virtual.VirtualPumpPlugin
import javax.inject.Inject
@ -18,7 +17,6 @@ class Objective0(injector: HasAndroidInjector) : Objective(injector, "config", R
@Inject lateinit var virtualPumpPlugin: VirtualPumpPlugin
@Inject lateinit var repository: AppRepository
@Inject lateinit var loop: Loop
@Inject lateinit var nsClientPlugin: NSClientPlugin
@Inject lateinit var iobCobCalculator: IobCobCalculator
init {
@ -27,9 +25,9 @@ class Objective0(injector: HasAndroidInjector) : Objective(injector, "config", R
return sp.getBoolean(R.string.key_ObjectivesbgIsAvailableInNS, false)
}
})
tasks.add(object : Task(this, R.string.nsclienthaswritepermission) {
tasks.add(object : Task(this, R.string.synchaswritepermission) {
override fun isCompleted(): Boolean {
return nsClientPlugin.hasWritePermission()
return activePlugin.firstActiveSync?.hasWritePermission == true
}
})
tasks.add(object : Task(this, R.string.virtualpump_uploadstatus_title) {

View file

@ -1,18 +1,15 @@
package info.nightscout.androidaps.plugins.constraints.objectives.objectives
import androidx.fragment.app.FragmentActivity
import dagger.android.HasAndroidInjector
import info.nightscout.androidaps.R
import info.nightscout.androidaps.plugins.constraints.objectives.ObjectivesPlugin
import info.nightscout.androidaps.plugins.general.nsclient.NSClientPlugin
import info.nightscout.androidaps.interfaces.ActivePlugin
import info.nightscout.androidaps.utils.T
import javax.inject.Inject
@Suppress("SpellCheckingInspection")
class Objective3 @Inject constructor(injector: HasAndroidInjector) : Objective(injector, "openloop", R.string.objectives_openloop_objective, R.string.objectives_openloop_gate) {
@Inject lateinit var objectivesPlugin: ObjectivesPlugin
@Inject lateinit var nsClientPlugin: NSClientPlugin
@Inject lateinit var activePlugin: ActivePlugin
init {
tasks.add(MinimumDurationTask(this, T.days(7).msecs()))
@ -22,17 +19,11 @@ class Objective3 @Inject constructor(injector: HasAndroidInjector) : Objective(i
}
override val progress: String
get() = if (sp.getInt(R.string.key_ObjectivesmanualEnacts, 0) >= MANUAL_ENACTS_NEEDED) rh.gs(R.string.completed_well_done) else sp.getInt(R.string.key_ObjectivesmanualEnacts, 0).toString() + " / " + MANUAL_ENACTS_NEEDED
get() = if (sp.getInt(R.string.key_ObjectivesmanualEnacts, 0) >= MANUAL_ENACTS_NEEDED) rh.gs(R.string.completed_well_done) else sp.getInt(R.string.key_ObjectivesmanualEnacts, 0)
.toString() + " / " + MANUAL_ENACTS_NEEDED
})
}
override fun specialActionEnabled(): Boolean =
nsClientPlugin.nsClientService?.isConnected == true && nsClientPlugin.nsClientService?.hasWriteAuth == true
override fun specialAction(activity: FragmentActivity, input: String) {
objectivesPlugin.completeObjectives(activity, input)
}
companion object {
private const val MANUAL_ENACTS_NEEDED = 20

View file

@ -10,28 +10,27 @@ import info.nightscout.androidaps.extensions.durationInMinutes
import info.nightscout.androidaps.extensions.safeQueryBroadcastReceivers
import info.nightscout.androidaps.extensions.toStringFull
import info.nightscout.androidaps.interfaces.ActivePlugin
import info.nightscout.interfaces.Config
import info.nightscout.androidaps.interfaces.IobCobCalculator
import info.nightscout.androidaps.interfaces.Loop
import info.nightscout.androidaps.interfaces.PluginBase
import info.nightscout.interfaces.PluginDescription
import info.nightscout.interfaces.PluginType
import info.nightscout.androidaps.interfaces.ProfileFunction
import info.nightscout.androidaps.interfaces.ResourceHelper
import info.nightscout.androidaps.plugins.aps.events.EventOpenAPSUpdateGui
import info.nightscout.androidaps.plugins.general.nsclient.data.DeviceStatusData
import info.nightscout.androidaps.plugins.general.nsclient.data.NSDeviceStatus
import info.nightscout.rx.events.EventOverviewBolusProgress
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.GlucoseStatusProvider
import info.nightscout.androidaps.plugins.sync.nsclient.data.ProcessedDeviceStatusData
import info.nightscout.androidaps.receivers.Intents
import info.nightscout.androidaps.receivers.ReceiverStatusStore
import info.nightscout.androidaps.utils.DateUtil
import info.nightscout.androidaps.utils.DefaultValueHelper
import info.nightscout.androidaps.utils.FabricPrivacy
import info.nightscout.interfaces.Config
import info.nightscout.interfaces.PluginDescription
import info.nightscout.interfaces.PluginType
import info.nightscout.rx.AapsSchedulers
import info.nightscout.rx.bus.RxBus
import info.nightscout.rx.events.Event
import info.nightscout.rx.events.EventAutosensCalculationFinished
import info.nightscout.rx.events.EventOverviewBolusProgress
import info.nightscout.rx.logging.AAPSLogger
import info.nightscout.rx.logging.LTag
import io.reactivex.rxjava3.disposables.CompositeDisposable
@ -52,14 +51,12 @@ class DataBroadcastPlugin @Inject constructor(
private val iobCobCalculator: IobCobCalculator,
private val profileFunction: ProfileFunction,
private val defaultValueHelper: DefaultValueHelper,
private val nsDeviceStatus: NSDeviceStatus,
private val deviceStatusData: DeviceStatusData,
private val processedDeviceStatusData: ProcessedDeviceStatusData,
private val loop: Loop,
private val activePlugin: ActivePlugin,
private var receiverStatusStore: ReceiverStatusStore,
private val config: Config,
private val glucoseStatusProvider: GlucoseStatusProvider
) : PluginBase(
PluginDescription()
.mainType(PluginType.GENERAL)
@ -143,7 +140,7 @@ class DataBroadcastPlugin @Inject constructor(
private fun loopStatus(bundle: Bundle) {
//batteries
bundle.putInt("phoneBattery", receiverStatusStore.batteryLevel)
bundle.putInt("rigBattery", nsDeviceStatus.uploaderStatus.replace("%", "").trim { it <= ' ' }.toInt())
bundle.putInt("rigBattery", processedDeviceStatusData.uploaderStatus.replace("%", "").trim { it <= ' ' }.toInt())
if (config.APS && loop.lastRun?.lastTBREnact != 0L) { //we are AndroidAPS
bundle.putLong("suggestedTimeStamp", loop.lastRun?.lastAPSRun ?: -1L)
@ -156,7 +153,7 @@ class DataBroadcastPlugin @Inject constructor(
bundle.putString("enacted", loop.lastRun?.request?.json().toString())
}
} else { //NSClient or remote
val data = deviceStatusData.openAPSData
val data = processedDeviceStatusData.openAPSData
if (data.clockSuggested != 0L && data.suggested != null) {
bundle.putLong("suggestedTimeStamp", data.clockSuggested)
bundle.putString("suggested", data.suggested.toString())

View file

@ -13,7 +13,7 @@ import info.nightscout.androidaps.interfaces.PluginBase
import info.nightscout.interfaces.PluginDescription
import info.nightscout.interfaces.PluginType
import info.nightscout.androidaps.interfaces.ResourceHelper
import info.nightscout.androidaps.plugins.general.nsclient.data.NSSettingsStatus
import info.nightscout.androidaps.plugins.sync.nsclient.data.NSSettingsStatus
import info.nightscout.plugins.general.maintenance.LoggerUtils
import info.nightscout.rx.logging.AAPSLogger
import info.nightscout.shared.sharedPreferences.SP

View file

@ -1,539 +0,0 @@
package info.nightscout.androidaps.plugins.general.nsclient
import android.content.Context
import androidx.work.Worker
import androidx.work.WorkerParameters
import androidx.work.workDataOf
import dagger.android.HasAndroidInjector
import info.nightscout.interfaces.Constants
import info.nightscout.androidaps.R
import info.nightscout.androidaps.database.AppRepository
import info.nightscout.androidaps.database.entities.TherapyEvent
import info.nightscout.androidaps.database.entities.UserEntry.Action
import info.nightscout.androidaps.database.entities.UserEntry.Sources
import info.nightscout.androidaps.database.entities.ValueWithUnit
import info.nightscout.androidaps.database.transactions.SyncNsBolusCalculatorResultTransaction
import info.nightscout.androidaps.database.transactions.SyncNsBolusTransaction
import info.nightscout.androidaps.database.transactions.SyncNsCarbsTransaction
import info.nightscout.androidaps.database.transactions.SyncNsEffectiveProfileSwitchTransaction
import info.nightscout.androidaps.database.transactions.SyncNsExtendedBolusTransaction
import info.nightscout.androidaps.database.transactions.SyncNsOfflineEventTransaction
import info.nightscout.androidaps.database.transactions.SyncNsProfileSwitchTransaction
import info.nightscout.androidaps.database.transactions.SyncNsTemporaryBasalTransaction
import info.nightscout.androidaps.database.transactions.SyncNsTemporaryTargetTransaction
import info.nightscout.androidaps.database.transactions.SyncNsTherapyEventTransaction
import info.nightscout.androidaps.extensions.bolusCalculatorResultFromJson
import info.nightscout.androidaps.extensions.bolusFromJson
import info.nightscout.androidaps.extensions.carbsFromJson
import info.nightscout.androidaps.extensions.effectiveProfileSwitchFromJson
import info.nightscout.androidaps.extensions.extendedBolusFromJson
import info.nightscout.androidaps.extensions.isEffectiveProfileSwitch
import info.nightscout.androidaps.extensions.offlineEventFromJson
import info.nightscout.androidaps.extensions.profileSwitchFromJson
import info.nightscout.androidaps.extensions.temporaryBasalFromJson
import info.nightscout.androidaps.extensions.temporaryTargetFromJson
import info.nightscout.androidaps.extensions.therapyEventFromJson
import info.nightscout.androidaps.interfaces.ActivePlugin
import info.nightscout.interfaces.BuildHelper
import info.nightscout.interfaces.Config
import info.nightscout.androidaps.interfaces.XDripBroadcast
import info.nightscout.androidaps.logging.UserEntryLogger
import info.nightscout.androidaps.plugins.general.overview.events.EventNewNotification
import info.nightscout.interfaces.notifications.Notification
import info.nightscout.androidaps.plugins.pump.virtual.VirtualPumpPlugin
import info.nightscout.androidaps.receivers.DataWorkerStorage
import info.nightscout.androidaps.utils.DateUtil
import info.nightscout.interfaces.utils.JsonHelper
import info.nightscout.interfaces.utils.JsonHelper.safeGetLong
import info.nightscout.rx.bus.RxBus
import info.nightscout.rx.logging.AAPSLogger
import info.nightscout.rx.logging.LTag
import info.nightscout.shared.sharedPreferences.SP
import java.util.concurrent.TimeUnit
import javax.inject.Inject
class NSClientAddUpdateWorker(
context: Context,
params: WorkerParameters
) : Worker(context, params) {
@Inject lateinit var nsClientPlugin: NSClientPlugin
@Inject lateinit var dataWorkerStorage: DataWorkerStorage
@Inject lateinit var aapsLogger: AAPSLogger
@Inject lateinit var buildHelper: BuildHelper
@Inject lateinit var sp: SP
@Inject lateinit var dateUtil: DateUtil
@Inject lateinit var config: Config
@Inject lateinit var repository: AppRepository
@Inject lateinit var activePlugin: ActivePlugin
@Inject lateinit var rxBus: RxBus
@Inject lateinit var uel: UserEntryLogger
@Inject lateinit var virtualPumpPlugin: VirtualPumpPlugin
@Inject lateinit var xDripBroadcast: XDripBroadcast
override fun doWork(): Result {
val treatments = dataWorkerStorage.pickupJSONArray(inputData.getLong(DataWorkerStorage.STORE_KEY, -1))
?: return Result.failure(workDataOf("Error" to "missing input data"))
var ret = Result.success()
var latestDateInReceivedData = 0L
for (i in 0 until treatments.length()) {
var json = treatments.getJSONObject(i)
aapsLogger.debug(LTag.DATABASE, "Received NS treatment: $json")
val insulin = JsonHelper.safeGetDouble(json, "insulin")
val carbs = JsonHelper.safeGetDouble(json, "carbs")
var eventType = JsonHelper.safeGetString(json, "eventType")
if (eventType == null) {
aapsLogger.debug(LTag.NSCLIENT, "Wrong treatment. Ignoring : $json")
continue
}
//Find latest date in treatment
val mills = safeGetLong(json, "mills")
if (mills != 0L && mills < dateUtil.now())
if (mills > latestDateInReceivedData) latestDateInReceivedData = mills
if (insulin > 0) {
if (sp.getBoolean(R.string.key_ns_receive_insulin, false) || config.NSCLIENT) {
bolusFromJson(json)?.let { bolus ->
repository.runTransactionForResult(SyncNsBolusTransaction(bolus))
.doOnError {
aapsLogger.error(LTag.DATABASE, "Error while saving bolus", it)
ret = Result.failure(workDataOf("Error" to it.toString()))
}
.blockingGet()
.also { result ->
result.inserted.forEach {
uel.log(
Action.BOLUS, Sources.NSClient, it.notes,
ValueWithUnit.Timestamp(it.timestamp),
ValueWithUnit.Insulin(it.amount)
)
aapsLogger.debug(LTag.DATABASE, "Inserted bolus $it")
}
result.invalidated.forEach {
uel.log(
Action.BOLUS_REMOVED, Sources.NSClient,
ValueWithUnit.Timestamp(it.timestamp),
ValueWithUnit.Insulin(it.amount)
)
aapsLogger.debug(LTag.DATABASE, "Invalidated bolus $it")
}
result.updatedNsId.forEach {
aapsLogger.debug(LTag.DATABASE, "Updated nsId of bolus $it")
}
result.updated.forEach {
aapsLogger.debug(LTag.DATABASE, "Updated amount of bolus $it")
}
}
} ?: aapsLogger.error("Error parsing bolus json $json")
}
}
if (carbs > 0) {
if (sp.getBoolean(R.string.key_ns_receive_carbs, false) || config.NSCLIENT) {
carbsFromJson(json)?.let { carb ->
repository.runTransactionForResult(SyncNsCarbsTransaction(carb))
.doOnError {
aapsLogger.error(LTag.DATABASE, "Error while saving carbs", it)
ret = Result.failure(workDataOf("Error" to it.toString()))
}
.blockingGet()
.also { result ->
result.inserted.forEach {
uel.log(
Action.CARBS, Sources.NSClient, it.notes,
ValueWithUnit.Timestamp(it.timestamp),
ValueWithUnit.Gram(it.amount.toInt())
)
aapsLogger.debug(LTag.DATABASE, "Inserted carbs $it")
}
result.invalidated.forEach {
uel.log(
Action.CARBS_REMOVED, Sources.NSClient,
ValueWithUnit.Timestamp(it.timestamp),
ValueWithUnit.Gram(it.amount.toInt())
)
aapsLogger.debug(LTag.DATABASE, "Invalidated carbs $it")
}
result.updated.forEach {
uel.log(
Action.CARBS, Sources.NSClient, it.notes,
ValueWithUnit.Timestamp(it.timestamp),
ValueWithUnit.Gram(it.amount.toInt())
)
aapsLogger.debug(LTag.DATABASE, "Updated carbs $it")
}
result.updatedNsId.forEach {
aapsLogger.debug(LTag.DATABASE, "Updated nsId carbs $it")
}
}
} ?: aapsLogger.error("Error parsing bolus json $json")
}
}
// Convert back emulated TBR -> EB
if (eventType == TherapyEvent.Type.TEMPORARY_BASAL.text && json.has("extendedEmulated")) {
val ebJson = json.getJSONObject("extendedEmulated")
ebJson.put("_id", json.getString("_id"))
ebJson.put("isValid", json.getBoolean("isValid"))
ebJson.put("mills", mills)
json = ebJson
eventType = JsonHelper.safeGetString(json, "eventType")
virtualPumpPlugin.fakeDataDetected = true
}
when {
insulin > 0 || carbs > 0 -> Any()
eventType == TherapyEvent.Type.TEMPORARY_TARGET.text ->
if (sp.getBoolean(R.string.key_ns_receive_temp_target, false) || config.NSCLIENT) {
temporaryTargetFromJson(json)?.let { temporaryTarget ->
repository.runTransactionForResult(SyncNsTemporaryTargetTransaction(temporaryTarget))
.doOnError {
aapsLogger.error(LTag.DATABASE, "Error while saving temporary target", it)
ret = Result.failure(workDataOf("Error" to it.toString()))
}
.blockingGet()
.also { result ->
result.inserted.forEach { tt ->
uel.log(
Action.TT, Sources.NSClient,
ValueWithUnit.TherapyEventTTReason(tt.reason),
ValueWithUnit.fromGlucoseUnit(tt.lowTarget, Constants.MGDL),
ValueWithUnit.fromGlucoseUnit(tt.highTarget, Constants.MGDL).takeIf { tt.lowTarget != tt.highTarget },
ValueWithUnit.Minute(TimeUnit.MILLISECONDS.toMinutes(tt.duration).toInt())
)
aapsLogger.debug(LTag.DATABASE, "Inserted TemporaryTarget $tt")
}
result.invalidated.forEach { tt ->
uel.log(
Action.TT_REMOVED, Sources.NSClient,
ValueWithUnit.TherapyEventTTReason(tt.reason),
ValueWithUnit.Mgdl(tt.lowTarget),
ValueWithUnit.Mgdl(tt.highTarget).takeIf { tt.lowTarget != tt.highTarget },
ValueWithUnit.Minute(TimeUnit.MILLISECONDS.toMinutes(tt.duration).toInt())
)
aapsLogger.debug(LTag.DATABASE, "Invalidated TemporaryTarget $tt")
}
result.ended.forEach { tt ->
uel.log(
Action.CANCEL_TT, Sources.NSClient,
ValueWithUnit.TherapyEventTTReason(tt.reason),
ValueWithUnit.Mgdl(tt.lowTarget),
ValueWithUnit.Mgdl(tt.highTarget).takeIf { tt.lowTarget != tt.highTarget },
ValueWithUnit.Minute(TimeUnit.MILLISECONDS.toMinutes(tt.duration).toInt())
)
aapsLogger.debug(LTag.DATABASE, "Updated TemporaryTarget $tt")
}
result.updatedNsId.forEach {
aapsLogger.debug(LTag.DATABASE, "Updated nsId TemporaryTarget $it")
}
result.updatedDuration.forEach {
aapsLogger.debug(LTag.DATABASE, "Updated duration TemporaryTarget $it")
}
}
} ?: aapsLogger.error("Error parsing TT json $json")
}
eventType == TherapyEvent.Type.NOTE.text && json.isEffectiveProfileSwitch() -> // replace this by new Type when available in NS
if (sp.getBoolean(R.string.key_ns_receive_profile_switch, false) || config.NSCLIENT) {
effectiveProfileSwitchFromJson(json, dateUtil)?.let { effectiveProfileSwitch ->
repository.runTransactionForResult(SyncNsEffectiveProfileSwitchTransaction(effectiveProfileSwitch))
.doOnError {
aapsLogger.error(LTag.DATABASE, "Error while saving EffectiveProfileSwitch", it)
ret = Result.failure(workDataOf("Error" to it.toString()))
}
.blockingGet()
.also { result ->
result.inserted.forEach {
uel.log(
Action.PROFILE_SWITCH, Sources.NSClient,
ValueWithUnit.Timestamp(it.timestamp)
)
aapsLogger.debug(LTag.DATABASE, "Inserted EffectiveProfileSwitch $it")
}
result.invalidated.forEach {
uel.log(
Action.PROFILE_SWITCH_REMOVED, Sources.NSClient,
ValueWithUnit.Timestamp(it.timestamp)
)
aapsLogger.debug(LTag.DATABASE, "Invalidated EffectiveProfileSwitch $it")
}
result.updatedNsId.forEach {
aapsLogger.debug(LTag.DATABASE, "Updated nsId EffectiveProfileSwitch $it")
}
}
} ?: aapsLogger.error("Error parsing EffectiveProfileSwitch json $json")
}
eventType == TherapyEvent.Type.BOLUS_WIZARD.text ->
bolusCalculatorResultFromJson(json)?.let { bolusCalculatorResult ->
repository.runTransactionForResult(SyncNsBolusCalculatorResultTransaction(bolusCalculatorResult))
.doOnError {
aapsLogger.error(LTag.DATABASE, "Error while saving BolusCalculatorResult", it)
ret = Result.failure(workDataOf("Error" to it.toString()))
}
.blockingGet()
.also { result ->
result.inserted.forEach {
uel.log(
Action.BOLUS_CALCULATOR_RESULT, Sources.NSClient,
ValueWithUnit.Timestamp(it.timestamp),
)
aapsLogger.debug(LTag.DATABASE, "Inserted BolusCalculatorResult $it")
}
result.invalidated.forEach {
uel.log(
Action.BOLUS_CALCULATOR_RESULT_REMOVED, Sources.NSClient,
ValueWithUnit.Timestamp(it.timestamp),
)
aapsLogger.debug(LTag.DATABASE, "Invalidated BolusCalculatorResult $it")
}
result.updatedNsId.forEach {
aapsLogger.debug(LTag.DATABASE, "Updated nsId BolusCalculatorResult $it")
}
}
} ?: aapsLogger.error("Error parsing BolusCalculatorResult json $json")
eventType == TherapyEvent.Type.CANNULA_CHANGE.text ||
eventType == TherapyEvent.Type.INSULIN_CHANGE.text ||
eventType == TherapyEvent.Type.SENSOR_CHANGE.text ||
eventType == TherapyEvent.Type.FINGER_STICK_BG_VALUE.text ||
eventType == TherapyEvent.Type.NONE.text ||
eventType == TherapyEvent.Type.ANNOUNCEMENT.text ||
eventType == TherapyEvent.Type.QUESTION.text ||
eventType == TherapyEvent.Type.EXERCISE.text ||
eventType == TherapyEvent.Type.NOTE.text ||
eventType == TherapyEvent.Type.PUMP_BATTERY_CHANGE.text ->
if (sp.getBoolean(R.string.key_ns_receive_therapy_events, false) || config.NSCLIENT) {
therapyEventFromJson(json)?.let { therapyEvent ->
repository.runTransactionForResult(SyncNsTherapyEventTransaction(therapyEvent))
.doOnError {
aapsLogger.error(LTag.DATABASE, "Error while saving therapy event", it)
ret = Result.failure(workDataOf("Error" to it.toString()))
}
.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 { therapyEvent ->
uel.log(action, Sources.NSClient,
therapyEvent.note ?: "",
ValueWithUnit.Timestamp(therapyEvent.timestamp),
ValueWithUnit.TherapyEventType(therapyEvent.type),
ValueWithUnit.fromGlucoseUnit(therapyEvent.glucose ?: 0.0, therapyEvent.glucoseUnit.toString).takeIf { therapyEvent.glucose != null }
)
aapsLogger.debug(LTag.DATABASE, "Inserted TherapyEvent $therapyEvent")
}
result.invalidated.forEach { therapyEvent ->
uel.log(Action.CAREPORTAL_REMOVED, Sources.NSClient,
therapyEvent.note ?: "",
ValueWithUnit.Timestamp(therapyEvent.timestamp),
ValueWithUnit.TherapyEventType(therapyEvent.type),
ValueWithUnit.fromGlucoseUnit(therapyEvent.glucose ?: 0.0, therapyEvent.glucoseUnit.toString).takeIf { therapyEvent.glucose != null }
)
aapsLogger.debug(LTag.DATABASE, "Invalidated TherapyEvent $therapyEvent")
}
result.updatedNsId.forEach {
aapsLogger.debug(LTag.DATABASE, "Updated nsId TherapyEvent $it")
}
result.updatedDuration.forEach {
aapsLogger.debug(LTag.DATABASE, "Updated nsId TherapyEvent $it")
}
}
} ?: aapsLogger.error("Error parsing TherapyEvent json $json")
}
eventType == TherapyEvent.Type.COMBO_BOLUS.text ->
if (buildHelper.isEngineeringMode() && sp.getBoolean(R.string.key_ns_receive_tbr_eb, false) || config.NSCLIENT) {
extendedBolusFromJson(json)?.let { extendedBolus ->
repository.runTransactionForResult(SyncNsExtendedBolusTransaction(extendedBolus))
.doOnError {
aapsLogger.error(LTag.DATABASE, "Error while saving extended bolus", it)
ret = Result.failure(workDataOf("Error" to it.toString()))
}
.blockingGet()
.also { result ->
result.inserted.forEach {
uel.log(
Action.EXTENDED_BOLUS, Sources.NSClient,
ValueWithUnit.Timestamp(it.timestamp),
ValueWithUnit.Insulin(it.amount),
ValueWithUnit.UnitPerHour(it.rate),
ValueWithUnit.Minute(TimeUnit.MILLISECONDS.toMinutes(it.duration).toInt())
)
aapsLogger.debug(LTag.DATABASE, "Inserted ExtendedBolus $it")
}
result.invalidated.forEach {
uel.log(
Action.EXTENDED_BOLUS_REMOVED, Sources.NSClient,
ValueWithUnit.Timestamp(it.timestamp),
ValueWithUnit.Insulin(it.amount),
ValueWithUnit.UnitPerHour(it.rate),
ValueWithUnit.Minute(TimeUnit.MILLISECONDS.toMinutes(it.duration).toInt())
)
aapsLogger.debug(LTag.DATABASE, "Invalidated ExtendedBolus $it")
}
result.ended.forEach {
uel.log(
Action.CANCEL_EXTENDED_BOLUS, Sources.NSClient,
ValueWithUnit.Timestamp(it.timestamp),
ValueWithUnit.Insulin(it.amount),
ValueWithUnit.UnitPerHour(it.rate),
ValueWithUnit.Minute(TimeUnit.MILLISECONDS.toMinutes(it.duration).toInt())
)
aapsLogger.debug(LTag.DATABASE, "Updated ExtendedBolus $it")
}
result.updatedNsId.forEach {
aapsLogger.debug(LTag.DATABASE, "Updated nsId ExtendedBolus $it")
}
result.updatedDuration.forEach {
aapsLogger.debug(LTag.DATABASE, "Updated duration ExtendedBolus $it")
}
}
} ?: aapsLogger.error("Error parsing ExtendedBolus json $json")
}
eventType == TherapyEvent.Type.TEMPORARY_BASAL.text ->
if (buildHelper.isEngineeringMode() && sp.getBoolean(R.string.key_ns_receive_tbr_eb, false) || config.NSCLIENT) {
temporaryBasalFromJson(json)?.let { temporaryBasal ->
repository.runTransactionForResult(SyncNsTemporaryBasalTransaction(temporaryBasal))
.doOnError {
aapsLogger.error(LTag.DATABASE, "Error while saving temporary basal", it)
ret = Result.failure(workDataOf("Error" to it.toString()))
}
.blockingGet()
.also { result ->
result.inserted.forEach {
uel.log(
Action.TEMP_BASAL, Sources.NSClient,
ValueWithUnit.Timestamp(it.timestamp),
if (it.isAbsolute) ValueWithUnit.UnitPerHour(it.rate) else ValueWithUnit.Percent(it.rate.toInt()),
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),
if (it.isAbsolute) ValueWithUnit.UnitPerHour(it.rate) else ValueWithUnit.Percent(it.rate.toInt()),
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),
if (it.isAbsolute) ValueWithUnit.UnitPerHour(it.rate) else ValueWithUnit.Percent(it.rate.toInt()),
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")
}
result.updatedDuration.forEach {
aapsLogger.debug(LTag.DATABASE, "Updated duration TemporaryBasal $it")
}
}
} ?: aapsLogger.error("Error parsing TemporaryBasal json $json")
}
eventType == TherapyEvent.Type.PROFILE_SWITCH.text ->
if (sp.getBoolean(R.string.key_ns_receive_profile_switch, false) || config.NSCLIENT) {
profileSwitchFromJson(json, dateUtil, activePlugin)?.let { profileSwitch ->
repository.runTransactionForResult(SyncNsProfileSwitchTransaction(profileSwitch))
.doOnError {
aapsLogger.error(LTag.DATABASE, "Error while saving ProfileSwitch", it)
ret = Result.failure(workDataOf("Error" to it.toString()))
}
.blockingGet()
.also { result ->
result.inserted.forEach {
uel.log(
Action.PROFILE_SWITCH, Sources.NSClient,
ValueWithUnit.Timestamp(it.timestamp)
)
aapsLogger.debug(LTag.DATABASE, "Inserted ProfileSwitch $it")
}
result.invalidated.forEach {
uel.log(
Action.PROFILE_SWITCH_REMOVED, Sources.NSClient,
ValueWithUnit.Timestamp(it.timestamp)
)
aapsLogger.debug(LTag.DATABASE, "Invalidated ProfileSwitch $it")
}
result.updatedNsId.forEach {
aapsLogger.debug(LTag.DATABASE, "Updated nsId ProfileSwitch $it")
}
}
} ?: aapsLogger.error("Error parsing ProfileSwitch json $json")
}
eventType == TherapyEvent.Type.APS_OFFLINE.text ->
if (sp.getBoolean(R.string.key_ns_receive_offline_event, false) && buildHelper.isEngineeringMode() || config.NSCLIENT) {
offlineEventFromJson(json)?.let { offlineEvent ->
repository.runTransactionForResult(SyncNsOfflineEventTransaction(offlineEvent))
.doOnError {
aapsLogger.error(LTag.DATABASE, "Error while saving OfflineEvent", it)
ret = Result.failure(workDataOf("Error" to it.toString()))
}
.blockingGet()
.also { result ->
result.inserted.forEach { oe ->
uel.log(
Action.LOOP_CHANGE, Sources.NSClient,
ValueWithUnit.OfflineEventReason(oe.reason),
ValueWithUnit.Minute(TimeUnit.MILLISECONDS.toMinutes(oe.duration).toInt())
)
aapsLogger.debug(LTag.DATABASE, "Inserted OfflineEvent $oe")
}
result.invalidated.forEach { oe ->
uel.log(
Action.LOOP_REMOVED, Sources.NSClient,
ValueWithUnit.OfflineEventReason(oe.reason),
ValueWithUnit.Minute(TimeUnit.MILLISECONDS.toMinutes(oe.duration).toInt())
)
aapsLogger.debug(LTag.DATABASE, "Invalidated OfflineEvent $oe")
}
result.ended.forEach { oe ->
uel.log(
Action.LOOP_CHANGE, Sources.NSClient,
ValueWithUnit.OfflineEventReason(oe.reason),
ValueWithUnit.Minute(TimeUnit.MILLISECONDS.toMinutes(oe.duration).toInt())
)
aapsLogger.debug(LTag.DATABASE, "Updated OfflineEvent $oe")
}
result.updatedNsId.forEach {
aapsLogger.debug(LTag.DATABASE, "Updated nsId OfflineEvent $it")
}
result.updatedDuration.forEach {
aapsLogger.debug(LTag.DATABASE, "Updated duration OfflineEvent $it")
}
}
} ?: aapsLogger.error("Error parsing OfflineEvent json $json")
}
}
if (sp.getBoolean(R.string.key_ns_receive_therapy_events, false) || config.NSCLIENT)
if (eventType == TherapyEvent.Type.ANNOUNCEMENT.text) {
val date = safeGetLong(json, "mills")
val now = System.currentTimeMillis()
val enteredBy = JsonHelper.safeGetString(json, "enteredBy", "")
val notes = JsonHelper.safeGetString(json, "notes", "")
if (date > now - 15 * 60 * 1000L && notes.isNotEmpty()
&& enteredBy != sp.getString("careportal_enteredby", "AndroidAPS")
) {
val defaultVal = config.NSCLIENT
if (sp.getBoolean(R.string.key_ns_announcements, defaultVal)) {
val announcement = Notification(Notification.NS_ANNOUNCEMENT, notes, Notification.ANNOUNCEMENT, 60)
rxBus.send(EventNewNotification(announcement))
}
}
}
}
nsClientPlugin.updateLatestDateReceivedIfNewer(latestDateInReceivedData)
xDripBroadcast.sendTreatments(treatments)
return ret
}
init {
(context.applicationContext as HasAndroidInjector).androidInjector().inject(this)
}
}

View file

@ -1,42 +0,0 @@
package info.nightscout.androidaps.plugins.general.nsclient.data
import android.text.Spanned
import org.json.JSONObject
import java.util.HashMap
import javax.inject.Inject
import javax.inject.Singleton
@Singleton
class DeviceStatusData @Inject constructor() {
class PumpData {
var clock = 0L
var isPercent = false
var percent = 0
var voltage = 0.0
var status = "N/A"
var reservoir = 0.0
var reservoirDisplayOverride = ""
var extended: Spanned? = null
var activeProfileName: String? = null
}
var pumpData: PumpData? = null
class Uploader {
var clock = 0L
var battery = 0
}
val uploaderMap = HashMap<String, Uploader>()
class OpenAPSData {
var clockSuggested = 0L
var clockEnacted = 0L
var suggested: JSONObject? = null
var enacted: JSONObject? = null
}
var openAPSData = OpenAPSData()
}

View file

@ -1,375 +0,0 @@
package info.nightscout.androidaps.plugins.general.nsclient.data
import android.text.Spanned
import dagger.android.HasAndroidInjector
import info.nightscout.androidaps.R
import info.nightscout.interfaces.Config
import info.nightscout.androidaps.interfaces.ResourceHelper
import info.nightscout.androidaps.plugins.aps.loop.APSResult
import info.nightscout.androidaps.plugins.configBuilder.RunningConfiguration
import info.nightscout.androidaps.utils.DateUtil
import info.nightscout.interfaces.utils.HtmlHelper.fromHtml
import info.nightscout.interfaces.utils.JsonHelper
import info.nightscout.interfaces.utils.Round
import info.nightscout.androidaps.utils.T
import info.nightscout.rx.logging.AAPSLogger
import info.nightscout.rx.logging.LTag
import info.nightscout.shared.sharedPreferences.SP
import org.json.JSONArray
import org.json.JSONException
import org.json.JSONObject
import javax.inject.Inject
import javax.inject.Singleton
/*
{
"_id": "594fdcec327b83c81b6b8c0f",
"device": "openaps://Sony D5803",
"pump": {
"battery": {
"percent": 100
},
"status": {
"status": "normal",
"timestamp": "2017-06-25T15:50:14Z"
},
"extended": {
"Version": "1.5-ac98852-2017.06.25",
"PumpIOB": 1.13,
"LastBolus": "25. 6. 2017 17:25:00",
"LastBolusAmount": 0.3,
"BaseBasalRate": 0.4,
"ActiveProfile": "2016 +30%"
},
"reservoir": 109,
"clock": "2017-06-25T15:55:10Z"
},
"openaps": {
"suggested": {
"temp": "absolute",
"bg": 115.9,
"tick": "+5",
"eventualBG": 105,
"snoozeBG": 105,
"predBGs": {
"IOB": [116, 114, 112, 110, 109, 107, 106, 105, 105, 104, 104, 104, 104, 104, 104, 104, 104, 105, 105, 105, 105, 105, 106, 106, 106, 106, 106, 107]
},
"sensitivityRatio": 0.81,
"variable_sens": 137.3,
"COB": 0,
"IOB": -0.035,
"reason": "COB: 0, Dev: -18, BGI: 0.43, ISF: 216, Target: 99; Eventual BG 105 > 99 but Min. Delta -2.60 < Exp. Delta 0.1; setting current basal of 0.4 as temp. Suggested rate is same as profile rate, no temp basal is active, doing nothing",
"timestamp": "2017-06-25T15:55:10Z"
},
"iob": {
"iob": -0.035,
"basaliob": -0.035,
"activity": -0.0004,
"time": "2017-06-25T15:55:10Z"
}
},
"uploaderBattery": 93,
"created_at": "2017-06-25T15:55:10Z",
"NSCLIENT_ID": 1498406118857
}
*/
@Suppress("SpellCheckingInspection")
@Singleton
class NSDeviceStatus @Inject constructor(
private val aapsLogger: AAPSLogger,
private val sp: SP,
private val rh: ResourceHelper,
private val nsSettingsStatus: NSSettingsStatus,
private val config: Config,
private val dateUtil: DateUtil,
private val runningConfiguration: RunningConfiguration,
private val deviceStatusData: DeviceStatusData
) {
private var data: JSONObject? = null
fun handleNewData(deviceStatuses: JSONArray) {
aapsLogger.debug(LTag.NSCLIENT, "Got NS deviceStatus: \$deviceStatuses")
try {
for (i in deviceStatuses.length() - 1 downTo 0) {
val devicestatusJson = deviceStatuses.getJSONObject(i)
if (devicestatusJson != null) {
setData(devicestatusJson)
if (devicestatusJson.has("pump")) {
// Objectives 0
sp.putBoolean(R.string.key_ObjectivespumpStatusIsAvailableInNS, true)
}
if (devicestatusJson.has("configuration") && config.NSCLIENT) {
// copy configuration of Insulin and Sensitivity from main AAPS
runningConfiguration.apply(devicestatusJson.getJSONObject("configuration"))
break
}
}
}
} catch (jsonException: JSONException) {
jsonException.printStackTrace()
}
}
private fun setData(obj: JSONObject): NSDeviceStatus {
data = obj
updatePumpData()
updateOpenApsData(obj)
updateUploaderData(obj)
return this
}
val device: String
get() {
try {
if (data!!.has("device")) {
var device = data!!.getString("device")
if (device.startsWith("openaps://")) {
device = device.substring(10)
return device
}
}
} catch (e: JSONException) {
aapsLogger.error("Unhandled exception", e)
}
return ""
}
enum class Levels(val level: Int) {
URGENT(2),
WARN(1),
INFO(0);
fun toColor(): String =
when (level) {
INFO.level -> "white"
WARN.level -> "yellow"
URGENT.level -> "red"
else -> "white"
}
}
val extendedPumpStatus: Spanned
get() = deviceStatusData.pumpData?.extended ?: fromHtml("")
val pumpStatus: Spanned
// test warning level // color
get() {
val pumpData = deviceStatusData.pumpData ?: return fromHtml("")
//String[] ALL_STATUS_FIELDS = {"reservoir", "battery", "clock", "status", "device"};
val string = StringBuilder()
.append("<span style=\"color:${rh.gac(R.attr.nsTitleColor)}\">")
.append(rh.gs(R.string.pump))
.append(": </span>")
// test warning level
val level = when {
pumpData.clock + nsSettingsStatus.extendedPumpSettings("urgentClock") * 60 * 1000L < dateUtil.now() -> Levels.URGENT
pumpData.reservoir < nsSettingsStatus.extendedPumpSettings("urgentRes") -> Levels.URGENT
pumpData.isPercent && pumpData.percent < nsSettingsStatus.extendedPumpSettings("urgentBattP") -> Levels.URGENT
!pumpData.isPercent && pumpData.voltage > 0 && pumpData.voltage < nsSettingsStatus.extendedPumpSettings("urgentBattV") -> Levels.URGENT
pumpData.clock + nsSettingsStatus.extendedPumpSettings("warnClock") * 60 * 1000L < dateUtil.now() -> Levels.WARN
pumpData.reservoir < nsSettingsStatus.extendedPumpSettings("warnRes") -> Levels.WARN
pumpData.isPercent && pumpData.percent < nsSettingsStatus.extendedPumpSettings("warnBattP") -> Levels.WARN
!pumpData.isPercent && pumpData.voltage > 0 && pumpData.voltage < nsSettingsStatus.extendedPumpSettings("warnBattV") -> Levels.WARN
else -> Levels.INFO
}
string.append("<span style=\"color:${level.toColor()}\">")
val insulinUnit = rh.gs(R.string.insulin_unit_shortname)
val fields = nsSettingsStatus.pumpExtendedSettingsFields()
if (pumpData.reservoirDisplayOverride != "") {
string.append(pumpData.reservoirDisplayOverride).append("$insulinUnit ")
}
else if (fields.contains("reservoir")) string.append(pumpData.reservoir.toInt()).append("$insulinUnit ")
if (fields.contains("battery") && pumpData.isPercent) string.append(pumpData.percent).append("% ")
if (fields.contains("battery") && !pumpData.isPercent) string.append(Round.roundTo(pumpData.voltage, 0.001)).append(" ")
if (fields.contains("clock")) string.append(dateUtil.minAgo(rh, pumpData.clock)).append(" ")
if (fields.contains("status")) string.append(pumpData.status).append(" ")
if (fields.contains("device")) string.append(device).append(" ")
string.append("</span>") // color
return fromHtml(string.toString())
}
private fun updatePumpData() {
try {
val data = this.data ?: return
val pump = if (data.has("pump")) data.getJSONObject("pump") else JSONObject()
val clock = if (pump.has("clock")) dateUtil.fromISODateString(pump.getString("clock")) else 0L
// check if this is new data
if (clock == 0L || deviceStatusData.pumpData != null && clock < deviceStatusData.pumpData!!.clock) return
// create new status and process data
val deviceStatusPumpData = DeviceStatusData.PumpData()
deviceStatusPumpData.clock = clock
if (pump.has("status") && pump.getJSONObject("status").has("status")) deviceStatusPumpData.status = pump.getJSONObject("status").getString("status")
if (pump.has("reservoir")) deviceStatusPumpData.reservoir = pump.getDouble("reservoir")
if (pump.has("reservoir_display_override")) deviceStatusPumpData.reservoirDisplayOverride = pump.getString("reservoir_display_override")
if (pump.has("battery") && pump.getJSONObject("battery").has("percent")) {
deviceStatusPumpData.isPercent = true
deviceStatusPumpData.percent = pump.getJSONObject("battery").getInt("percent")
} else if (pump.has("battery") && pump.getJSONObject("battery").has("voltage")) {
deviceStatusPumpData.isPercent = false
deviceStatusPumpData.voltage = pump.getJSONObject("battery").getDouble("voltage")
}
if (pump.has("extended")) {
val extendedJson = pump.getJSONObject("extended")
val extended = StringBuilder()
val keys: Iterator<*> = extendedJson.keys()
while (keys.hasNext()) {
val key = keys.next() as String
val value = extendedJson.getString(key)
extended.append("<b>").append(key).append(":</b> ").append(value).append("<br>")
}
deviceStatusPumpData.extended = fromHtml(extended.toString())
deviceStatusPumpData.activeProfileName = JsonHelper.safeGetStringAllowNull(extendedJson, "ActiveProfile", null)
}
deviceStatusData.pumpData = deviceStatusPumpData
} catch (e: Exception) {
aapsLogger.error("Unhandled exception", e)
}
}
private fun updateOpenApsData(jsonObject: JSONObject) {
try {
val openAps = if (jsonObject.has("openaps")) jsonObject.getJSONObject("openaps") else JSONObject()
val suggested = if (openAps.has("suggested")) openAps.getJSONObject("suggested") else JSONObject()
val enacted = if (openAps.has("enacted")) openAps.getJSONObject("enacted") else JSONObject()
var clock = if (suggested.has("timestamp")) dateUtil.fromISODateString(suggested.getString("timestamp")) else 0L
// check if this is new data
if (clock != 0L && clock > deviceStatusData.openAPSData.clockSuggested) {
deviceStatusData.openAPSData.suggested = suggested
deviceStatusData.openAPSData.clockSuggested = clock
}
clock = if (enacted.has("timestamp")) dateUtil.fromISODateString(enacted.getString("timestamp")) else 0L
// check if this is new data
if (clock != 0L && clock > deviceStatusData.openAPSData.clockEnacted) {
deviceStatusData.openAPSData.enacted = enacted
deviceStatusData.openAPSData.clockEnacted = clock
}
} catch (e: Exception) {
aapsLogger.error("Unhandled exception", e)
}
}
val openApsStatus: Spanned
get() {
val string = StringBuilder()
.append("<span style=\"color:${rh.gac(R.attr.nsTitleColor)}\">")
.append(rh.gs(R.string.openaps_short))
.append(": </span>")
// test warning level
val level = when {
deviceStatusData.openAPSData.clockSuggested + T.mins(sp.getLong(R.string.key_nsalarm_urgent_staledatavalue, 31)).msecs() < dateUtil.now() -> Levels.URGENT
deviceStatusData.openAPSData.clockSuggested + T.mins(sp.getLong(R.string.key_nsalarm_staledatavalue, 16)).msecs() < dateUtil.now() -> Levels.WARN
else -> Levels.INFO
}
string.append("<span style=\"color:${level.toColor()}\">")
if (deviceStatusData.openAPSData.clockSuggested != 0L) string.append(dateUtil.minAgo(rh, deviceStatusData.openAPSData.clockSuggested)).append(" ")
string.append("</span>") // color
return fromHtml(string.toString())
}
val extendedOpenApsStatus: Spanned
get() {
val string = StringBuilder()
try {
if (deviceStatusData.openAPSData.enacted != null && deviceStatusData.openAPSData.clockEnacted != deviceStatusData.openAPSData.clockSuggested) string.append("<b>")
.append(dateUtil.minAgo(rh, deviceStatusData.openAPSData.clockEnacted)).append("</b> ").append(deviceStatusData.openAPSData.enacted!!.getString("reason")).append("<br>")
if (deviceStatusData.openAPSData.suggested != null) string.append("<b>").append(dateUtil.minAgo(rh, deviceStatusData.openAPSData.clockSuggested)).append("</b> ")
.append(deviceStatusData.openAPSData.suggested!!.getString("reason")).append("<br>")
return fromHtml(string.toString())
} catch (e: JSONException) {
aapsLogger.error("Unhandled exception", e)
}
return fromHtml("")
}
private fun updateUploaderData(jsonObject: JSONObject) {
try {
val clock =
when {
jsonObject.has("mills") -> jsonObject.getLong("mills")
jsonObject.has("created_at") -> dateUtil.fromISODateString(jsonObject.getString("created_at"))
else -> 0L
}
val device = device
val battery: Int =
when {
jsonObject.has("uploaderBattery") -> jsonObject.getInt("uploaderBattery")
jsonObject.has("uploader") && jsonObject.getJSONObject("uploader").has("battery") -> jsonObject.getJSONObject("uploader").getInt("battery")
else -> 0
}
var uploader = deviceStatusData.uploaderMap[device]
// check if this is new data
if (clock != 0L && battery != 0 && (uploader == null || clock > uploader.clock)) {
if (uploader == null) uploader = DeviceStatusData.Uploader()
uploader.battery = battery
uploader.clock = clock
deviceStatusData.uploaderMap[device] = uploader
}
} catch (e: Exception) {
aapsLogger.error("Unhandled exception", e)
}
}
val uploaderStatus: String
get() {
val iterator: Iterator<*> = deviceStatusData.uploaderMap.entries.iterator()
var minBattery = 100
while (iterator.hasNext()) {
val pair = iterator.next() as Map.Entry<*, *>
val uploader = pair.value as DeviceStatusData.Uploader
if (minBattery > uploader.battery) minBattery = uploader.battery
}
return "$minBattery%"
}
val uploaderStatusSpanned: Spanned
get() {
val string = StringBuilder()
string.append("<span style=\"color:${rh.gac(R.attr.nsTitleColor)}\">")
string.append(rh.gs(R.string.uploader_short))
string.append(": </span>")
val iterator: Iterator<*> = deviceStatusData.uploaderMap.entries.iterator()
var minBattery = 100
while (iterator.hasNext()) {
val pair = iterator.next() as Map.Entry<*, *>
val uploader = pair.value as DeviceStatusData.Uploader
if (minBattery > uploader.battery) minBattery = uploader.battery
}
string.append(minBattery)
string.append("%")
return fromHtml(string.toString())
}
val extendedUploaderStatus: Spanned
get() {
val string = StringBuilder()
val iterator: Iterator<*> = deviceStatusData.uploaderMap.entries.iterator()
while (iterator.hasNext()) {
val pair = iterator.next() as Map.Entry<*, *>
val uploader = pair.value as DeviceStatusData.Uploader
val device = pair.key as String
string.append("<b>").append(device).append(":</b> ").append(uploader.battery).append("%<br>")
}
return fromHtml(string.toString())
}
val openApsTimestamp: Long
get() =
if (deviceStatusData.openAPSData.clockSuggested != 0L) {
deviceStatusData.openAPSData.clockSuggested
} else {
-1
}
fun getAPSResult(injector: HasAndroidInjector): APSResult {
val result = APSResult(injector)
result.json = deviceStatusData.openAPSData.suggested
result.date = deviceStatusData.openAPSData.clockSuggested
return result
}
}

View file

@ -1,8 +0,0 @@
package info.nightscout.androidaps.plugins.general.nsclient.events
import info.nightscout.androidaps.events.EventStatus
import info.nightscout.androidaps.interfaces.ResourceHelper
class EventNSClientStatus(var text: String) : EventStatus() {
override fun getStatus(rh: ResourceHelper): String = text
}

View file

@ -1,5 +0,0 @@
package info.nightscout.androidaps.plugins.general.nsclient.events
import info.nightscout.rx.events.EventUpdateGui
class EventNSClientUpdateGUI : EventUpdateGui()

View file

@ -27,7 +27,6 @@ import androidx.recyclerview.widget.LinearLayoutManager
import com.jjoe64.graphview.GraphView
import dagger.android.HasAndroidInjector
import dagger.android.support.DaggerFragment
import info.nightscout.interfaces.Constants
import info.nightscout.androidaps.R
import info.nightscout.androidaps.data.ProfileSealed
import info.nightscout.androidaps.database.AppRepository
@ -51,9 +50,7 @@ import info.nightscout.androidaps.extensions.runOnUiThread
import info.nightscout.androidaps.extensions.toVisibility
import info.nightscout.androidaps.extensions.valueToUnitsString
import info.nightscout.androidaps.interfaces.ActivePlugin
import info.nightscout.interfaces.BuildHelper
import info.nightscout.androidaps.interfaces.CommandQueue
import info.nightscout.interfaces.Config
import info.nightscout.androidaps.interfaces.Constraint
import info.nightscout.androidaps.interfaces.Constraints
import info.nightscout.androidaps.interfaces.GlucoseUnit
@ -67,7 +64,6 @@ import info.nightscout.androidaps.interfaces.TrendCalculator
import info.nightscout.androidaps.logging.UserEntryLogger
import info.nightscout.androidaps.plugins.aps.loop.events.EventNewOpenLoopNotification
import info.nightscout.androidaps.plugins.aps.openAPSSMB.DetermineBasalResultSMB
import info.nightscout.androidaps.plugins.general.nsclient.data.NSDeviceStatus
import info.nightscout.androidaps.plugins.general.overview.activities.QuickWizardListActivity
import info.nightscout.androidaps.plugins.general.overview.events.EventUpdateOverviewCalcProgress
import info.nightscout.androidaps.plugins.general.overview.events.EventUpdateOverviewGraph
@ -81,11 +77,12 @@ import info.nightscout.androidaps.plugins.pump.common.defs.PumpType
import info.nightscout.androidaps.plugins.pump.omnipod.eros.OmnipodErosPumpPlugin
import info.nightscout.androidaps.plugins.source.DexcomPlugin
import info.nightscout.androidaps.plugins.source.XdripPlugin
import info.nightscout.androidaps.plugins.sync.nsclient.data.NSSettingsStatus
import info.nightscout.androidaps.plugins.sync.nsclient.data.ProcessedDeviceStatusData
import info.nightscout.androidaps.skins.SkinProvider
import info.nightscout.androidaps.utils.DateUtil
import info.nightscout.androidaps.utils.DefaultValueHelper
import info.nightscout.androidaps.utils.FabricPrivacy
import info.nightscout.interfaces.utils.JsonHelper
import info.nightscout.androidaps.utils.ToastUtils
import info.nightscout.androidaps.utils.alertDialogs.OKDialog
import info.nightscout.androidaps.utils.protection.ProtectionCheck
@ -93,6 +90,10 @@ import info.nightscout.androidaps.utils.ui.SingleClickButton
import info.nightscout.androidaps.utils.ui.UIRunnable
import info.nightscout.androidaps.utils.wizard.QuickWizard
import info.nightscout.automation.AutomationPlugin
import info.nightscout.interfaces.BuildHelper
import info.nightscout.interfaces.Config
import info.nightscout.interfaces.Constants
import info.nightscout.interfaces.utils.JsonHelper
import info.nightscout.plugins.constraints.bgQualityCheck.BgQualityCheckPlugin
import info.nightscout.rx.AapsSchedulers
import info.nightscout.rx.bus.RxBus
@ -128,7 +129,8 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
@Inject lateinit var profileFunction: ProfileFunction
@Inject lateinit var constraintChecker: Constraints
@Inject lateinit var statusLightHandler: StatusLightHandler
@Inject lateinit var nsDeviceStatus: NSDeviceStatus
@Inject lateinit var processedDeviceStatusData: ProcessedDeviceStatusData
@Inject lateinit var nsSettingsStatus: NSSettingsStatus
@Inject lateinit var loop: Loop
@Inject lateinit var activePlugin: ActivePlugin
@Inject lateinit var iobCobCalculator: IobCobCalculator
@ -722,16 +724,16 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
}
// pump status from ns
binding.pump.text = nsDeviceStatus.pumpStatus
binding.pump.setOnClickListener { activity?.let { OKDialog.show(it, rh.gs(R.string.pump), nsDeviceStatus.extendedPumpStatus) } }
binding.pump.text = processedDeviceStatusData.pumpStatus(nsSettingsStatus)
binding.pump.setOnClickListener { activity?.let { OKDialog.show(it, rh.gs(R.string.pump), processedDeviceStatusData.extendedPumpStatus) } }
// OpenAPS status from ns
binding.openaps.text = nsDeviceStatus.openApsStatus
binding.openaps.setOnClickListener { activity?.let { OKDialog.show(it, rh.gs(R.string.openaps), nsDeviceStatus.extendedOpenApsStatus) } }
binding.openaps.text = processedDeviceStatusData.openApsStatus
binding.openaps.setOnClickListener { activity?.let { OKDialog.show(it, rh.gs(R.string.openaps), processedDeviceStatusData.extendedOpenApsStatus) } }
// Uploader status from ns
binding.uploader.text = nsDeviceStatus.uploaderStatusSpanned
binding.uploader.setOnClickListener { activity?.let { OKDialog.show(it, rh.gs(R.string.uploader), nsDeviceStatus.extendedUploaderStatus) } }
binding.uploader.text = processedDeviceStatusData.uploaderStatusSpanned
binding.uploader.setOnClickListener { activity?.let { OKDialog.show(it, rh.gs(R.string.uploader), processedDeviceStatusData.extendedUploaderStatus) } }
}
}
@ -1118,7 +1120,7 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
val isfMgdl = profile?.getIsfMgdl()
val variableSens =
if (config.APS && request is DetermineBasalResultSMB) request.variableSens ?: 0.0
else if (config.NSCLIENT) JsonHelper.safeGetDouble(nsDeviceStatus.getAPSResult(injector).json, "variable_sens")
else if (config.NSCLIENT) JsonHelper.safeGetDouble(processedDeviceStatusData.getAPSResult(injector).json, "variable_sens")
else 0.0
if (variableSens != isfMgdl && variableSens != 0.0 && isfMgdl != null) {

View file

@ -6,17 +6,15 @@ import info.nightscout.androidaps.R
import info.nightscout.androidaps.database.AppRepository
import info.nightscout.androidaps.database.ValueWrapper
import info.nightscout.androidaps.database.entities.TherapyEvent
import info.nightscout.androidaps.extensions.age
import info.nightscout.plugins.sync.nsclient.extensions.age
import info.nightscout.androidaps.interfaces.ActivePlugin
import info.nightscout.interfaces.Config
import info.nightscout.androidaps.plugins.pump.common.defs.PumpType
import info.nightscout.androidaps.plugins.pump.omnipod.eros.OmnipodErosPumpPlugin
import info.nightscout.androidaps.plugins.pump.omnipod.eros.driver.definition.OmnipodConstants
import info.nightscout.androidaps.utils.DateUtil
import info.nightscout.androidaps.utils.DecimalFormatter
import info.nightscout.androidaps.utils.WarnColors
import info.nightscout.androidaps.interfaces.ResourceHelper
import info.nightscout.androidaps.plugins.pump.eopatch.AppConstant
import info.nightscout.shared.sharedPreferences.SP
import javax.inject.Inject
import javax.inject.Singleton

View file

@ -3,8 +3,8 @@ package info.nightscout.androidaps.plugins.general.overview.notifications
import dagger.android.HasAndroidInjector
import info.nightscout.androidaps.R
import info.nightscout.androidaps.interfaces.ResourceHelper
import info.nightscout.androidaps.plugins.general.nsclient.NSClientPlugin
import info.nightscout.androidaps.plugins.general.nsclient.data.NSAlarm
import info.nightscout.androidaps.plugins.sync.nsclient.NSClientPlugin
import info.nightscout.androidaps.plugins.sync.nsclient.data.NSAlarm
import info.nightscout.androidaps.utils.DefaultValueHelper
import info.nightscout.androidaps.utils.T
import info.nightscout.interfaces.notifications.Notification

View file

@ -6,7 +6,7 @@ import android.view.View
import android.view.ViewGroup
import dagger.android.support.DaggerFragment
import info.nightscout.androidaps.databinding.WearFragmentBinding
import info.nightscout.androidaps.plugins.general.nsclient.events.EventNSClientUpdateGUI
import info.nightscout.androidaps.plugins.sync.nsShared.events.EventNSClientUpdateGUI
import info.nightscout.androidaps.utils.DateUtil
import info.nightscout.androidaps.utils.FabricPrivacy
import info.nightscout.rx.AapsSchedulers
@ -65,7 +65,7 @@ class WearFragment : DaggerFragment() {
_binding = null
}
fun updateGui() {
private fun updateGui() {
_binding ?: return
binding.connectedDevice.text = wearPlugin.connectedDevice
}

View file

@ -3,12 +3,17 @@ package info.nightscout.androidaps.plugins.general.wear.wearintegration
import android.app.NotificationManager
import android.content.Context
import dagger.android.HasAndroidInjector
import info.nightscout.interfaces.Constants
import info.nightscout.androidaps.R
import info.nightscout.androidaps.data.DetailedBolusInfo
import info.nightscout.androidaps.database.AppRepository
import info.nightscout.androidaps.database.ValueWrapper
import info.nightscout.androidaps.database.entities.*
import info.nightscout.androidaps.database.entities.Bolus
import info.nightscout.androidaps.database.entities.GlucoseValue
import info.nightscout.androidaps.database.entities.TemporaryBasal
import info.nightscout.androidaps.database.entities.TemporaryTarget
import info.nightscout.androidaps.database.entities.TotalDailyDose
import info.nightscout.androidaps.database.entities.UserEntry
import info.nightscout.androidaps.database.entities.ValueWithUnit
import info.nightscout.androidaps.database.interfaces.end
import info.nightscout.androidaps.database.transactions.CancelCurrentTemporaryTargetIfAnyTransaction
import info.nightscout.androidaps.database.transactions.InsertAndCancelCurrentTemporaryTargetTransaction
@ -18,19 +23,37 @@ import info.nightscout.androidaps.extensions.toStringShort
import info.nightscout.androidaps.extensions.total
import info.nightscout.androidaps.extensions.valueToUnits
import info.nightscout.androidaps.extensions.valueToUnitsString
import info.nightscout.androidaps.interfaces.*
import info.nightscout.androidaps.interfaces.ActivePlugin
import info.nightscout.androidaps.interfaces.CommandQueue
import info.nightscout.androidaps.interfaces.Constraint
import info.nightscout.androidaps.interfaces.Constraints
import info.nightscout.androidaps.interfaces.GlucoseUnit
import info.nightscout.androidaps.interfaces.IobCobCalculator
import info.nightscout.androidaps.interfaces.Loop
import info.nightscout.androidaps.interfaces.PluginBase
import info.nightscout.androidaps.interfaces.Profile
import info.nightscout.androidaps.interfaces.ProfileFunction
import info.nightscout.androidaps.interfaces.ResourceHelper
import info.nightscout.androidaps.interfaces.TrendCalculator
import info.nightscout.androidaps.logging.UserEntryLogger
import info.nightscout.androidaps.plugins.general.nsclient.data.NSDeviceStatus
import info.nightscout.androidaps.plugins.general.overview.graphExtensions.GlucoseValueDataPoint
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.GlucoseStatusProvider
import info.nightscout.interfaces.queue.Callback
import info.nightscout.androidaps.plugins.sync.nsclient.data.ProcessedDeviceStatusData
import info.nightscout.androidaps.receivers.ReceiverStatusStore
import info.nightscout.androidaps.services.AlarmSoundServiceHelper
import info.nightscout.androidaps.utils.*
import info.nightscout.androidaps.utils.DateUtil
import info.nightscout.androidaps.utils.DecimalFormatter
import info.nightscout.androidaps.utils.DefaultValueHelper
import info.nightscout.androidaps.utils.FabricPrivacy
import info.nightscout.androidaps.utils.HardLimits
import info.nightscout.androidaps.utils.T
import info.nightscout.androidaps.utils.ToastUtils
import info.nightscout.androidaps.utils.wizard.BolusWizard
import info.nightscout.androidaps.utils.wizard.QuickWizard
import info.nightscout.androidaps.utils.wizard.QuickWizardEntry
import info.nightscout.interfaces.Config
import info.nightscout.interfaces.Constants
import info.nightscout.interfaces.queue.Callback
import info.nightscout.rx.AapsSchedulers
import info.nightscout.rx.bus.RxBus
import info.nightscout.rx.events.EventMobileToWear
@ -43,7 +66,9 @@ import io.reactivex.rxjava3.disposables.CompositeDisposable
import io.reactivex.rxjava3.kotlin.plusAssign
import java.text.DateFormat
import java.text.SimpleDateFormat
import java.util.*
import java.util.Date
import java.util.LinkedList
import java.util.Locale
import java.util.concurrent.TimeUnit
import java.util.stream.Collectors
import javax.inject.Inject
@ -66,7 +91,7 @@ class DataHandlerMobile @Inject constructor(
private val glucoseStatusProvider: GlucoseStatusProvider,
private val profileFunction: ProfileFunction,
private val loop: Loop,
private val nsDeviceStatus: NSDeviceStatus,
private val processedDeviceStatusData: ProcessedDeviceStatusData,
private val receiverStatusStore: ReceiverStatusStore,
private val quickWizard: QuickWizard,
private val defaultValueHelper: DefaultValueHelper,
@ -872,11 +897,11 @@ class DataHandlerMobile @Inject constructor(
//batteries
val phoneBattery = receiverStatusStore.batteryLevel
val rigBattery = nsDeviceStatus.uploaderStatus.trim { it <= ' ' }
val rigBattery = processedDeviceStatusData.uploaderStatus.trim { it <= ' ' }
//OpenAPS status
val openApsStatus =
if (config.APS) loop.lastRun?.let { if (it.lastTBREnact != 0L) it.lastTBREnact else -1 } ?: -1
else nsDeviceStatus.openApsTimestamp
else processedDeviceStatusData.openApsTimestamp
rxBus.send(
EventMobileToWear(

View file

@ -1,26 +1,25 @@
package info.nightscout.androidaps.plugins.sensitivity
import dagger.android.HasAndroidInjector
import info.nightscout.interfaces.Constants
import info.nightscout.androidaps.R
import info.nightscout.androidaps.annotations.OpenForTesting
import info.nightscout.androidaps.database.AppRepository
import info.nightscout.androidaps.database.entities.TherapyEvent
import info.nightscout.androidaps.extensions.isPSEvent5minBack
import info.nightscout.androidaps.extensions.isTherapyEventEvent5minBack
import info.nightscout.interfaces.PluginDescription
import info.nightscout.interfaces.PluginType
import info.nightscout.androidaps.interfaces.Profile
import info.nightscout.androidaps.interfaces.ProfileFunction
import info.nightscout.androidaps.interfaces.ResourceHelper
import info.nightscout.androidaps.interfaces.Sensitivity.SensitivityType
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.AutosensDataStore
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.AutosensResult
import info.nightscout.plugins.sync.nsclient.extensions.isTherapyEventEvent5minBack
import info.nightscout.androidaps.utils.DateUtil
import info.nightscout.androidaps.utils.extensions.isPSEvent5minBack
import info.nightscout.interfaces.Constants
import info.nightscout.interfaces.PluginDescription
import info.nightscout.interfaces.PluginType
import info.nightscout.plugins.utils.Percentile
import info.nightscout.rx.logging.AAPSLogger
import info.nightscout.rx.logging.LTag
import info.nightscout.shared.sharedPreferences.SP
import org.json.JSONException
import org.json.JSONObject

View file

@ -1,27 +1,26 @@
package info.nightscout.androidaps.plugins.sensitivity
import dagger.android.HasAndroidInjector
import info.nightscout.interfaces.Constants
import info.nightscout.androidaps.R
import info.nightscout.androidaps.annotations.OpenForTesting
import info.nightscout.androidaps.database.AppRepository
import info.nightscout.androidaps.database.entities.TherapyEvent
import info.nightscout.androidaps.extensions.isPSEvent5minBack
import info.nightscout.androidaps.extensions.isTherapyEventEvent5minBack
import info.nightscout.interfaces.PluginDescription
import info.nightscout.interfaces.PluginType
import info.nightscout.androidaps.interfaces.Profile
import info.nightscout.androidaps.interfaces.ProfileFunction
import info.nightscout.androidaps.interfaces.ResourceHelper
import info.nightscout.androidaps.interfaces.Sensitivity.SensitivityType
import info.nightscout.interfaces.aps.SMBDefaults
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.AutosensDataStore
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.AutosensResult
import info.nightscout.plugins.sync.nsclient.extensions.isTherapyEventEvent5minBack
import info.nightscout.androidaps.utils.DateUtil
import info.nightscout.androidaps.utils.extensions.isPSEvent5minBack
import info.nightscout.interfaces.Constants
import info.nightscout.interfaces.PluginDescription
import info.nightscout.interfaces.PluginType
import info.nightscout.interfaces.aps.SMBDefaults
import info.nightscout.plugins.utils.Percentile
import info.nightscout.rx.logging.AAPSLogger
import info.nightscout.rx.logging.LTag
import info.nightscout.shared.sharedPreferences.SP
import org.json.JSONException
import org.json.JSONObject

View file

@ -2,22 +2,22 @@ package info.nightscout.androidaps.plugins.sensitivity
import androidx.collection.LongSparseArray
import dagger.android.HasAndroidInjector
import info.nightscout.interfaces.Constants
import info.nightscout.androidaps.R
import info.nightscout.androidaps.annotations.OpenForTesting
import info.nightscout.androidaps.database.AppRepository
import info.nightscout.androidaps.database.entities.TherapyEvent
import info.nightscout.androidaps.extensions.isPSEvent5minBack
import info.nightscout.androidaps.extensions.isTherapyEventEvent5minBack
import info.nightscout.interfaces.PluginDescription
import info.nightscout.interfaces.PluginType
import info.nightscout.androidaps.interfaces.Profile
import info.nightscout.androidaps.interfaces.ProfileFunction
import info.nightscout.androidaps.interfaces.ResourceHelper
import info.nightscout.androidaps.interfaces.Sensitivity.SensitivityType
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.AutosensDataStore
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.AutosensResult
import info.nightscout.plugins.sync.nsclient.extensions.isTherapyEventEvent5minBack
import info.nightscout.androidaps.utils.DateUtil
import info.nightscout.androidaps.utils.extensions.isPSEvent5minBack
import info.nightscout.interfaces.Constants
import info.nightscout.interfaces.PluginDescription
import info.nightscout.interfaces.PluginType
import info.nightscout.rx.logging.AAPSLogger
import info.nightscout.rx.logging.LTag
import info.nightscout.shared.sharedPreferences.SP
@ -147,13 +147,16 @@ class SensitivityWeightedAveragePlugin @Inject constructor(
else -> "Sensitivity normal"
}
aapsLogger.debug(LTag.AUTOSENS, sensResult)
val output = fillResult(ratio, current.cob, pastSensitivity, ratioLimit,
sensResult, data.size())
val output = fillResult(
ratio, current.cob, pastSensitivity, ratioLimit,
sensResult, data.size()
)
aapsLogger.debug(
LTag.AUTOSENS, "Sensitivity to: "
+ dateUtil.dateAndTimeString(toTime) +
" ratio: " + output.ratio
+ " mealCOB: " + current.cob)
+ dateUtil.dateAndTimeString(toTime) +
" ratio: " + output.ratio
+ " mealCOB: " + current.cob
)
return output
}
@ -178,7 +181,10 @@ class SensitivityWeightedAveragePlugin @Inject constructor(
override fun applyConfiguration(configuration: JSONObject) {
try {
if (configuration.has(rh.gs(R.string.key_absorption_maxtime))) sp.putDouble(R.string.key_absorption_maxtime, configuration.getDouble(rh.gs(R.string.key_absorption_maxtime)))
if (configuration.has(rh.gs(R.string.key_openapsama_autosens_period))) sp.putDouble(R.string.key_openapsama_autosens_period, configuration.getDouble(rh.gs(R.string.key_openapsama_autosens_period)))
if (configuration.has(rh.gs(R.string.key_openapsama_autosens_period))) sp.putDouble(
R.string.key_openapsama_autosens_period,
configuration.getDouble(rh.gs(R.string.key_openapsama_autosens_period))
)
if (configuration.has(rh.gs(R.string.key_openapsama_autosens_max))) sp.getDouble(R.string.key_openapsama_autosens_max, configuration.getDouble(rh.gs(R.string.key_openapsama_autosens_max)))
if (configuration.has(rh.gs(R.string.key_openapsama_autosens_min))) sp.getDouble(R.string.key_openapsama_autosens_min, configuration.getDouble(rh.gs(R.string.key_openapsama_autosens_min)))
} catch (e: JSONException) {

View file

@ -9,24 +9,27 @@ import info.nightscout.androidaps.R
import info.nightscout.androidaps.database.AppRepository
import info.nightscout.androidaps.database.entities.GlucoseValue
import info.nightscout.androidaps.database.transactions.CgmSourceTransaction
import info.nightscout.androidaps.interfaces.ActivePlugin
import info.nightscout.androidaps.interfaces.BgSource
import info.nightscout.interfaces.Config
import info.nightscout.androidaps.interfaces.PluginBase
import info.nightscout.interfaces.PluginDescription
import info.nightscout.interfaces.PluginType
import info.nightscout.androidaps.interfaces.ResourceHelper
import info.nightscout.androidaps.interfaces.XDripBroadcast
import info.nightscout.androidaps.plugins.general.nsclient.NSClientPlugin
import info.nightscout.androidaps.plugins.general.nsclient.data.NSSgv
import info.nightscout.androidaps.plugins.general.overview.events.EventDismissNotification
import info.nightscout.interfaces.notifications.Notification
import info.nightscout.androidaps.plugins.sync.nsShared.StoreDataForDb
import info.nightscout.androidaps.plugins.sync.nsclient.data.NSSgv
import info.nightscout.androidaps.receivers.DataWorkerStorage
import info.nightscout.androidaps.utils.DateUtil
import info.nightscout.androidaps.utils.T
import info.nightscout.interfaces.Config
import info.nightscout.interfaces.PluginDescription
import info.nightscout.interfaces.PluginType
import info.nightscout.interfaces.notifications.Notification
import info.nightscout.rx.bus.RxBus
import info.nightscout.rx.logging.AAPSLogger
import info.nightscout.rx.logging.LTag
import info.nightscout.sdk.localmodel.entry.NSSgvV3
import info.nightscout.shared.sharedPreferences.SP
import org.json.JSONArray
import org.json.JSONObject
import javax.inject.Inject
import javax.inject.Singleton
@ -39,12 +42,12 @@ class NSClientSourcePlugin @Inject constructor(
config: Config
) : PluginBase(
PluginDescription()
.mainType(PluginType.BGSOURCE)
.fragmentClass(BGSourceFragment::class.java.name)
.pluginIcon(R.drawable.ic_nsclient_bg)
.pluginName(R.string.nsclientbg)
.shortName(R.string.nsclientbgshort)
.description(R.string.description_source_ns_client),
.mainType(PluginType.BGSOURCE)
.fragmentClass(BGSourceFragment::class.java.name)
.pluginIcon(R.drawable.ic_nsclient_bg)
.pluginName(R.string.nsclientbg)
.shortName(R.string.nsclientbgshort)
.description(R.string.description_source_ns_client),
aapsLogger, rh, injector
), BgSource {
@ -65,7 +68,7 @@ class NSClientSourcePlugin @Inject constructor(
override fun shouldUploadToNs(glucoseValue: GlucoseValue): Boolean = false
private fun detectSource(glucoseValue: GlucoseValue) {
internal fun detectSource(glucoseValue: GlucoseValue) {
if (glucoseValue.timestamp > lastBGTimeStamp) {
isAdvancedFilteringEnabled = arrayOf(
GlucoseValue.SourceSensor.DEXCOM_NATIVE_UNKNOWN,
@ -93,8 +96,8 @@ class NSClientSourcePlugin @Inject constructor(
@Inject lateinit var dataWorkerStorage: DataWorkerStorage
@Inject lateinit var repository: AppRepository
@Inject lateinit var xDripBroadcast: XDripBroadcast
@Inject lateinit var dexcomPlugin: DexcomPlugin
@Inject lateinit var nsClientPlugin: NSClientPlugin
@Inject lateinit var activePlugin: ActivePlugin
@Inject lateinit var storeDataForDb: StoreDataForDb
init {
(context.applicationContext as HasAndroidInjector).androidInjector().inject(this)
@ -113,52 +116,60 @@ class NSClientSourcePlugin @Inject constructor(
)
}
private fun toGv(sgv: NSSgvV3): CgmSourceTransaction.TransactionGlucoseValue {
return CgmSourceTransaction.TransactionGlucoseValue(
timestamp = sgv.date,
value = sgv.sgv,
noise = sgv.noise?.toDouble(),
raw = sgv.filtered ?: sgv.sgv,
trendArrow = GlucoseValue.TrendArrow.fromString(sgv.direction.nsName),
nightscoutId = sgv.identifier,
sourceSensor = GlucoseValue.SourceSensor.fromString(sgv.device),
isValid = sgv.isValid
)
}
@Suppress("SpellCheckingInspection")
override fun doWork(): Result {
var ret = Result.success()
val sgvs = dataWorkerStorage.pickupJSONArray(inputData.getLong(DataWorkerStorage.STORE_KEY, -1))
val sgvs = dataWorkerStorage.pickupObject(inputData.getLong(DataWorkerStorage.STORE_KEY, -1))
?: return Result.failure(workDataOf("Error" to "missing input data"))
xDripBroadcast.sendSgvs(sgvs)
if (!nsClientSourcePlugin.isEnabled() && !sp.getBoolean(R.string.key_ns_receive_cgm, false))
return Result.success(workDataOf("Result" to "Sync not enabled"))
try {
var latestDateInReceivedData: Long = 0
var latestDateInReceivedData: Long = 0
aapsLogger.debug(LTag.BGSOURCE, "Received NS Data: $sgvs")
val glucoseValues = mutableListOf<CgmSourceTransaction.TransactionGlucoseValue>()
aapsLogger.debug(LTag.BGSOURCE, "Received NS Data: $sgvs")
val glucoseValues = mutableListOf<CgmSourceTransaction.TransactionGlucoseValue>()
for (i in 0 until sgvs.length()) {
val sgv = toGv(sgvs.getJSONObject(i)) ?: continue
if (sgv.timestamp < dateUtil.now() && sgv.timestamp > latestDateInReceivedData) latestDateInReceivedData = sgv.timestamp
glucoseValues += sgv
try {
if (sgvs is JSONArray) { // V1 client
xDripBroadcast.sendSgvs(sgvs)
for (i in 0 until sgvs.length()) {
val sgv = toGv(sgvs.getJSONObject(i)) ?: continue
if (sgv.timestamp < dateUtil.now() && sgv.timestamp > latestDateInReceivedData) latestDateInReceivedData = sgv.timestamp
glucoseValues += sgv
}
} else if (sgvs is List<*>) { // V3 client
// xDripBroadcast.sendSgvs(sgvs)
for (i in 0 until sgvs.size) {
val sgv = toGv(sgvs[i] as NSSgvV3)
if (sgv.timestamp < dateUtil.now() && sgv.timestamp > latestDateInReceivedData) latestDateInReceivedData = sgv.timestamp
glucoseValues += sgv
}
}
activePlugin.activeNsClient?.updateLatestBgReceivedIfNewer(latestDateInReceivedData)
// Was that sgv more less 5 mins ago ?
if (T.msecs(dateUtil.now() - latestDateInReceivedData).mins() < 5L) {
rxBus.send(EventDismissNotification(Notification.NS_ALARM))
rxBus.send(EventDismissNotification(Notification.NS_URGENT_ALARM))
}
nsClientPlugin.updateLatestDateReceivedIfNewer(latestDateInReceivedData)
repository.runTransactionForResult(CgmSourceTransaction(glucoseValues, emptyList(), null, !nsClientSourcePlugin.isEnabled()))
.doOnError {
aapsLogger.error(LTag.DATABASE, "Error while saving values from NSClient App", it)
ret = Result.failure(workDataOf("Error" to it.toString()))
}
.blockingGet()
.also { result ->
result.updated.forEach {
xDripBroadcast.send(it)
nsClientSourcePlugin.detectSource(it)
aapsLogger.debug(LTag.DATABASE, "Updated bg $it")
}
result.inserted.forEach {
xDripBroadcast.send(it)
nsClientSourcePlugin.detectSource(it)
aapsLogger.debug(LTag.DATABASE, "Inserted bg $it")
}
}
storeDataForDb.glucoseValues.addAll(glucoseValues)
} catch (e: Exception) {
aapsLogger.error("Unhandled exception", e)
ret = Result.failure(workDataOf("Error" to e.toString()))

View file

@ -9,15 +9,15 @@ import info.nightscout.androidaps.database.AppRepository
import info.nightscout.androidaps.database.entities.GlucoseValue
import info.nightscout.androidaps.database.transactions.CgmSourceTransaction
import info.nightscout.androidaps.interfaces.BgSource
import info.nightscout.interfaces.BuildHelper
import info.nightscout.androidaps.interfaces.PluginBase
import info.nightscout.interfaces.PluginDescription
import info.nightscout.interfaces.PluginType
import info.nightscout.androidaps.interfaces.ResourceHelper
import info.nightscout.androidaps.interfaces.XDripBroadcast
import info.nightscout.androidaps.plugins.pump.virtual.VirtualPumpPlugin
import info.nightscout.androidaps.utils.T
import info.nightscout.androidaps.utils.extensions.isRunningTest
import info.nightscout.interfaces.BuildHelper
import info.nightscout.interfaces.PluginDescription
import info.nightscout.interfaces.PluginType
import info.nightscout.rx.logging.AAPSLogger
import info.nightscout.rx.logging.LTag
import info.nightscout.shared.sharedPreferences.SP

View file

@ -1,6 +1,8 @@
package info.nightscout.androidaps.plugins.general.nsclient
package info.nightscout.androidaps.plugins.sync.nsShared
import android.os.Bundle
import android.os.Handler
import android.os.HandlerThread
import android.view.LayoutInflater
import android.view.Menu
import android.view.MenuInflater
@ -12,26 +14,30 @@ import androidx.core.view.MenuProvider
import androidx.lifecycle.Lifecycle
import dagger.android.support.DaggerFragment
import info.nightscout.androidaps.R
import info.nightscout.androidaps.database.entities.UserEntry.Action
import info.nightscout.androidaps.database.entities.UserEntry.Sources
import info.nightscout.androidaps.database.entities.UserEntry
import info.nightscout.androidaps.databinding.NsClientFragmentBinding
import info.nightscout.androidaps.interfaces.ActivePlugin
import info.nightscout.androidaps.interfaces.DataSyncSelector
import info.nightscout.androidaps.interfaces.NsClient
import info.nightscout.androidaps.interfaces.PluginBase
import info.nightscout.androidaps.interfaces.PluginFragment
import info.nightscout.androidaps.interfaces.ResourceHelper
import info.nightscout.androidaps.logging.UserEntryLogger
import info.nightscout.androidaps.plugins.general.nsclient.events.EventNSClientUpdateGUI
import info.nightscout.androidaps.plugins.sync.nsShared.events.EventNSClientUpdateGUI
import info.nightscout.androidaps.plugins.sync.nsclientV3.NSClientV3Plugin
import info.nightscout.androidaps.utils.FabricPrivacy
import info.nightscout.androidaps.utils.alertDialogs.OKDialog
import info.nightscout.rx.AapsSchedulers
import info.nightscout.rx.bus.RxBus
import info.nightscout.rx.events.EventNSClientRestart
import info.nightscout.rx.logging.AAPSLogger
import info.nightscout.shared.sharedPreferences.SP
import io.reactivex.rxjava3.disposables.CompositeDisposable
import io.reactivex.rxjava3.kotlin.plusAssign
import javax.inject.Inject
class NSClientFragment : DaggerFragment(), MenuProvider {
class NSClientFragment : DaggerFragment(), MenuProvider, PluginFragment {
@Inject lateinit var nsClientPlugin: NSClientPlugin
@Inject lateinit var sp: SP
@Inject lateinit var rh: ResourceHelper
@Inject lateinit var rxBus: RxBus
@ -39,6 +45,8 @@ class NSClientFragment : DaggerFragment(), MenuProvider {
@Inject lateinit var aapsSchedulers: AapsSchedulers
@Inject lateinit var dataSyncSelector: DataSyncSelector
@Inject lateinit var uel: UserEntryLogger
@Inject lateinit var aapsLogger: AAPSLogger
@Inject lateinit var activePlugin: ActivePlugin
companion object {
@ -46,10 +54,17 @@ class NSClientFragment : DaggerFragment(), MenuProvider {
const val ID_MENU_RESTART = 508
const val ID_MENU_SEND_NOW = 509
const val ID_MENU_FULL_SYNC = 510
const val ID_MENU_TEST = 601
}
override var plugin: PluginBase? = null
private val nsClientPlugin
get() = activePlugin.activeNsClient
private val version: NsClient.Version get() = nsClientPlugin?.version ?: NsClient.Version.NONE
private val disposable = CompositeDisposable()
private var handler = Handler(HandlerThread(this::class.simpleName + "Handler").also { it.start() }.looper)
private var _binding: NsClientFragmentBinding? = null
// This property is only valid between onCreateView and
@ -65,22 +80,22 @@ class NSClientFragment : DaggerFragment(), MenuProvider {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
binding.autoscroll.isChecked = nsClientPlugin.autoscroll
binding.autoscroll.isChecked = sp.getBoolean(R.string.key_nsclientinternal_autoscroll, true)
binding.autoscroll.setOnCheckedChangeListener { _, isChecked ->
sp.putBoolean(R.string.key_nsclientinternal_autoscroll, isChecked)
nsClientPlugin.autoscroll = isChecked
updateGui()
}
binding.paused.isChecked = nsClientPlugin.paused
binding.paused.isChecked = sp.getBoolean(R.string.key_nsclientinternal_paused, false)
binding.paused.setOnCheckedChangeListener { _, isChecked ->
uel.log(if (isChecked) Action.NS_PAUSED else Action.NS_RESUME, Sources.NSClient)
nsClientPlugin.pause(isChecked)
uel.log(if (isChecked) UserEntry.Action.NS_PAUSED else UserEntry.Action.NS_RESUME, UserEntry.Sources.NSClient)
nsClientPlugin?.pause(isChecked)
updateGui()
}
}
override fun onCreateMenu(menu: Menu, inflater: MenuInflater) {
menu.add(Menu.FIRST, ID_MENU_TEST, 0, "Test").setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER)
menu.add(Menu.FIRST, ID_MENU_CLEAR_LOG, 0, rh.gs(R.string.clearlog)).setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER)
menu.add(Menu.FIRST, ID_MENU_RESTART, 0, rh.gs(R.string.restart)).setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER)
menu.add(Menu.FIRST, ID_MENU_SEND_NOW, 0, rh.gs(R.string.deliver_now)).setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER)
@ -91,7 +106,7 @@ class NSClientFragment : DaggerFragment(), MenuProvider {
override fun onMenuItemSelected(item: MenuItem): Boolean =
when (item.itemId) {
ID_MENU_CLEAR_LOG -> {
nsClientPlugin.clearLog()
nsClientPlugin?.clearLog()
true
}
@ -101,7 +116,7 @@ class NSClientFragment : DaggerFragment(), MenuProvider {
}
ID_MENU_SEND_NOW -> {
nsClientPlugin.resend("GUI")
nsClientPlugin?.resend("GUI")
true
}
@ -109,12 +124,17 @@ class NSClientFragment : DaggerFragment(), MenuProvider {
context?.let { context ->
OKDialog.showConfirmation(
context, rh.gs(R.string.nsclientinternal), rh.gs(R.string.full_sync_comment),
Runnable { dataSyncSelector.resetToNextFullSync() }
Runnable { nsClientPlugin?.resetToFullSync() }
)
}
true
}
ID_MENU_TEST -> {
nsClientPlugin?.let { plugin -> if (plugin is NSClientV3Plugin) handler.post { plugin.test() } }
true
}
else -> false
}
@ -134,12 +154,11 @@ class NSClientFragment : DaggerFragment(), MenuProvider {
private fun updateGui() {
if (_binding == null) return
nsClientPlugin.updateLog()
binding.paused.isChecked = sp.getBoolean(R.string.key_nsclientinternal_paused, false)
binding.log.text = nsClientPlugin.textLog
if (nsClientPlugin.autoscroll) binding.logScrollview.fullScroll(ScrollView.FOCUS_DOWN)
binding.url.text = nsClientPlugin.url()
binding.status.text = nsClientPlugin.status
binding.log.text = nsClientPlugin?.textLog()
if (sp.getBoolean(R.string.key_nsclientinternal_autoscroll, true)) binding.logScrollview.fullScroll(ScrollView.FOCUS_DOWN)
binding.url.text = nsClientPlugin?.address
binding.status.text = nsClientPlugin?.status
val size = dataSyncSelector.queueSize()
binding.queue.text = if (size >= 0) size.toString() else rh.gs(R.string.value_unavailable_short)
}

View file

@ -0,0 +1,719 @@
package info.nightscout.androidaps.plugins.sync.nsShared
import android.content.Context
import android.os.SystemClock
import androidx.work.Worker
import androidx.work.WorkerParameters
import dagger.android.HasAndroidInjector
import info.nightscout.androidaps.R
import info.nightscout.androidaps.database.AppRepository
import info.nightscout.androidaps.database.entities.Bolus
import info.nightscout.androidaps.database.entities.BolusCalculatorResult
import info.nightscout.androidaps.database.entities.Carbs
import info.nightscout.androidaps.database.entities.EffectiveProfileSwitch
import info.nightscout.androidaps.database.entities.ExtendedBolus
import info.nightscout.androidaps.database.entities.GlucoseValue
import info.nightscout.androidaps.database.entities.OfflineEvent
import info.nightscout.androidaps.database.entities.ProfileSwitch
import info.nightscout.androidaps.database.entities.TemporaryBasal
import info.nightscout.androidaps.database.entities.TemporaryTarget
import info.nightscout.androidaps.database.entities.TherapyEvent
import info.nightscout.androidaps.database.entities.UserEntry
import info.nightscout.androidaps.database.entities.ValueWithUnit
import info.nightscout.androidaps.database.transactions.CgmSourceTransaction
import info.nightscout.androidaps.database.transactions.SyncNsBolusCalculatorResultTransaction
import info.nightscout.androidaps.database.transactions.SyncNsBolusTransaction
import info.nightscout.androidaps.database.transactions.SyncNsCarbsTransaction
import info.nightscout.androidaps.database.transactions.SyncNsEffectiveProfileSwitchTransaction
import info.nightscout.androidaps.database.transactions.SyncNsExtendedBolusTransaction
import info.nightscout.androidaps.database.transactions.SyncNsOfflineEventTransaction
import info.nightscout.androidaps.database.transactions.SyncNsProfileSwitchTransaction
import info.nightscout.androidaps.database.transactions.SyncNsTemporaryBasalTransaction
import info.nightscout.androidaps.database.transactions.SyncNsTemporaryTargetTransaction
import info.nightscout.androidaps.database.transactions.SyncNsTherapyEventTransaction
import info.nightscout.androidaps.database.transactions.UserEntryTransaction
import info.nightscout.androidaps.interfaces.ActivePlugin
import info.nightscout.androidaps.interfaces.NsClient
import info.nightscout.androidaps.interfaces.XDripBroadcast
import info.nightscout.androidaps.logging.UserEntryLogger
import info.nightscout.androidaps.plugins.general.overview.events.EventNewNotification
import info.nightscout.androidaps.plugins.pump.virtual.VirtualPumpPlugin
import info.nightscout.androidaps.plugins.source.NSClientSourcePlugin
import info.nightscout.androidaps.plugins.sync.nsShared.events.EventNSClientNewLog
import info.nightscout.androidaps.utils.DateUtil
import info.nightscout.interfaces.Config
import info.nightscout.interfaces.Constants
import info.nightscout.interfaces.notifications.Notification
import info.nightscout.rx.bus.RxBus
import info.nightscout.rx.logging.AAPSLogger
import info.nightscout.rx.logging.LTag
import info.nightscout.sdk.localmodel.treatment.NSBolus
import info.nightscout.sdk.localmodel.treatment.NSBolusWizard
import info.nightscout.sdk.localmodel.treatment.NSCarbs
import info.nightscout.sdk.localmodel.treatment.NSEffectiveProfileSwitch
import info.nightscout.sdk.localmodel.treatment.NSExtendedBolus
import info.nightscout.sdk.localmodel.treatment.NSOfflineEvent
import info.nightscout.sdk.localmodel.treatment.NSProfileSwitch
import info.nightscout.sdk.localmodel.treatment.NSTemporaryBasal
import info.nightscout.sdk.localmodel.treatment.NSTemporaryTarget
import info.nightscout.sdk.localmodel.treatment.NSTherapyEvent
import info.nightscout.shared.sharedPreferences.SP
import java.util.concurrent.TimeUnit
import javax.inject.Inject
import javax.inject.Singleton
@Singleton
class StoreDataForDb @Inject constructor(
private val aapsLogger: AAPSLogger,
private val rxBus: RxBus,
private val repository: AppRepository,
private val sp: SP,
private val uel: UserEntryLogger,
private val dateUtil: DateUtil,
private val activePlugin: ActivePlugin,
private val config: Config,
private val nsClientSourcePlugin: NSClientSourcePlugin,
private val xDripBroadcast: XDripBroadcast,
private val virtualPumpPlugin: VirtualPumpPlugin
) {
val glucoseValues: MutableList<CgmSourceTransaction.TransactionGlucoseValue> = mutableListOf()
val boluses: MutableList<Bolus> = mutableListOf()
val carbs: MutableList<Carbs> = mutableListOf()
val temporaryTargets: MutableList<TemporaryTarget> = mutableListOf()
val effectiveProfileSwitches: MutableList<EffectiveProfileSwitch> = mutableListOf()
val bolusCalculatorResults: MutableList<BolusCalculatorResult> = mutableListOf()
val therapyEvents: MutableList<TherapyEvent> = mutableListOf()
val extendedBoluses: MutableList<ExtendedBolus> = mutableListOf()
val temporaryBasals: MutableList<TemporaryBasal> = mutableListOf()
val profileSwitches: MutableList<ProfileSwitch> = mutableListOf()
val offlineEvents: MutableList<OfflineEvent> = mutableListOf()
private val userEntries: MutableList<UserEntryTransaction.Entry> = mutableListOf()
private val inserted = HashMap<String, Long>()
private val updated = HashMap<String, Long>()
private val invalidated = HashMap<String, Long>()
private val nsIdUpdated = HashMap<String, Long>()
private val durationUpdated = HashMap<String, Long>()
private val ended = HashMap<String, Long>()
private val pause = 1000L // to slow down db operations
class StoreBgWorker(
context: Context,
params: WorkerParameters
) : Worker(context, params) {
@Inject lateinit var storeDataForDb: StoreDataForDb
override fun doWork(): Result {
storeDataForDb.storeGlucoseValuesToDb()
return Result.success()
}
init {
(context.applicationContext as HasAndroidInjector).androidInjector().inject(this)
}
}
fun <T> HashMap<T, Long>.inc(key: T) =
if (containsKey(key)) merge(key, 1, Long::plus)
else put(key, 1)
private fun storeGlucoseValuesToDb() {
rxBus.send(EventNSClientNewLog("PROCESSING BG", "", activePlugin.activeNsClient?.version ?: NsClient.Version.V3))
if (glucoseValues.isNotEmpty())
repository.runTransactionForResult(CgmSourceTransaction(glucoseValues, emptyList(), null))
.doOnError {
aapsLogger.error(LTag.DATABASE, "Error while saving values from NSClient App", it)
}
.blockingGet()
.also { result ->
glucoseValues.clear()
result.updated.forEach {
xDripBroadcast.send(it)
nsClientSourcePlugin.detectSource(it)
aapsLogger.debug(LTag.DATABASE, "Updated bg $it")
updated.inc(GlucoseValue::class.java.simpleName)
}
result.inserted.forEach {
xDripBroadcast.send(it)
nsClientSourcePlugin.detectSource(it)
aapsLogger.debug(LTag.DATABASE, "Inserted bg $it")
inserted.inc(GlucoseValue::class.java.simpleName)
}
result.updatedNsId.forEach {
xDripBroadcast.send(it)
nsClientSourcePlugin.detectSource(it)
aapsLogger.debug(LTag.DATABASE, "Updated nsId bg $it")
nsIdUpdated.inc(GlucoseValue::class.java.simpleName)
}
}
sendLog("GlucoseValue", GlucoseValue::class.java.simpleName)
SystemClock.sleep(pause)
rxBus.send(EventNSClientNewLog("DONE BG", "", activePlugin.activeNsClient?.version ?: NsClient.Version.V3))
}
fun storeTreatmentsToDb() {
rxBus.send(EventNSClientNewLog("PROCESSING TR", "", activePlugin.activeNsClient?.version ?: NsClient.Version.V3))
if (boluses.isNotEmpty())
repository.runTransactionForResult(SyncNsBolusTransaction(boluses))
.doOnError {
aapsLogger.error(LTag.DATABASE, "Error while saving bolus", it)
}
.blockingGet()
.also { result ->
boluses.clear()
result.inserted.forEach {
if (config.NSCLIENT.not()) userEntries.add(
UserEntryTransaction.Entry(
dateUtil.now(),
UserEntry.Action.BOLUS, UserEntry.Sources.NSClient, it.notes ?: "",
listOf(ValueWithUnit.Timestamp(it.timestamp), ValueWithUnit.Insulin(it.amount))
)
)
aapsLogger.debug(LTag.DATABASE, "Inserted bolus $it")
inserted.inc(NSBolus::class.java.simpleName)
}
result.invalidated.forEach {
if (config.NSCLIENT.not()) userEntries.add(
UserEntryTransaction.Entry(
dateUtil.now(),
UserEntry.Action.BOLUS_REMOVED, UserEntry.Sources.NSClient, "",
listOf(ValueWithUnit.Timestamp(it.timestamp), ValueWithUnit.Insulin(it.amount))
)
)
aapsLogger.debug(LTag.DATABASE, "Invalidated bolus $it")
invalidated.inc(NSBolus::class.java.simpleName)
}
result.updatedNsId.forEach {
aapsLogger.debug(LTag.DATABASE, "Updated nsId of bolus $it")
nsIdUpdated.inc(NSBolus::class.java.simpleName)
}
result.updated.forEach {
aapsLogger.debug(LTag.DATABASE, "Updated amount of bolus $it")
updated.inc(NSBolus::class.java.simpleName)
}
}
sendLog("Bolus", NSBolus::class.java.simpleName)
SystemClock.sleep(pause)
if (carbs.isNotEmpty())
repository.runTransactionForResult(SyncNsCarbsTransaction(carbs))
.doOnError {
aapsLogger.error(LTag.DATABASE, "Error while saving carbs", it)
}
.blockingGet()
.also { result ->
carbs.clear()
result.inserted.forEach {
if (config.NSCLIENT.not()) userEntries.add(
UserEntryTransaction.Entry(
dateUtil.now(),
UserEntry.Action.CARBS, UserEntry.Sources.NSClient, it.notes ?: "",
listOf(ValueWithUnit.Timestamp(it.timestamp), ValueWithUnit.Gram(it.amount.toInt()))
)
)
aapsLogger.debug(LTag.DATABASE, "Inserted carbs $it")
inserted.inc(NSCarbs::class.java.simpleName)
}
result.invalidated.forEach {
if (config.NSCLIENT.not()) userEntries.add(
UserEntryTransaction.Entry(
dateUtil.now(),
UserEntry.Action.CARBS_REMOVED, UserEntry.Sources.NSClient, "",
listOf(ValueWithUnit.Timestamp(it.timestamp), ValueWithUnit.Gram(it.amount.toInt()))
)
)
aapsLogger.debug(LTag.DATABASE, "Invalidated carbs $it")
invalidated.inc(NSCarbs::class.java.simpleName)
}
result.updated.forEach {
if (config.NSCLIENT.not()) userEntries.add(
UserEntryTransaction.Entry(
dateUtil.now(),
UserEntry.Action.CARBS, UserEntry.Sources.NSClient, it.notes ?: "",
listOf(ValueWithUnit.Timestamp(it.timestamp), ValueWithUnit.Gram(it.amount.toInt()))
)
)
aapsLogger.debug(LTag.DATABASE, "Updated carbs $it")
updated.inc(NSCarbs::class.java.simpleName)
}
result.updatedNsId.forEach {
aapsLogger.debug(LTag.DATABASE, "Updated nsId carbs $it")
nsIdUpdated.inc(NSCarbs::class.java.simpleName)
}
}
sendLog("Carbs", NSCarbs::class.java.simpleName)
SystemClock.sleep(pause)
if (temporaryTargets.isNotEmpty())
repository.runTransactionForResult(SyncNsTemporaryTargetTransaction(temporaryTargets))
.doOnError {
aapsLogger.error(LTag.DATABASE, "Error while saving temporary target", it)
}
.blockingGet()
.also { result ->
temporaryTargets.clear()
result.inserted.forEach { tt ->
if (config.NSCLIENT.not()) userEntries.add(
UserEntryTransaction.Entry(
dateUtil.now(),
UserEntry.Action.TT, UserEntry.Sources.NSClient, "",
listOf(
ValueWithUnit.TherapyEventTTReason(tt.reason),
ValueWithUnit.fromGlucoseUnit(tt.lowTarget, Constants.MGDL),
ValueWithUnit.fromGlucoseUnit(tt.highTarget, Constants.MGDL).takeIf { tt.lowTarget != tt.highTarget },
ValueWithUnit.Minute(TimeUnit.MILLISECONDS.toMinutes(tt.duration).toInt())
)
)
)
aapsLogger.debug(LTag.DATABASE, "Inserted TemporaryTarget $tt")
inserted.inc(NSTemporaryTarget::class.java.simpleName)
}
result.invalidated.forEach { tt ->
if (config.NSCLIENT.not()) userEntries.add(
UserEntryTransaction.Entry(
dateUtil.now(),
UserEntry.Action.TT_REMOVED, UserEntry.Sources.NSClient, "",
listOf(
ValueWithUnit.TherapyEventTTReason(tt.reason),
ValueWithUnit.Mgdl(tt.lowTarget),
ValueWithUnit.Mgdl(tt.highTarget).takeIf { tt.lowTarget != tt.highTarget },
ValueWithUnit.Minute(TimeUnit.MILLISECONDS.toMinutes(tt.duration).toInt())
)
)
)
aapsLogger.debug(LTag.DATABASE, "Invalidated TemporaryTarget $tt")
invalidated.inc(NSTemporaryTarget::class.java.simpleName)
}
result.ended.forEach { tt ->
if (config.NSCLIENT.not()) userEntries.add(
UserEntryTransaction.Entry(
dateUtil.now(),
UserEntry.Action.CANCEL_TT, UserEntry.Sources.NSClient, "",
listOf(
ValueWithUnit.TherapyEventTTReason(tt.reason),
ValueWithUnit.Mgdl(tt.lowTarget),
ValueWithUnit.Mgdl(tt.highTarget).takeIf { tt.lowTarget != tt.highTarget },
ValueWithUnit.Minute(TimeUnit.MILLISECONDS.toMinutes(tt.duration).toInt())
)
)
)
aapsLogger.debug(LTag.DATABASE, "Updated TemporaryTarget $tt")
ended.inc(NSTemporaryTarget::class.java.simpleName)
}
result.updatedNsId.forEach {
aapsLogger.debug(LTag.DATABASE, "Updated nsId TemporaryTarget $it")
nsIdUpdated.inc(NSTemporaryTarget::class.java.simpleName)
}
result.updatedDuration.forEach {
aapsLogger.debug(LTag.DATABASE, "Updated duration TemporaryTarget $it")
durationUpdated.inc(NSTemporaryTarget::class.java.simpleName)
}
}
sendLog("TemporaryTarget", NSTemporaryTarget::class.java.simpleName)
SystemClock.sleep(pause)
if (temporaryBasals.isNotEmpty())
repository.runTransactionForResult(SyncNsTemporaryBasalTransaction(temporaryBasals))
.doOnError {
aapsLogger.error(LTag.DATABASE, "Error while saving temporary basal", it)
}
.blockingGet()
.also { result ->
temporaryBasals.clear()
result.inserted.forEach {
if (config.NSCLIENT.not()) userEntries.add(
UserEntryTransaction.Entry(
dateUtil.now(),
UserEntry.Action.TEMP_BASAL, UserEntry.Sources.NSClient, "",
listOf(
ValueWithUnit.Timestamp(it.timestamp),
if (it.isAbsolute) ValueWithUnit.UnitPerHour(it.rate) else ValueWithUnit.Percent(it.rate.toInt()),
ValueWithUnit.Minute(TimeUnit.MILLISECONDS.toMinutes(it.duration).toInt())
)
)
)
aapsLogger.debug(LTag.DATABASE, "Inserted TemporaryBasal $it")
inserted.inc(NSTemporaryBasal::class.java.simpleName)
}
result.invalidated.forEach {
if (config.NSCLIENT.not()) userEntries.add(
UserEntryTransaction.Entry(
dateUtil.now(),
UserEntry.Action.TEMP_BASAL_REMOVED, UserEntry.Sources.NSClient, "",
listOf(
ValueWithUnit.Timestamp(it.timestamp),
if (it.isAbsolute) ValueWithUnit.UnitPerHour(it.rate) else ValueWithUnit.Percent(it.rate.toInt()),
ValueWithUnit.Minute(TimeUnit.MILLISECONDS.toMinutes(it.duration).toInt())
)
)
)
aapsLogger.debug(LTag.DATABASE, "Invalidated TemporaryBasal $it")
invalidated.inc(NSTemporaryBasal::class.java.simpleName)
}
result.ended.forEach {
if (config.NSCLIENT.not()) userEntries.add(
UserEntryTransaction.Entry(
dateUtil.now(),
UserEntry.Action.CANCEL_TEMP_BASAL, UserEntry.Sources.NSClient, "",
listOf(
ValueWithUnit.Timestamp(it.timestamp),
if (it.isAbsolute) ValueWithUnit.UnitPerHour(it.rate) else ValueWithUnit.Percent(it.rate.toInt()),
ValueWithUnit.Minute(TimeUnit.MILLISECONDS.toMinutes(it.duration).toInt())
)
)
)
aapsLogger.debug(LTag.DATABASE, "Ended TemporaryBasal $it")
ended.inc(NSTemporaryBasal::class.java.simpleName)
}
result.updatedNsId.forEach {
aapsLogger.debug(LTag.DATABASE, "Updated nsId TemporaryBasal $it")
nsIdUpdated.inc(NSTemporaryBasal::class.java.simpleName)
}
result.updatedDuration.forEach {
aapsLogger.debug(LTag.DATABASE, "Updated duration TemporaryBasal $it")
durationUpdated.inc(NSTemporaryBasal::class.java.simpleName)
}
}
sendLog("TemporaryBasal", NSTemporaryBasal::class.java.simpleName)
SystemClock.sleep(pause)
if (effectiveProfileSwitches.isNotEmpty())
repository.runTransactionForResult(SyncNsEffectiveProfileSwitchTransaction(effectiveProfileSwitches))
.doOnError {
aapsLogger.error(LTag.DATABASE, "Error while saving EffectiveProfileSwitch", it)
}
.blockingGet()
.also { result ->
effectiveProfileSwitches.clear()
result.inserted.forEach {
if (config.NSCLIENT.not()) userEntries.add(
UserEntryTransaction.Entry(
dateUtil.now(),
UserEntry.Action.PROFILE_SWITCH, UserEntry.Sources.NSClient, "",
listOf(ValueWithUnit.Timestamp(it.timestamp))
)
)
aapsLogger.debug(LTag.DATABASE, "Inserted EffectiveProfileSwitch $it")
inserted.inc(NSEffectiveProfileSwitch::class.java.simpleName)
}
result.invalidated.forEach {
if (config.NSCLIENT.not()) userEntries.add(
UserEntryTransaction.Entry(
dateUtil.now(),
UserEntry.Action.PROFILE_SWITCH_REMOVED, UserEntry.Sources.NSClient, "",
listOf(ValueWithUnit.Timestamp(it.timestamp))
)
)
aapsLogger.debug(LTag.DATABASE, "Invalidated EffectiveProfileSwitch $it")
invalidated.inc(NSEffectiveProfileSwitch::class.java.simpleName)
}
result.updatedNsId.forEach {
aapsLogger.debug(LTag.DATABASE, "Updated nsId EffectiveProfileSwitch $it")
nsIdUpdated.inc(NSEffectiveProfileSwitch::class.java.simpleName)
}
}
sendLog("EffectiveProfileSwitch", NSEffectiveProfileSwitch::class.java.simpleName)
SystemClock.sleep(pause)
if (profileSwitches.isNotEmpty())
repository.runTransactionForResult(SyncNsProfileSwitchTransaction(profileSwitches))
.doOnError {
aapsLogger.error(LTag.DATABASE, "Error while saving ProfileSwitch", it)
}
.blockingGet()
.also { result ->
profileSwitches.clear()
result.inserted.forEach {
if (config.NSCLIENT.not()) userEntries.add(
UserEntryTransaction.Entry(
dateUtil.now(),
UserEntry.Action.PROFILE_SWITCH, UserEntry.Sources.NSClient, "",
listOf(ValueWithUnit.Timestamp(it.timestamp))
)
)
aapsLogger.debug(LTag.DATABASE, "Inserted ProfileSwitch $it")
inserted.inc(NSProfileSwitch::class.java.simpleName)
}
result.invalidated.forEach {
if (config.NSCLIENT.not()) userEntries.add(
UserEntryTransaction.Entry(
dateUtil.now(),
UserEntry.Action.PROFILE_SWITCH_REMOVED, UserEntry.Sources.NSClient, "",
listOf(ValueWithUnit.Timestamp(it.timestamp))
)
)
aapsLogger.debug(LTag.DATABASE, "Invalidated ProfileSwitch $it")
invalidated.inc(NSProfileSwitch::class.java.simpleName)
}
result.updatedNsId.forEach {
aapsLogger.debug(LTag.DATABASE, "Updated nsId ProfileSwitch $it")
nsIdUpdated.inc(NSProfileSwitch::class.java.simpleName)
}
}
sendLog("ProfileSwitch", NSProfileSwitch::class.java.simpleName)
SystemClock.sleep(pause)
if (bolusCalculatorResults.isNotEmpty())
repository.runTransactionForResult(SyncNsBolusCalculatorResultTransaction(bolusCalculatorResults))
.doOnError {
aapsLogger.error(LTag.DATABASE, "Error while saving BolusCalculatorResult", it)
}
.blockingGet()
.also { result ->
bolusCalculatorResults.clear()
result.inserted.forEach {
aapsLogger.debug(LTag.DATABASE, "Inserted BolusCalculatorResult $it")
inserted.inc(NSBolusWizard::class.java.simpleName)
}
result.invalidated.forEach {
aapsLogger.debug(LTag.DATABASE, "Invalidated BolusCalculatorResult $it")
invalidated.inc(NSBolusWizard::class.java.simpleName)
}
result.updatedNsId.forEach {
aapsLogger.debug(LTag.DATABASE, "Updated nsId BolusCalculatorResult $it")
nsIdUpdated.inc(NSBolusWizard::class.java.simpleName)
}
}
sendLog("BolusCalculatorResult", NSBolusWizard::class.java.simpleName)
SystemClock.sleep(pause)
if (sp.getBoolean(R.string.key_ns_receive_therapy_events, false) || config.NSCLIENT)
therapyEvents.filter { it.type == TherapyEvent.Type.ANNOUNCEMENT }.forEach {
if (it.timestamp > dateUtil.now() - 15 * 60 * 1000L &&
it.note?.isNotEmpty() == true &&
it.enteredBy != sp.getString("careportal_enteredby", "AndroidAPS")
) {
if (sp.getBoolean(R.string.key_ns_announcements, config.NSCLIENT))
rxBus.send(EventNewNotification(Notification(Notification.NS_ANNOUNCEMENT, it.note ?: "", Notification.ANNOUNCEMENT, 60)))
}
}
if (therapyEvents.isNotEmpty())
repository.runTransactionForResult(SyncNsTherapyEventTransaction(therapyEvents))
.doOnError {
aapsLogger.error(LTag.DATABASE, "Error while saving therapy event", it)
}
.blockingGet()
.also { result ->
therapyEvents.clear()
result.inserted.forEach { therapyEvent ->
val action = when (therapyEvent.type) {
TherapyEvent.Type.CANNULA_CHANGE -> UserEntry.Action.SITE_CHANGE
TherapyEvent.Type.INSULIN_CHANGE -> UserEntry.Action.RESERVOIR_CHANGE
else -> UserEntry.Action.CAREPORTAL
}
if (config.NSCLIENT.not()) userEntries.add(
UserEntryTransaction.Entry(
dateUtil.now(),
action, UserEntry.Sources.NSClient, therapyEvent.note ?: "",
listOf(ValueWithUnit.Timestamp(therapyEvent.timestamp),
ValueWithUnit.TherapyEventType(therapyEvent.type),
ValueWithUnit.fromGlucoseUnit(therapyEvent.glucose ?: 0.0, therapyEvent.glucoseUnit.toString).takeIf { therapyEvent.glucose != null })
)
)
aapsLogger.debug(LTag.DATABASE, "Inserted TherapyEvent $therapyEvent")
inserted.inc(NSTherapyEvent::class.java.simpleName)
}
result.invalidated.forEach { therapyEvent ->
if (config.NSCLIENT.not()) userEntries.add(
UserEntryTransaction.Entry(
dateUtil.now(),
UserEntry.Action.CAREPORTAL_REMOVED, UserEntry.Sources.NSClient, therapyEvent.note ?: "",
listOf(ValueWithUnit.Timestamp(therapyEvent.timestamp),
ValueWithUnit.TherapyEventType(therapyEvent.type),
ValueWithUnit.fromGlucoseUnit(therapyEvent.glucose ?: 0.0, therapyEvent.glucoseUnit.toString).takeIf { therapyEvent.glucose != null })
)
)
aapsLogger.debug(LTag.DATABASE, "Invalidated TherapyEvent $therapyEvent")
invalidated.inc(NSTherapyEvent::class.java.simpleName)
}
result.updatedNsId.forEach {
aapsLogger.debug(LTag.DATABASE, "Updated nsId TherapyEvent $it")
nsIdUpdated.inc(NSTherapyEvent::class.java.simpleName)
}
result.updatedDuration.forEach {
aapsLogger.debug(LTag.DATABASE, "Updated nsId TherapyEvent $it")
durationUpdated.inc(NSTherapyEvent::class.java.simpleName)
}
}
sendLog("TherapyEvent", NSTherapyEvent::class.java.simpleName)
SystemClock.sleep(pause)
if (offlineEvents.isNotEmpty())
repository.runTransactionForResult(SyncNsOfflineEventTransaction(offlineEvents))
.doOnError {
aapsLogger.error(LTag.DATABASE, "Error while saving OfflineEvent", it)
}
.blockingGet()
.also { result ->
result.inserted.forEach { oe ->
if (config.NSCLIENT.not()) userEntries.add(
UserEntryTransaction.Entry(
dateUtil.now(),
UserEntry.Action.LOOP_CHANGE, UserEntry.Sources.NSClient, "",
listOf(
ValueWithUnit.OfflineEventReason(oe.reason),
ValueWithUnit.Minute(TimeUnit.MILLISECONDS.toMinutes(oe.duration).toInt())
)
)
)
aapsLogger.debug(LTag.DATABASE, "Inserted OfflineEvent $oe")
inserted.inc(NSOfflineEvent::class.java.simpleName)
}
result.invalidated.forEach { oe ->
if (config.NSCLIENT.not()) userEntries.add(
UserEntryTransaction.Entry(
dateUtil.now(),
UserEntry.Action.LOOP_REMOVED, UserEntry.Sources.NSClient, "",
listOf(
ValueWithUnit.OfflineEventReason(oe.reason),
ValueWithUnit.Minute(TimeUnit.MILLISECONDS.toMinutes(oe.duration).toInt())
)
)
)
aapsLogger.debug(LTag.DATABASE, "Invalidated OfflineEvent $oe")
invalidated.inc(NSOfflineEvent::class.java.simpleName)
}
result.ended.forEach { oe ->
if (config.NSCLIENT.not()) userEntries.add(
UserEntryTransaction.Entry(
dateUtil.now(),
UserEntry.Action.LOOP_CHANGE, UserEntry.Sources.NSClient, "",
listOf(
ValueWithUnit.OfflineEventReason(oe.reason),
ValueWithUnit.Minute(TimeUnit.MILLISECONDS.toMinutes(oe.duration).toInt())
)
)
)
aapsLogger.debug(LTag.DATABASE, "Updated OfflineEvent $oe")
ended.inc(NSOfflineEvent::class.java.simpleName)
}
result.updatedNsId.forEach {
aapsLogger.debug(LTag.DATABASE, "Updated nsId OfflineEvent $it")
nsIdUpdated.inc(NSOfflineEvent::class.java.simpleName)
}
result.updatedDuration.forEach {
aapsLogger.debug(LTag.DATABASE, "Updated duration OfflineEvent $it")
durationUpdated.inc(NSOfflineEvent::class.java.simpleName)
}
}
sendLog("OfflineEvent", NSOfflineEvent::class.java.simpleName)
SystemClock.sleep(pause)
if (extendedBoluses.isNotEmpty())
repository.runTransactionForResult(SyncNsExtendedBolusTransaction(extendedBoluses))
.doOnError {
aapsLogger.error(LTag.DATABASE, "Error while saving extended bolus", it)
}
.blockingGet()
.also { result ->
result.inserted.forEach {
if (config.NSCLIENT.not()) userEntries.add(
UserEntryTransaction.Entry(
dateUtil.now(),
UserEntry.Action.EXTENDED_BOLUS, UserEntry.Sources.NSClient, "",
listOf(
ValueWithUnit.Timestamp(it.timestamp),
ValueWithUnit.Insulin(it.amount),
ValueWithUnit.UnitPerHour(it.rate),
ValueWithUnit.Minute(TimeUnit.MILLISECONDS.toMinutes(it.duration).toInt())
)
)
)
if (it.isEmulatingTempBasal) virtualPumpPlugin.fakeDataDetected = true
aapsLogger.debug(LTag.DATABASE, "Inserted ExtendedBolus $it")
inserted.inc(NSExtendedBolus::class.java.simpleName)
}
result.invalidated.forEach {
if (config.NSCLIENT.not()) userEntries.add(
UserEntryTransaction.Entry(
dateUtil.now(),
UserEntry.Action.EXTENDED_BOLUS_REMOVED, UserEntry.Sources.NSClient, "",
listOf(
ValueWithUnit.Timestamp(it.timestamp),
ValueWithUnit.Insulin(it.amount),
ValueWithUnit.UnitPerHour(it.rate),
ValueWithUnit.Minute(TimeUnit.MILLISECONDS.toMinutes(it.duration).toInt())
)
)
)
aapsLogger.debug(LTag.DATABASE, "Invalidated ExtendedBolus $it")
invalidated.inc(NSExtendedBolus::class.java.simpleName)
}
result.ended.forEach {
if (config.NSCLIENT.not()) userEntries.add(
UserEntryTransaction.Entry(
dateUtil.now(),
UserEntry.Action.CANCEL_EXTENDED_BOLUS, UserEntry.Sources.NSClient, "",
listOf(
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")
ended.inc(NSExtendedBolus::class.java.simpleName)
}
result.updatedNsId.forEach {
aapsLogger.debug(LTag.DATABASE, "Updated nsId ExtendedBolus $it")
nsIdUpdated.inc(NSExtendedBolus::class.java.simpleName)
}
result.updatedDuration.forEach {
aapsLogger.debug(LTag.DATABASE, "Updated duration ExtendedBolus $it")
durationUpdated.inc(NSExtendedBolus::class.java.simpleName)
}
}
sendLog("ExtendedBolus", NSExtendedBolus::class.java.simpleName)
SystemClock.sleep(pause)
uel.log(userEntries)
rxBus.send(EventNSClientNewLog("DONE TR", "", activePlugin.activeNsClient?.version ?: NsClient.Version.V3))
}
private fun sendLog(item: String, clazz: String) {
inserted[clazz]?.let {
rxBus.send(EventNSClientNewLog("INSERT", "$item $it", activePlugin.activeNsClient?.version ?: NsClient.Version.V3))
}
inserted.remove(clazz)
updated[clazz]?.let {
rxBus.send(EventNSClientNewLog("UPDATE", "$item $it", activePlugin.activeNsClient?.version ?: NsClient.Version.V3))
}
updated.remove(clazz)
invalidated[clazz]?.let {
rxBus.send(EventNSClientNewLog("INVALIDATE", "$item $it", activePlugin.activeNsClient?.version ?: NsClient.Version.V3))
}
invalidated.remove(clazz)
nsIdUpdated[clazz]?.let {
rxBus.send(EventNSClientNewLog("NS_ID", "$item $it", activePlugin.activeNsClient?.version ?: NsClient.Version.V3))
}
nsIdUpdated.remove(clazz)
durationUpdated[clazz]?.let {
rxBus.send(EventNSClientNewLog("DURATION", "$item $it", activePlugin.activeNsClient?.version ?: NsClient.Version.V3))
}
durationUpdated.remove(clazz)
ended[clazz]?.let {
rxBus.send(EventNSClientNewLog("CUT", "$item $it", activePlugin.activeNsClient?.version ?: NsClient.Version.V3))
}
ended.remove(clazz)
}
}

View file

@ -1,10 +1,11 @@
package info.nightscout.androidaps.plugins.general.nsclient.events
package info.nightscout.androidaps.plugins.sync.nsShared.events
import info.nightscout.androidaps.interfaces.NsClient
import info.nightscout.rx.events.Event
import java.text.SimpleDateFormat
import java.util.Locale
class EventNSClientNewLog(var action: String, var logText: String) : Event() {
class EventNSClientNewLog(val action: String, val logText: String, val version: NsClient.Version) : Event() {
var date = System.currentTimeMillis()
private var timeFormat = SimpleDateFormat("HH:mm:ss", Locale.getDefault())

View file

@ -1,4 +1,4 @@
package info.nightscout.androidaps.plugins.general.nsclient.events
package info.nightscout.androidaps.plugins.sync.nsShared.events
import info.nightscout.rx.events.Event

View file

@ -0,0 +1,9 @@
package info.nightscout.androidaps.plugins.sync.nsShared.events
import info.nightscout.androidaps.events.EventStatus
import info.nightscout.androidaps.interfaces.NsClient
import info.nightscout.androidaps.interfaces.ResourceHelper
class EventNSClientStatus(var text: String, val version: NsClient.Version) : EventStatus() {
override fun getStatus(rh: ResourceHelper): String = text
}

View file

@ -0,0 +1,5 @@
package info.nightscout.androidaps.plugins.sync.nsShared.events
import info.nightscout.rx.events.EventUpdateGui
class EventNSClientUpdateGUI : EventUpdateGui()

View file

@ -1,4 +1,4 @@
package info.nightscout.androidaps.plugins.general.nsclient
package info.nightscout.androidaps.plugins.sync.nsclient
import info.nightscout.androidaps.R
import info.nightscout.androidaps.database.AppRepository
@ -20,7 +20,9 @@ import info.nightscout.androidaps.extensions.toJson
import info.nightscout.androidaps.interfaces.ActivePlugin
import info.nightscout.androidaps.interfaces.DataSyncSelector
import info.nightscout.androidaps.interfaces.ProfileFunction
import info.nightscout.plugins.sync.nsclient.extensions.toJson
import info.nightscout.androidaps.utils.DateUtil
import info.nightscout.androidaps.utils.extensions.toJson
import info.nightscout.plugins.profile.ProfilePlugin
import info.nightscout.rx.logging.AAPSLogger
import info.nightscout.rx.logging.LTag
@ -34,7 +36,6 @@ class DataSyncSelectorImplementation @Inject constructor(
private val aapsLogger: AAPSLogger,
private val dateUtil: DateUtil,
private val profileFunction: ProfileFunction,
private val nsClientPlugin: NSClientPlugin,
private val activePlugin: ActivePlugin,
private val appRepository: AppRepository,
private val profilePlugin: ProfilePlugin
@ -96,30 +97,10 @@ class DataSyncSelectorImplementation @Inject constructor(
}
override fun resetToNextFullSync() {
appRepository.getLastGlucoseValueIdWrapped().blockingGet().run {
val currentLast = if (this is ValueWrapper.Existing) this.value else 0L
sp.putLong(R.string.key_ns_glucose_value_new_data_id, currentLast)
}
sp.remove(R.string.key_ns_glucose_value_last_synced_id)
appRepository.getLastTemporaryBasalIdWrapped().blockingGet().run {
val currentLast = if (this is ValueWrapper.Existing) this.value else 0L
sp.putLong(R.string.key_ns_temporary_basal_new_data_id, currentLast)
}
sp.remove(R.string.key_ns_temporary_basal_last_synced_id)
appRepository.getLastTempTargetIdWrapped().blockingGet().run {
val currentLast = if (this is ValueWrapper.Existing) this.value else 0L
sp.putLong(R.string.key_ns_temporary_target_new_data_id, currentLast)
}
sp.remove(R.string.key_ns_temporary_target_last_synced_id)
appRepository.getLastExtendedBolusIdWrapped().blockingGet().run {
val currentLast = if (this is ValueWrapper.Existing) this.value else 0L
sp.putLong(R.string.key_ns_extended_bolus_new_data_id, currentLast)
}
sp.remove(R.string.key_ns_extended_bolus_last_synced_id)
sp.remove(R.string.key_ns_food_last_synced_id)
sp.remove(R.string.key_ns_bolus_last_synced_id)
sp.remove(R.string.key_ns_carbs_last_synced_id)
@ -137,7 +118,7 @@ class DataSyncSelectorImplementation @Inject constructor(
override fun confirmLastBolusIdIfGreater(lastSynced: Long) {
if (lastSynced > sp.getLong(R.string.key_ns_bolus_last_synced_id, 0)) {
aapsLogger.debug(LTag.NSCLIENT, "Setting Bolus data sync from $lastSynced")
//aapsLogger.debug(LTag.NSCLIENT, "Setting Bolus data sync from $lastSynced")
sp.putLong(R.string.key_ns_bolus_last_synced_id, lastSynced)
}
}
@ -153,9 +134,7 @@ class DataSyncSelectorImplementation @Inject constructor(
}
}
//private var lastBolusId = -1L
//private var lastBolusTime = -1L
override fun processChangedBolusesCompat(): Boolean {
override tailrec fun processChangedBolusesCompat() {
val lastDbIdWrapped = appRepository.getLastBolusIdWrapped().blockingGet()
val lastDbId = if (lastDbIdWrapped is ValueWrapper.Existing) lastDbIdWrapped.value else 0L
var startId = sp.getLong(R.string.key_ns_bolus_last_synced_id, 0)
@ -163,27 +142,35 @@ class DataSyncSelectorImplementation @Inject constructor(
sp.putLong(R.string.key_ns_bolus_last_synced_id, 0)
startId = 0
}
//if (startId == lastBolusId && dateUtil.now() - lastBolusTime < 5000) return false
//lastBolusId = startId
//lastBolusTime = dateUtil.now()
queueCounter.bolusesRemaining = lastDbId - startId
appRepository.getNextSyncElementBolus(startId).blockingGet()?.let { bolus ->
aapsLogger.info(LTag.NSCLIENT, "Loading Bolus data Start: $startId ID: ${bolus.first.id} HistoryID: ${bolus.second.id} ")
when {
// only NsId changed, no need to upload
bolus.first.onlyNsIdAdded(bolus.second) -> {
// new record with existing NS id => must be coming from NS => ignore
bolus.first.id == bolus.second.id && bolus.first.interfaceIDs.nightscoutId != null -> {
aapsLogger.info(LTag.NSCLIENT, "Ignoring Bolus. Loaded from NS: ${bolus.first.id} HistoryID: ${bolus.second.id} ")
confirmLastBolusIdIfGreater(bolus.second.id)
//lastBolusId = -1
processChangedBolusesCompat()
return
}
// only NsId changed, no need to upload
bolus.first.onlyNsIdAdded(bolus.second) -> {
aapsLogger.info(LTag.NSCLIENT, "Ignoring Bolus. Only NS id changed ID: ${bolus.first.id} HistoryID: ${bolus.second.id} ")
return false
confirmLastBolusIdIfGreater(bolus.second.id)
processChangedBolusesCompat()
return
}
// without nsId = create new
bolus.first.interfaceIDs.nightscoutId == null ->
nsClientPlugin.nsClientService?.dbAdd("treatments", bolus.first.toJson(true, dateUtil), DataSyncSelector.PairBolus(bolus.first, bolus.second.id), "$startId/$lastDbId")
// with nsId = update
bolus.first.interfaceIDs.nightscoutId != null ->
nsClientPlugin.nsClientService?.dbUpdate(
bolus.first.interfaceIDs.nightscoutId == null ->
activePlugin.activeNsClient?.nsClientService?.dbAdd(
"treatments",
bolus.first.toJson(true, dateUtil),
DataSyncSelector.PairBolus(bolus.first, bolus.second.id),
" $startId/$lastDbId"
)
// with nsId = update if it's modified record
bolus.first.interfaceIDs.nightscoutId != null && bolus.first.id != bolus.second.id ->
activePlugin.activeNsClient?.nsClientService?.dbUpdate(
"treatments",
bolus.first.interfaceIDs.nightscoutId,
bolus.first.toJson(false, dateUtil),
@ -191,14 +178,13 @@ class DataSyncSelectorImplementation @Inject constructor(
"$startId/$lastDbId"
)
}
return true
return
}
return false
}
override fun confirmLastCarbsIdIfGreater(lastSynced: Long) {
if (lastSynced > sp.getLong(R.string.key_ns_carbs_last_synced_id, 0)) {
aapsLogger.debug(LTag.NSCLIENT, "Setting Carbs data sync from $lastSynced")
//aapsLogger.debug(LTag.NSCLIENT, "Setting Carbs data sync from $lastSynced")
sp.putLong(R.string.key_ns_carbs_last_synced_id, lastSynced)
}
}
@ -211,9 +197,7 @@ class DataSyncSelectorImplementation @Inject constructor(
}
}
//private var lastCarbsId = -1L
//private var lastCarbsTime = -1L
override fun processChangedCarbsCompat(): Boolean {
override tailrec fun processChangedCarbsCompat() {
val lastDbIdWrapped = appRepository.getLastCarbsIdWrapped().blockingGet()
val lastDbId = if (lastDbIdWrapped is ValueWrapper.Existing) lastDbIdWrapped.value else 0L
var startId = sp.getLong(R.string.key_ns_carbs_last_synced_id, 0)
@ -221,27 +205,30 @@ class DataSyncSelectorImplementation @Inject constructor(
sp.putLong(R.string.key_ns_carbs_last_synced_id, 0)
startId = 0
}
//if (startId == lastCarbsId && dateUtil.now() - lastCarbsTime < 5000) return false
//lastCarbsId = startId
//lastCarbsTime = dateUtil.now()
queueCounter.carbsRemaining = lastDbId - startId
appRepository.getNextSyncElementCarbs(startId).blockingGet()?.let { carb ->
aapsLogger.info(LTag.NSCLIENT, "Loading Carbs data Start: $startId ID: ${carb.first.id} HistoryID: ${carb.second.id} ")
when {
// only NsId changed, no need to upload
carb.first.onlyNsIdAdded(carb.second) -> {
// new record with existing NS id => must be coming from NS => ignore
carb.first.id == carb.second.id && carb.first.interfaceIDs.nightscoutId != null -> {
aapsLogger.info(LTag.NSCLIENT, "Ignoring Carbs. Loaded from NS: ${carb.first.id} HistoryID: ${carb.second.id} ")
confirmLastCarbsIdIfGreater(carb.second.id)
//lastCarbsId = -1
processChangedCarbsCompat()
return
}
// only NsId changed, no need to upload
carb.first.onlyNsIdAdded(carb.second) -> {
aapsLogger.info(LTag.NSCLIENT, "Ignoring Carbs. Only NS id changed ID: ${carb.first.id} HistoryID: ${carb.second.id} ")
return false
confirmLastCarbsIdIfGreater(carb.second.id)
processChangedCarbsCompat()
return
}
// without nsId = create new
carb.first.interfaceIDs.nightscoutId == null ->
nsClientPlugin.nsClientService?.dbAdd("treatments", carb.first.toJson(true, dateUtil), DataSyncSelector.PairCarbs(carb.first, carb.second.id), "$startId/$lastDbId")
// with nsId = update
carb.first.interfaceIDs.nightscoutId != null ->
nsClientPlugin.nsClientService?.dbUpdate(
carb.first.interfaceIDs.nightscoutId == null ->
activePlugin.activeNsClient?.nsClientService?.dbAdd("treatments", carb.first.toJson(true, dateUtil), DataSyncSelector.PairCarbs(carb.first, carb.second.id), "$startId/$lastDbId")
// with nsId = update if it's modified record
carb.first.interfaceIDs.nightscoutId != null && carb.first.id != carb.second.id ->
activePlugin.activeNsClient?.nsClientService?.dbUpdate(
"treatments",
carb.first.interfaceIDs.nightscoutId,
carb.first.toJson(false, dateUtil),
@ -249,14 +236,13 @@ class DataSyncSelectorImplementation @Inject constructor(
"$startId/$lastDbId"
)
}
return true
return
}
return false
}
override fun confirmLastBolusCalculatorResultsIdIfGreater(lastSynced: Long) {
if (lastSynced > sp.getLong(R.string.key_ns_bolus_calculator_result_last_synced_id, 0)) {
aapsLogger.debug(LTag.NSCLIENT, "Setting BolusCalculatorResult data sync from $lastSynced")
//aapsLogger.debug(LTag.NSCLIENT, "Setting BolusCalculatorResult data sync from $lastSynced")
sp.putLong(R.string.key_ns_bolus_calculator_result_last_synced_id, lastSynced)
}
}
@ -269,9 +255,7 @@ class DataSyncSelectorImplementation @Inject constructor(
}
}
//private var lastBcrId = -1L
//private var lastBcrTime = -1L
override fun processChangedBolusCalculatorResultsCompat(): Boolean {
override tailrec fun processChangedBolusCalculatorResultsCompat() {
val lastDbIdWrapped = appRepository.getLastBolusCalculatorResultIdWrapped().blockingGet()
val lastDbId = if (lastDbIdWrapped is ValueWrapper.Existing) lastDbIdWrapped.value else 0L
var startId = sp.getLong(R.string.key_ns_bolus_calculator_result_last_synced_id, 0)
@ -279,44 +263,46 @@ class DataSyncSelectorImplementation @Inject constructor(
sp.putLong(R.string.key_ns_bolus_calculator_result_last_synced_id, 0)
startId = 0
}
//if (startId == lastBcrId && dateUtil.now() - lastBcrTime < 5000) return false
//lastBcrId = startId
//lastBcrTime = dateUtil.now()
queueCounter.bcrRemaining = lastDbId - startId
appRepository.getNextSyncElementBolusCalculatorResult(startId).blockingGet()?.let { bolusCalculatorResult ->
aapsLogger.info(LTag.NSCLIENT, "Loading BolusCalculatorResult data Start: $startId ID: ${bolusCalculatorResult.first.id} HistoryID: ${bolusCalculatorResult.second.id} ")
when {
// only NsId changed, no need to upload
bolusCalculatorResult.first.onlyNsIdAdded(bolusCalculatorResult.second) -> {
// new record with existing NS id => must be coming from NS => ignore
bolusCalculatorResult.first.id == bolusCalculatorResult.second.id && bolusCalculatorResult.first.interfaceIDs.nightscoutId != null -> {
aapsLogger.info(LTag.NSCLIENT, "Ignoring BolusCalculatorResult. Loaded from NS: ${bolusCalculatorResult.first.id} HistoryID: ${bolusCalculatorResult.second.id} ")
confirmLastBolusCalculatorResultsIdIfGreater(bolusCalculatorResult.second.id)
//lastBcrId = -1
processChangedBolusCalculatorResultsCompat()
return
}
// only NsId changed, no need to upload
bolusCalculatorResult.first.onlyNsIdAdded(bolusCalculatorResult.second) -> {
aapsLogger.info(LTag.NSCLIENT, "Ignoring BolusCalculatorResult. Only NS id changed ID: ${bolusCalculatorResult.first.id} HistoryID: ${bolusCalculatorResult.second.id} ")
return false
confirmLastBolusCalculatorResultsIdIfGreater(bolusCalculatorResult.second.id)
processChangedBolusCalculatorResultsCompat()
return
}
// without nsId = create new
bolusCalculatorResult.first.interfaceIDs.nightscoutId == null ->
nsClientPlugin.nsClientService?.dbAdd(
bolusCalculatorResult.first.interfaceIDs.nightscoutId == null ->
activePlugin.activeNsClient?.nsClientService?.dbAdd(
"treatments",
bolusCalculatorResult.first.toJson(true, dateUtil, profileFunction),
DataSyncSelector.PairBolusCalculatorResult(bolusCalculatorResult.first, bolusCalculatorResult.second.id),
"$startId/$lastDbId"
)
// with nsId = update
bolusCalculatorResult.first.interfaceIDs.nightscoutId != null ->
nsClientPlugin.nsClientService?.dbUpdate(
// with nsId = update if it's modified record
bolusCalculatorResult.first.interfaceIDs.nightscoutId != null && bolusCalculatorResult.first.id != bolusCalculatorResult.second.id ->
activePlugin.activeNsClient?.nsClientService?.dbUpdate(
"treatments", bolusCalculatorResult.first.interfaceIDs.nightscoutId, bolusCalculatorResult.first.toJson(false, dateUtil, profileFunction),
DataSyncSelector.PairBolusCalculatorResult(bolusCalculatorResult.first, bolusCalculatorResult.second.id), "$startId/$lastDbId"
)
}
return true
return
}
return false
}
override fun confirmLastTempTargetsIdIfGreater(lastSynced: Long) {
if (lastSynced > sp.getLong(R.string.key_ns_temporary_target_last_synced_id, 0)) {
aapsLogger.debug(LTag.NSCLIENT, "Setting TemporaryTarget data sync from $lastSynced")
//aapsLogger.debug(LTag.NSCLIENT, "Setting TemporaryTarget data sync from $lastSynced")
sp.putLong(R.string.key_ns_temporary_target_last_synced_id, lastSynced)
}
}
@ -329,9 +315,7 @@ class DataSyncSelectorImplementation @Inject constructor(
}
}
//private var lastTtId = -1L
//private var lastTtTime = -1L
override fun processChangedTempTargetsCompat(): Boolean {
override tailrec fun processChangedTempTargetsCompat() {
val lastDbIdWrapped = appRepository.getLastTempTargetIdWrapped().blockingGet()
val lastDbId = if (lastDbIdWrapped is ValueWrapper.Existing) lastDbIdWrapped.value else 0L
var startId = sp.getLong(R.string.key_ns_temporary_target_last_synced_id, 0)
@ -339,40 +323,35 @@ class DataSyncSelectorImplementation @Inject constructor(
sp.putLong(R.string.key_ns_temporary_target_last_synced_id, 0)
startId = 0
}
//if (startId == lastTtId && dateUtil.now() - lastTtTime < 5000) return false
//lastTtId = startId
//lastTtTime = dateUtil.now()
queueCounter.ttsRemaining = lastDbId - startId
appRepository.getNextSyncElementTemporaryTarget(startId).blockingGet()?.let { tt ->
aapsLogger.info(LTag.NSCLIENT, "Loading TemporaryTarget data Start: $startId ID: ${tt.first.id} HistoryID: ${tt.second.id} ")
when {
// record is not valid record and we are within first sync, no need to upload
tt.first.id != tt.second.id && tt.second.id <= sp.getLong(R.string.key_ns_temporary_target_new_data_id, 0) -> {
// new record with existing NS id => must be coming from NS => ignore
tt.first.id == tt.second.id && tt.first.interfaceIDs.nightscoutId != null -> {
aapsLogger.info(LTag.NSCLIENT, "Ignoring TemporaryTarget. Loaded from NS: ${tt.first.id} HistoryID: ${tt.second.id} ")
confirmLastTempTargetsIdIfGreater(tt.second.id)
//lastTbrId = -1
processChangedTempTargetsCompat()
aapsLogger.info(LTag.NSCLIENT, "Ignoring TemporaryTarget. Change within first sync ID: ${tt.first.id} HistoryID: ${tt.second.id} ")
return false
return
}
// only NsId changed, no need to upload
tt.first.onlyNsIdAdded(tt.second) -> {
confirmLastTempTargetsIdIfGreater(tt.second.id)
//lastTtId = -1
processChangedTempTargetsCompat()
tt.first.onlyNsIdAdded(tt.second) -> {
aapsLogger.info(LTag.NSCLIENT, "Ignoring TemporaryTarget. Only NS id changed ID: ${tt.first.id} HistoryID: ${tt.second.id} ")
return false
confirmLastTempTargetsIdIfGreater(tt.second.id)
processChangedTempTargetsCompat()
return
}
// without nsId = create new
tt.first.interfaceIDs.nightscoutId == null ->
nsClientPlugin.nsClientService?.dbAdd(
tt.first.interfaceIDs.nightscoutId == null ->
activePlugin.activeNsClient?.nsClientService?.dbAdd(
"treatments",
tt.first.toJson(true, profileFunction.getUnits(), dateUtil),
DataSyncSelector.PairTemporaryTarget(tt.first, tt.second.id),
"$startId/$lastDbId"
)
// existing with nsId = update
tt.first.interfaceIDs.nightscoutId != null ->
nsClientPlugin.nsClientService?.dbUpdate(
tt.first.interfaceIDs.nightscoutId != null ->
activePlugin.activeNsClient?.nsClientService?.dbUpdate(
"treatments",
tt.first.interfaceIDs.nightscoutId,
tt.first.toJson(false, profileFunction.getUnits(), dateUtil),
@ -380,14 +359,13 @@ class DataSyncSelectorImplementation @Inject constructor(
"$startId/$lastDbId"
)
}
return true
return
}
return false
}
override fun confirmLastFoodIdIfGreater(lastSynced: Long) {
if (lastSynced > sp.getLong(R.string.key_ns_food_last_synced_id, 0)) {
aapsLogger.debug(LTag.NSCLIENT, "Setting Food data sync from $lastSynced")
//aapsLogger.debug(LTag.NSCLIENT, "Setting Food data sync from $lastSynced")
sp.putLong(R.string.key_ns_food_last_synced_id, lastSynced)
}
}
@ -400,9 +378,7 @@ class DataSyncSelectorImplementation @Inject constructor(
}
}
//private var lastFoodId = -1L
//private var lastFoodTime = -1L
override fun processChangedFoodsCompat(): Boolean {
override tailrec fun processChangedFoodsCompat() {
val lastDbIdWrapped = appRepository.getLastFoodIdWrapped().blockingGet()
val lastDbId = if (lastDbIdWrapped is ValueWrapper.Existing) lastDbIdWrapped.value else 0L
var startId = sp.getLong(R.string.key_ns_food_last_synced_id, 0)
@ -410,27 +386,30 @@ class DataSyncSelectorImplementation @Inject constructor(
sp.putLong(R.string.key_ns_food_last_synced_id, 0)
startId = 0
}
//if (startId == lastFoodId && dateUtil.now() - lastFoodTime < 5000) return false
//lastFoodId = startId
//lastFoodTime = dateUtil.now()
queueCounter.foodsRemaining = lastDbId - startId
appRepository.getNextSyncElementFood(startId).blockingGet()?.let { food ->
aapsLogger.info(LTag.NSCLIENT, "Loading Food data Start: $startId ID: ${food.first.id} HistoryID: ${food.second} ")
when {
// only NsId changed, no need to upload
food.first.onlyNsIdAdded(food.second) -> {
// new record with existing NS id => must be coming from NS => ignore
food.first.id == food.second.id && food.first.interfaceIDs.nightscoutId != null -> {
aapsLogger.info(LTag.NSCLIENT, "Ignoring Food. Loaded from NS: ${food.first.id} HistoryID: ${food.second.id} ")
confirmLastFoodIdIfGreater(food.second.id)
//lastFoodId = -1
processChangedFoodsCompat()
return
}
// only NsId changed, no need to upload
food.first.onlyNsIdAdded(food.second) -> {
aapsLogger.info(LTag.NSCLIENT, "Ignoring Food. Only NS id changed ID: ${food.first.id} HistoryID: ${food.second.id} ")
return false
confirmLastFoodIdIfGreater(food.second.id)
processChangedFoodsCompat()
return
}
// without nsId = create new
food.first.interfaceIDs.nightscoutId == null ->
nsClientPlugin.nsClientService?.dbAdd("food", food.first.toJson(true), DataSyncSelector.PairFood(food.first, food.second.id), "$startId/$lastDbId")
food.first.interfaceIDs.nightscoutId == null ->
activePlugin.activeNsClient?.nsClientService?.dbAdd("food", food.first.toJson(true), DataSyncSelector.PairFood(food.first, food.second.id), "$startId/$lastDbId")
// with nsId = update
food.first.interfaceIDs.nightscoutId != null ->
nsClientPlugin.nsClientService?.dbUpdate(
food.first.interfaceIDs.nightscoutId != null ->
activePlugin.activeNsClient?.nsClientService?.dbUpdate(
"food",
food.first.interfaceIDs.nightscoutId,
food.first.toJson(false),
@ -438,14 +417,13 @@ class DataSyncSelectorImplementation @Inject constructor(
"$startId/$lastDbId"
)
}
return true
return
}
return false
}
override fun confirmLastGlucoseValueIdIfGreater(lastSynced: Long) {
if (lastSynced > sp.getLong(R.string.key_ns_glucose_value_last_synced_id, 0)) {
aapsLogger.debug(LTag.NSCLIENT, "Setting GlucoseValue data sync from $lastSynced")
//aapsLogger.debug(LTag.NSCLIENT, "Setting GlucoseValue data sync from $lastSynced")
sp.putLong(R.string.key_ns_glucose_value_last_synced_id, lastSynced)
}
}
@ -458,8 +436,6 @@ class DataSyncSelectorImplementation @Inject constructor(
}
}
//private var lastGvId = -1L
//private var lastGvTime = -1L
override tailrec fun processChangedGlucoseValuesCompat() {
val lastDbIdWrapped = appRepository.getLastGlucoseValueIdWrapped().blockingGet()
val lastDbId = if (lastDbIdWrapped is ValueWrapper.Existing) lastDbIdWrapped.value else 0L
@ -468,35 +444,31 @@ class DataSyncSelectorImplementation @Inject constructor(
sp.putLong(R.string.key_ns_glucose_value_last_synced_id, 0)
startId = 0
}
//if (startId == lastGvId && dateUtil.now() - lastGvTime < 5000) return false
//lastGvId = startId
//lastGvTime = dateUtil.now()
queueCounter.gvsRemaining = lastDbId - startId
var tailCall = false
appRepository.getNextSyncElementGlucoseValue(startId).blockingGet()?.let { gv ->
aapsLogger.info(LTag.NSCLIENT, "Loading GlucoseValue data ID: ${gv.first.id} HistoryID: ${gv.second.id} ")
if (activePlugin.activeBgSource.shouldUploadToNs(gv.first)) {
when {
// record is not valid record and we are within first sync, no need to upload
gv.first.id != gv.second.id && gv.second.id <= sp.getLong(R.string.key_ns_glucose_value_new_data_id, 0) -> {
// new record with existing NS id => must be coming from NS => ignore
gv.first.id == gv.second.id && gv.first.interfaceIDs.nightscoutId != null -> {
aapsLogger.info(LTag.NSCLIENT, "Ignoring GlucoseValue. Loaded from NS: ${gv.first.id} HistoryID: ${gv.second.id} ")
confirmLastGlucoseValueIdIfGreater(gv.second.id)
//lastGvId = -1
aapsLogger.info(LTag.NSCLIENT, "Ignoring GlucoseValue. Change within first sync ID: ${gv.first.id} HistoryID: ${gv.second.id} ")
tailCall = true
processChangedGlucoseValuesCompat()
return
}
// only NsId changed, no need to upload
gv.first.onlyNsIdAdded(gv.second) -> {
confirmLastGlucoseValueIdIfGreater(gv.second.id)
//lastGvId = -1
gv.first.onlyNsIdAdded(gv.second) -> {
aapsLogger.info(LTag.NSCLIENT, "Ignoring GlucoseValue. Only NS id changed ID: ${gv.first.id} HistoryID: ${gv.second.id} ")
tailCall = true
confirmLastGlucoseValueIdIfGreater(gv.second.id)
processChangedGlucoseValuesCompat()
return
}
// without nsId = create new
gv.first.interfaceIDs.nightscoutId == null ->
nsClientPlugin.nsClientService?.dbAdd("entries", gv.first.toJson(true, dateUtil), DataSyncSelector.PairGlucoseValue(gv.first, gv.second.id), "$startId/$lastDbId")
gv.first.interfaceIDs.nightscoutId == null ->
activePlugin.activeNsClient?.nsClientService?.dbAdd("entries", gv.first.toJson(true, dateUtil), DataSyncSelector.PairGlucoseValue(gv.first, gv.second.id), "$startId/$lastDbId")
// with nsId = update
else -> // gv.first.interfaceIDs.nightscoutId != null
nsClientPlugin.nsClientService?.dbUpdate(
else -> // gv.first.interfaceIDs.nightscoutId != null
activePlugin.activeNsClient?.nsClientService?.dbUpdate(
"entries",
gv.first.interfaceIDs.nightscoutId,
gv.first.toJson(false, dateUtil),
@ -506,18 +478,15 @@ class DataSyncSelectorImplementation @Inject constructor(
}
} else {
confirmLastGlucoseValueIdIfGreater(gv.second.id)
//lastGvId = -1
tailCall = true
processChangedGlucoseValuesCompat()
return
}
}
if (tailCall) {
processChangedGlucoseValuesCompat()
}
}
override fun confirmLastTherapyEventIdIfGreater(lastSynced: Long) {
if (lastSynced > sp.getLong(R.string.key_ns_therapy_event_last_synced_id, 0)) {
aapsLogger.debug(LTag.NSCLIENT, "Setting TherapyEvents data sync from $lastSynced")
//aapsLogger.debug(LTag.NSCLIENT, "Setting TherapyEvents data sync from $lastSynced")
sp.putLong(R.string.key_ns_therapy_event_last_synced_id, lastSynced)
}
}
@ -530,9 +499,7 @@ class DataSyncSelectorImplementation @Inject constructor(
}
}
//private var lastTeId = -1L
//private var lastTeTime = -1L
override fun processChangedTherapyEventsCompat(): Boolean {
override tailrec fun processChangedTherapyEventsCompat() {
val lastDbIdWrapped = appRepository.getLastTherapyEventIdWrapped().blockingGet()
val lastDbId = if (lastDbIdWrapped is ValueWrapper.Existing) lastDbIdWrapped.value else 0L
var startId = sp.getLong(R.string.key_ns_therapy_event_last_synced_id, 0)
@ -540,27 +507,30 @@ class DataSyncSelectorImplementation @Inject constructor(
sp.putLong(R.string.key_ns_therapy_event_last_synced_id, 0)
startId = 0
}
//if (startId == lastTeId && dateUtil.now() - lastTeTime < 5000) return false
//lastTeId = startId
//lastTeTime = dateUtil.now()
queueCounter.tesRemaining = lastDbId - startId
appRepository.getNextSyncElementTherapyEvent(startId).blockingGet()?.let { te ->
aapsLogger.info(LTag.NSCLIENT, "Loading TherapyEvents data Start: $startId ID: ${te.first.id} HistoryID: ${te.second} ")
when {
// only NsId changed, no need to upload
te.first.onlyNsIdAdded(te.second) -> {
// new record with existing NS id => must be coming from NS => ignore
te.first.id == te.second.id && te.first.interfaceIDs.nightscoutId != null -> {
aapsLogger.info(LTag.NSCLIENT, "Ignoring TherapyEvent. Loaded from NS: ${te.first.id} HistoryID: ${te.second.id} ")
confirmLastTherapyEventIdIfGreater(te.second.id)
//lastTeId = -1
processChangedTherapyEventsCompat()
aapsLogger.info(LTag.NSCLIENT, "Ignoring TherapyEvents. Only NS id changed ID: ${te.first.id} HistoryID: ${te.second.id} ")
return false
return
}
// only NsId changed, no need to upload
te.first.onlyNsIdAdded(te.second) -> {
aapsLogger.info(LTag.NSCLIENT, "Ignoring TherapyEvent. Only NS id changed ID: ${te.first.id} HistoryID: ${te.second.id} ")
confirmLastTherapyEventIdIfGreater(te.second.id)
processChangedTherapyEventsCompat()
return
}
// without nsId = create new
te.first.interfaceIDs.nightscoutId == null ->
nsClientPlugin.nsClientService?.dbAdd("treatments", te.first.toJson(true, dateUtil), DataSyncSelector.PairTherapyEvent(te.first, te.second.id), "$startId/$lastDbId")
te.first.interfaceIDs.nightscoutId == null ->
activePlugin.activeNsClient?.nsClientService?.dbAdd("treatments", te.first.toJson(true, dateUtil), DataSyncSelector.PairTherapyEvent(te.first, te.second.id), "$startId/$lastDbId")
// nsId = update
te.first.interfaceIDs.nightscoutId != null ->
nsClientPlugin.nsClientService?.dbUpdate(
te.first.interfaceIDs.nightscoutId != null ->
activePlugin.activeNsClient?.nsClientService?.dbUpdate(
"treatments",
te.first.interfaceIDs.nightscoutId,
te.first.toJson(false, dateUtil),
@ -568,14 +538,13 @@ class DataSyncSelectorImplementation @Inject constructor(
"$startId/$lastDbId"
)
}
return true
return
}
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")
//aapsLogger.debug(LTag.NSCLIENT, "Setting DeviceStatus data sync from $lastSynced")
sp.putLong(R.string.key_ns_device_status_last_synced_id, lastSynced)
}
}
@ -587,9 +556,7 @@ class DataSyncSelectorImplementation @Inject constructor(
}
}
//private var lastDsId = -1L
//private var lastDsTime = -1L
override fun processChangedDeviceStatusesCompat(): Boolean {
override fun processChangedDeviceStatusesCompat() {
val lastDbIdWrapped = appRepository.getLastDeviceStatusIdWrapped().blockingGet()
val lastDbId = if (lastDbIdWrapped is ValueWrapper.Existing) lastDbIdWrapped.value else 0L
var startId = sp.getLong(R.string.key_ns_device_status_last_synced_id, 0)
@ -597,27 +564,23 @@ class DataSyncSelectorImplementation @Inject constructor(
sp.putLong(R.string.key_ns_device_status_last_synced_id, 0)
startId = 0
}
//if (startId == lastDsId && dateUtil.now() - lastDsTime < 5000) return false
//lastDsId = startId
//lastDsTime = dateUtil.now()
queueCounter.dssRemaining = lastDbId - startId
appRepository.getNextSyncElementDeviceStatus(startId).blockingGet()?.let { deviceStatus ->
aapsLogger.info(LTag.NSCLIENT, "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, "$startId/$lastDbId")
activePlugin.activeNsClient?.nsClientService?.dbAdd("devicestatus", deviceStatus.toJson(dateUtil), deviceStatus, "$startId/$lastDbId")
// with nsId = ignore
deviceStatus.interfaceIDs.nightscoutId != null -> Any()
}
return true
return
}
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")
//aapsLogger.debug(LTag.NSCLIENT, "Setting TemporaryBasal data sync from $lastSynced")
sp.putLong(R.string.key_ns_temporary_basal_last_synced_id, lastSynced)
}
}
@ -630,9 +593,7 @@ class DataSyncSelectorImplementation @Inject constructor(
}
}
//private var lastTbrId = -1L
//private var lastTbrTime = -1L
override fun processChangedTemporaryBasalsCompat(): Boolean {
override tailrec fun processChangedTemporaryBasalsCompat() {
val lastDbIdWrapped = appRepository.getLastTemporaryBasalIdWrapped().blockingGet()
val lastDbId = if (lastDbIdWrapped is ValueWrapper.Existing) lastDbIdWrapped.value else 0L
var startId = sp.getLong(R.string.key_ns_temporary_basal_last_synced_id, 0)
@ -640,42 +601,37 @@ class DataSyncSelectorImplementation @Inject constructor(
sp.putLong(R.string.key_ns_temporary_basal_last_synced_id, 0)
startId = 0
}
//if (startId == lastTbrId && dateUtil.now() - lastTbrTime < 5000) return false
//lastTbrId = startId
//lastTbrTime = dateUtil.now()
queueCounter.tbrsRemaining = lastDbId - startId
appRepository.getNextSyncElementTemporaryBasal(startId).blockingGet()?.let { tb ->
aapsLogger.info(LTag.NSCLIENT, "Loading TemporaryBasal data Start: $startId ID: ${tb.first.id} HistoryID: ${tb.second} ")
val profile = profileFunction.getProfile(tb.first.timestamp)
if (profile != null) {
when {
// record is not valid record and we are within first sync, no need to upload
tb.first.id != tb.second.id && tb.second.id <= sp.getLong(R.string.key_ns_temporary_basal_new_data_id, 0) -> {
// new record with existing NS id => must be coming from NS => ignore
tb.first.id == tb.second.id && tb.first.interfaceIDs.nightscoutId != null -> {
aapsLogger.info(LTag.NSCLIENT, "Ignoring TemporaryBasal. Loaded from NS: ${tb.first.id} HistoryID: ${tb.second.id} ")
confirmLastTemporaryBasalIdIfGreater(tb.second.id)
//lastTbrId = -1
processChangedTemporaryBasalsCompat()
aapsLogger.info(LTag.NSCLIENT, "Ignoring TemporaryBasal. Change within first sync ID: ${tb.first.id} HistoryID: ${tb.second.id} ")
return false
return
}
// only NsId changed, no need to upload
tb.first.onlyNsIdAdded(tb.second) -> {
confirmLastTemporaryBasalIdIfGreater(tb.second.id)
//lastTbrId = -1
processChangedTemporaryBasalsCompat()
tb.first.onlyNsIdAdded(tb.second) -> {
aapsLogger.info(LTag.NSCLIENT, "Ignoring TemporaryBasal. Only NS id changed ID: ${tb.first.id} HistoryID: ${tb.second.id} ")
return false
confirmLastTemporaryBasalIdIfGreater(tb.second.id)
processChangedTemporaryBasalsCompat()
return
}
// without nsId = create new
tb.first.interfaceIDs.nightscoutId == null ->
nsClientPlugin.nsClientService?.dbAdd(
tb.first.interfaceIDs.nightscoutId == null ->
activePlugin.activeNsClient?.nsClientService?.dbAdd(
"treatments",
tb.first.toJson(true, profile, dateUtil),
DataSyncSelector.PairTemporaryBasal(tb.first, tb.second.id),
"$startId/$lastDbId"
)
// with nsId = update
tb.first.interfaceIDs.nightscoutId != null ->
nsClientPlugin.nsClientService?.dbUpdate(
tb.first.interfaceIDs.nightscoutId != null ->
activePlugin.activeNsClient?.nsClientService?.dbUpdate(
"treatments",
tb.first.interfaceIDs.nightscoutId,
tb.first.toJson(false, profile, dateUtil),
@ -683,19 +639,19 @@ class DataSyncSelectorImplementation @Inject constructor(
"$startId/$lastDbId"
)
}
return true
return
} else {
aapsLogger.info(LTag.NSCLIENT, "Ignoring TemporaryBasal. No profile: ${tb.first.id} HistoryID: ${tb.second.id} ")
confirmLastTemporaryBasalIdIfGreater(tb.second.id)
//lastTbrId = -1
processChangedTemporaryBasalsCompat()
return
}
}
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")
//aapsLogger.debug(LTag.NSCLIENT, "Setting ExtendedBolus data sync from $lastSynced")
sp.putLong(R.string.key_ns_extended_bolus_last_synced_id, lastSynced)
}
}
@ -708,9 +664,7 @@ class DataSyncSelectorImplementation @Inject constructor(
}
}
//private var lastEbId = -1L
//private var lastEbTime = -1L
override fun processChangedExtendedBolusesCompat(): Boolean {
override tailrec fun processChangedExtendedBolusesCompat() {
val lastDbIdWrapped = appRepository.getLastExtendedBolusIdWrapped().blockingGet()
val lastDbId = if (lastDbIdWrapped is ValueWrapper.Existing) lastDbIdWrapped.value else 0L
var startId = sp.getLong(R.string.key_ns_extended_bolus_last_synced_id, 0)
@ -718,42 +672,37 @@ class DataSyncSelectorImplementation @Inject constructor(
sp.putLong(R.string.key_ns_extended_bolus_last_synced_id, 0)
startId = 0
}
//if (startId == lastEbId && dateUtil.now() - lastEbTime < 5000) return false
//lastEbId = startId
//lastEbTime = dateUtil.now()
queueCounter.ebsRemaining = lastDbId - startId
appRepository.getNextSyncElementExtendedBolus(startId).blockingGet()?.let { eb ->
aapsLogger.info(LTag.NSCLIENT, "Loading ExtendedBolus data Start: $startId ID: ${eb.first.id} HistoryID: ${eb.second} ")
val profile = profileFunction.getProfile(eb.first.timestamp)
if (profile != null) {
when {
// record is not valid record and we are within first sync, no need to upload
eb.first.id != eb.second.id && eb.second.id <= sp.getLong(R.string.key_ns_extended_bolus_new_data_id, 0) -> {
// new record with existing NS id => must be coming from NS => ignore
eb.first.id == eb.second.id && eb.first.interfaceIDs.nightscoutId != null -> {
aapsLogger.info(LTag.NSCLIENT, "Ignoring ExtendedBolus. Loaded from NS: ${eb.first.id} HistoryID: ${eb.second.id} ")
confirmLastExtendedBolusIdIfGreater(eb.second.id)
//lastTbrId = -1
processChangedExtendedBolusesCompat()
aapsLogger.info(LTag.NSCLIENT, "Ignoring ExtendedBolus. Change within first sync ID: ${eb.first.id} HistoryID: ${eb.second.id} ")
return false
return
}
// only NsId changed, no need to upload
eb.first.onlyNsIdAdded(eb.second) -> {
confirmLastExtendedBolusIdIfGreater(eb.second.id)
//lastEbId = -1
processChangedExtendedBolusesCompat()
eb.first.onlyNsIdAdded(eb.second) -> {
aapsLogger.info(LTag.NSCLIENT, "Ignoring ExtendedBolus. Only NS id changed ID: ${eb.first.id} HistoryID: ${eb.second.id} ")
return false
confirmLastExtendedBolusIdIfGreater(eb.second.id)
processChangedExtendedBolusesCompat()
return
}
// without nsId = create new
eb.first.interfaceIDs.nightscoutId == null ->
nsClientPlugin.nsClientService?.dbAdd(
eb.first.interfaceIDs.nightscoutId == null ->
activePlugin.activeNsClient?.nsClientService?.dbAdd(
"treatments",
eb.first.toJson(true, profile, dateUtil),
DataSyncSelector.PairExtendedBolus(eb.first, eb.second.id),
"$startId/$lastDbId"
)
// with nsId = update
eb.first.interfaceIDs.nightscoutId != null ->
nsClientPlugin.nsClientService?.dbUpdate(
eb.first.interfaceIDs.nightscoutId != null ->
activePlugin.activeNsClient?.nsClientService?.dbUpdate(
"treatments",
eb.first.interfaceIDs.nightscoutId,
eb.first.toJson(false, profile, dateUtil),
@ -761,19 +710,19 @@ class DataSyncSelectorImplementation @Inject constructor(
"$startId/$lastDbId"
)
}
return true
return
} else {
aapsLogger.info(LTag.NSCLIENT, "Ignoring ExtendedBolus. No profile: ${eb.first.id} HistoryID: ${eb.second.id} ")
confirmLastExtendedBolusIdIfGreater(eb.second.id)
//lastEbId = -1
processChangedExtendedBolusesCompat()
return
}
}
return false
}
override fun confirmLastProfileSwitchIdIfGreater(lastSynced: Long) {
if (lastSynced > sp.getLong(R.string.key_ns_profile_switch_last_synced_id, 0)) {
aapsLogger.debug(LTag.NSCLIENT, "Setting ProfileSwitch data sync from $lastSynced")
//aapsLogger.debug(LTag.NSCLIENT, "Setting ProfileSwitch data sync from $lastSynced")
sp.putLong(R.string.key_ns_profile_switch_last_synced_id, lastSynced)
}
}
@ -785,9 +734,7 @@ class DataSyncSelectorImplementation @Inject constructor(
}
}
//private var lastPsId = -1L
//private var lastPsTime = -1L
override fun processChangedProfileSwitchesCompat(): Boolean {
override tailrec fun processChangedProfileSwitchesCompat() {
val lastDbIdWrapped = appRepository.getLastProfileSwitchIdWrapped().blockingGet()
val lastDbId = if (lastDbIdWrapped is ValueWrapper.Existing) lastDbIdWrapped.value else 0L
var startId = sp.getLong(R.string.key_ns_profile_switch_last_synced_id, 0)
@ -795,27 +742,30 @@ class DataSyncSelectorImplementation @Inject constructor(
sp.putLong(R.string.key_ns_profile_switch_last_synced_id, 0)
startId = 0
}
//if (startId == lastPsId && dateUtil.now() - lastPsTime < 5000) return false
//lastPsId = startId
//lastPsTime = dateUtil.now()
queueCounter.pssRemaining = lastDbId - startId
appRepository.getNextSyncElementProfileSwitch(startId).blockingGet()?.let { ps ->
aapsLogger.info(LTag.NSCLIENT, "Loading ProfileSwitch data Start: $startId ID: ${ps.first.id} HistoryID: ${ps.second} ")
when {
// only NsId changed, no need to upload
ps.first.onlyNsIdAdded(ps.second) -> {
// new record with existing NS id => must be coming from NS => ignore
ps.first.id == ps.second.id && ps.first.interfaceIDs.nightscoutId != null -> {
aapsLogger.info(LTag.NSCLIENT, "Ignoring ProfileSwitch. Loaded from NS: ${ps.first.id} HistoryID: ${ps.second.id} ")
confirmLastProfileSwitchIdIfGreater(ps.second.id)
//lastPsId = -1
processChangedProfileSwitchesCompat()
return
}
// only NsId changed, no need to upload
ps.first.onlyNsIdAdded(ps.second) -> {
aapsLogger.info(LTag.NSCLIENT, "Ignoring ProfileSwitch. Only NS id changed ID: ${ps.first.id} HistoryID: ${ps.second.id} ")
return false
confirmLastProfileSwitchIdIfGreater(ps.second.id)
processChangedProfileSwitchesCompat()
return
}
// without nsId = create new
ps.first.interfaceIDs.nightscoutId == null ->
nsClientPlugin.nsClientService?.dbAdd("treatments", ps.first.toJson(true, dateUtil), DataSyncSelector.PairProfileSwitch(ps.first, ps.second.id), "$startId/$lastDbId")
ps.first.interfaceIDs.nightscoutId == null ->
activePlugin.activeNsClient?.nsClientService?.dbAdd("treatments", ps.first.toJson(true, dateUtil), DataSyncSelector.PairProfileSwitch(ps.first, ps.second.id), "$startId/$lastDbId")
// with nsId = update
ps.first.interfaceIDs.nightscoutId != null ->
nsClientPlugin.nsClientService?.dbUpdate(
ps.first.interfaceIDs.nightscoutId != null ->
activePlugin.activeNsClient?.nsClientService?.dbUpdate(
"treatments",
ps.first.interfaceIDs.nightscoutId,
ps.first.toJson(false, dateUtil),
@ -823,14 +773,13 @@ class DataSyncSelectorImplementation @Inject constructor(
"$startId/$lastDbId"
)
}
return true
return
}
return false
}
override fun confirmLastEffectiveProfileSwitchIdIfGreater(lastSynced: Long) {
if (lastSynced > sp.getLong(R.string.key_ns_effective_profile_switch_last_synced_id, 0)) {
aapsLogger.debug(LTag.NSCLIENT, "Setting EffectiveProfileSwitch data sync from $lastSynced")
//aapsLogger.debug(LTag.NSCLIENT, "Setting EffectiveProfileSwitch data sync from $lastSynced")
sp.putLong(R.string.key_ns_effective_profile_switch_last_synced_id, lastSynced)
}
}
@ -842,9 +791,7 @@ class DataSyncSelectorImplementation @Inject constructor(
}
}
//private var lastEpsId = -1L
//private var lastEpsTime = -1L
override fun processChangedEffectiveProfileSwitchesCompat(): Boolean {
override tailrec fun processChangedEffectiveProfileSwitchesCompat() {
val lastDbIdWrapped = appRepository.getLastEffectiveProfileSwitchIdWrapped().blockingGet()
val lastDbId = if (lastDbIdWrapped is ValueWrapper.Existing) lastDbIdWrapped.value else 0L
var startId = sp.getLong(R.string.key_ns_effective_profile_switch_last_synced_id, 0)
@ -852,27 +799,35 @@ class DataSyncSelectorImplementation @Inject constructor(
sp.putLong(R.string.key_ns_effective_profile_switch_last_synced_id, 0)
startId = 0
}
//if (startId == lastEpsId && dateUtil.now() - lastEpsTime < 5000) return false
//lastEpsId = startId
//lastEpsTime = dateUtil.now()
queueCounter.epssRemaining = lastDbId - startId
appRepository.getNextSyncElementEffectiveProfileSwitch(startId).blockingGet()?.let { ps ->
aapsLogger.info(LTag.NSCLIENT, "Loading EffectiveProfileSwitch data Start: $startId ID: ${ps.first.id} HistoryID: ${ps.second} ")
when {
// only NsId changed, no need to upload
ps.first.onlyNsIdAdded(ps.second) -> {
// new record with existing NS id => must be coming from NS => ignore
ps.first.id == ps.second.id && ps.first.interfaceIDs.nightscoutId != null -> {
aapsLogger.info(LTag.NSCLIENT, "Ignoring EffectiveProfileSwitch. Loaded from NS: ${ps.first.id} HistoryID: ${ps.second.id} ")
confirmLastEffectiveProfileSwitchIdIfGreater(ps.second.id)
//lastEpsId = -1
processChangedEffectiveProfileSwitchesCompat()
return
}
// only NsId changed, no need to upload
ps.first.onlyNsIdAdded(ps.second) -> {
aapsLogger.info(LTag.NSCLIENT, "Ignoring EffectiveProfileSwitch. Only NS id changed ID: ${ps.first.id} HistoryID: ${ps.second.id} ")
return false
confirmLastEffectiveProfileSwitchIdIfGreater(ps.second.id)
processChangedEffectiveProfileSwitchesCompat()
return
}
// without nsId = create new
ps.first.interfaceIDs.nightscoutId == null ->
nsClientPlugin.nsClientService?.dbAdd("treatments", ps.first.toJson(true, dateUtil), DataSyncSelector.PairEffectiveProfileSwitch(ps.first, ps.second.id), "$startId/$lastDbId")
ps.first.interfaceIDs.nightscoutId == null ->
activePlugin.activeNsClient?.nsClientService?.dbAdd(
"treatments",
ps.first.toJson(true, dateUtil),
DataSyncSelector.PairEffectiveProfileSwitch(ps.first, ps.second.id),
"$startId/$lastDbId"
)
// with nsId = update
ps.first.interfaceIDs.nightscoutId != null ->
nsClientPlugin.nsClientService?.dbUpdate(
ps.first.interfaceIDs.nightscoutId != null ->
activePlugin.activeNsClient?.nsClientService?.dbUpdate(
"treatments",
ps.first.interfaceIDs.nightscoutId,
ps.first.toJson(false, dateUtil),
@ -880,14 +835,13 @@ class DataSyncSelectorImplementation @Inject constructor(
"$startId/$lastDbId"
)
}
return true
return
}
return false
}
override fun confirmLastOfflineEventIdIfGreater(lastSynced: Long) {
if (lastSynced > sp.getLong(R.string.key_ns_offline_event_last_synced_id, 0)) {
aapsLogger.debug(LTag.NSCLIENT, "Setting OfflineEvent data sync from $lastSynced")
//aapsLogger.debug(LTag.NSCLIENT, "Setting OfflineEvent data sync from $lastSynced")
sp.putLong(R.string.key_ns_offline_event_last_synced_id, lastSynced)
}
}
@ -900,9 +854,7 @@ class DataSyncSelectorImplementation @Inject constructor(
}
}
//private var lastOeId = -1L
//private var lastOeTime = -1L
override fun processChangedOfflineEventsCompat(): Boolean {
override tailrec fun processChangedOfflineEventsCompat() {
val lastDbIdWrapped = appRepository.getLastOfflineEventIdWrapped().blockingGet()
val lastDbId = if (lastDbIdWrapped is ValueWrapper.Existing) lastDbIdWrapped.value else 0L
var startId = sp.getLong(R.string.key_ns_offline_event_last_synced_id, 0)
@ -910,27 +862,30 @@ class DataSyncSelectorImplementation @Inject constructor(
sp.putLong(R.string.key_ns_offline_event_last_synced_id, 0)
startId = 0
}
//if (startId == lastOeId && dateUtil.now() - lastOeTime < 5000) return false
//lastOeId = startId
//lastOeTime = dateUtil.now()
queueCounter.oesRemaining = lastDbId - startId
appRepository.getNextSyncElementOfflineEvent(startId).blockingGet()?.let { oe ->
aapsLogger.info(LTag.NSCLIENT, "Loading OfflineEvent data Start: $startId ID: ${oe.first.id} HistoryID: ${oe.second} ")
when {
// only NsId changed, no need to upload
oe.first.onlyNsIdAdded(oe.second) -> {
// new record with existing NS id => must be coming from NS => ignore
oe.first.id == oe.second.id && oe.first.interfaceIDs.nightscoutId != null -> {
aapsLogger.info(LTag.NSCLIENT, "Ignoring OfflineEvent. Loaded from NS: ${oe.first.id} HistoryID: ${oe.second.id} ")
confirmLastOfflineEventIdIfGreater(oe.second.id)
//lastOeId = -1
processChangedOfflineEventsCompat()
return
}
// only NsId changed, no need to upload
oe.first.onlyNsIdAdded(oe.second) -> {
aapsLogger.info(LTag.NSCLIENT, "Ignoring OfflineEvent. Only NS id changed ID: ${oe.first.id} HistoryID: ${oe.second.id} ")
return false
confirmLastOfflineEventIdIfGreater(oe.second.id)
processChangedOfflineEventsCompat()
return
}
// without nsId = create new
oe.first.interfaceIDs.nightscoutId == null ->
nsClientPlugin.nsClientService?.dbAdd("treatments", oe.first.toJson(true, dateUtil), DataSyncSelector.PairOfflineEvent(oe.first, oe.second.id), "$startId/$lastDbId")
oe.first.interfaceIDs.nightscoutId == null ->
activePlugin.activeNsClient?.nsClientService?.dbAdd("treatments", oe.first.toJson(true, dateUtil), DataSyncSelector.PairOfflineEvent(oe.first, oe.second.id), "$startId/$lastDbId")
// existing with nsId = update
oe.first.interfaceIDs.nightscoutId != null ->
nsClientPlugin.nsClientService?.dbUpdate(
oe.first.interfaceIDs.nightscoutId != null ->
activePlugin.activeNsClient?.nsClientService?.dbUpdate(
"treatments",
oe.first.interfaceIDs.nightscoutId,
oe.first.toJson(false, dateUtil),
@ -938,9 +893,8 @@ class DataSyncSelectorImplementation @Inject constructor(
"$startId/$lastDbId"
)
}
return true
return
}
return false
}
override fun confirmLastProfileStore(lastSynced: Long) {
@ -954,7 +908,7 @@ class DataSyncSelectorImplementation @Inject constructor(
if (lastChange > lastSync) {
if (profilePlugin.profile?.allProfilesValid != true) return
val profileJson = profilePlugin.profile?.data ?: return
nsClientPlugin.nsClientService?.dbAdd("profile", profileJson, DataSyncSelector.PairProfileStore(profileJson, dateUtil.now()), "")
activePlugin.activeNsClient?.nsClientService?.dbAdd("profile", profileJson, DataSyncSelector.PairProfileStore(profileJson, dateUtil.now()), "")
}
}
}

View file

@ -1,4 +1,4 @@
package info.nightscout.androidaps.plugins.general.nsclient
package info.nightscout.androidaps.plugins.sync.nsclient
import android.content.Context
import android.os.SystemClock
@ -36,8 +36,9 @@ import info.nightscout.androidaps.interfaces.DataSyncSelector.PairProfileSwitch
import info.nightscout.androidaps.interfaces.DataSyncSelector.PairTemporaryBasal
import info.nightscout.androidaps.interfaces.DataSyncSelector.PairTemporaryTarget
import info.nightscout.androidaps.interfaces.DataSyncSelector.PairTherapyEvent
import info.nightscout.androidaps.plugins.general.nsclient.acks.NSAddAck
import info.nightscout.androidaps.plugins.general.nsclient.events.EventNSClientNewLog
import info.nightscout.androidaps.interfaces.NsClient
import info.nightscout.androidaps.plugins.sync.nsShared.events.EventNSClientNewLog
import info.nightscout.androidaps.plugins.sync.nsclient.acks.NSAddAck
import info.nightscout.androidaps.receivers.DataWorkerStorage
import info.nightscout.rx.AapsSchedulers
import info.nightscout.rx.bus.RxBus
@ -68,7 +69,7 @@ class NSClientAddAckWorker(
if (sp.getBoolean(R.string.key_ns_sync_slow, false)) SystemClock.sleep(1000)
when (ack.originalObject) {
is PairTemporaryTarget -> {
is PairTemporaryTarget -> {
val pair = ack.originalObject
pair.value.interfaceIDs.nightscoutId = ack.id
repository.runTransactionForResult(UpdateNsIdTemporaryTargetTransaction(pair.value))
@ -82,12 +83,12 @@ class NSClientAddAckWorker(
dataSyncSelector.confirmLastTempTargetsIdIfGreater(pair.updateRecordId)
}
.blockingGet()
rxBus.send(EventNSClientNewLog("DBADD", "Acked TemporaryTarget " + pair.value.interfaceIDs.nightscoutId))
rxBus.send(EventNSClientNewLog("DBADD", "Acked TemporaryTarget " + pair.value.interfaceIDs.nightscoutId, NsClient.Version.V1))
// Send new if waiting
dataSyncSelector.processChangedTempTargetsCompat()
}
is PairGlucoseValue -> {
is PairGlucoseValue -> {
val pair = ack.originalObject
pair.value.interfaceIDs.nightscoutId = ack.id
repository.runTransactionForResult(UpdateNsIdGlucoseValueTransaction(pair.value))
@ -101,12 +102,12 @@ class NSClientAddAckWorker(
dataSyncSelector.confirmLastGlucoseValueIdIfGreater(pair.updateRecordId)
}
.blockingGet()
rxBus.send(EventNSClientNewLog("DBADD", "Acked GlucoseValue " + pair.value.interfaceIDs.nightscoutId))
rxBus.send(EventNSClientNewLog("DBADD", "Acked GlucoseValue " + pair.value.interfaceIDs.nightscoutId, NsClient.Version.V1))
// Send new if waiting
dataSyncSelector.processChangedGlucoseValuesCompat()
}
is PairFood -> {
is PairFood -> {
val pair = ack.originalObject
pair.value.interfaceIDs.nightscoutId = ack.id
repository.runTransactionForResult(UpdateNsIdFoodTransaction(pair.value))
@ -120,12 +121,12 @@ class NSClientAddAckWorker(
dataSyncSelector.confirmLastFoodIdIfGreater(pair.updateRecordId)
}
.blockingGet()
rxBus.send(EventNSClientNewLog("DBADD", "Acked Food " + pair.value.interfaceIDs.nightscoutId))
rxBus.send(EventNSClientNewLog("DBADD", "Acked Food " + pair.value.interfaceIDs.nightscoutId, NsClient.Version.V1))
// Send new if waiting
dataSyncSelector.processChangedFoodsCompat()
}
is PairTherapyEvent -> {
is PairTherapyEvent -> {
val pair = ack.originalObject
pair.value.interfaceIDs.nightscoutId = ack.id
repository.runTransactionForResult(UpdateNsIdTherapyEventTransaction(pair.value))
@ -139,12 +140,12 @@ class NSClientAddAckWorker(
dataSyncSelector.confirmLastTherapyEventIdIfGreater(pair.updateRecordId)
}
.blockingGet()
rxBus.send(EventNSClientNewLog("DBADD", "Acked TherapyEvent " + pair.value.interfaceIDs.nightscoutId))
rxBus.send(EventNSClientNewLog("DBADD", "Acked TherapyEvent " + pair.value.interfaceIDs.nightscoutId, NsClient.Version.V1))
// Send new if waiting
dataSyncSelector.processChangedTherapyEventsCompat()
}
is PairBolus -> {
is PairBolus -> {
val pair = ack.originalObject
pair.value.interfaceIDs.nightscoutId = ack.id
repository.runTransactionForResult(UpdateNsIdBolusTransaction(pair.value))
@ -158,12 +159,12 @@ class NSClientAddAckWorker(
dataSyncSelector.confirmLastBolusIdIfGreater(pair.updateRecordId)
}
.blockingGet()
rxBus.send(EventNSClientNewLog("DBADD", "Acked Bolus " + pair.value.interfaceIDs.nightscoutId))
rxBus.send(EventNSClientNewLog("DBADD", "Acked Bolus " + pair.value.interfaceIDs.nightscoutId, NsClient.Version.V1))
// Send new if waiting
dataSyncSelector.processChangedBolusesCompat()
}
is PairCarbs -> {
is PairCarbs -> {
val pair = ack.originalObject
pair.value.interfaceIDs.nightscoutId = ack.id
repository.runTransactionForResult(UpdateNsIdCarbsTransaction(pair.value))
@ -177,12 +178,12 @@ class NSClientAddAckWorker(
dataSyncSelector.confirmLastCarbsIdIfGreater(pair.updateRecordId)
}
.blockingGet()
rxBus.send(EventNSClientNewLog("DBADD", "Acked Carbs " + pair.value.interfaceIDs.nightscoutId))
rxBus.send(EventNSClientNewLog("DBADD", "Acked Carbs " + pair.value.interfaceIDs.nightscoutId, NsClient.Version.V1))
// Send new if waiting
dataSyncSelector.processChangedCarbsCompat()
}
is PairBolusCalculatorResult -> {
is PairBolusCalculatorResult -> {
val pair = ack.originalObject
pair.value.interfaceIDs.nightscoutId = ack.id
repository.runTransactionForResult(UpdateNsIdBolusCalculatorResultTransaction(pair.value))
@ -196,12 +197,12 @@ class NSClientAddAckWorker(
dataSyncSelector.confirmLastBolusCalculatorResultsIdIfGreater(pair.updateRecordId)
}
.blockingGet()
rxBus.send(EventNSClientNewLog("DBADD", "Acked BolusCalculatorResult " + pair.value.interfaceIDs.nightscoutId))
rxBus.send(EventNSClientNewLog("DBADD", "Acked BolusCalculatorResult " + pair.value.interfaceIDs.nightscoutId, NsClient.Version.V1))
// Send new if waiting
dataSyncSelector.processChangedBolusCalculatorResultsCompat()
}
is PairTemporaryBasal -> {
is PairTemporaryBasal -> {
val pair = ack.originalObject
pair.value.interfaceIDs.nightscoutId = ack.id
repository.runTransactionForResult(UpdateNsIdTemporaryBasalTransaction(pair.value))
@ -215,12 +216,12 @@ class NSClientAddAckWorker(
dataSyncSelector.confirmLastTemporaryBasalIdIfGreater(pair.updateRecordId)
}
.blockingGet()
rxBus.send(EventNSClientNewLog("DBADD", "Acked TemporaryBasal " + pair.value.interfaceIDs.nightscoutId))
rxBus.send(EventNSClientNewLog("DBADD", "Acked TemporaryBasal " + pair.value.interfaceIDs.nightscoutId, NsClient.Version.V1))
// Send new if waiting
dataSyncSelector.processChangedTemporaryBasalsCompat()
}
is PairExtendedBolus -> {
is PairExtendedBolus -> {
val pair = ack.originalObject
pair.value.interfaceIDs.nightscoutId = ack.id
repository.runTransactionForResult(UpdateNsIdExtendedBolusTransaction(pair.value))
@ -234,12 +235,12 @@ class NSClientAddAckWorker(
dataSyncSelector.confirmLastExtendedBolusIdIfGreater(pair.updateRecordId)
}
.blockingGet()
rxBus.send(EventNSClientNewLog("DBADD", "Acked ExtendedBolus " + pair.value.interfaceIDs.nightscoutId))
rxBus.send(EventNSClientNewLog("DBADD", "Acked ExtendedBolus " + pair.value.interfaceIDs.nightscoutId, NsClient.Version.V1))
// Send new if waiting
dataSyncSelector.processChangedExtendedBolusesCompat()
}
is PairProfileSwitch -> {
is PairProfileSwitch -> {
val pair = ack.originalObject
pair.value.interfaceIDs.nightscoutId = ack.id
repository.runTransactionForResult(UpdateNsIdProfileSwitchTransaction(pair.value))
@ -253,12 +254,12 @@ class NSClientAddAckWorker(
dataSyncSelector.confirmLastProfileSwitchIdIfGreater(pair.updateRecordId)
}
.blockingGet()
rxBus.send(EventNSClientNewLog("DBADD", "Acked ProfileSwitch " + pair.value.interfaceIDs.nightscoutId))
rxBus.send(EventNSClientNewLog("DBADD", "Acked ProfileSwitch " + pair.value.interfaceIDs.nightscoutId, NsClient.Version.V1))
// Send new if waiting
dataSyncSelector.processChangedProfileSwitchesCompat()
}
is PairEffectiveProfileSwitch -> {
is PairEffectiveProfileSwitch -> {
val pair = ack.originalObject
pair.value.interfaceIDs.nightscoutId = ack.id
repository.runTransactionForResult(UpdateNsIdEffectiveProfileSwitchTransaction(pair.value))
@ -272,12 +273,12 @@ class NSClientAddAckWorker(
dataSyncSelector.confirmLastEffectiveProfileSwitchIdIfGreater(pair.updateRecordId)
}
.blockingGet()
rxBus.send(EventNSClientNewLog("DBADD", "Acked EffectiveProfileSwitch " + pair.value.interfaceIDs.nightscoutId))
rxBus.send(EventNSClientNewLog("DBADD", "Acked EffectiveProfileSwitch " + pair.value.interfaceIDs.nightscoutId, NsClient.Version.V1))
// Send new if waiting
dataSyncSelector.processChangedEffectiveProfileSwitchesCompat()
}
is DeviceStatus -> {
is DeviceStatus -> {
val deviceStatus = ack.originalObject
deviceStatus.interfaceIDs.nightscoutId = ack.id
repository.runTransactionForResult(UpdateNsIdDeviceStatusTransaction(deviceStatus))
@ -291,17 +292,17 @@ class NSClientAddAckWorker(
dataSyncSelector.confirmLastDeviceStatusIdIfGreater(deviceStatus.id)
}
.blockingGet()
rxBus.send(EventNSClientNewLog("DBADD", "Acked DeviceStatus " + deviceStatus.interfaceIDs.nightscoutId))
rxBus.send(EventNSClientNewLog("DBADD", "Acked DeviceStatus " + deviceStatus.interfaceIDs.nightscoutId, NsClient.Version.V1))
// Send new if waiting
dataSyncSelector.processChangedDeviceStatusesCompat()
}
is PairProfileStore -> {
is PairProfileStore -> {
dataSyncSelector.confirmLastProfileStore(ack.originalObject.timestampSync)
rxBus.send(EventNSClientNewLog("DBADD", "Acked ProfileStore " + ack.id))
rxBus.send(EventNSClientNewLog("DBADD", "Acked ProfileStore " + ack.id, NsClient.Version.V1))
}
is PairOfflineEvent -> {
is PairOfflineEvent -> {
val pair = ack.originalObject
pair.value.interfaceIDs.nightscoutId = ack.id
repository.runTransactionForResult(UpdateNsIdOfflineEventTransaction(pair.value))
@ -315,7 +316,7 @@ class NSClientAddAckWorker(
dataSyncSelector.confirmLastOfflineEventIdIfGreater(pair.updateRecordId)
}
.blockingGet()
rxBus.send(EventNSClientNewLog("DBADD", "Acked OfflineEvent " + pair.value.interfaceIDs.nightscoutId))
rxBus.send(EventNSClientNewLog("DBADD", "Acked OfflineEvent " + pair.value.interfaceIDs.nightscoutId, NsClient.Version.V1))
// Send new if waiting
dataSyncSelector.processChangedOfflineEventsCompat()
}

View file

@ -0,0 +1,180 @@
package info.nightscout.androidaps.plugins.sync.nsclient
import android.content.Context
import androidx.work.Worker
import androidx.work.WorkerParameters
import androidx.work.workDataOf
import dagger.android.HasAndroidInjector
import info.nightscout.androidaps.R
import info.nightscout.androidaps.database.AppRepository
import info.nightscout.androidaps.database.entities.TherapyEvent
import info.nightscout.androidaps.extensions.bolusCalculatorResultFromJson
import info.nightscout.androidaps.interfaces.ActivePlugin
import info.nightscout.androidaps.interfaces.XDripBroadcast
import info.nightscout.androidaps.logging.UserEntryLogger
import info.nightscout.androidaps.plugins.pump.virtual.VirtualPumpPlugin
import info.nightscout.androidaps.plugins.sync.nsShared.StoreDataForDb
import info.nightscout.androidaps.receivers.DataWorkerStorage
import info.nightscout.androidaps.utils.DateUtil
import info.nightscout.interfaces.BuildHelper
import info.nightscout.interfaces.Config
import info.nightscout.interfaces.utils.JsonHelper
import info.nightscout.plugins.sync.nsclient.extensions.bolusFromJson
import info.nightscout.plugins.sync.nsclient.extensions.carbsFromJson
import info.nightscout.plugins.sync.nsclient.extensions.effectiveProfileSwitchFromJson
import info.nightscout.plugins.sync.nsclient.extensions.extendedBolusFromJson
import info.nightscout.plugins.sync.nsclient.extensions.isEffectiveProfileSwitch
import info.nightscout.plugins.sync.nsclient.extensions.offlineEventFromJson
import info.nightscout.plugins.sync.nsclient.extensions.profileSwitchFromJson
import info.nightscout.plugins.sync.nsclient.extensions.temporaryBasalFromJson
import info.nightscout.plugins.sync.nsclient.extensions.temporaryTargetFromJson
import info.nightscout.plugins.sync.nsclient.extensions.therapyEventFromJson
import info.nightscout.rx.bus.RxBus
import info.nightscout.rx.logging.AAPSLogger
import info.nightscout.rx.logging.LTag
import info.nightscout.shared.sharedPreferences.SP
import javax.inject.Inject
class NSClientAddUpdateWorker(
context: Context,
params: WorkerParameters
) : Worker(context, params) {
@Inject lateinit var dataWorkerStorage: DataWorkerStorage
@Inject lateinit var aapsLogger: AAPSLogger
@Inject lateinit var buildHelper: BuildHelper
@Inject lateinit var sp: SP
@Inject lateinit var dateUtil: DateUtil
@Inject lateinit var config: Config
@Inject lateinit var repository: AppRepository
@Inject lateinit var activePlugin: ActivePlugin
@Inject lateinit var rxBus: RxBus
@Inject lateinit var uel: UserEntryLogger
@Inject lateinit var virtualPumpPlugin: VirtualPumpPlugin
@Inject lateinit var xDripBroadcast: XDripBroadcast
@Inject lateinit var storeDataForDb: StoreDataForDb
override fun doWork(): Result {
val treatments = dataWorkerStorage.pickupJSONArray(inputData.getLong(DataWorkerStorage.STORE_KEY, -1))
?: return Result.failure(workDataOf("Error" to "missing input data"))
val ret = Result.success()
var latestDateInReceivedData = 0L
for (i in 0 until treatments.length()) {
var json = treatments.getJSONObject(i)
aapsLogger.debug(LTag.DATABASE, "Received NS treatment: $json")
val insulin = JsonHelper.safeGetDouble(json, "insulin")
val carbs = JsonHelper.safeGetDouble(json, "carbs")
var eventType = JsonHelper.safeGetString(json, "eventType")
if (eventType == null) {
aapsLogger.debug(LTag.NSCLIENT, "Wrong treatment. Ignoring : $json")
continue
}
//Find latest date in treatment
val mills = JsonHelper.safeGetLong(json, "mills")
if (mills != 0L && mills < dateUtil.now())
if (mills > latestDateInReceivedData) latestDateInReceivedData = mills
if (insulin > 0) {
if (sp.getBoolean(R.string.key_ns_receive_insulin, false) || config.NSCLIENT) {
bolusFromJson(json)?.let { bolus ->
storeDataForDb.boluses.add(bolus)
} ?: aapsLogger.error("Error parsing bolus json $json")
}
}
if (carbs > 0) {
if (sp.getBoolean(R.string.key_ns_receive_carbs, false) || config.NSCLIENT) {
carbsFromJson(json)?.let { carb ->
storeDataForDb.carbs.add(carb)
} ?: 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"))
ebJson.put("mills", mills)
json = ebJson
eventType = JsonHelper.safeGetString(json, "eventType")
virtualPumpPlugin.fakeDataDetected = true
}
when {
insulin > 0 || carbs > 0 -> Any()
eventType == TherapyEvent.Type.TEMPORARY_TARGET.text ->
if (sp.getBoolean(R.string.key_ns_receive_temp_target, false) || config.NSCLIENT) {
temporaryTargetFromJson(json)?.let { temporaryTarget ->
storeDataForDb.temporaryTargets.add(temporaryTarget)
} ?: aapsLogger.error("Error parsing TT json $json")
}
eventType == TherapyEvent.Type.NOTE.text && json.isEffectiveProfileSwitch() -> // replace this by new Type when available in NS
if (sp.getBoolean(R.string.key_ns_receive_profile_switch, false) || config.NSCLIENT) {
effectiveProfileSwitchFromJson(json, dateUtil)?.let { effectiveProfileSwitch ->
storeDataForDb.effectiveProfileSwitches.add(effectiveProfileSwitch)
} ?: aapsLogger.error("Error parsing EffectiveProfileSwitch json $json")
}
eventType == TherapyEvent.Type.BOLUS_WIZARD.text ->
bolusCalculatorResultFromJson(json)?.let { bolusCalculatorResult ->
storeDataForDb.bolusCalculatorResults.add(bolusCalculatorResult)
} ?: aapsLogger.error("Error parsing BolusCalculatorResult json $json")
eventType == TherapyEvent.Type.CANNULA_CHANGE.text ||
eventType == TherapyEvent.Type.INSULIN_CHANGE.text ||
eventType == TherapyEvent.Type.SENSOR_CHANGE.text ||
eventType == TherapyEvent.Type.FINGER_STICK_BG_VALUE.text ||
eventType == TherapyEvent.Type.NONE.text ||
eventType == TherapyEvent.Type.ANNOUNCEMENT.text ||
eventType == TherapyEvent.Type.QUESTION.text ||
eventType == TherapyEvent.Type.EXERCISE.text ||
eventType == TherapyEvent.Type.NOTE.text ||
eventType == TherapyEvent.Type.PUMP_BATTERY_CHANGE.text ->
if (sp.getBoolean(R.string.key_ns_receive_therapy_events, false) || config.NSCLIENT) {
therapyEventFromJson(json)?.let { therapyEvent ->
storeDataForDb.therapyEvents.add(therapyEvent)
} ?: aapsLogger.error("Error parsing TherapyEvent json $json")
}
eventType == TherapyEvent.Type.COMBO_BOLUS.text ->
if (buildHelper.isEngineeringMode() && sp.getBoolean(R.string.key_ns_receive_tbr_eb, false) || config.NSCLIENT) {
extendedBolusFromJson(json)?.let { extendedBolus ->
storeDataForDb.extendedBoluses.add(extendedBolus)
} ?: aapsLogger.error("Error parsing ExtendedBolus json $json")
}
eventType == TherapyEvent.Type.TEMPORARY_BASAL.text ->
if (buildHelper.isEngineeringMode() && sp.getBoolean(R.string.key_ns_receive_tbr_eb, false) || config.NSCLIENT) {
temporaryBasalFromJson(json)?.let { temporaryBasal ->
storeDataForDb.temporaryBasals.add(temporaryBasal)
} ?: aapsLogger.error("Error parsing TemporaryBasal json $json")
}
eventType == TherapyEvent.Type.PROFILE_SWITCH.text ->
if (sp.getBoolean(R.string.key_ns_receive_profile_switch, false) || config.NSCLIENT) {
profileSwitchFromJson(json, dateUtil, activePlugin)?.let { profileSwitch ->
storeDataForDb.profileSwitches.add(profileSwitch)
} ?: aapsLogger.error("Error parsing ProfileSwitch json $json")
}
eventType == TherapyEvent.Type.APS_OFFLINE.text ->
if (sp.getBoolean(R.string.key_ns_receive_offline_event, false) && buildHelper.isEngineeringMode() || config.NSCLIENT) {
offlineEventFromJson(json)?.let { offlineEvent ->
storeDataForDb.offlineEvents.add(offlineEvent)
} ?: aapsLogger.error("Error parsing OfflineEvent json $json")
}
}
}
storeDataForDb.storeTreatmentsToDb()
activePlugin.activeNsClient?.updateLatestTreatmentReceivedIfNewer(latestDateInReceivedData)
xDripBroadcast.sendTreatments(treatments)
return ret
}
init {
(context.applicationContext as HasAndroidInjector).androidInjector().inject(this)
}
}

View file

@ -1,4 +1,4 @@
package info.nightscout.androidaps.plugins.general.nsclient
package info.nightscout.androidaps.plugins.sync.nsclient
import android.content.Context
import androidx.work.Worker
@ -6,15 +6,11 @@ import androidx.work.WorkerParameters
import androidx.work.workDataOf
import dagger.android.HasAndroidInjector
import info.nightscout.androidaps.R
import info.nightscout.androidaps.database.AppRepository
import info.nightscout.androidaps.database.transactions.SyncNsTherapyEventTransaction
import info.nightscout.androidaps.extensions.therapyEventFromNsMbg
import info.nightscout.interfaces.BuildHelper
import info.nightscout.interfaces.Config
import info.nightscout.androidaps.plugins.general.nsclient.data.NSMbg
import info.nightscout.androidaps.plugins.sync.nsShared.StoreDataForDb
import info.nightscout.androidaps.plugins.sync.nsclient.data.NSMbg
import info.nightscout.androidaps.receivers.DataWorkerStorage
import info.nightscout.rx.logging.AAPSLogger
import info.nightscout.rx.logging.LTag
import info.nightscout.androidaps.utils.extensions.therapyEventFromNsMbg
import info.nightscout.interfaces.Config
import info.nightscout.shared.sharedPreferences.SP
import javax.inject.Inject
@ -23,15 +19,13 @@ class NSClientMbgWorker(
params: WorkerParameters
) : Worker(context, params) {
@Inject lateinit var repository: AppRepository
@Inject lateinit var dataWorkerStorage: DataWorkerStorage
@Inject lateinit var aapsLogger: AAPSLogger
@Inject lateinit var sp: SP
@Inject lateinit var buildHelper: BuildHelper
@Inject lateinit var config: Config
@Inject lateinit var storeDataForDb: StoreDataForDb
override fun doWork(): Result {
var ret = Result.success()
val ret = Result.success()
val acceptNSData = sp.getBoolean(R.string.key_ns_receive_therapy_events, false) || config.NSCLIENT
if (!acceptNSData) return Result.success(workDataOf("Result" to "Sync not enabled"))
@ -41,16 +35,9 @@ class NSClientMbgWorker(
for (i in 0 until mbgArray.length()) {
val nsMbg = NSMbg(mbgArray.getJSONObject(i))
if (!nsMbg.isValid()) continue
repository.runTransactionForResult(SyncNsTherapyEventTransaction(therapyEventFromNsMbg(nsMbg)))
.doOnError {
aapsLogger.error("Error while saving therapy event", it)
ret = Result.failure(workDataOf("Error" to it.toString()))
}
.blockingGet()
.also {
aapsLogger.debug(LTag.DATABASE, "Saved therapy event $it")
}
storeDataForDb.therapyEvents.add(therapyEventFromNsMbg(nsMbg))
}
// storeDataForDb.storeTreatmentsToDb() don't do this. It will be stored along with other treatments
return ret
}

View file

@ -1,4 +1,4 @@
package info.nightscout.androidaps.plugins.general.nsclient
package info.nightscout.androidaps.plugins.sync.nsclient
import android.content.ComponentName
import android.content.Context
@ -7,29 +7,34 @@ import android.content.ServiceConnection
import android.os.Handler
import android.os.HandlerThread
import android.os.IBinder
import android.text.Spanned
import androidx.preference.PreferenceFragmentCompat
import androidx.preference.PreferenceScreen
import androidx.preference.SwitchPreference
import dagger.android.HasAndroidInjector
import info.nightscout.interfaces.Constants
import info.nightscout.androidaps.R
import info.nightscout.androidaps.events.EventPreferenceChange
import info.nightscout.androidaps.interfaces.DataSyncSelector
import info.nightscout.androidaps.interfaces.NsClient
import info.nightscout.androidaps.interfaces.PluginBase
import info.nightscout.androidaps.interfaces.ResourceHelper
import info.nightscout.androidaps.interfaces.Sync
import info.nightscout.androidaps.plugins.sync.nsShared.events.EventNSClientUpdateGUI
import info.nightscout.androidaps.plugins.sync.nsShared.NSClientFragment
import info.nightscout.androidaps.plugins.sync.nsShared.events.EventNSClientNewLog
import info.nightscout.androidaps.plugins.sync.nsShared.events.EventNSClientResend
import info.nightscout.androidaps.plugins.sync.nsShared.events.EventNSClientStatus
import info.nightscout.androidaps.plugins.sync.nsclient.data.AlarmAck
import info.nightscout.androidaps.plugins.sync.nsclient.data.NSAlarm
import info.nightscout.androidaps.plugins.sync.nsclient.services.NSClientService
import info.nightscout.androidaps.utils.FabricPrivacy
import info.nightscout.androidaps.utils.ToastUtils
import info.nightscout.interfaces.BuildHelper
import info.nightscout.interfaces.Config
import info.nightscout.androidaps.interfaces.PluginBase
import info.nightscout.interfaces.Constants
import info.nightscout.interfaces.PluginDescription
import info.nightscout.interfaces.PluginType
import info.nightscout.androidaps.interfaces.ResourceHelper
import info.nightscout.androidaps.plugins.general.nsclient.data.AlarmAck
import info.nightscout.androidaps.plugins.general.nsclient.data.NSAlarm
import info.nightscout.androidaps.plugins.general.nsclient.events.EventNSClientNewLog
import info.nightscout.androidaps.plugins.general.nsclient.events.EventNSClientResend
import info.nightscout.androidaps.plugins.general.nsclient.events.EventNSClientStatus
import info.nightscout.androidaps.plugins.general.nsclient.events.EventNSClientUpdateGUI
import info.nightscout.androidaps.plugins.general.nsclient.services.NSClientService
import info.nightscout.androidaps.utils.FabricPrivacy
import info.nightscout.interfaces.utils.HtmlHelper.fromHtml
import info.nightscout.androidaps.utils.ToastUtils
import info.nightscout.rx.AapsSchedulers
import info.nightscout.rx.bus.RxBus
import info.nightscout.rx.events.EventAppExit
@ -55,17 +60,16 @@ class NSClientPlugin @Inject constructor(
private val sp: SP,
private val nsClientReceiverDelegate: NsClientReceiverDelegate,
private val config: Config,
private val buildHelper: BuildHelper
) : PluginBase(
private val buildHelper: BuildHelper,
private val dataSyncSelector: DataSyncSelector
) : NsClient, Sync, PluginBase(
PluginDescription()
.mainType(PluginType.GENERAL)
.mainType(PluginType.SYNC)
.fragmentClass(NSClientFragment::class.java.name)
.pluginIcon(R.drawable.ic_nightscout_syncs)
.pluginName(R.string.nsclientinternal)
.shortName(R.string.nsclientinternal_shortname)
.preferencesId(R.xml.pref_nsclientinternal)
.alwaysEnabled(config.NSCLIENT)
.visibleByDefault(config.NSCLIENT)
.description(R.string.description_ns_client),
aapsLogger, rh, injector
) {
@ -73,19 +77,14 @@ class NSClientPlugin @Inject constructor(
private val disposable = CompositeDisposable()
private val handler = Handler(HandlerThread(this::class.simpleName + "Handler").also { it.start() }.looper)
private val listLog: MutableList<EventNSClientNewLog> = ArrayList()
var textLog = fromHtml("")
var paused = false
var autoscroll = false
var status = ""
var nsClientService: NSClientService? = null
override var status = ""
override var nsClientService: NSClientService? = null
val isAllowed: Boolean
get() = nsClientReceiverDelegate.allowed
val blockingReason: String
get() = nsClientReceiverDelegate.blockingReason
override fun onStart() {
paused = sp.getBoolean(R.string.key_nsclientinternal_paused, false)
autoscroll = sp.getBoolean(R.string.key_nsclientinternal_autoscroll, true)
context.bindService(Intent(context, NSClientService::class.java), mConnection, Context.BIND_AUTO_CREATE)
super.onStart()
nsClientReceiverDelegate.grabReceiversState()
@ -93,8 +92,10 @@ class NSClientPlugin @Inject constructor(
.toObservable(EventNSClientStatus::class.java)
.observeOn(aapsSchedulers.io)
.subscribe({ event: EventNSClientStatus ->
status = event.getStatus(rh)
rxBus.send(EventNSClientUpdateGUI())
if (event.version == NsClient.Version.V1) {
status = event.getStatus(rh)
rxBus.send(EventNSClientUpdateGUI())
}
}, fabricPrivacy::logException)
disposable += rxBus
.toObservable(EventNetworkChange::class.java)
@ -112,6 +113,7 @@ class NSClientPlugin @Inject constructor(
.toObservable(EventNSClientNewLog::class.java)
.observeOn(aapsSchedulers.io)
.subscribe({ event: EventNSClientNewLog ->
if (event.version != NsClient.Version.V1) return@subscribe
addToLog(event)
aapsLogger.debug(LTag.NSCLIENT, event.action + " " + event.logText)
}, fabricPrivacy::logException)
@ -138,17 +140,13 @@ class NSClientPlugin @Inject constructor(
preferenceFragment.findPreference<SwitchPreference>(rh.gs(R.string.key_ns_create_announcements_from_errors))?.isVisible = false
preferenceFragment.findPreference<SwitchPreference>(rh.gs(R.string.key_ns_create_announcements_from_carbs_req))?.isVisible = false
// preferenceFragment.findPreference<SwitchPreference>(rh.gs(R.string.key_ns_sync_use_absolute))?.isVisible = false
} else {
// APS or pumpControl mode
// preferenceFragment.findPreference<SwitchPreference>(rh.gs(R.string.key_ns_receive_profile_switch))?.isVisible = buildHelper.isEngineeringMode()
// preferenceFragment.findPreference<SwitchPreference>(rh.gs(R.string.key_ns_receive_insulin))?.isVisible = buildHelper.isEngineeringMode()
// preferenceFragment.findPreference<SwitchPreference>(rh.gs(R.string.key_ns_receive_carbs))?.isVisible = buildHelper.isEngineeringMode()
// preferenceFragment.findPreference<SwitchPreference>(rh.gs(R.string.key_ns_receive_temp_target))?.isVisible = buildHelper.isEngineeringMode()
}
preferenceFragment.findPreference<SwitchPreference>(rh.gs(R.string.key_ns_receive_tbr_eb))?.isVisible = buildHelper.isEngineeringMode()
}
override val hasWritePermission: Boolean get() = nsClientService?.hasWriteAuth ?: false
override val connected: Boolean get() = nsClientService?.isConnected ?: false
private val mConnection: ServiceConnection = object : ServiceConnection {
override fun onServiceDisconnected(name: ComponentName) {
aapsLogger.debug(LTag.NSCLIENT, "Service is disconnected")
@ -162,55 +160,53 @@ class NSClientPlugin @Inject constructor(
}
}
@Synchronized fun clearLog() {
override fun clearLog() {
handler.post {
synchronized(listLog) { listLog.clear() }
rxBus.send(EventNSClientUpdateGUI())
}
}
@Synchronized private fun addToLog(ev: EventNSClientNewLog) {
handler.post {
synchronized(listLog) {
listLog.add(ev)
// remove the first line if log is too large
if (listLog.size >= Constants.MAX_LOG_LINES) {
listLog.removeAt(0)
}
private fun addToLog(ev: EventNSClientNewLog) {
synchronized(listLog) {
listLog.add(ev)
// remove the first line if log is too large
if (listLog.size >= Constants.MAX_LOG_LINES) {
listLog.removeAt(0)
}
rxBus.send(EventNSClientUpdateGUI())
}
rxBus.send(EventNSClientUpdateGUI())
}
@Synchronized fun updateLog() {
override fun textLog(): Spanned {
try {
val newTextLog = StringBuilder()
synchronized(listLog) {
for (log in listLog) {
newTextLog.append(log.toPreparedHtml())
}
for (log in listLog) newTextLog.append(log.toPreparedHtml())
}
textLog = fromHtml(newTextLog.toString())
return fromHtml(newTextLog.toString())
} catch (e: OutOfMemoryError) {
ToastUtils.showToastInUiThread(context, rxBus, "Out of memory!\nStop using this phone !!!", R.raw.error)
}
return fromHtml("")
}
fun resend(reason: String) {
override fun resend(reason: String) {
nsClientService?.resend(reason)
}
fun pause(newState: Boolean) {
override fun pause(newState: Boolean) {
sp.putBoolean(R.string.key_nsclientinternal_paused, newState)
paused = newState
rxBus.send(EventPreferenceChange(rh, R.string.key_nsclientinternal_paused))
}
fun url(): String = nsClientService?.nsURL ?: ""
fun hasWritePermission(): Boolean = nsClientService?.hasWriteAuth ?: false
override val version: NsClient.Version
get() = NsClient.Version.V1
override val address: String get() = nsClientService?.nsURL ?: ""
fun handleClearAlarm(originalAlarm: NSAlarm, silenceTimeInMilliseconds: Long) {
if (!isEnabled(PluginType.GENERAL)) return
if (!isEnabled()) return
if (!sp.getBoolean(R.string.key_ns_upload, true)) {
aapsLogger.debug(LTag.NSCLIENT, "Upload disabled. Message dropped")
return
@ -223,7 +219,15 @@ class NSClientPlugin @Inject constructor(
})
}
fun updateLatestDateReceivedIfNewer(latestReceived: Long) {
override fun updateLatestBgReceivedIfNewer(latestReceived: Long) {
nsClientService?.let { if (latestReceived > it.latestDateInReceivedData) it.latestDateInReceivedData = latestReceived }
}
override fun updateLatestTreatmentReceivedIfNewer(latestReceived: Long) {
nsClientService?.let { if (latestReceived > it.latestDateInReceivedData) it.latestDateInReceivedData = latestReceived }
}
override fun resetToFullSync() {
dataSyncSelector.resetToNextFullSync()
}
}

View file

@ -1,4 +1,4 @@
package info.nightscout.androidaps.plugins.general.nsclient
package info.nightscout.androidaps.plugins.sync.nsclient
import android.content.Context
import androidx.work.Worker
@ -19,8 +19,9 @@ import info.nightscout.androidaps.interfaces.DataSyncSelector.PairProfileSwitch
import info.nightscout.androidaps.interfaces.DataSyncSelector.PairTemporaryBasal
import info.nightscout.androidaps.interfaces.DataSyncSelector.PairTemporaryTarget
import info.nightscout.androidaps.interfaces.DataSyncSelector.PairTherapyEvent
import info.nightscout.androidaps.plugins.general.nsclient.acks.NSUpdateAck
import info.nightscout.androidaps.plugins.general.nsclient.events.EventNSClientNewLog
import info.nightscout.androidaps.interfaces.NsClient
import info.nightscout.androidaps.plugins.sync.nsShared.events.EventNSClientNewLog
import info.nightscout.androidaps.plugins.sync.nsclient.acks.NSUpdateAck
import info.nightscout.androidaps.receivers.DataWorkerStorage
import info.nightscout.rx.AapsSchedulers
import info.nightscout.rx.bus.RxBus
@ -50,7 +51,7 @@ class NSClientUpdateRemoveAckWorker(
is PairTemporaryTarget -> {
val pair = ack.originalObject
dataSyncSelector.confirmLastTempTargetsIdIfGreater(pair.updateRecordId)
rxBus.send(EventNSClientNewLog("DBUPDATE", "Acked TemporaryTarget" + ack._id))
rxBus.send(EventNSClientNewLog("DBUPDATE", "Acked TemporaryTarget" + ack._id, NsClient.Version.V1))
// Send new if waiting
dataSyncSelector.processChangedTempTargetsCompat()
ret = Result.success(workDataOf("ProcessedData" to pair.toString()))
@ -59,7 +60,7 @@ class NSClientUpdateRemoveAckWorker(
is PairGlucoseValue -> {
val pair = ack.originalObject
dataSyncSelector.confirmLastGlucoseValueIdIfGreater(pair.updateRecordId)
rxBus.send(EventNSClientNewLog("DBUPDATE", "Acked GlucoseValue " + ack._id))
rxBus.send(EventNSClientNewLog("DBUPDATE", "Acked GlucoseValue " + ack._id, NsClient.Version.V1))
// Send new if waiting
dataSyncSelector.processChangedGlucoseValuesCompat()
ret = Result.success(workDataOf("ProcessedData" to pair.toString()))
@ -68,7 +69,7 @@ class NSClientUpdateRemoveAckWorker(
is PairFood -> {
val pair = ack.originalObject
dataSyncSelector.confirmLastFoodIdIfGreater(pair.updateRecordId)
rxBus.send(EventNSClientNewLog("DBUPDATE", "Acked Food " + ack._id))
rxBus.send(EventNSClientNewLog("DBUPDATE", "Acked Food " + ack._id, NsClient.Version.V1))
// Send new if waiting
dataSyncSelector.processChangedFoodsCompat()
ret = Result.success(workDataOf("ProcessedData" to pair.toString()))
@ -77,7 +78,7 @@ class NSClientUpdateRemoveAckWorker(
is PairTherapyEvent -> {
val pair = ack.originalObject
dataSyncSelector.confirmLastTherapyEventIdIfGreater(pair.updateRecordId)
rxBus.send(EventNSClientNewLog("DBUPDATE", "Acked TherapyEvent " + ack._id))
rxBus.send(EventNSClientNewLog("DBUPDATE", "Acked TherapyEvent " + ack._id, NsClient.Version.V1))
// Send new if waiting
dataSyncSelector.processChangedTherapyEventsCompat()
ret = Result.success(workDataOf("ProcessedData" to pair.toString()))
@ -86,7 +87,7 @@ class NSClientUpdateRemoveAckWorker(
is PairBolus -> {
val pair = ack.originalObject
dataSyncSelector.confirmLastBolusIdIfGreater(pair.updateRecordId)
rxBus.send(EventNSClientNewLog("DBUPDATE", "Acked Bolus " + ack._id))
rxBus.send(EventNSClientNewLog("DBUPDATE", "Acked Bolus " + ack._id, NsClient.Version.V1))
// Send new if waiting
dataSyncSelector.processChangedBolusesCompat()
ret = Result.success(workDataOf("ProcessedData" to pair.toString()))
@ -95,7 +96,7 @@ class NSClientUpdateRemoveAckWorker(
is PairCarbs -> {
val pair = ack.originalObject
dataSyncSelector.confirmLastCarbsIdIfGreater(pair.updateRecordId)
rxBus.send(EventNSClientNewLog("DBUPDATE", "Acked Carbs " + ack._id))
rxBus.send(EventNSClientNewLog("DBUPDATE", "Acked Carbs " + ack._id, NsClient.Version.V1))
// Send new if waiting
dataSyncSelector.processChangedCarbsCompat()
ret = Result.success(workDataOf("ProcessedData" to pair.toString()))
@ -104,7 +105,7 @@ class NSClientUpdateRemoveAckWorker(
is PairBolusCalculatorResult -> {
val pair = ack.originalObject
dataSyncSelector.confirmLastBolusCalculatorResultsIdIfGreater(pair.updateRecordId)
rxBus.send(EventNSClientNewLog("DBUPDATE", "Acked BolusCalculatorResult " + ack._id))
rxBus.send(EventNSClientNewLog("DBUPDATE", "Acked BolusCalculatorResult " + ack._id, NsClient.Version.V1))
// Send new if waiting
dataSyncSelector.processChangedBolusCalculatorResultsCompat()
ret = Result.success(workDataOf("ProcessedData" to pair.toString()))
@ -113,7 +114,7 @@ class NSClientUpdateRemoveAckWorker(
is PairTemporaryBasal -> {
val pair = ack.originalObject
dataSyncSelector.confirmLastTemporaryBasalIdIfGreater(pair.updateRecordId)
rxBus.send(EventNSClientNewLog("DBUPDATE", "Acked TemporaryBasal " + ack._id))
rxBus.send(EventNSClientNewLog("DBUPDATE", "Acked TemporaryBasal " + ack._id, NsClient.Version.V1))
// Send new if waiting
dataSyncSelector.processChangedTemporaryBasalsCompat()
ret = Result.success(workDataOf("ProcessedData" to pair.toString()))
@ -122,7 +123,7 @@ class NSClientUpdateRemoveAckWorker(
is PairExtendedBolus -> {
val pair = ack.originalObject
dataSyncSelector.confirmLastExtendedBolusIdIfGreater(pair.updateRecordId)
rxBus.send(EventNSClientNewLog("DBUPDATE", "Acked ExtendedBolus " + ack._id))
rxBus.send(EventNSClientNewLog("DBUPDATE", "Acked ExtendedBolus " + ack._id, NsClient.Version.V1))
// Send new if waiting
dataSyncSelector.processChangedExtendedBolusesCompat()
ret = Result.success(workDataOf("ProcessedData" to pair.toString()))
@ -131,7 +132,7 @@ class NSClientUpdateRemoveAckWorker(
is PairProfileSwitch -> {
val pair = ack.originalObject
dataSyncSelector.confirmLastProfileSwitchIdIfGreater(pair.updateRecordId)
rxBus.send(EventNSClientNewLog("DBUPDATE", "Acked ProfileSwitch " + ack._id))
rxBus.send(EventNSClientNewLog("DBUPDATE", "Acked ProfileSwitch " + ack._id, NsClient.Version.V1))
// Send new if waiting
dataSyncSelector.processChangedProfileSwitchesCompat()
ret = Result.success(workDataOf("ProcessedData" to pair.toString()))
@ -140,7 +141,7 @@ class NSClientUpdateRemoveAckWorker(
is PairEffectiveProfileSwitch -> {
val pair = ack.originalObject
dataSyncSelector.confirmLastEffectiveProfileSwitchIdIfGreater(pair.updateRecordId)
rxBus.send(EventNSClientNewLog("DBUPDATE", "Acked EffectiveProfileSwitch " + ack._id))
rxBus.send(EventNSClientNewLog("DBUPDATE", "Acked EffectiveProfileSwitch " + ack._id, NsClient.Version.V1))
// Send new if waiting
dataSyncSelector.processChangedEffectiveProfileSwitchesCompat()
ret = Result.success(workDataOf("ProcessedData" to pair.toString()))
@ -149,7 +150,7 @@ class NSClientUpdateRemoveAckWorker(
is PairOfflineEvent -> {
val pair = ack.originalObject
dataSyncSelector.confirmLastOfflineEventIdIfGreater(pair.updateRecordId)
rxBus.send(EventNSClientNewLog("DBUPDATE", "Acked OfflineEvent" + ack._id))
rxBus.send(EventNSClientNewLog("DBUPDATE", "Acked OfflineEvent" + ack._id, NsClient.Version.V1))
// Send new if waiting
dataSyncSelector.processChangedOfflineEventsCompat()
ret = Result.success(workDataOf("ProcessedData" to pair.toString()))

View file

@ -1,4 +1,4 @@
package info.nightscout.androidaps.plugins.general.nsclient
package info.nightscout.androidaps.plugins.sync.nsclient
import info.nightscout.androidaps.R
import info.nightscout.androidaps.events.EventPreferenceChange

View file

@ -1,4 +1,4 @@
package info.nightscout.androidaps.plugins.general.nsclient.acks
package info.nightscout.androidaps.plugins.sync.nsclient.acks
import info.nightscout.rx.bus.RxBus
import info.nightscout.rx.events.Event
@ -16,7 +16,7 @@ class NSAddAck(
) : Event(), Ack {
var id: String? = null
var nsClientID: String? = null
private var nsClientID: String? = null
var json: JSONObject? = null
override fun call(vararg args: Any) {
// Regular response

View file

@ -1,4 +1,4 @@
package info.nightscout.androidaps.plugins.general.nsclient.acks
package info.nightscout.androidaps.plugins.sync.nsclient.acks
import info.nightscout.rx.bus.RxBus
import info.nightscout.rx.events.Event

View file

@ -1,4 +1,4 @@
package info.nightscout.androidaps.plugins.general.nsclient.acks
package info.nightscout.androidaps.plugins.sync.nsclient.acks
import info.nightscout.rx.bus.RxBus
import info.nightscout.rx.events.Event

View file

@ -1,4 +1,4 @@
package info.nightscout.androidaps.plugins.general.nsclient.data;
package info.nightscout.androidaps.plugins.sync.nsclient.data;
/**
* Created by mike on 11.06.2017.

View file

@ -1,4 +1,4 @@
package info.nightscout.androidaps.plugins.general.nsclient.data
package info.nightscout.androidaps.plugins.sync.nsclient.data
import info.nightscout.interfaces.utils.JsonHelper
import org.json.JSONObject

View file

@ -0,0 +1,173 @@
package info.nightscout.androidaps.plugins.sync.nsclient.data
import info.nightscout.androidaps.R
import info.nightscout.androidaps.interfaces.NsClient
import info.nightscout.androidaps.plugins.configBuilder.RunningConfiguration
import info.nightscout.androidaps.utils.DateUtil
import info.nightscout.interfaces.Config
import info.nightscout.interfaces.utils.HtmlHelper
import info.nightscout.interfaces.utils.JsonHelper
import info.nightscout.sdk.remotemodel.RemoteDeviceStatus
import info.nightscout.shared.sharedPreferences.SP
import javax.inject.Inject
import javax.inject.Singleton
/*
{
"_id": "594fdcec327b83c81b6b8c0f",
"device": "openaps://Sony D5803",
"pump": {
"battery": {
"percent": 100
},
"status": {
"status": "normal",
"timestamp": "2017-06-25T15:50:14Z"
},
"extended": {
"Version": "1.5-ac98852-2017.06.25",
"PumpIOB": 1.13,
"LastBolus": "25. 6. 2017 17:25:00",
"LastBolusAmount": 0.3,
"BaseBasalRate": 0.4,
"ActiveProfile": "2016 +30%"
},
"reservoir": 109,
"clock": "2017-06-25T15:55:10Z"
},
"openaps": {
"suggested": {
"temp": "absolute",
"bg": 115.9,
"tick": "+5",
"eventualBG": 105,
"snoozeBG": 105,
"predBGs": {
"IOB": [116, 114, 112, 110, 109, 107, 106, 105, 105, 104, 104, 104, 104, 104, 104, 104, 104, 105, 105, 105, 105, 105, 106, 106, 106, 106, 106, 107]
},
"sensitivityRatio": 0.81,
"variable_sens": 137.3,
"COB": 0,
"IOB": -0.035,
"reason": "COB: 0, Dev: -18, BGI: 0.43, ISF: 216, Target: 99; Eventual BG 105 > 99 but Min. Delta -2.60 < Exp. Delta 0.1; setting current basal of 0.4 as temp. Suggested rate is same as profile rate, no temp basal is active, doing nothing",
"timestamp": "2017-06-25T15:55:10Z"
},
"iob": {
"iob": -0.035,
"basaliob": -0.035,
"activity": -0.0004,
"time": "2017-06-25T15:55:10Z"
}
},
"uploaderBattery": 93,
"created_at": "2017-06-25T15:55:10Z",
"NSCLIENT_ID": 1498406118857
}
*/
@Suppress("SpellCheckingInspection")
@Singleton
class NSDeviceStatusHandler @Inject constructor(
private val sp: SP,
private val config: Config,
private val dateUtil: DateUtil,
private val runningConfiguration: RunningConfiguration,
private val processedDeviceStatusData: ProcessedDeviceStatusData
) {
fun handleNewData(deviceStatuses: Array<RemoteDeviceStatus>, version: NsClient.Version) {
var configurationDetected = false
for (i in deviceStatuses.size - 1 downTo 0) {
val nsDeviceStatus = deviceStatuses[i]
updatePumpData(nsDeviceStatus)
updateDeviceData(nsDeviceStatus)
updateOpenApsData(nsDeviceStatus)
updateUploaderData(nsDeviceStatus)
nsDeviceStatus.pump?.let { sp.putBoolean(R.string.key_ObjectivespumpStatusIsAvailableInNS, true) } // Objective 0
if (config.NSCLIENT && !configurationDetected)
nsDeviceStatus.configuration?.let {
// copy configuration of Insulin and Sensitivity from main AAPS
runningConfiguration.apply(it, version)
configurationDetected = true // pick only newest
}
}
}
private fun updateDeviceData(deviceStatus: RemoteDeviceStatus) {
val createdAt = deviceStatus.createdAt?.let { dateUtil.fromISODateString(it) } ?: return
processedDeviceStatusData.device?.let { if (createdAt < it.createdAt) return } // take only newer record
deviceStatus.device?.let {
if (it.startsWith("openaps://")) processedDeviceStatusData.device = ProcessedDeviceStatusData.Device(createdAt, it.substring(10))
}
}
private fun updatePumpData(remoteDeviceStatus: RemoteDeviceStatus) {
val pump = remoteDeviceStatus.pump ?: return
val clock = pump.clock?.let { dateUtil.fromISODateString(it) } ?: return
processedDeviceStatusData.pumpData?.let { if (clock < it.clock) return } // take only newer record
// create new status and process data
processedDeviceStatusData.pumpData = ProcessedDeviceStatusData.PumpData().also { deviceStatusPumpData ->
deviceStatusPumpData.clock = clock
pump.status?.status?.let { deviceStatusPumpData.status = it }
pump.reservoir?.let { deviceStatusPumpData.reservoir = it }
pump.reservoirDisplayOverride?.let { deviceStatusPumpData.reservoirDisplayOverride = it }
pump.battery?.percent?.let {
deviceStatusPumpData.isPercent = true
deviceStatusPumpData.percent = it
}
pump.battery?.voltage?.let {
deviceStatusPumpData.isPercent = false
deviceStatusPumpData.voltage = it
}
pump.extended?.let {
val extended = StringBuilder()
val keys: Iterator<*> = it.keys()
while (keys.hasNext()) {
val key = keys.next() as String
val value = it.getString(key)
extended.append("<b>").append(key).append(":</b> ").append(value).append("<br>")
}
deviceStatusPumpData.extended = HtmlHelper.fromHtml(extended.toString())
deviceStatusPumpData.activeProfileName = JsonHelper.safeGetStringAllowNull(it, "ActiveProfile", null)
}
}
}
private fun updateOpenApsData(remoteDeviceStatus: RemoteDeviceStatus) {
remoteDeviceStatus.openaps?.suggested?.let {
JsonHelper.safeGetString(it, "timestamp")?.let { timestamp ->
val clock = dateUtil.fromISODateString(timestamp)
// check if this is new data
if (clock > processedDeviceStatusData.openAPSData.clockSuggested) {
processedDeviceStatusData.openAPSData.suggested = it
processedDeviceStatusData.openAPSData.clockSuggested = clock
}
}
}
remoteDeviceStatus.openaps?.enacted?.let {
JsonHelper.safeGetString(it, "timestamp")?.let { timestamp ->
val clock = dateUtil.fromISODateString(timestamp)
// check if this is new data
if (clock > processedDeviceStatusData.openAPSData.clockEnacted) {
processedDeviceStatusData.openAPSData.enacted = it
processedDeviceStatusData.openAPSData.clockEnacted = clock
}
}
}
}
private fun updateUploaderData(remoteDeviceStatus: RemoteDeviceStatus) {
val clock = remoteDeviceStatus.createdAt?.let { dateUtil.fromISODateString(it) } ?: return
val device = remoteDeviceStatus.device ?: return
val battery = remoteDeviceStatus.uploaderBattery ?: remoteDeviceStatus.uploader?.battery ?: return
var uploader = processedDeviceStatusData.uploaderMap[device]
// check if this is new data
if (uploader == null || clock > uploader.clock) {
if (uploader == null) uploader = ProcessedDeviceStatusData.Uploader()
uploader.battery = battery
uploader.clock = clock
processedDeviceStatusData.uploaderMap[device] = uploader
}
}
}

View file

@ -1,4 +1,4 @@
package info.nightscout.androidaps.plugins.general.nsclient.data
package info.nightscout.androidaps.plugins.sync.nsclient.data
import info.nightscout.interfaces.utils.JsonHelper
import org.json.JSONObject

View file

@ -1,4 +1,4 @@
package info.nightscout.androidaps.plugins.general.nsclient.data
package info.nightscout.androidaps.plugins.sync.nsclient.data
import android.content.Context
import info.nightscout.androidaps.R
@ -113,7 +113,6 @@ import javax.inject.Singleton
"activeProfile": "2016 +30%"
}
*/
@Suppress("SpellCheckingInspection")
@OpenForTesting
@Singleton
class NSSettingsStatus @Inject constructor(
@ -234,11 +233,6 @@ class NSSettingsStatus @Inject constructor(
fun pumpExtendedSettingsFields(): String =
JsonHelper.safeGetString(extendedPumpSettings(), "fields", "")
fun openAPSEnabledAlerts(): Boolean {
val openaps = JsonHelper.safeGetJSONObject(getExtendedSettings(), "openaps", null)
return JsonHelper.safeGetBoolean(openaps, "enableAlerts")
}
fun copyStatusLightsNsSettings(context: Context?) {
val action = Runnable {
getExtendedWarnValue("cage", "warn")?.let { sp.putDouble(R.string.key_statuslights_cage_warning, it) }

View file

@ -1,4 +1,4 @@
package info.nightscout.androidaps.plugins.general.nsclient.data
package info.nightscout.androidaps.plugins.sync.nsclient.data
import info.nightscout.interfaces.utils.JsonHelper
import org.json.JSONObject

View file

@ -0,0 +1,211 @@
package info.nightscout.androidaps.plugins.sync.nsclient.data
import android.text.Spanned
import dagger.android.HasAndroidInjector
import info.nightscout.androidaps.R
import info.nightscout.androidaps.interfaces.ResourceHelper
import info.nightscout.androidaps.plugins.aps.loop.APSResult
import info.nightscout.androidaps.utils.DateUtil
import info.nightscout.androidaps.utils.T
import info.nightscout.interfaces.utils.HtmlHelper
import info.nightscout.interfaces.utils.JsonHelper
import info.nightscout.interfaces.utils.Round
import info.nightscout.shared.sharedPreferences.SP
import org.json.JSONObject
import javax.inject.Inject
import javax.inject.Singleton
@Suppress("SpellCheckingInspection")
@Singleton
class ProcessedDeviceStatusData @Inject constructor(
private val rh: ResourceHelper,
private val dateUtil: DateUtil,
private val sp: SP
) {
enum class Levels(val level: Int) {
URGENT(2),
WARN(1),
INFO(0);
fun toColor(): String =
when (level) {
INFO.level -> "white"
WARN.level -> "yellow"
URGENT.level -> "red"
else -> "white"
}
}
class PumpData {
var clock = 0L
var isPercent = false
var percent = 0
var voltage = 0.0
var status = "N/A"
var reservoir = 0.0
var reservoirDisplayOverride = ""
var extended: Spanned? = null
var activeProfileName: String? = null
}
var pumpData: PumpData? = null
data class Device(
val createdAt: Long,
val device: String?
)
var device: Device? = null
class Uploader {
var clock = 0L
var battery = 0
}
val uploaderMap = HashMap<String, Uploader>()
class OpenAPSData {
var clockSuggested = 0L
var clockEnacted = 0L
var suggested: JSONObject? = null
var enacted: JSONObject? = null
}
var openAPSData = OpenAPSData()
// test warning level // color
fun pumpStatus(nsSettingsStatus: NSSettingsStatus): Spanned {
val pumpData = pumpData ?: return HtmlHelper.fromHtml("")
//String[] ALL_STATUS_FIELDS = {"reservoir", "battery", "clock", "status", "device"};
val string = StringBuilder()
.append("<span style=\"color:${rh.gac(R.attr.nsTitleColor)}\">")
.append(rh.gs(R.string.pump))
.append(": </span>")
// test warning level
val level = when {
pumpData.clock + nsSettingsStatus.extendedPumpSettings("urgentClock") * 60 * 1000L < dateUtil.now() -> Levels.URGENT
pumpData.reservoir < nsSettingsStatus.extendedPumpSettings("urgentRes") -> Levels.URGENT
pumpData.isPercent && pumpData.percent < nsSettingsStatus.extendedPumpSettings("urgentBattP") -> Levels.URGENT
!pumpData.isPercent && pumpData.voltage > 0 && pumpData.voltage < nsSettingsStatus.extendedPumpSettings("urgentBattV") -> Levels.URGENT
pumpData.clock + nsSettingsStatus.extendedPumpSettings("warnClock") * 60 * 1000L < dateUtil.now() -> Levels.WARN
pumpData.reservoir < nsSettingsStatus.extendedPumpSettings("warnRes") -> Levels.WARN
pumpData.isPercent && pumpData.percent < nsSettingsStatus.extendedPumpSettings("warnBattP") -> Levels.WARN
!pumpData.isPercent && pumpData.voltage > 0 && pumpData.voltage < nsSettingsStatus.extendedPumpSettings("warnBattV") -> Levels.WARN
else -> Levels.INFO
}
string.append("<span style=\"color:${level.toColor()}\">")
val insulinUnit = rh.gs(R.string.insulin_unit_shortname)
val fields = nsSettingsStatus.pumpExtendedSettingsFields()
if (pumpData.reservoirDisplayOverride != "")
string.append(pumpData.reservoirDisplayOverride).append("$insulinUnit ")
else if (fields.contains("reservoir")) string.append(pumpData.reservoir.toInt()).append("$insulinUnit ")
if (fields.contains("battery") && pumpData.isPercent) string.append(pumpData.percent).append("% ")
if (fields.contains("battery") && !pumpData.isPercent) string.append(Round.roundTo(pumpData.voltage, 0.001)).append(" ")
if (fields.contains("clock")) string.append(dateUtil.minAgo(rh, pumpData.clock)).append(" ")
if (fields.contains("status")) string.append(pumpData.status).append(" ")
if (fields.contains("device")) string.append(device).append(" ")
string.append("</span>") // color
return HtmlHelper.fromHtml(string.toString())
}
val extendedPumpStatus: Spanned get() = pumpData?.extended ?: HtmlHelper.fromHtml("")
val extendedOpenApsStatus: Spanned
get() {
val string = StringBuilder()
val enacted = openAPSData.enacted
val suggested = openAPSData.suggested
if (enacted != null && openAPSData.clockEnacted != openAPSData.clockSuggested) string
.append("<b>")
.append(dateUtil.minAgo(rh, openAPSData.clockEnacted))
.append("</b> ")
.append(JsonHelper.safeGetString(enacted, "reason"))
.append("<br>")
if (suggested != null) string
.append("<b>")
.append(dateUtil.minAgo(rh, openAPSData.clockSuggested))
.append("</b> ")
.append(JsonHelper.safeGetString(suggested, "reason"))
.append("<br>")
return HtmlHelper.fromHtml(string.toString())
}
val openApsStatus: Spanned
get() {
val string = StringBuilder()
.append("<span style=\"color:${rh.gac(R.attr.nsTitleColor)}\">")
.append(rh.gs(R.string.openaps_short))
.append(": </span>")
// test warning level
val level = when {
openAPSData.clockSuggested + T.mins(sp.getLong(R.string.key_nsalarm_urgent_staledatavalue, 31)).msecs() < dateUtil.now() -> Levels.URGENT
openAPSData.clockSuggested + T.mins(sp.getLong(R.string.key_nsalarm_staledatavalue, 16)).msecs() < dateUtil.now() -> Levels.WARN
else -> Levels.INFO
}
string.append("<span style=\"color:${level.toColor()}\">")
if (openAPSData.clockSuggested != 0L) string.append(dateUtil.minAgo(rh, openAPSData.clockSuggested)).append(" ")
string.append("</span>") // color
return HtmlHelper.fromHtml(string.toString())
}
val openApsTimestamp: Long
get() = if (openAPSData.clockSuggested != 0L) openAPSData.clockSuggested else -1
fun getAPSResult(injector: HasAndroidInjector): APSResult {
val result = APSResult(injector)
result.json = openAPSData.suggested
result.date = openAPSData.clockSuggested
return result
}
val uploaderStatus: String
get() {
val iterator: Iterator<*> = uploaderMap.entries.iterator()
var minBattery = 100
while (iterator.hasNext()) {
val pair = iterator.next() as Map.Entry<*, *>
val uploader = pair.value as Uploader
if (minBattery > uploader.battery) minBattery = uploader.battery
}
return "$minBattery%"
}
val uploaderStatusSpanned: Spanned
get() {
val string = StringBuilder()
string.append("<span style=\"color:${rh.gac(R.attr.nsTitleColor)}\">")
string.append(rh.gs(R.string.uploader_short))
string.append(": </span>")
val iterator: Iterator<*> = uploaderMap.entries.iterator()
var minBattery = 100
while (iterator.hasNext()) {
val pair = iterator.next() as Map.Entry<*, *>
val uploader = pair.value as Uploader
if (minBattery > uploader.battery) minBattery = uploader.battery
}
string.append(minBattery)
string.append("%")
return HtmlHelper.fromHtml(string.toString())
}
val extendedUploaderStatus: Spanned
get() {
val string = StringBuilder()
val iterator: Iterator<*> = uploaderMap.entries.iterator()
while (iterator.hasNext()) {
val pair = iterator.next() as Map.Entry<*, *>
val uploader = pair.value as Uploader
val device = pair.key as String
string.append("<b>").append(device).append(":</b> ").append(uploader.battery).append("%<br>")
}
return HtmlHelper.fromHtml(string.toString())
}
}

View file

@ -1,4 +1,4 @@
package info.nightscout.androidaps.plugins.general.nsclient.services
package info.nightscout.androidaps.plugins.sync.nsclient.services
import android.annotation.SuppressLint
import android.content.Context
@ -12,42 +12,47 @@ import android.os.SystemClock
import androidx.work.OneTimeWorkRequest
import com.google.common.base.Charsets
import com.google.common.hash.Hashing
import com.google.gson.GsonBuilder
import com.google.gson.JsonDeserializer
import dagger.android.DaggerService
import dagger.android.HasAndroidInjector
import info.nightscout.androidaps.R
import info.nightscout.androidaps.database.AppRepository
import info.nightscout.androidaps.events.EventPreferenceChange
import info.nightscout.interfaces.BuildHelper
import info.nightscout.interfaces.Config
import info.nightscout.androidaps.interfaces.DataSyncSelector
import info.nightscout.androidaps.interfaces.NsClient
import info.nightscout.androidaps.interfaces.ResourceHelper
import info.nightscout.androidaps.plugins.general.nsclient.NSClientAddAckWorker
import info.nightscout.androidaps.plugins.general.nsclient.NSClientAddUpdateWorker
import info.nightscout.androidaps.plugins.general.nsclient.NSClientMbgWorker
import info.nightscout.androidaps.plugins.general.nsclient.NSClientPlugin
import info.nightscout.androidaps.plugins.general.nsclient.NSClientUpdateRemoveAckWorker
import info.nightscout.androidaps.plugins.general.nsclient.acks.NSAddAck
import info.nightscout.androidaps.plugins.general.nsclient.acks.NSAuthAck
import info.nightscout.androidaps.plugins.general.nsclient.acks.NSUpdateAck
import info.nightscout.androidaps.plugins.general.nsclient.data.AlarmAck
import info.nightscout.androidaps.plugins.general.nsclient.data.NSAlarm
import info.nightscout.androidaps.plugins.general.nsclient.data.NSDeviceStatus
import info.nightscout.androidaps.plugins.general.nsclient.data.NSSettingsStatus
import info.nightscout.androidaps.plugins.general.nsclient.events.EventNSClientNewLog
import info.nightscout.androidaps.plugins.general.nsclient.events.EventNSClientStatus
import info.nightscout.androidaps.plugins.general.nsclient.events.EventNSClientUpdateGUI
import info.nightscout.androidaps.plugins.sync.nsShared.events.EventNSClientUpdateGUI
import info.nightscout.androidaps.plugins.general.overview.events.EventDismissNotification
import info.nightscout.androidaps.plugins.general.overview.events.EventNewNotification
import info.nightscout.interfaces.notifications.Notification
import info.nightscout.androidaps.plugins.general.overview.notifications.NotificationWithAction
import info.nightscout.androidaps.plugins.source.NSClientSourcePlugin.NSClientSourceWorker
import info.nightscout.androidaps.plugins.source.NSClientSourcePlugin
import info.nightscout.androidaps.plugins.sync.nsShared.StoreDataForDb
import info.nightscout.androidaps.plugins.sync.nsShared.events.EventNSClientNewLog
import info.nightscout.androidaps.plugins.sync.nsShared.events.EventNSClientStatus
import info.nightscout.androidaps.plugins.sync.nsclient.NSClientAddAckWorker
import info.nightscout.androidaps.plugins.sync.nsclient.NSClientAddUpdateWorker
import info.nightscout.androidaps.plugins.sync.nsclient.NSClientMbgWorker
import info.nightscout.androidaps.plugins.sync.nsclient.NSClientPlugin
import info.nightscout.androidaps.plugins.sync.nsclient.NSClientUpdateRemoveAckWorker
import info.nightscout.androidaps.plugins.sync.nsclient.acks.NSAddAck
import info.nightscout.androidaps.plugins.sync.nsclient.acks.NSAuthAck
import info.nightscout.androidaps.plugins.sync.nsclient.acks.NSUpdateAck
import info.nightscout.androidaps.plugins.sync.nsclient.data.AlarmAck
import info.nightscout.androidaps.plugins.sync.nsclient.data.NSAlarm
import info.nightscout.androidaps.plugins.sync.nsclient.data.NSDeviceStatusHandler
import info.nightscout.androidaps.plugins.sync.nsclient.data.NSSettingsStatus
import info.nightscout.androidaps.plugins.sync.nsclientV3.NSClientV3Plugin
import info.nightscout.androidaps.receivers.DataWorkerStorage
import info.nightscout.androidaps.utils.DateUtil
import info.nightscout.androidaps.utils.FabricPrivacy
import info.nightscout.androidaps.utils.T.Companion.mins
import info.nightscout.interfaces.BuildHelper
import info.nightscout.interfaces.Config
import info.nightscout.interfaces.notifications.Notification
import info.nightscout.interfaces.utils.JsonHelper.safeGetString
import info.nightscout.interfaces.utils.JsonHelper.safeGetStringAllowNull
import info.nightscout.androidaps.utils.T.Companion.mins
import info.nightscout.plugins.general.food.FoodPlugin.FoodWorker
import info.nightscout.plugins.general.food.FoodPlugin
import info.nightscout.plugins.profile.ProfilePlugin
import info.nightscout.rx.AapsSchedulers
import info.nightscout.rx.bus.RxBus
@ -56,6 +61,7 @@ import info.nightscout.rx.events.EventConfigBuilderChange
import info.nightscout.rx.events.EventNSClientRestart
import info.nightscout.rx.logging.AAPSLogger
import info.nightscout.rx.logging.LTag
import info.nightscout.sdk.remotemodel.RemoteDeviceStatus
import info.nightscout.shared.sharedPreferences.SP
import io.reactivex.rxjava3.disposables.CompositeDisposable
import io.reactivex.rxjava3.kotlin.plusAssign
@ -69,13 +75,13 @@ import java.net.URISyntaxException
import java.util.Locale
import javax.inject.Inject
class NSClientService : DaggerService() {
class NSClientService : DaggerService(), NsClient.NSClientService {
@Inject lateinit var injector: HasAndroidInjector
@Inject lateinit var aapsLogger: AAPSLogger
@Inject lateinit var aapsSchedulers: AapsSchedulers
@Inject lateinit var nsSettingsStatus: NSSettingsStatus
@Inject lateinit var nsDeviceStatus: NSDeviceStatus
@Inject lateinit var nsDeviceStatusHandler: NSDeviceStatusHandler
@Inject lateinit var rxBus: RxBus
@Inject lateinit var rh: ResourceHelper
@Inject lateinit var sp: SP
@ -206,13 +212,13 @@ class NSClientService : DaggerService() {
connectionStatus += ')'
isConnected = true
hasWriteAuth = ack.write && ack.writeTreatment
rxBus.send(EventNSClientStatus(connectionStatus))
rxBus.send(EventNSClientNewLog("AUTH", connectionStatus))
rxBus.send(EventNSClientStatus(connectionStatus, NsClient.Version.V1))
rxBus.send(EventNSClientNewLog("AUTH", connectionStatus, NsClient.Version.V1))
if (!ack.write) {
rxBus.send(EventNSClientNewLog("ERROR", "Write permission not granted "))
rxBus.send(EventNSClientNewLog("ERROR", "Write permission not granted ", NsClient.Version.V1))
}
if (!ack.writeTreatment) {
rxBus.send(EventNSClientNewLog("ERROR", "Write treatment permission not granted "))
rxBus.send(EventNSClientNewLog("ERROR", "Write treatment permission not granted ", NsClient.Version.V1))
}
if (!hasWriteAuth) {
val noWritePerm = Notification(Notification.NSCLIENT_NO_WRITE_PERMISSION, rh.gs(R.string.nowritepermission), Notification.URGENT)
@ -235,21 +241,21 @@ class NSClientService : DaggerService() {
fun initialize() {
dataCounter = 0
readPreferences()
@Suppress("UnstableApiUsage", "DEPRECATION")
@Suppress("DEPRECATION")
if (nsAPISecret != "") nsApiHashCode = Hashing.sha1().hashString(nsAPISecret, Charsets.UTF_8).toString()
rxBus.send(EventNSClientStatus("Initializing"))
rxBus.send(EventNSClientStatus("Initializing", NsClient.Version.V1))
if (!nsClientPlugin.isAllowed) {
rxBus.send(EventNSClientNewLog("NSCLIENT", nsClientPlugin.blockingReason))
rxBus.send(EventNSClientStatus(nsClientPlugin.blockingReason))
} else if (nsClientPlugin.paused) {
rxBus.send(EventNSClientNewLog("NSCLIENT", "paused"))
rxBus.send(EventNSClientStatus("Paused"))
rxBus.send(EventNSClientNewLog("NSCLIENT", nsClientPlugin.blockingReason, NsClient.Version.V1))
rxBus.send(EventNSClientStatus(nsClientPlugin.blockingReason, NsClient.Version.V1))
} else if (sp.getBoolean(R.string.key_nsclientinternal_paused, false)) {
rxBus.send(EventNSClientNewLog("NSCLIENT", "paused", NsClient.Version.V1))
rxBus.send(EventNSClientStatus("Paused", NsClient.Version.V1))
} else if (!nsEnabled) {
rxBus.send(EventNSClientNewLog("NSCLIENT", "disabled"))
rxBus.send(EventNSClientStatus("Disabled"))
rxBus.send(EventNSClientNewLog("NSCLIENT", "disabled", NsClient.Version.V1))
rxBus.send(EventNSClientStatus("Disabled", NsClient.Version.V1))
} else if (nsURL != "" && (buildHelper.isEngineeringMode() || nsURL.lowercase(Locale.getDefault()).startsWith("https://"))) {
try {
rxBus.send(EventNSClientStatus("Connecting ..."))
rxBus.send(EventNSClientStatus("Connecting ...", NsClient.Version.V1))
val opt = IO.Options()
opt.forceNew = true
opt.reconnection = true
@ -260,7 +266,7 @@ class NSClientService : DaggerService() {
socket.on(Socket.EVENT_CONNECT_ERROR, onError)
socket.on(Socket.EVENT_CONNECT_TIMEOUT, onError)
socket.on(Socket.EVENT_PING, onPing)
rxBus.send(EventNSClientNewLog("NSCLIENT", "do connect"))
rxBus.send(EventNSClientNewLog("NSCLIENT", "do connect", NsClient.Version.V1))
socket.connect()
socket.on("dataUpdate", onDataUpdate)
socket.on("announcement", onAnnouncement)
@ -269,25 +275,25 @@ class NSClientService : DaggerService() {
socket.on("clear_alarm", onClearAlarm)
}
} catch (e: URISyntaxException) {
rxBus.send(EventNSClientNewLog("NSCLIENT", "Wrong URL syntax"))
rxBus.send(EventNSClientStatus("Wrong URL syntax"))
rxBus.send(EventNSClientNewLog("NSCLIENT", "Wrong URL syntax", NsClient.Version.V1))
rxBus.send(EventNSClientStatus("Wrong URL syntax", NsClient.Version.V1))
} catch (e: RuntimeException) {
rxBus.send(EventNSClientNewLog("NSCLIENT", "Wrong URL syntax"))
rxBus.send(EventNSClientStatus("Wrong URL syntax"))
rxBus.send(EventNSClientNewLog("NSCLIENT", "Wrong URL syntax", NsClient.Version.V1))
rxBus.send(EventNSClientStatus("Wrong URL syntax", NsClient.Version.V1))
}
} else if (nsURL.lowercase(Locale.getDefault()).startsWith("http://")) {
rxBus.send(EventNSClientNewLog("NSCLIENT", "NS URL not encrypted"))
rxBus.send(EventNSClientStatus("Not encrypted"))
rxBus.send(EventNSClientNewLog("NSCLIENT", "NS URL not encrypted", NsClient.Version.V1))
rxBus.send(EventNSClientStatus("Not encrypted", NsClient.Version.V1))
} else {
rxBus.send(EventNSClientNewLog("NSCLIENT", "No NS URL specified"))
rxBus.send(EventNSClientStatus("Not configured"))
rxBus.send(EventNSClientNewLog("NSCLIENT", "No NS URL specified", NsClient.Version.V1))
rxBus.send(EventNSClientStatus("Not configured", NsClient.Version.V1))
}
}
private val onConnect = Emitter.Listener {
connectCounter++
val socketId = socket?.id() ?: "NULL"
rxBus.send(EventNSClientNewLog("NSCLIENT", "connect #$connectCounter event. ID: $socketId"))
rxBus.send(EventNSClientNewLog("NSCLIENT", "connect #$connectCounter event. ID: $socketId", NsClient.Version.V1))
if (socket != null) sendAuthMessage(NSAuthAck(rxBus))
watchdog()
}
@ -301,16 +307,16 @@ class NSClientService : DaggerService() {
reconnections.remove(r)
}
}
rxBus.send(EventNSClientNewLog("WATCHDOG", "connections in last " + WATCHDOG_INTERVAL_MINUTES + " minutes: " + reconnections.size + "/" + WATCHDOG_MAX_CONNECTIONS))
rxBus.send(EventNSClientNewLog("WATCHDOG", "connections in last " + WATCHDOG_INTERVAL_MINUTES + " minutes: " + reconnections.size + "/" + WATCHDOG_MAX_CONNECTIONS, NsClient.Version.V1))
if (reconnections.size >= WATCHDOG_MAX_CONNECTIONS) {
val n = Notification(Notification.NS_MALFUNCTION, rh.gs(R.string.nsmalfunction), Notification.URGENT)
rxBus.send(EventNewNotification(n))
rxBus.send(EventNSClientNewLog("WATCHDOG", "pausing for $WATCHDOG_RECONNECT_IN minutes"))
rxBus.send(EventNSClientNewLog("WATCHDOG", "pausing for $WATCHDOG_RECONNECT_IN minutes", NsClient.Version.V1))
nsClientPlugin.pause(true)
rxBus.send(EventNSClientUpdateGUI())
Thread {
SystemClock.sleep(mins(WATCHDOG_RECONNECT_IN.toLong()).msecs())
rxBus.send(EventNSClientNewLog("WATCHDOG", "re-enabling NSClient"))
rxBus.send(EventNSClientNewLog("WATCHDOG", "re-enabling NSClient", NsClient.Version.V1))
nsClientPlugin.pause(false)
}.start()
}
@ -319,7 +325,7 @@ class NSClientService : DaggerService() {
private val onDisconnect = Emitter.Listener { args ->
aapsLogger.debug(LTag.NSCLIENT, "disconnect reason: {}", *args)
rxBus.send(EventNSClientNewLog("NSCLIENT", "disconnect event"))
rxBus.send(EventNSClientNewLog("NSCLIENT", "disconnect event", NsClient.Version.V1))
}
@Synchronized fun destroy() {
@ -331,7 +337,7 @@ class NSClientService : DaggerService() {
socket?.off("alarm")
socket?.off("urgent_alarm")
socket?.off("clear_alarm")
rxBus.send(EventNSClientNewLog("NSCLIENT", "destroy"))
rxBus.send(EventNSClientNewLog("NSCLIENT", "destroy", NsClient.Version.V1))
isConnected = false
hasWriteAuth = false
socket?.disconnect()
@ -350,11 +356,11 @@ class NSClientService : DaggerService() {
aapsLogger.error("Unhandled exception", e)
return
}
rxBus.send(EventNSClientNewLog("AUTH", "requesting auth"))
rxBus.send(EventNSClientNewLog("AUTH", "requesting auth", NsClient.Version.V1))
socket?.emit("authorize", authMessage, ack)
}
fun readPreferences() {
private fun readPreferences() {
nsEnabled = nsClientPlugin.isEnabled()
nsURL = sp.getString(R.string.key_nsclientinternal_url, "")
nsAPISecret = sp.getString(R.string.key_nsclientinternal_api_secret, "")
@ -366,10 +372,10 @@ class NSClientService : DaggerService() {
if (args.isNotEmpty() && args[0] != null) {
msg = args[0].toString()
}
rxBus.send(EventNSClientNewLog("ERROR", msg))
rxBus.send(EventNSClientNewLog("ERROR", msg, NsClient.Version.V1))
}
private val onPing = Emitter.Listener {
rxBus.send(EventNSClientNewLog("PING", "received"))
rxBus.send(EventNSClientNewLog("PING", "received", NsClient.Version.V1))
// send data if there is something waiting
resend("Ping received")
}
@ -439,7 +445,7 @@ class NSClientService : DaggerService() {
val data: JSONObject
try {
data = args[0] as JSONObject
rxBus.send(EventNSClientNewLog("CLEARALARM", "received"))
rxBus.send(EventNSClientNewLog("CLEARALARM", "received", NsClient.Version.V1))
rxBus.send(EventDismissNotification(Notification.NS_ALARM))
rxBus.send(EventDismissNotification(Notification.NS_URGENT_ALARM))
aapsLogger.debug(LTag.NSCLIENT, data.toString())
@ -458,19 +464,19 @@ class NSClientService : DaggerService() {
try {
// delta means only increment/changes are coming
val isDelta = data.has("delta")
rxBus.send(EventNSClientNewLog("DATA", "Data packet #" + dataCounter++ + if (isDelta) " delta" else " full"))
rxBus.send(EventNSClientNewLog("DATA", "Data packet #" + dataCounter++ + if (isDelta) " delta" else " full", NsClient.Version.V1))
if (data.has("status")) {
val status = data.getJSONObject("status")
nsSettingsStatus.handleNewData(status)
} else if (!isDelta) {
rxBus.send(EventNSClientNewLog("ERROR", "Unsupported Nightscout version "))
rxBus.send(EventNSClientNewLog("ERROR", "Unsupported Nightscout version ", NsClient.Version.V1))
}
if (data.has("profiles")) {
val profiles = data.getJSONArray("profiles")
if (profiles.length() > 0) {
// take the newest
val profileStoreJson = profiles[profiles.length() - 1] as JSONObject
rxBus.send(EventNSClientNewLog("PROFILE", "profile received"))
rxBus.send(EventNSClientNewLog("PROFILE", "profile received", NsClient.Version.V1))
dataWorkerStorage.enqueue(
OneTimeWorkRequest.Builder(ProfilePlugin.NSProfileWorker::class.java)
.setInputData(dataWorkerStorage.storeInputData(profileStoreJson))
@ -481,7 +487,7 @@ class NSClientService : DaggerService() {
if (data.has("treatments")) {
val treatments = data.getJSONArray("treatments")
val addedOrUpdatedTreatments = JSONArray()
if (treatments.length() > 0) rxBus.send(EventNSClientNewLog("DATA", "received " + treatments.length() + " treatments"))
if (treatments.length() > 0) rxBus.send(EventNSClientNewLog("DATA", "received " + treatments.length() + " treatments", NsClient.Version.V1))
for (index in 0 until treatments.length()) {
val jsonTreatment = treatments.getJSONObject(index)
val action = safeGetStringAllowNull(jsonTreatment, "action", null)
@ -497,24 +503,31 @@ class NSClientService : DaggerService() {
}
}
if (data.has("devicestatus")) {
val devicestatuses = data.getJSONArray("devicestatus")
if (devicestatuses.length() > 0) {
rxBus.send(EventNSClientNewLog("DATA", "received " + devicestatuses.length() + " device statuses"))
nsDeviceStatus.handleNewData(devicestatuses)
val deserializer: JsonDeserializer<JSONObject?> =
JsonDeserializer<JSONObject?> { json, _, _ ->
JSONObject(json.asJsonObject.toString())
}
val gson = GsonBuilder().also {
it.registerTypeAdapter(JSONObject::class.java, deserializer)
}.create()
val devicestatuses = gson.fromJson(data.getString("devicestatus"), Array<RemoteDeviceStatus>::class.java)
if (devicestatuses.isNotEmpty()) {
rxBus.send(EventNSClientNewLog("DATA", "received " + devicestatuses.size + " device statuses", NsClient.Version.V1))
nsDeviceStatusHandler.handleNewData(devicestatuses, NsClient.Version.V1)
}
}
if (data.has("food")) {
val foods = data.getJSONArray("food")
if (foods.length() > 0) rxBus.send(EventNSClientNewLog("DATA", "received " + foods.length() + " foods"))
if (foods.length() > 0) rxBus.send(EventNSClientNewLog("DATA", "received " + foods.length() + " foods", NsClient.Version.V1))
dataWorkerStorage.enqueue(
OneTimeWorkRequest.Builder(FoodWorker::class.java)
OneTimeWorkRequest.Builder(FoodPlugin.FoodWorker::class.java)
.setInputData(dataWorkerStorage.storeInputData(foods))
.build()
)
}
if (data.has("mbgs")) {
val mbgArray = data.getJSONArray("mbgs")
if (mbgArray.length() > 0) rxBus.send(EventNSClientNewLog("DATA", "received " + mbgArray.length() + " mbgs"))
if (mbgArray.length() > 0) rxBus.send(EventNSClientNewLog("DATA", "received " + mbgArray.length() + " mbgs", NsClient.Version.V1))
dataWorkerStorage.enqueue(
OneTimeWorkRequest.Builder(NSClientMbgWorker::class.java)
.setInputData(dataWorkerStorage.storeInputData(mbgArray))
@ -523,23 +536,26 @@ class NSClientService : DaggerService() {
}
if (data.has("cals")) {
val cals = data.getJSONArray("cals")
if (cals.length() > 0) rxBus.send(EventNSClientNewLog("DATA", "received " + cals.length() + " cals"))
if (cals.length() > 0) rxBus.send(EventNSClientNewLog("DATA", "received " + cals.length() + " cals", NsClient.Version.V1))
// Calibrations ignored
}
if (data.has("sgvs")) {
val sgvs = data.getJSONArray("sgvs")
if (sgvs.length() > 0) {
rxBus.send(EventNSClientNewLog("DATA", "received " + sgvs.length() + " sgvs"))
rxBus.send(EventNSClientNewLog("DATA", "received " + sgvs.length() + " sgvs", NsClient.Version.V1))
// Objective0
sp.putBoolean(R.string.key_ObjectivesbgIsAvailableInNS, true)
dataWorkerStorage.enqueue(
OneTimeWorkRequest.Builder(NSClientSourceWorker::class.java)
.setInputData(dataWorkerStorage.storeInputData(sgvs))
.build()
)
dataWorkerStorage
.beginUniqueWork(
NSClientV3Plugin.JOB_NAME,
OneTimeWorkRequest.Builder(NSClientSourcePlugin.NSClientSourceWorker::class.java)
.setInputData(dataWorkerStorage.storeInputData(sgvs))
.build()
).then(OneTimeWorkRequest.Builder(StoreDataForDb.StoreBgWorker::class.java).build())
.enqueue()
}
}
rxBus.send(EventNSClientNewLog("LAST", dateUtil.dateAndTimeString(latestDateInReceivedData)))
rxBus.send(EventNSClientNewLog("LAST", dateUtil.dateAndTimeString(latestDateInReceivedData), NsClient.Version.V1))
} catch (e: JSONException) {
aapsLogger.error("Unhandled exception", e)
}
@ -550,7 +566,7 @@ class NSClientService : DaggerService() {
}
}
fun dbUpdate(collection: String, _id: String?, data: JSONObject?, originalObject: Any, progress: String) {
override fun dbUpdate(collection: String, _id: String?, data: JSONObject?, originalObject: Any, progress: String) {
try {
if (_id == null) return
if (!isConnected || !hasWriteAuth) return
@ -562,7 +578,7 @@ class NSClientService : DaggerService() {
rxBus.send(
EventNSClientNewLog(
"DBUPDATE $collection", "Sent " + originalObject.javaClass.simpleName + " " +
"" + _id + " " + data + progress
"" + _id + " " + data + progress, NsClient.Version.V1
)
)
} catch (e: JSONException) {
@ -570,14 +586,14 @@ class NSClientService : DaggerService() {
}
}
fun dbAdd(collection: String, data: JSONObject, originalObject: Any, progress: String) {
override fun dbAdd(collection: String, data: JSONObject, originalObject: Any, progress: String) {
try {
if (!isConnected || !hasWriteAuth) return
val message = JSONObject()
message.put("collection", collection)
message.put("data", data)
socket?.emit("dbAdd", message, NSAddAck(aapsLogger, rxBus, originalObject))
rxBus.send(EventNSClientNewLog("DBADD $collection", "Sent " + originalObject.javaClass.simpleName + " " + data + " " + progress))
rxBus.send(EventNSClientNewLog("DBADD $collection", "Sent " + originalObject.javaClass.simpleName + " " + data + " " + progress, NsClient.Version.V1))
} catch (e: JSONException) {
aapsLogger.error("Unhandled exception", e)
}
@ -586,7 +602,7 @@ class NSClientService : DaggerService() {
fun sendAlarmAck(alarmAck: AlarmAck) {
if (!isConnected || !hasWriteAuth) return
socket?.emit("ack", alarmAck.level, alarmAck.group, alarmAck.silenceTime)
rxBus.send(EventNSClientNewLog("ALARMACK ", alarmAck.level.toString() + " " + alarmAck.group + " " + alarmAck.silenceTime))
rxBus.send(EventNSClientNewLog("ALARMACK ", alarmAck.level.toString() + " " + alarmAck.group + " " + alarmAck.silenceTime, NsClient.Version.V1))
}
fun resend(reason: String) {
@ -602,9 +618,9 @@ class NSClientService : DaggerService() {
// "AndroidAPS:NSClientService_onDataUpdate")
// wakeLock.acquire(mins(10).msecs())
try {
rxBus.send(EventNSClientNewLog("QUEUE", "Resend started: $reason"))
rxBus.send(EventNSClientNewLog("QUEUE", "Resend started: $reason", NsClient.Version.V1))
dataSyncSelector.doUpload()
rxBus.send(EventNSClientNewLog("QUEUE", "Resend ended: $reason"))
rxBus.send(EventNSClientNewLog("QUEUE", "Resend ended: $reason", NsClient.Version.V1))
} finally {
// if (wakeLock.isHeld) wakeLock.release()
}
@ -622,7 +638,7 @@ class NSClientService : DaggerService() {
val nsAlarm = NSAlarm(announcement)
val notification: Notification = NotificationWithAction(injector, nsAlarm)
rxBus.send(EventNewNotification(notification))
rxBus.send(EventNSClientNewLog("ANNOUNCEMENT", safeGetString(announcement, "message", "received")))
rxBus.send(EventNSClientNewLog("ANNOUNCEMENT", safeGetString(announcement, "message", "received"), NsClient.Version.V1))
aapsLogger.debug(LTag.NSCLIENT, announcement.toString())
}
}
@ -636,7 +652,7 @@ class NSClientService : DaggerService() {
val notification: Notification = NotificationWithAction(injector, nsAlarm)
rxBus.send(EventNewNotification(notification))
}
rxBus.send(EventNSClientNewLog("ALARM", safeGetString(alarm, "message", "received")))
rxBus.send(EventNSClientNewLog("ALARM", safeGetString(alarm, "message", "received"), NsClient.Version.V1))
aapsLogger.debug(LTag.NSCLIENT, alarm.toString())
}
}
@ -650,7 +666,7 @@ class NSClientService : DaggerService() {
val notification: Notification = NotificationWithAction(injector, nsAlarm)
rxBus.send(EventNewNotification(notification))
}
rxBus.send(EventNSClientNewLog("URGENTALARM", safeGetString(alarm, "message", "received")))
rxBus.send(EventNSClientNewLog("URGENTALARM", safeGetString(alarm, "message", "received"), NsClient.Version.V1))
aapsLogger.debug(LTag.NSCLIENT, alarm.toString())
}
}

View file

@ -0,0 +1,316 @@
package info.nightscout.androidaps.plugins.sync.nsclientV3
import android.content.Context
import android.os.Handler
import android.os.HandlerThread
import android.text.Spanned
import androidx.preference.PreferenceFragmentCompat
import androidx.preference.PreferenceScreen
import androidx.preference.SwitchPreference
import androidx.work.ExistingWorkPolicy
import androidx.work.OneTimeWorkRequest
import androidx.work.WorkInfo
import androidx.work.WorkManager
import dagger.android.HasAndroidInjector
import info.nightscout.androidaps.R
import info.nightscout.androidaps.events.EventPreferenceChange
import info.nightscout.androidaps.interfaces.NsClient
import info.nightscout.androidaps.interfaces.PluginBase
import info.nightscout.androidaps.interfaces.ResourceHelper
import info.nightscout.androidaps.interfaces.Sync
import info.nightscout.androidaps.plugins.sync.nsShared.events.EventNSClientUpdateGUI
import info.nightscout.androidaps.plugins.sync.nsShared.NSClientFragment
import info.nightscout.androidaps.plugins.sync.nsShared.events.EventNSClientNewLog
import info.nightscout.androidaps.plugins.sync.nsShared.events.EventNSClientResend
import info.nightscout.androidaps.plugins.sync.nsShared.events.EventNSClientStatus
import info.nightscout.androidaps.plugins.sync.nsclient.NsClientReceiverDelegate
import info.nightscout.androidaps.plugins.sync.nsclient.data.AlarmAck
import info.nightscout.androidaps.plugins.sync.nsclient.data.NSAlarm
import info.nightscout.androidaps.plugins.sync.nsclient.services.NSClientService
import info.nightscout.androidaps.plugins.sync.nsclientV3.workers.LoadBgWorker
import info.nightscout.androidaps.plugins.sync.nsclientV3.workers.LoadLastModificationWorker
import info.nightscout.androidaps.plugins.sync.nsclientV3.workers.LoadStatusWorker
import info.nightscout.androidaps.utils.DateUtil
import info.nightscout.androidaps.utils.FabricPrivacy
import info.nightscout.androidaps.utils.T
import info.nightscout.androidaps.utils.ToastUtils
import info.nightscout.interfaces.BuildHelper
import info.nightscout.interfaces.Config
import info.nightscout.interfaces.Constants
import info.nightscout.interfaces.PluginDescription
import info.nightscout.interfaces.PluginType
import info.nightscout.interfaces.utils.HtmlHelper
import info.nightscout.rx.AapsSchedulers
import info.nightscout.rx.bus.RxBus
import info.nightscout.rx.events.EventChargingState
import info.nightscout.rx.events.EventNetworkChange
import info.nightscout.rx.logging.AAPSLogger
import info.nightscout.rx.logging.LTag
import info.nightscout.sdk.NSAndroidClientImpl
import info.nightscout.sdk.interfaces.NSAndroidClient
import info.nightscout.sdk.remotemodel.LastModified
import info.nightscout.shared.sharedPreferences.SP
import io.reactivex.rxjava3.disposables.CompositeDisposable
import io.reactivex.rxjava3.kotlin.plusAssign
import kotlinx.serialization.decodeFromString
import kotlinx.serialization.json.Json
import javax.inject.Inject
import javax.inject.Singleton
import kotlin.math.max
@Singleton
class NSClientV3Plugin @Inject constructor(
injector: HasAndroidInjector,
aapsLogger: AAPSLogger,
private val aapsSchedulers: AapsSchedulers,
private val rxBus: RxBus,
rh: ResourceHelper,
private val context: Context,
private val fabricPrivacy: FabricPrivacy,
private val sp: SP,
private val nsClientReceiverDelegate: NsClientReceiverDelegate,
private val config: Config,
private val buildHelper: BuildHelper,
private val dateUtil: DateUtil
) : NsClient, Sync, PluginBase(
PluginDescription()
.mainType(PluginType.SYNC)
.fragmentClass(NSClientFragment::class.java.name)
.pluginIcon(R.drawable.ic_nightscout_syncs)
.pluginName(R.string.nsclientv3)
.shortName(R.string.nsclientv3_shortname)
.preferencesId(R.xml.pref_nsclientinternal)
.description(R.string.description_ns_client_v3),
aapsLogger, rh, injector
) {
companion object {
val JOB_NAME: String = this::class.java.simpleName
}
private val disposable = CompositeDisposable()
private val handler = Handler(HandlerThread(this::class.simpleName + "Handler").also { it.start() }.looper)
private val listLog: MutableList<EventNSClientNewLog> = ArrayList()
override var status = ""
override val nsClientService: NSClientService? = null // service not needed
internal lateinit var nsAndroidClient: NSAndroidClient
// private lateinit var nsAndroidRxClient: NSAndroidRxClient
val isAllowed: Boolean
get() = nsClientReceiverDelegate.allowed
val blockingReason: String
get() = nsClientReceiverDelegate.blockingReason
private val maxAge = T.days(77).msecs()
internal var lastModified: LastModified? = null // timestamp of last modification for every collection
internal var lastFetched =
LastModified(
LastModified.Collections(
dateUtil.now() - maxAge,
dateUtil.now() - maxAge,
dateUtil.now() - maxAge,
dateUtil.now() - maxAge
)
) // timestamp of last fetched data for every collection
override fun onStart() {
// context.bindService(Intent(context, NSClientService::class.java), mConnection, Context.BIND_AUTO_CREATE)
super.onStart()
lastFetched = Json.decodeFromString(
sp.getString(
R.string.key_nsclientv2_lastmodified,
Json.encodeToString(
LastModified.serializer(),
LastModified(LastModified.Collections(dateUtil.now() - maxAge, dateUtil.now() - maxAge, dateUtil.now() - maxAge, dateUtil.now() - maxAge))
)
)
)
lastFetched.collections.entries = max(dateUtil.now() - maxAge, lastFetched.collections.entries)
lastFetched.collections.treatments = max(dateUtil.now() - maxAge, lastFetched.collections.treatments)
lastFetched.collections.profile = max(dateUtil.now() - maxAge, lastFetched.collections.profile)
lastFetched.collections.devicestatus = max(dateUtil.now() - maxAge, lastFetched.collections.devicestatus)
nsAndroidClient = NSAndroidClientImpl(
baseUrl = sp.getString(R.string.key_nsclientinternal_url, "").lowercase().replace("https://", ""),
accessToken = sp.getString(R.string.key_nsclient_token, ""),
context = context,
logging = true
)
nsClientReceiverDelegate.grabReceiversState()
disposable += rxBus
.toObservable(EventNSClientStatus::class.java)
.observeOn(aapsSchedulers.io)
.subscribe({ event ->
if (event.version == NsClient.Version.V3) {
status = event.getStatus(rh)
rxBus.send(EventNSClientUpdateGUI())
}
}, fabricPrivacy::logException)
disposable += rxBus
.toObservable(EventNetworkChange::class.java)
.observeOn(aapsSchedulers.io)
.subscribe({ ev -> nsClientReceiverDelegate.onStatusEvent(ev) }, fabricPrivacy::logException)
disposable += rxBus
.toObservable(EventPreferenceChange::class.java)
.observeOn(aapsSchedulers.io)
.subscribe({ ev -> nsClientReceiverDelegate.onStatusEvent(ev) }, fabricPrivacy::logException)
// disposable += rxBus
// .toObservable(EventAppExit::class.java)
// .observeOn(aapsSchedulers.io)
// .subscribe({ if (nsClientService != null) context.unbindService(mConnection) }, fabricPrivacy::logException)
disposable += rxBus
.toObservable(EventNSClientNewLog::class.java)
.observeOn(aapsSchedulers.io)
.subscribe({ event ->
if (event.version != NsClient.Version.V3) return@subscribe
addToLog(event)
aapsLogger.debug(LTag.NSCLIENT, event.action + " " + event.logText)
}, fabricPrivacy::logException)
disposable += rxBus
.toObservable(EventChargingState::class.java)
.observeOn(aapsSchedulers.io)
.subscribe({ ev -> nsClientReceiverDelegate.onStatusEvent(ev) }, fabricPrivacy::logException)
disposable += rxBus
.toObservable(EventNSClientResend::class.java)
.observeOn(aapsSchedulers.io)
.subscribe({ event -> resend(event.reason) }, fabricPrivacy::logException)
}
override fun onStop() {
// context.applicationContext.unbindService(mConnection)
disposable.clear()
super.onStop()
}
override fun preprocessPreferences(preferenceFragment: PreferenceFragmentCompat) {
super.preprocessPreferences(preferenceFragment)
if (config.NSCLIENT) {
preferenceFragment.findPreference<PreferenceScreen>(rh.gs(R.string.ns_sync_options))?.isVisible = false
preferenceFragment.findPreference<SwitchPreference>(rh.gs(R.string.key_ns_create_announcements_from_errors))?.isVisible = false
preferenceFragment.findPreference<SwitchPreference>(rh.gs(R.string.key_ns_create_announcements_from_carbs_req))?.isVisible = false
}
preferenceFragment.findPreference<SwitchPreference>(rh.gs(R.string.key_ns_receive_tbr_eb))?.isVisible = buildHelper.isEngineeringMode()
}
override val hasWritePermission: Boolean get() = nsClientService?.hasWriteAuth ?: false
override val connected: Boolean get() = nsClientService?.isConnected ?: false
override fun clearLog() {
handler.post {
synchronized(listLog) { listLog.clear() }
rxBus.send(EventNSClientUpdateGUI())
}
}
private fun addToLog(ev: EventNSClientNewLog) {
synchronized(listLog) {
listLog.add(ev)
// remove the first line if log is too large
if (listLog.size >= Constants.MAX_LOG_LINES) {
listLog.removeAt(0)
}
}
rxBus.send(EventNSClientUpdateGUI())
}
override fun textLog(): Spanned {
try {
val newTextLog = StringBuilder()
synchronized(listLog) {
for (log in listLog) newTextLog.append(log.toPreparedHtml())
}
return HtmlHelper.fromHtml(newTextLog.toString())
} catch (e: OutOfMemoryError) {
ToastUtils.showToastInUiThread(context, rxBus, "Out of memory!\nStop using this phone !!!", R.raw.error)
}
return HtmlHelper.fromHtml("")
}
override fun resend(reason: String) {
nsClientService?.resend(reason)
}
override fun pause(newState: Boolean) {
sp.putBoolean(R.string.key_nsclientinternal_paused, newState)
rxBus.send(EventPreferenceChange(rh, R.string.key_nsclientinternal_paused))
}
override val version: NsClient.Version
get() = NsClient.Version.V3
override val address: String get() = sp.getString(R.string.key_nsclientinternal_url, "")
fun handleClearAlarm(originalAlarm: NSAlarm, silenceTimeInMilliseconds: Long) {
if (!isEnabled()) return
if (!sp.getBoolean(R.string.key_ns_upload, true)) {
aapsLogger.debug(LTag.NSCLIENT, "Upload disabled. Message dropped")
return
}
nsClientService?.sendAlarmAck(
AlarmAck().also { ack ->
ack.level = originalAlarm.level()
ack.group = originalAlarm.group()
ack.silenceTime = silenceTimeInMilliseconds
})
}
override fun updateLatestBgReceivedIfNewer(latestReceived: Long) {
if (latestReceived > lastFetched.collections.entries) {
lastFetched.collections.entries = latestReceived
storeLastFetched()
}
}
override fun updateLatestTreatmentReceivedIfNewer(latestReceived: Long) {
lastFetched.collections.treatments = latestReceived
storeLastFetched()
}
override fun resetToFullSync() {
lastFetched = LastModified(
LastModified.Collections(
dateUtil.now() - maxAge,
dateUtil.now() - maxAge,
dateUtil.now() - maxAge,
dateUtil.now() - maxAge
)
)
storeLastFetched()
}
private fun storeLastFetched() {
sp.putString(R.string.key_nsclientv2_lastmodified, Json.encodeToString(LastModified.serializer(), lastFetched))
}
fun test() {
if (workIsRunning(arrayOf(JOB_NAME)))
rxBus.send(EventNSClientNewLog("RUN", "Already running", NsClient.Version.V3))
else {
rxBus.send(EventNSClientNewLog("RUN", "Starting next round", NsClient.Version.V3))
WorkManager.getInstance(context)
.beginUniqueWork(
"NSCv3Load",
ExistingWorkPolicy.REPLACE,
OneTimeWorkRequest.Builder(LoadStatusWorker::class.java).build()
)
.then(OneTimeWorkRequest.Builder(LoadLastModificationWorker::class.java).build())
.then(OneTimeWorkRequest.Builder(LoadBgWorker::class.java).build())
// LoadTreatmentsWorker is enqueued after BG finish
//.then(OneTimeWorkRequest.Builder(LoadTreatmentsWorker::class.java).build())
.enqueue()
}
}
private fun workIsRunning(workNames: Array<String>): Boolean {
for (workName in workNames)
for (workInfo in WorkManager.getInstance(context).getWorkInfosForUniqueWork(workName).get())
if (workInfo.state == WorkInfo.State.BLOCKED || workInfo.state == WorkInfo.State.ENQUEUED || workInfo.state == WorkInfo.State.RUNNING)
return true
return false
}
}

View file

@ -0,0 +1,19 @@
package info.nightscout.androidaps.plugins.sync.nsclientV3.extensions
import com.google.gson.Gson
import com.google.gson.JsonSyntaxException
import info.nightscout.androidaps.database.entities.BolusCalculatorResult
import info.nightscout.sdk.localmodel.treatment.NSBolusWizard
fun NSBolusWizard.toBolusCalculatorResult(): BolusCalculatorResult? =
try {
Gson().fromJson(bolusCalculatorResult, BolusCalculatorResult::class.java)
.also {
it.id = 0
it.isValid = isValid
it.interfaceIDs.nightscoutId = identifier
it.version = 0
}
} catch (e: JsonSyntaxException) {
null
}

View file

@ -0,0 +1,24 @@
package info.nightscout.androidaps.plugins.sync.nsclientV3.extensions
import info.nightscout.androidaps.database.embedments.InterfaceIDs
import info.nightscout.androidaps.database.entities.Bolus
import info.nightscout.sdk.localmodel.treatment.NSBolus
fun NSBolus.toBolus(): Bolus =
Bolus(
isValid = isValid,
timestamp = date,
utcOffset = utcOffset,
amount = insulin,
type = type.toBolusType(),
notes = notes,
interfaceIDs_backing = InterfaceIDs(nightscoutId = identifier, pumpId = pumpId, pumpType = InterfaceIDs.PumpType.fromString(pumpType), pumpSerial = pumpSerial, endId = endId)
)
fun NSBolus.BolusType?.toBolusType(): Bolus.Type =
when (this) {
NSBolus.BolusType.NORMAL -> Bolus.Type.NORMAL
NSBolus.BolusType.SMB -> Bolus.Type.SMB
NSBolus.BolusType.PRIMING -> Bolus.Type.PRIMING
null -> Bolus.Type.NORMAL
}

View file

@ -0,0 +1,16 @@
package info.nightscout.androidaps.plugins.sync.nsclientV3.extensions
import info.nightscout.androidaps.database.embedments.InterfaceIDs
import info.nightscout.androidaps.database.entities.Carbs
import info.nightscout.sdk.localmodel.treatment.NSCarbs
fun NSCarbs.toCarbs(): Carbs =
Carbs(
isValid = isValid,
timestamp = date,
utcOffset = utcOffset,
amount = carbs,
notes = notes,
duration = duration,
interfaceIDs_backing = InterfaceIDs(nightscoutId = identifier, pumpId = pumpId, pumpType = InterfaceIDs.PumpType.fromString(pumpType), pumpSerial = pumpSerial, endId = endId)
)

View file

@ -0,0 +1,33 @@
package info.nightscout.androidaps.plugins.sync.nsclientV3.extensions
import info.nightscout.androidaps.data.ProfileSealed
import info.nightscout.androidaps.database.embedments.InterfaceIDs
import info.nightscout.androidaps.database.entities.EffectiveProfileSwitch
import info.nightscout.androidaps.utils.DateUtil
import info.nightscout.androidaps.utils.extensions.pureProfileFromJson
import info.nightscout.plugins.sync.nsclient.extensions.fromConstant
import info.nightscout.sdk.localmodel.treatment.NSEffectiveProfileSwitch
fun NSEffectiveProfileSwitch.toEffectiveProfileSwitch(dateUtil: DateUtil): EffectiveProfileSwitch? {
val pureProfile = pureProfileFromJson(profileJson, dateUtil) ?: return null
val profileSealed = ProfileSealed.Pure(pureProfile)
return EffectiveProfileSwitch(
isValid = isValid,
timestamp = date,
utcOffset = utcOffset,
basalBlocks = profileSealed.basalBlocks,
isfBlocks = profileSealed.isfBlocks,
icBlocks = profileSealed.icBlocks,
targetBlocks = profileSealed.targetBlocks,
glucoseUnit = EffectiveProfileSwitch.GlucoseUnit.fromConstant(profileSealed.units),
originalProfileName = originalProfileName,
originalCustomizedName = originalCustomizedName,
originalTimeshift = originalTimeshift,
originalPercentage = originalPercentage,
originalDuration = originalDuration,
originalEnd = originalEnd,
insulinConfiguration = profileSealed.insulinConfiguration,
interfaceIDs_backing = InterfaceIDs(nightscoutId = identifier, pumpId = pumpId, pumpType = InterfaceIDs.PumpType.fromString(pumpType), pumpSerial = pumpSerial, endId = endId)
)
}

View file

@ -0,0 +1,16 @@
package info.nightscout.androidaps.plugins.sync.nsclientV3.extensions
import info.nightscout.androidaps.database.embedments.InterfaceIDs
import info.nightscout.androidaps.database.entities.ExtendedBolus
import info.nightscout.sdk.localmodel.treatment.NSExtendedBolus
fun NSExtendedBolus.toExtendedBolus(): ExtendedBolus =
ExtendedBolus(
isValid = isValid,
timestamp = date,
utcOffset = utcOffset,
amount = enteredinsulin,
duration = duration,
isEmulatingTempBasal = isEmulatingTempbasal,
interfaceIDs_backing = InterfaceIDs(nightscoutId = identifier, pumpId = pumpId, pumpType = InterfaceIDs.PumpType.fromString(pumpType), pumpSerial = pumpSerial, endId = endId)
)

View file

@ -0,0 +1,25 @@
package info.nightscout.androidaps.plugins.sync.nsclientV3.extensions
import info.nightscout.androidaps.database.embedments.InterfaceIDs
import info.nightscout.androidaps.database.entities.OfflineEvent
import info.nightscout.sdk.localmodel.treatment.NSOfflineEvent
fun NSOfflineEvent.toOfflineEvent(): OfflineEvent =
OfflineEvent(
isValid = isValid,
timestamp = date,
utcOffset = utcOffset,
duration = duration,
reason = reason.toReason(),
interfaceIDs_backing = InterfaceIDs(nightscoutId = identifier, pumpId = pumpId, pumpType = InterfaceIDs.PumpType.fromString(pumpType), pumpSerial = pumpSerial, endId = endId)
)
fun NSOfflineEvent.Reason?.toReason(): OfflineEvent.Reason =
when (this) {
NSOfflineEvent.Reason.DISCONNECT_PUMP -> OfflineEvent.Reason.DISCONNECT_PUMP
NSOfflineEvent.Reason.SUSPEND -> OfflineEvent.Reason.SUSPEND
NSOfflineEvent.Reason.DISABLE_LOOP -> OfflineEvent.Reason.DISABLE_LOOP
NSOfflineEvent.Reason.SUPER_BOLUS -> OfflineEvent.Reason.SUPER_BOLUS
NSOfflineEvent.Reason.OTHER -> OfflineEvent.Reason.OTHER
null -> OfflineEvent.Reason.OTHER
}

View file

@ -0,0 +1,36 @@
package info.nightscout.androidaps.plugins.sync.nsclientV3.extensions
import info.nightscout.androidaps.data.ProfileSealed
import info.nightscout.androidaps.database.embedments.InterfaceIDs
import info.nightscout.androidaps.database.entities.ProfileSwitch
import info.nightscout.androidaps.interfaces.ActivePlugin
import info.nightscout.androidaps.utils.DateUtil
import info.nightscout.androidaps.utils.T
import info.nightscout.androidaps.utils.extensions.fromConstant
import info.nightscout.androidaps.utils.extensions.pureProfileFromJson
import info.nightscout.sdk.localmodel.treatment.NSProfileSwitch
fun NSProfileSwitch.toProfileSwitch(activePlugin: ActivePlugin, dateUtil: DateUtil): ProfileSwitch? {
val pureProfile =
profileJson?.let { pureProfileFromJson(it, dateUtil) ?: return null }
?: activePlugin.activeProfileSource.profile?.getSpecificProfile(profileName) ?: return null
val profileSealed = ProfileSealed.Pure(pureProfile)
return ProfileSwitch(
isValid = isValid,
timestamp = date,
utcOffset = utcOffset,
basalBlocks = profileSealed.basalBlocks,
isfBlocks = profileSealed.isfBlocks,
icBlocks = profileSealed.icBlocks,
targetBlocks = profileSealed.targetBlocks,
glucoseUnit = ProfileSwitch.GlucoseUnit.fromConstant(profileSealed.units),
profileName = originalProfileName ?: profileName,
timeshift = timeShift ?: 0,
percentage = percentage ?: 100,
duration = originalDuration ?: T.mins(duration ?: 0).msecs(),
insulinConfiguration = profileSealed.insulinConfiguration,
interfaceIDs_backing = InterfaceIDs(nightscoutId = identifier, pumpId = pumpId, pumpType = InterfaceIDs.PumpType.fromString(pumpType), pumpSerial = pumpSerial, endId = endId)
)
}

View file

@ -0,0 +1,27 @@
package info.nightscout.androidaps.plugins.sync.nsclientV3.extensions
import info.nightscout.androidaps.database.embedments.InterfaceIDs
import info.nightscout.androidaps.database.entities.TemporaryBasal
import info.nightscout.sdk.localmodel.treatment.NSTemporaryBasal
fun NSTemporaryBasal.toTemporaryBasal(): TemporaryBasal =
TemporaryBasal(
isValid = isValid,
timestamp = date,
utcOffset = utcOffset,
type = type.toType(),
rate = rate,
isAbsolute = isAbsolute,
duration = duration,
interfaceIDs_backing = InterfaceIDs(nightscoutId = identifier, pumpId = pumpId, pumpType = InterfaceIDs.PumpType.fromString(pumpType), pumpSerial = pumpSerial, endId = endId)
)
fun NSTemporaryBasal.Type?.toType(): TemporaryBasal.Type =
when (this) {
NSTemporaryBasal.Type.NORMAL -> TemporaryBasal.Type.NORMAL
NSTemporaryBasal.Type.EMULATED_PUMP_SUSPEND -> TemporaryBasal.Type.EMULATED_PUMP_SUSPEND
NSTemporaryBasal.Type.PUMP_SUSPEND -> TemporaryBasal.Type.PUMP_SUSPEND
NSTemporaryBasal.Type.SUPERBOLUS -> TemporaryBasal.Type.SUPERBOLUS
NSTemporaryBasal.Type.FAKE_EXTENDED -> TemporaryBasal.Type.FAKE_EXTENDED
null -> TemporaryBasal.Type.NORMAL
}

View file

@ -0,0 +1,28 @@
package info.nightscout.androidaps.plugins.sync.nsclientV3.extensions
import info.nightscout.androidaps.database.embedments.InterfaceIDs
import info.nightscout.androidaps.database.entities.TemporaryTarget
import info.nightscout.sdk.localmodel.treatment.NSTemporaryTarget
fun NSTemporaryTarget.toTemporaryTarget(): TemporaryTarget =
TemporaryTarget(
isValid = isValid,
timestamp = date,
utcOffset = utcOffset,
reason = reason.toReason(),
highTarget = targetTop.asMgdl(),
lowTarget = targetBottom.asMgdl(),
duration = duration,
interfaceIDs_backing = InterfaceIDs(nightscoutId = identifier, pumpId = pumpId, pumpType = InterfaceIDs.PumpType.fromString(pumpType), pumpSerial = pumpSerial, endId = endId)
)
fun NSTemporaryTarget.Reason?.toReason(): TemporaryTarget.Reason =
when (this) {
NSTemporaryTarget.Reason.CUSTOM -> TemporaryTarget.Reason.CUSTOM
NSTemporaryTarget.Reason.HYPOGLYCEMIA -> TemporaryTarget.Reason.HYPOGLYCEMIA
NSTemporaryTarget.Reason.ACTIVITY -> TemporaryTarget.Reason.ACTIVITY
NSTemporaryTarget.Reason.EATING_SOON -> TemporaryTarget.Reason.EATING_SOON
NSTemporaryTarget.Reason.AUTOMATION -> TemporaryTarget.Reason.AUTOMATION
NSTemporaryTarget.Reason.WEAR -> TemporaryTarget.Reason.WEAR
null -> TemporaryTarget.Reason.CUSTOM
}

View file

@ -0,0 +1,68 @@
package info.nightscout.androidaps.plugins.sync.nsclientV3.extensions
import info.nightscout.androidaps.database.embedments.InterfaceIDs
import info.nightscout.androidaps.database.entities.TherapyEvent
import info.nightscout.sdk.localmodel.entry.NsUnits
import info.nightscout.sdk.localmodel.treatment.EventType
import info.nightscout.sdk.localmodel.treatment.NSTherapyEvent
fun NSTherapyEvent.toTherapyEvent(): TherapyEvent =
TherapyEvent(
isValid = isValid,
timestamp = date,
utcOffset = utcOffset,
glucoseUnit = units.toUnits(),
type = eventType.toType(),
note = notes,
enteredBy = enteredBy,
glucose = glucose,
glucoseType = glucoseType.toMeterType(),
duration = duration,
interfaceIDs_backing = InterfaceIDs(nightscoutId = identifier, pumpId = pumpId, pumpType = InterfaceIDs.PumpType.fromString(pumpType), pumpSerial = pumpSerial, endId = endId)
)
fun EventType.toType(): TherapyEvent.Type =
when (this) {
EventType.CANNULA_CHANGE -> TherapyEvent.Type.CANNULA_CHANGE
EventType.INSULIN_CHANGE -> TherapyEvent.Type.INSULIN_CHANGE
EventType.PUMP_BATTERY_CHANGE -> TherapyEvent.Type.PUMP_BATTERY_CHANGE
EventType.SENSOR_CHANGE -> TherapyEvent.Type.SENSOR_CHANGE
EventType.SENSOR_STARTED -> TherapyEvent.Type.SENSOR_STARTED
EventType.SENSOR_STOPPED -> TherapyEvent.Type.SENSOR_STOPPED
EventType.FINGER_STICK_BG_VALUE -> TherapyEvent.Type.FINGER_STICK_BG_VALUE
EventType.EXERCISE -> TherapyEvent.Type.EXERCISE
EventType.ANNOUNCEMENT -> TherapyEvent.Type.ANNOUNCEMENT
EventType.QUESTION -> TherapyEvent.Type.QUESTION
EventType.NOTE -> TherapyEvent.Type.NOTE
EventType.APS_OFFLINE -> TherapyEvent.Type.APS_OFFLINE
EventType.DAD_ALERT -> TherapyEvent.Type.DAD_ALERT
EventType.NS_MBG -> TherapyEvent.Type.NS_MBG
EventType.CARBS_CORRECTION -> TherapyEvent.Type.CARBS_CORRECTION
EventType.BOLUS_WIZARD -> TherapyEvent.Type.BOLUS_WIZARD
EventType.CORRECTION_BOLUS -> TherapyEvent.Type.CORRECTION_BOLUS
EventType.MEAL_BOLUS -> TherapyEvent.Type.MEAL_BOLUS
EventType.COMBO_BOLUS -> TherapyEvent.Type.COMBO_BOLUS
EventType.TEMPORARY_TARGET -> TherapyEvent.Type.TEMPORARY_TARGET
EventType.TEMPORARY_TARGET_CANCEL -> TherapyEvent.Type.TEMPORARY_TARGET_CANCEL
EventType.PROFILE_SWITCH -> TherapyEvent.Type.PROFILE_SWITCH
EventType.SNACK_BOLUS -> TherapyEvent.Type.SNACK_BOLUS
EventType.TEMPORARY_BASAL -> TherapyEvent.Type.TEMPORARY_BASAL
EventType.TEMPORARY_BASAL_START -> TherapyEvent.Type.TEMPORARY_BASAL_START
EventType.TEMPORARY_BASAL_END -> TherapyEvent.Type.TEMPORARY_BASAL_END
EventType.NONE -> TherapyEvent.Type.NONE
}
fun NSTherapyEvent.MeterType?.toMeterType(): TherapyEvent.MeterType =
when (this) {
NSTherapyEvent.MeterType.FINGER -> TherapyEvent.MeterType.FINGER
NSTherapyEvent.MeterType.SENSOR -> TherapyEvent.MeterType.SENSOR
NSTherapyEvent.MeterType.MANUAL -> TherapyEvent.MeterType.MANUAL
null -> TherapyEvent.MeterType.MANUAL
}
fun NsUnits?.toUnits(): TherapyEvent.GlucoseUnit =
when (this) {
NsUnits.MG_DL -> TherapyEvent.GlucoseUnit.MGDL
NsUnits.MMOL_L -> TherapyEvent.GlucoseUnit.MMOL
null -> TherapyEvent.GlucoseUnit.MGDL
}

View file

@ -0,0 +1,100 @@
package info.nightscout.androidaps.plugins.sync.nsclientV3.workers
import android.content.Context
import androidx.work.ExistingWorkPolicy
import androidx.work.OneTimeWorkRequest
import androidx.work.WorkManager
import androidx.work.Worker
import androidx.work.WorkerParameters
import androidx.work.workDataOf
import dagger.android.HasAndroidInjector
import info.nightscout.androidaps.R
import info.nightscout.androidaps.interfaces.NsClient
import info.nightscout.androidaps.plugins.source.NSClientSourcePlugin
import info.nightscout.androidaps.plugins.sync.nsShared.StoreDataForDb
import info.nightscout.androidaps.plugins.sync.nsShared.events.EventNSClientNewLog
import info.nightscout.androidaps.plugins.sync.nsclientV3.NSClientV3Plugin
import info.nightscout.androidaps.receivers.DataWorkerStorage
import info.nightscout.androidaps.utils.DateUtil
import info.nightscout.rx.bus.RxBus
import info.nightscout.rx.logging.AAPSLogger
import info.nightscout.shared.sharedPreferences.SP
import kotlinx.coroutines.runBlocking
import javax.inject.Inject
class LoadBgWorker(
context: Context, params: WorkerParameters
) : Worker(context, params) {
@Inject lateinit var aapsLogger: AAPSLogger
@Inject lateinit var dataWorkerStorage: DataWorkerStorage
@Inject lateinit var rxBus: RxBus
@Inject lateinit var sp: SP
@Inject lateinit var context: Context
@Inject lateinit var dateUtil: DateUtil
@Inject lateinit var nsClientV3Plugin: NSClientV3Plugin
companion object {
val JOB_NAME: String = this::class.java.simpleName
}
override fun doWork(): Result {
var ret = Result.success()
runBlocking {
if ((nsClientV3Plugin.lastModified?.collections?.entries ?: Long.MAX_VALUE) > nsClientV3Plugin.lastFetched.collections.entries)
try {
//val sgvs = nsClientV3Plugin.nsAndroidClient.getSgvsModifiedSince(nsClientV3Plugin.lastFetched.collections.entries)
val sgvs = nsClientV3Plugin.nsAndroidClient.getSgvsNewerThan(nsClientV3Plugin.lastFetched.collections.entries, 500)
aapsLogger.debug("SGVS: $sgvs")
if (sgvs.isNotEmpty()) {
rxBus.send(
EventNSClientNewLog(
"RCV",
"${sgvs.size} SVGs from ${dateUtil.dateAndTimeAndSecondsString(nsClientV3Plugin.lastFetched.collections.entries)}",
NsClient.Version.V3
)
)
// Objective0
sp.putBoolean(R.string.key_ObjectivesbgIsAvailableInNS, true)
// Schedule processing of fetched data and continue of loading
WorkManager.getInstance(context).beginUniqueWork(
JOB_NAME,
ExistingWorkPolicy.APPEND_OR_REPLACE,
OneTimeWorkRequest.Builder(NSClientSourcePlugin.NSClientSourceWorker::class.java).setInputData(dataWorkerStorage.storeInputData(sgvs)).build()
).then(OneTimeWorkRequest.Builder(LoadBgWorker::class.java).build()).enqueue()
} else {
rxBus.send(EventNSClientNewLog("END", "No SGVs from ${dateUtil.dateAndTimeAndSecondsString(nsClientV3Plugin.lastFetched.collections.entries)}", NsClient.Version.V3))
WorkManager.getInstance(context)
.beginUniqueWork(
NSClientV3Plugin.JOB_NAME,
ExistingWorkPolicy.APPEND_OR_REPLACE,
OneTimeWorkRequest.Builder(StoreDataForDb.StoreBgWorker::class.java).build()
)
.then(OneTimeWorkRequest.Builder(LoadTreatmentsWorker::class.java).build())
.enqueue()
}
} catch (error: Exception) {
aapsLogger.error("Error: ", error)
ret = Result.failure(workDataOf("Error" to error.toString()))
}
else {
rxBus.send(EventNSClientNewLog("END", "No new SGVs from ${dateUtil.dateAndTimeAndSecondsString(nsClientV3Plugin.lastFetched.collections.entries)}", NsClient.Version.V3))
WorkManager.getInstance(context)
.beginUniqueWork(
NSClientV3Plugin.JOB_NAME,
ExistingWorkPolicy.APPEND_OR_REPLACE,
OneTimeWorkRequest.Builder(StoreDataForDb.StoreBgWorker::class.java).build()
)
.then(OneTimeWorkRequest.Builder(LoadTreatmentsWorker::class.java).build())
.enqueue()
}
}
return ret
}
init {
(context.applicationContext as HasAndroidInjector).androidInjector().inject(this)
}
}

View file

@ -0,0 +1,58 @@
package info.nightscout.androidaps.plugins.sync.nsclientV3.workers
import android.content.Context
import androidx.work.Worker
import androidx.work.WorkerParameters
import androidx.work.workDataOf
import dagger.android.HasAndroidInjector
import info.nightscout.androidaps.interfaces.NsClient
import info.nightscout.androidaps.plugins.sync.nsShared.events.EventNSClientNewLog
import info.nightscout.androidaps.plugins.sync.nsclient.data.NSDeviceStatusHandler
import info.nightscout.androidaps.plugins.sync.nsclientV3.NSClientV3Plugin
import info.nightscout.androidaps.receivers.DataWorkerStorage
import info.nightscout.androidaps.utils.DateUtil
import info.nightscout.androidaps.utils.T
import info.nightscout.rx.bus.RxBus
import info.nightscout.rx.logging.AAPSLogger
import kotlinx.coroutines.runBlocking
import javax.inject.Inject
class LoadDeviceStatusWorker(
context: Context,
params: WorkerParameters
) : Worker(context, params) {
@Inject lateinit var aapsLogger: AAPSLogger
@Inject lateinit var dataWorkerStorage: DataWorkerStorage
@Inject lateinit var rxBus: RxBus
@Inject lateinit var context: Context
@Inject lateinit var nsClientV3Plugin: NSClientV3Plugin
@Inject lateinit var dateUtil: DateUtil
@Inject lateinit var nsDeviceStatusHandler: NSDeviceStatusHandler
override fun doWork(): Result {
var ret = Result.success()
runBlocking {
try {
val from = dateUtil.now() - T.mins(7).msecs()
val deviceStatuses = nsClientV3Plugin.nsAndroidClient.getDeviceStatusModifiedSince(from)
aapsLogger.debug("DEVICESTATUSES: $deviceStatuses")
if (deviceStatuses.isNotEmpty()) {
rxBus.send(EventNSClientNewLog("RCV", "${deviceStatuses.size} DSs from ${dateUtil.dateAndTimeAndSecondsString(from)}", NsClient.Version.V3))
nsDeviceStatusHandler.handleNewData(deviceStatuses.toTypedArray(), NsClient.Version.V3)
} else {
rxBus.send(EventNSClientNewLog("END", "No DSs from ${dateUtil.dateAndTimeAndSecondsString(from)}", NsClient.Version.V3))
}
} catch (error: Exception) {
aapsLogger.error("Error: ", error)
ret = Result.failure(workDataOf("Error" to error.toString()))
}
}
return ret
}
init {
(context.applicationContext as HasAndroidInjector).androidInjector().inject(this)
}
}

View file

@ -0,0 +1,39 @@
package info.nightscout.androidaps.plugins.sync.nsclientV3.workers
import android.content.Context
import androidx.work.Worker
import androidx.work.WorkerParameters
import androidx.work.workDataOf
import dagger.android.HasAndroidInjector
import info.nightscout.androidaps.plugins.sync.nsclientV3.NSClientV3Plugin
import info.nightscout.rx.logging.AAPSLogger
import kotlinx.coroutines.runBlocking
import javax.inject.Inject
class LoadLastModificationWorker(
context: Context, params: WorkerParameters
) : Worker(context, params) {
@Inject lateinit var aapsLogger: AAPSLogger
@Inject lateinit var nsClientV3Plugin: NSClientV3Plugin
override fun doWork(): Result {
var ret = Result.success()
runBlocking {
try {
val lm = nsClientV3Plugin.nsAndroidClient.getLastModified()
nsClientV3Plugin.lastModified = lm
aapsLogger.debug("LAST MODIFIED: ${nsClientV3Plugin.lastModified}")
} catch (error: Exception) {
aapsLogger.error("Error: ", error)
ret = Result.failure(workDataOf("Error" to error.toString()))
}
}
return ret
}
init {
(context.applicationContext as HasAndroidInjector).androidInjector().inject(this)
}
}

View file

@ -0,0 +1,38 @@
package info.nightscout.androidaps.plugins.sync.nsclientV3.workers
import android.content.Context
import androidx.work.Worker
import androidx.work.WorkerParameters
import androidx.work.workDataOf
import dagger.android.HasAndroidInjector
import info.nightscout.androidaps.plugins.sync.nsclientV3.NSClientV3Plugin
import info.nightscout.rx.logging.AAPSLogger
import kotlinx.coroutines.runBlocking
import javax.inject.Inject
class LoadStatusWorker(
context: Context, params: WorkerParameters
) : Worker(context, params) {
@Inject lateinit var aapsLogger: AAPSLogger
@Inject lateinit var nsClientV3Plugin: NSClientV3Plugin
override fun doWork(): Result {
var ret = Result.success()
runBlocking {
try {
val status = nsClientV3Plugin.nsAndroidClient.getStatus()
aapsLogger.debug("STATUS: $status")
} catch (error: Exception) {
aapsLogger.error("Error: ", error)
ret = Result.failure(workDataOf("Error" to error.toString()))
}
}
return ret
}
init {
(context.applicationContext as HasAndroidInjector).androidInjector().inject(this)
}
}

View file

@ -0,0 +1,97 @@
package info.nightscout.androidaps.plugins.sync.nsclientV3.workers
import android.content.Context
import androidx.work.ExistingWorkPolicy
import androidx.work.OneTimeWorkRequest
import androidx.work.WorkManager
import androidx.work.Worker
import androidx.work.WorkerParameters
import androidx.work.workDataOf
import dagger.android.HasAndroidInjector
import info.nightscout.androidaps.interfaces.NsClient
import info.nightscout.androidaps.plugins.sync.nsShared.StoreDataForDb
import info.nightscout.androidaps.plugins.sync.nsShared.events.EventNSClientNewLog
import info.nightscout.androidaps.plugins.sync.nsclientV3.NSClientV3Plugin
import info.nightscout.androidaps.receivers.DataWorkerStorage
import info.nightscout.androidaps.utils.DateUtil
import info.nightscout.rx.bus.RxBus
import info.nightscout.rx.logging.AAPSLogger
import kotlinx.coroutines.runBlocking
import javax.inject.Inject
class LoadTreatmentsWorker(
context: Context,
params: WorkerParameters
) : Worker(context, params) {
@Inject lateinit var aapsLogger: AAPSLogger
@Inject lateinit var dataWorkerStorage: DataWorkerStorage
@Inject lateinit var rxBus: RxBus
@Inject lateinit var context: Context
@Inject lateinit var nsClientV3Plugin: NSClientV3Plugin
@Inject lateinit var dateUtil: DateUtil
@Inject lateinit var storeDataForDb: StoreDataForDb
override fun doWork(): Result {
var ret = Result.success()
runBlocking {
if ((nsClientV3Plugin.lastModified?.collections?.treatments ?: Long.MAX_VALUE) > nsClientV3Plugin.lastFetched.collections.treatments)
try {
val treatments = nsClientV3Plugin.nsAndroidClient.getTreatmentsModifiedSince(nsClientV3Plugin.lastFetched.collections.treatments, 500)
aapsLogger.debug("TREATMENTS: $treatments")
if (treatments.isNotEmpty()) {
rxBus.send(
EventNSClientNewLog(
"RCV",
"${treatments.size} TRs from ${dateUtil.dateAndTimeAndSecondsString(nsClientV3Plugin.lastFetched.collections.treatments)}",
NsClient.Version.V3
)
)
// Schedule processing of fetched data and continue of loading
WorkManager.getInstance(context)
.beginUniqueWork(
NSClientV3Plugin.JOB_NAME,
ExistingWorkPolicy.APPEND_OR_REPLACE,
OneTimeWorkRequest.Builder(ProcessTreatmentsWorker::class.java)
.setInputData(dataWorkerStorage.storeInputData(treatments))
.build()
).then(OneTimeWorkRequest.Builder(LoadTreatmentsWorker::class.java).build())
.enqueue()
} else {
rxBus.send(
EventNSClientNewLog(
"END", "No TRs from ${dateUtil.dateAndTimeAndSecondsString(nsClientV3Plugin.lastFetched.collections.treatments)}",
NsClient.Version.V3
)
)
storeDataForDb.storeTreatmentsToDb()
WorkManager.getInstance(context)
.enqueueUniqueWork(
NSClientV3Plugin.JOB_NAME,
ExistingWorkPolicy.APPEND_OR_REPLACE,
OneTimeWorkRequest.Builder(LoadDeviceStatusWorker::class.java).build()
)
}
} catch (error: Exception) {
aapsLogger.error("Error: ", error)
ret = Result.failure(workDataOf("Error" to error.toString()))
}
else {
rxBus.send(EventNSClientNewLog("END", "No new TRs from ${dateUtil.dateAndTimeAndSecondsString(nsClientV3Plugin.lastFetched.collections.treatments)}", NsClient.Version.V3))
storeDataForDb.storeTreatmentsToDb()
WorkManager.getInstance(context)
.enqueueUniqueWork(
NSClientV3Plugin.JOB_NAME,
ExistingWorkPolicy.APPEND_OR_REPLACE,
OneTimeWorkRequest.Builder(LoadDeviceStatusWorker::class.java).build()
)
}
}
return ret
}
init {
(context.applicationContext as HasAndroidInjector).androidInjector().inject(this)
}
}

View file

@ -0,0 +1,158 @@
package info.nightscout.androidaps.plugins.sync.nsclientV3.workers
import android.content.Context
import androidx.work.Worker
import androidx.work.WorkerParameters
import androidx.work.workDataOf
import dagger.android.HasAndroidInjector
import info.nightscout.androidaps.R
import info.nightscout.androidaps.database.AppRepository
import info.nightscout.androidaps.interfaces.ActivePlugin
import info.nightscout.androidaps.interfaces.XDripBroadcast
import info.nightscout.androidaps.logging.UserEntryLogger
import info.nightscout.androidaps.plugins.pump.virtual.VirtualPumpPlugin
import info.nightscout.androidaps.plugins.sync.nsShared.StoreDataForDb
import info.nightscout.androidaps.plugins.sync.nsclientV3.extensions.toBolus
import info.nightscout.androidaps.plugins.sync.nsclientV3.extensions.toBolusCalculatorResult
import info.nightscout.androidaps.plugins.sync.nsclientV3.extensions.toCarbs
import info.nightscout.androidaps.plugins.sync.nsclientV3.extensions.toEffectiveProfileSwitch
import info.nightscout.androidaps.plugins.sync.nsclientV3.extensions.toExtendedBolus
import info.nightscout.androidaps.plugins.sync.nsclientV3.extensions.toOfflineEvent
import info.nightscout.androidaps.plugins.sync.nsclientV3.extensions.toProfileSwitch
import info.nightscout.androidaps.plugins.sync.nsclientV3.extensions.toTemporaryBasal
import info.nightscout.androidaps.plugins.sync.nsclientV3.extensions.toTemporaryTarget
import info.nightscout.androidaps.plugins.sync.nsclientV3.extensions.toTherapyEvent
import info.nightscout.androidaps.receivers.DataWorkerStorage
import info.nightscout.androidaps.utils.DateUtil
import info.nightscout.interfaces.BuildHelper
import info.nightscout.interfaces.Config
import info.nightscout.interfaces.Constants
import info.nightscout.rx.bus.RxBus
import info.nightscout.rx.logging.AAPSLogger
import info.nightscout.rx.logging.LTag
import info.nightscout.sdk.localmodel.treatment.NSBolus
import info.nightscout.sdk.localmodel.treatment.NSBolusWizard
import info.nightscout.sdk.localmodel.treatment.NSCarbs
import info.nightscout.sdk.localmodel.treatment.NSEffectiveProfileSwitch
import info.nightscout.sdk.localmodel.treatment.NSExtendedBolus
import info.nightscout.sdk.localmodel.treatment.NSOfflineEvent
import info.nightscout.sdk.localmodel.treatment.NSProfileSwitch
import info.nightscout.sdk.localmodel.treatment.NSTemporaryBasal
import info.nightscout.sdk.localmodel.treatment.NSTemporaryTarget
import info.nightscout.sdk.localmodel.treatment.NSTherapyEvent
import info.nightscout.sdk.localmodel.treatment.NSTreatment
import info.nightscout.shared.sharedPreferences.SP
import javax.inject.Inject
class ProcessTreatmentsWorker(
context: Context,
params: WorkerParameters
) : Worker(context, params) {
@Inject lateinit var dataWorkerStorage: DataWorkerStorage
@Inject lateinit var aapsLogger: AAPSLogger
@Inject lateinit var buildHelper: BuildHelper
@Inject lateinit var sp: SP
@Inject lateinit var dateUtil: DateUtil
@Inject lateinit var config: Config
@Inject lateinit var repository: AppRepository
@Inject lateinit var activePlugin: ActivePlugin
@Inject lateinit var rxBus: RxBus
@Inject lateinit var uel: UserEntryLogger
@Inject lateinit var virtualPumpPlugin: VirtualPumpPlugin
@Inject lateinit var xDripBroadcast: XDripBroadcast
@Inject lateinit var storeDataForDb: StoreDataForDb
override fun doWork(): Result {
@Suppress("UNCHECKED_CAST")
val treatments = dataWorkerStorage.pickupObject(inputData.getLong(DataWorkerStorage.STORE_KEY, -1)) as List<NSTreatment>?
?: return Result.failure(workDataOf("Error" to "missing input data"))
val ret = Result.success()
var latestDateInReceivedData = 0L
for (treatment in treatments) {
aapsLogger.debug(LTag.DATABASE, "Received NS treatment: $treatment")
//Find latest date in treatment
val mills = treatment.date
if (mills != 0L && mills < dateUtil.now())
if (mills > latestDateInReceivedData) latestDateInReceivedData = mills
when (treatment) {
is NSBolus ->
if (sp.getBoolean(R.string.key_ns_receive_insulin, false) || config.NSCLIENT)
storeDataForDb.boluses.add(treatment.toBolus())
is NSCarbs ->
if (sp.getBoolean(R.string.key_ns_receive_carbs, false) || config.NSCLIENT)
storeDataForDb.carbs.add(treatment.toCarbs())
is NSTemporaryTarget ->
if (sp.getBoolean(R.string.key_ns_receive_temp_target, false) || config.NSCLIENT) {
if (treatment.duration > 0L) {
// not ending event
if (treatment.targetBottomAsMgdl() < Constants.MIN_TT_MGDL
|| treatment.targetBottomAsMgdl() > Constants.MAX_TT_MGDL
|| treatment.targetTopAsMgdl() < Constants.MIN_TT_MGDL
|| treatment.targetTopAsMgdl() > Constants.MAX_TT_MGDL
|| treatment.targetBottomAsMgdl() > treatment.targetTopAsMgdl()
) {
aapsLogger.debug(LTag.DATABASE, "Ignored TemporaryTarget $treatment")
continue
}
}
storeDataForDb.temporaryTargets.add(treatment.toTemporaryTarget())
}
is NSTemporaryBasal ->
if (buildHelper.isEngineeringMode() && sp.getBoolean(R.string.key_ns_receive_tbr_eb, false) || config.NSCLIENT)
storeDataForDb.temporaryBasals.add(treatment.toTemporaryBasal())
is NSEffectiveProfileSwitch ->
if (sp.getBoolean(R.string.key_ns_receive_profile_switch, false) || config.NSCLIENT) {
treatment.toEffectiveProfileSwitch(dateUtil)?.let { effectiveProfileSwitch ->
storeDataForDb.effectiveProfileSwitches.add(effectiveProfileSwitch)
}
}
is NSProfileSwitch ->
if (sp.getBoolean(R.string.key_ns_receive_profile_switch, false) || config.NSCLIENT) {
treatment.toProfileSwitch(activePlugin, dateUtil)?.let { profileSwitch ->
storeDataForDb.profileSwitches.add(profileSwitch)
}
}
is NSBolusWizard ->
treatment.toBolusCalculatorResult()?.let { bolusCalculatorResult ->
storeDataForDb.bolusCalculatorResults.add(bolusCalculatorResult)
}
is NSTherapyEvent ->
if (sp.getBoolean(R.string.key_ns_receive_therapy_events, false) || config.NSCLIENT)
treatment.toTherapyEvent().let { therapyEvent ->
storeDataForDb.therapyEvents.add(therapyEvent)
}
is NSOfflineEvent ->
if (sp.getBoolean(R.string.key_ns_receive_offline_event, false) && buildHelper.isEngineeringMode() || config.NSCLIENT)
treatment.toOfflineEvent().let { offlineEvent ->
storeDataForDb.offlineEvents.add(offlineEvent)
}
is NSExtendedBolus ->
if (buildHelper.isEngineeringMode() && sp.getBoolean(R.string.key_ns_receive_tbr_eb, false) || config.NSCLIENT)
treatment.toExtendedBolus().let { extendedBolus ->
storeDataForDb.extendedBoluses.add(extendedBolus)
}
}
}
activePlugin.activeNsClient?.updateLatestTreatmentReceivedIfNewer(latestDateInReceivedData)
// xDripBroadcast.sendTreatments(treatments)
return ret
}
init {
(context.applicationContext as HasAndroidInjector).androidInjector().inject(this)
}
}

View file

@ -1,4 +1,4 @@
package info.nightscout.androidaps.plugins.general.tidepool
package info.nightscout.androidaps.plugins.sync.tidepool
import android.os.Bundle
import android.view.LayoutInflater
@ -8,10 +8,10 @@ import android.widget.ScrollView
import dagger.android.support.DaggerFragment
import info.nightscout.androidaps.R
import info.nightscout.androidaps.databinding.TidepoolFragmentBinding
import info.nightscout.androidaps.plugins.general.tidepool.comm.TidepoolUploader
import info.nightscout.androidaps.plugins.general.tidepool.events.EventTidepoolDoUpload
import info.nightscout.androidaps.plugins.general.tidepool.events.EventTidepoolResetData
import info.nightscout.androidaps.plugins.general.tidepool.events.EventTidepoolUpdateGUI
import info.nightscout.androidaps.plugins.sync.tidepool.comm.TidepoolUploader
import info.nightscout.androidaps.plugins.sync.tidepool.events.EventTidepoolUpdateGUI
import info.nightscout.androidaps.utils.FabricPrivacy
import info.nightscout.rx.AapsSchedulers
import info.nightscout.rx.bus.RxBus
@ -57,13 +57,13 @@ class TidepoolFragment : DaggerFragment() {
.toObservable(EventTidepoolUpdateGUI::class.java)
.observeOn(aapsSchedulers.main)
.subscribe({
if (_binding == null) return@subscribe
tidepoolPlugin.updateLog()
binding.log.text = tidepoolPlugin.textLog
binding.status.text = tidepoolUploader.connectionStatus.name
binding.log.text = tidepoolPlugin.textLog
binding.logscrollview.fullScroll(ScrollView.FOCUS_DOWN)
}, fabricPrivacy::logException)
if (_binding == null) return@subscribe
tidepoolPlugin.updateLog()
binding.log.text = tidepoolPlugin.textLog
binding.status.text = tidepoolUploader.connectionStatus.name
binding.log.text = tidepoolPlugin.textLog
binding.logscrollview.fullScroll(ScrollView.FOCUS_DOWN)
}, fabricPrivacy::logException)
}
@Synchronized

View file

@ -1,32 +1,31 @@
package info.nightscout.androidaps.plugins.general.tidepool
package info.nightscout.androidaps.plugins.sync.tidepool
import android.content.Context
import android.text.Spanned
import androidx.preference.Preference
import androidx.preference.PreferenceFragmentCompat
import dagger.android.HasAndroidInjector
import info.nightscout.interfaces.Constants
import info.nightscout.androidaps.R
import info.nightscout.androidaps.events.EventNewBG
import info.nightscout.androidaps.events.EventPreferenceChange
import info.nightscout.androidaps.interfaces.PluginBase
import info.nightscout.interfaces.PluginDescription
import info.nightscout.interfaces.PluginType
import info.nightscout.androidaps.interfaces.ResourceHelper
import info.nightscout.androidaps.plugins.general.tidepool.comm.TidepoolUploader
import info.nightscout.androidaps.plugins.general.tidepool.comm.TidepoolUploader.ConnectionStatus.CONNECTED
import info.nightscout.androidaps.plugins.general.tidepool.comm.TidepoolUploader.ConnectionStatus.DISCONNECTED
import info.nightscout.androidaps.plugins.general.tidepool.comm.UploadChunk
import info.nightscout.androidaps.interfaces.Sync
import info.nightscout.androidaps.plugins.general.tidepool.events.EventTidepoolDoUpload
import info.nightscout.androidaps.plugins.general.tidepool.events.EventTidepoolResetData
import info.nightscout.androidaps.plugins.general.tidepool.events.EventTidepoolStatus
import info.nightscout.androidaps.plugins.general.tidepool.events.EventTidepoolUpdateGUI
import info.nightscout.androidaps.plugins.general.tidepool.utils.RateLimit
import info.nightscout.androidaps.plugins.sync.tidepool.comm.TidepoolUploader
import info.nightscout.androidaps.plugins.sync.tidepool.comm.UploadChunk
import info.nightscout.androidaps.plugins.sync.tidepool.events.EventTidepoolStatus
import info.nightscout.androidaps.plugins.sync.tidepool.events.EventTidepoolUpdateGUI
import info.nightscout.androidaps.plugins.sync.tidepool.utils.RateLimit
import info.nightscout.androidaps.receivers.ReceiverStatusStore
import info.nightscout.androidaps.utils.FabricPrivacy
import info.nightscout.interfaces.utils.HtmlHelper
import info.nightscout.androidaps.utils.T
import info.nightscout.androidaps.utils.ToastUtils
import info.nightscout.interfaces.Constants
import info.nightscout.interfaces.PluginDescription
import info.nightscout.interfaces.PluginType
import info.nightscout.interfaces.utils.HtmlHelper
import info.nightscout.rx.AapsSchedulers
import info.nightscout.rx.bus.RxBus
import info.nightscout.rx.events.EventNetworkChange
@ -52,14 +51,14 @@ class TidepoolPlugin @Inject constructor(
private val sp: SP,
private val rateLimit: RateLimit,
private val receiverStatusStore: ReceiverStatusStore
) : PluginBase(
) : Sync, PluginBase(
PluginDescription()
.mainType(PluginType.GENERAL)
.pluginName(R.string.tidepool)
.shortName(R.string.tidepool_shortname)
.fragmentClass(TidepoolFragment::class.qualifiedName)
.preferencesId(R.xml.pref_tidepool)
.description(R.string.description_tidepool),
.mainType(PluginType.SYNC)
.pluginName(R.string.tidepool)
.shortName(R.string.tidepool_shortname)
.fragmentClass(TidepoolFragment::class.qualifiedName)
.preferencesId(R.xml.pref_tidepool)
.description(R.string.description_tidepool),
aapsLogger, rh, injector
) {
@ -79,14 +78,14 @@ class TidepoolPlugin @Inject constructor(
.toObservable(EventTidepoolResetData::class.java)
.observeOn(aapsSchedulers.io)
.subscribe({
if (tidepoolUploader.connectionStatus != CONNECTED) {
aapsLogger.debug(LTag.TIDEPOOL, "Not connected for delete Dataset")
} else {
tidepoolUploader.deleteDataSet()
sp.putLong(R.string.key_tidepool_last_end, 0)
tidepoolUploader.doLogin()
}
}, fabricPrivacy::logException)
if (tidepoolUploader.connectionStatus != TidepoolUploader.ConnectionStatus.CONNECTED) {
aapsLogger.debug(LTag.TIDEPOOL, "Not connected for delete Dataset")
} else {
tidepoolUploader.deleteDataSet()
sp.putLong(R.string.key_tidepool_last_end, 0)
tidepoolUploader.doLogin()
}
}, fabricPrivacy::logException)
disposable += rxBus
.toObservable(EventTidepoolStatus::class.java)
.observeOn(aapsSchedulers.io)
@ -95,26 +94,27 @@ class TidepoolPlugin @Inject constructor(
.toObservable(EventNewBG::class.java)
.observeOn(aapsSchedulers.io)
.filter { it.glucoseValue != null } // better would be optional in API level >24
.map { it.glucoseValue }
.map { it.glucoseValue!! }
.subscribe({ bgReading ->
if (bgReading!!.timestamp < uploadChunk.getLastEnd())
uploadChunk.setLastEnd(bgReading.timestamp )
if (isEnabled(PluginType.GENERAL)
&& (!sp.getBoolean(R.string.key_tidepool_only_while_charging, false) || receiverStatusStore.isCharging)
&& (!sp.getBoolean(R.string.key_tidepool_only_while_unmetered, false) || receiverStatusStore.isWifiConnected)
&& rateLimit.rateLimit("tidepool-new-data-upload", T.mins(4).secs().toInt()))
doUpload()
}, fabricPrivacy::logException)
if (bgReading!!.timestamp < uploadChunk.getLastEnd())
uploadChunk.setLastEnd(bgReading.timestamp)
if (isEnabled()
&& (!sp.getBoolean(R.string.key_tidepool_only_while_charging, false) || receiverStatusStore.isCharging)
&& (!sp.getBoolean(R.string.key_tidepool_only_while_unmetered, false) || receiverStatusStore.isWifiConnected)
&& rateLimit.rateLimit("tidepool-new-data-upload", T.mins(4).secs().toInt())
)
doUpload()
}, fabricPrivacy::logException)
disposable += rxBus
.toObservable(EventPreferenceChange::class.java)
.observeOn(aapsSchedulers.io)
.subscribe({ event ->
if (event.isChanged(rh, R.string.key_tidepool_dev_servers)
|| event.isChanged(rh, R.string.key_tidepool_username)
|| event.isChanged(rh, R.string.key_tidepool_password)
)
tidepoolUploader.resetInstance()
}, fabricPrivacy::logException)
if (event.isChanged(rh, R.string.key_tidepool_dev_servers)
|| event.isChanged(rh, R.string.key_tidepool_username)
|| event.isChanged(rh, R.string.key_tidepool_password)
)
tidepoolUploader.resetInstance()
}, fabricPrivacy::logException)
disposable += rxBus
.toObservable(EventNetworkChange::class.java)
.observeOn(aapsSchedulers.io)
@ -141,10 +141,10 @@ class TidepoolPlugin @Inject constructor(
private fun doUpload() =
when (tidepoolUploader.connectionStatus) {
DISCONNECTED -> tidepoolUploader.doLogin(true)
CONNECTED -> tidepoolUploader.doUpload()
TidepoolUploader.ConnectionStatus.DISCONNECTED -> tidepoolUploader.doLogin(true)
TidepoolUploader.ConnectionStatus.CONNECTED -> tidepoolUploader.doUpload()
else -> {
else -> {
}
}
@ -175,4 +175,10 @@ class TidepoolPlugin @Inject constructor(
}
}
override val status: String
get() = tidepoolUploader.connectionStatus.name
override val hasWritePermission: Boolean
get() = tidepoolUploader.connectionStatus == TidepoolUploader.ConnectionStatus.CONNECTED
override val connected: Boolean
get() = tidepoolUploader.connectionStatus == TidepoolUploader.ConnectionStatus.CONNECTED
}

View file

@ -1,4 +1,4 @@
package info.nightscout.androidaps.plugins.general.tidepool.comm
package info.nightscout.androidaps.plugins.sync.tidepool.comm
import info.nightscout.rx.logging.AAPSLogger
import info.nightscout.rx.logging.LTag

View file

@ -1,7 +1,7 @@
package info.nightscout.androidaps.plugins.general.tidepool.comm
package info.nightscout.androidaps.plugins.sync.tidepool.comm
import info.nightscout.androidaps.plugins.general.tidepool.messages.AuthReplyMessage
import info.nightscout.androidaps.plugins.general.tidepool.messages.DatasetReplyMessage
import info.nightscout.androidaps.plugins.sync.tidepool.messages.AuthReplyMessage
import info.nightscout.androidaps.plugins.sync.tidepool.messages.DatasetReplyMessage
import okhttp3.Headers
class Session(val authHeader: String?,

View file

@ -1,9 +1,9 @@
package info.nightscout.androidaps.plugins.general.tidepool.comm
package info.nightscout.androidaps.plugins.sync.tidepool.comm
import info.nightscout.androidaps.BuildConfig
import info.nightscout.androidaps.plugins.general.tidepool.messages.AuthReplyMessage
import info.nightscout.androidaps.plugins.general.tidepool.messages.DatasetReplyMessage
import info.nightscout.androidaps.plugins.general.tidepool.messages.UploadReplyMessage
import info.nightscout.androidaps.plugins.sync.tidepool.messages.AuthReplyMessage
import info.nightscout.androidaps.plugins.sync.tidepool.messages.DatasetReplyMessage
import info.nightscout.androidaps.plugins.sync.tidepool.messages.UploadReplyMessage
import okhttp3.RequestBody
import retrofit2.Call
import retrofit2.http.*

View file

@ -1,6 +1,6 @@
package info.nightscout.androidaps.plugins.general.tidepool.comm
package info.nightscout.androidaps.plugins.sync.tidepool.comm
import info.nightscout.androidaps.plugins.general.tidepool.events.EventTidepoolStatus
import info.nightscout.androidaps.plugins.sync.tidepool.events.EventTidepoolStatus
import info.nightscout.rx.bus.RxBus
import info.nightscout.rx.logging.AAPSLogger
import info.nightscout.rx.logging.LTag
@ -8,7 +8,8 @@ import retrofit2.Call
import retrofit2.Callback
import retrofit2.Response
internal class TidepoolCallback<T>(private val aapsLogger: AAPSLogger, private val rxBus: RxBus, private val session: Session, val name: String, val onSuccess: () -> Unit, val onFail: () -> Unit) : Callback<T> {
internal class TidepoolCallback<T>(private val aapsLogger: AAPSLogger, private val rxBus: RxBus, private val session: Session, val name: String, val onSuccess: () -> Unit, val onFail: () -> Unit) :
Callback<T> {
override fun onResponse(call: Call<T>, response: Response<T>) {
if (response.isSuccessful && response.body() != null) {

View file

@ -1,4 +1,4 @@
package info.nightscout.androidaps.plugins.general.tidepool.comm
package info.nightscout.androidaps.plugins.sync.tidepool.comm
import android.content.Context
import android.os.PowerManager
@ -7,12 +7,12 @@ import info.nightscout.androidaps.BuildConfig
import info.nightscout.androidaps.R
import info.nightscout.androidaps.interfaces.ActivePlugin
import info.nightscout.androidaps.interfaces.ResourceHelper
import info.nightscout.androidaps.plugins.general.tidepool.events.EventTidepoolStatus
import info.nightscout.androidaps.plugins.general.tidepool.messages.AuthReplyMessage
import info.nightscout.androidaps.plugins.general.tidepool.messages.AuthRequestMessage
import info.nightscout.androidaps.plugins.general.tidepool.messages.DatasetReplyMessage
import info.nightscout.androidaps.plugins.general.tidepool.messages.OpenDatasetRequestMessage
import info.nightscout.androidaps.plugins.general.tidepool.messages.UploadReplyMessage
import info.nightscout.androidaps.plugins.sync.tidepool.events.EventTidepoolStatus
import info.nightscout.androidaps.plugins.sync.tidepool.messages.AuthReplyMessage
import info.nightscout.androidaps.plugins.sync.tidepool.messages.AuthRequestMessage
import info.nightscout.androidaps.plugins.sync.tidepool.messages.DatasetReplyMessage
import info.nightscout.androidaps.plugins.sync.tidepool.messages.OpenDatasetRequestMessage
import info.nightscout.androidaps.plugins.sync.tidepool.messages.UploadReplyMessage
import info.nightscout.androidaps.utils.DateUtil
import info.nightscout.androidaps.utils.T
import info.nightscout.androidaps.utils.alertDialogs.OKDialog
@ -111,9 +111,9 @@ class TidepoolUploader @Inject constructor(
call?.enqueue(TidepoolCallback<AuthReplyMessage>(aapsLogger, rxBus, session!!, "Login", {
startSession(session!!, doUpload)
}, {
connectionStatus = ConnectionStatus.FAILED
releaseWakeLock()
}))
connectionStatus = ConnectionStatus.FAILED
releaseWakeLock()
}))
return
} else {
aapsLogger.debug(LTag.TIDEPOOL, "Cannot do login as user credentials have not been set correctly")
@ -132,8 +132,12 @@ class TidepoolUploader @Inject constructor(
call?.enqueue(TidepoolCallback<AuthReplyMessage>(aapsLogger, rxBus, session, "Login", {
OKDialog.show(rootContext, rh.gs(R.string.tidepool), "Successfully logged into Tidepool.")
}, {
OKDialog.show(rootContext, rh.gs(R.string.tidepool), "Failed to log into Tidepool.\nCheck that your user name and password are correct.")
}))
OKDialog.show(
rootContext,
rh.gs(R.string.tidepool),
"Failed to log into Tidepool.\nCheck that your user name and password are correct."
)
}))
}
?: OKDialog.show(rootContext, rh.gs(R.string.tidepool), "Cannot do login as user credentials have not been set correctly")
@ -144,14 +148,18 @@ class TidepoolUploader @Inject constructor(
extendWakeLock(30000)
if (session.authReply?.userid != null) {
// See if we already have an open data set to write to
val datasetCall = session.service!!.getOpenDataSets(session.token!!,
session.authReply!!.userid!!, BuildConfig.APPLICATION_ID, 1)
val datasetCall = session.service!!.getOpenDataSets(
session.token!!,
session.authReply!!.userid!!, BuildConfig.APPLICATION_ID, 1
)
datasetCall.enqueue(TidepoolCallback<List<DatasetReplyMessage>>(aapsLogger, rxBus, session, "Get Open Datasets", {
if (session.datasetReply == null) {
rxBus.send(EventTidepoolStatus(("Creating new dataset")))
val call = session.service.openDataSet(session.token!!, session.authReply!!.userid!!,
OpenDatasetRequestMessage(activePlugin.activePump.serialNumber(), dateUtil).getBody())
val call = session.service.openDataSet(
session.token!!, session.authReply!!.userid!!,
OpenDatasetRequestMessage(activePlugin.activePump.serialNumber(), dateUtil).getBody()
)
call.enqueue(TidepoolCallback<DatasetReplyMessage>(aapsLogger, rxBus, session, "Open New Dataset", {
connectionStatus = ConnectionStatus.CONNECTED
rxBus.send(EventTidepoolStatus(("New dataset OK")))
@ -159,10 +167,10 @@ class TidepoolUploader @Inject constructor(
else
releaseWakeLock()
}, {
rxBus.send(EventTidepoolStatus(("New dataset FAILED")))
connectionStatus = ConnectionStatus.FAILED
releaseWakeLock()
}))
rxBus.send(EventTidepoolStatus(("New dataset FAILED")))
connectionStatus = ConnectionStatus.FAILED
releaseWakeLock()
}))
} else {
aapsLogger.debug(LTag.TIDEPOOL, "Existing Dataset: " + session.datasetReply!!.getUploadId())
// TODO: Wouldn't need to do this if we could block on the above `call.enqueue`.
@ -174,10 +182,10 @@ class TidepoolUploader @Inject constructor(
releaseWakeLock()
}
}, {
connectionStatus = ConnectionStatus.FAILED
rxBus.send(EventTidepoolStatus(("Open dataset FAILED")))
releaseWakeLock()
}))
connectionStatus = ConnectionStatus.FAILED
rxBus.send(EventTidepoolStatus(("Open dataset FAILED")))
releaseWakeLock()
}))
} else {
aapsLogger.error("Got login response but cannot determine userId - cannot proceed")
connectionStatus = ConnectionStatus.FAILED
@ -222,9 +230,9 @@ class TidepoolUploader @Inject constructor(
releaseWakeLock()
uploadNext()
}, {
rxBus.send(EventTidepoolStatus(("Upload FAILED")))
releaseWakeLock()
}))
rxBus.send(EventTidepoolStatus(("Upload FAILED")))
releaseWakeLock()
}))
}
}
}
@ -248,10 +256,10 @@ class TidepoolUploader @Inject constructor(
rxBus.send(EventTidepoolStatus(("Dataset removed OK")))
releaseWakeLock()
}, {
connectionStatus = ConnectionStatus.DISCONNECTED
rxBus.send(EventTidepoolStatus(("Dataset remove FAILED")))
releaseWakeLock()
}))
connectionStatus = ConnectionStatus.DISCONNECTED
rxBus.send(EventTidepoolStatus(("Dataset remove FAILED")))
releaseWakeLock()
}))
} else {
aapsLogger.error("Got login response but cannot determine datasetId - cannot proceed")
}
@ -273,10 +281,10 @@ class TidepoolUploader @Inject constructor(
rxBus.send(EventTidepoolStatus(("All data removed OK")))
releaseWakeLock()
}, {
connectionStatus = ConnectionStatus.DISCONNECTED
rxBus.send(EventTidepoolStatus(("All data remove FAILED")))
releaseWakeLock()
}))
connectionStatus = ConnectionStatus.DISCONNECTED
rxBus.send(EventTidepoolStatus(("All data remove FAILED")))
releaseWakeLock()
}))
} catch (e: IllegalArgumentException) {
aapsLogger.error("Got login response but cannot determine userId - cannot proceed")
}

View file

@ -1,4 +1,4 @@
package info.nightscout.androidaps.plugins.general.tidepool.comm
package info.nightscout.androidaps.plugins.sync.tidepool.comm
import info.nightscout.androidaps.R
import info.nightscout.androidaps.database.AppRepository
@ -6,15 +6,15 @@ import info.nightscout.androidaps.database.entities.EffectiveProfileSwitch
import info.nightscout.androidaps.database.entities.TemporaryBasal
import info.nightscout.androidaps.interfaces.ActivePlugin
import info.nightscout.androidaps.interfaces.ProfileFunction
import info.nightscout.androidaps.plugins.general.tidepool.elements.BasalElement
import info.nightscout.androidaps.plugins.general.tidepool.elements.BaseElement
import info.nightscout.androidaps.plugins.general.tidepool.elements.BloodGlucoseElement
import info.nightscout.androidaps.plugins.general.tidepool.elements.BolusElement
import info.nightscout.androidaps.plugins.general.tidepool.elements.ProfileElement
import info.nightscout.androidaps.plugins.general.tidepool.elements.SensorGlucoseElement
import info.nightscout.androidaps.plugins.general.tidepool.elements.WizardElement
import info.nightscout.androidaps.plugins.general.tidepool.events.EventTidepoolStatus
import info.nightscout.androidaps.plugins.general.tidepool.utils.GsonInstance
import info.nightscout.androidaps.plugins.sync.tidepool.elements.BasalElement
import info.nightscout.androidaps.plugins.sync.tidepool.elements.BaseElement
import info.nightscout.androidaps.plugins.sync.tidepool.elements.BloodGlucoseElement
import info.nightscout.androidaps.plugins.sync.tidepool.elements.BolusElement
import info.nightscout.androidaps.plugins.sync.tidepool.elements.ProfileElement
import info.nightscout.androidaps.plugins.sync.tidepool.elements.SensorGlucoseElement
import info.nightscout.androidaps.plugins.sync.tidepool.elements.WizardElement
import info.nightscout.androidaps.plugins.sync.tidepool.events.EventTidepoolStatus
import info.nightscout.androidaps.plugins.sync.tidepool.utils.GsonInstance
import info.nightscout.androidaps.utils.DateUtil
import info.nightscout.androidaps.utils.T
import info.nightscout.rx.bus.RxBus

View file

@ -1,4 +1,4 @@
package info.nightscout.androidaps.plugins.general.tidepool.elements
package info.nightscout.androidaps.plugins.sync.tidepool.elements
import com.google.gson.annotations.Expose
import info.nightscout.androidaps.interfaces.Profile

View file

@ -1,4 +1,4 @@
package info.nightscout.androidaps.plugins.general.tidepool.elements
package info.nightscout.androidaps.plugins.sync.tidepool.elements
import com.google.gson.annotations.Expose
import info.nightscout.androidaps.utils.DateUtil

View file

@ -1,9 +1,9 @@
package info.nightscout.androidaps.plugins.general.tidepool.elements
package info.nightscout.androidaps.plugins.sync.tidepool.elements
import com.google.gson.annotations.Expose
import info.nightscout.androidaps.interfaces.Profile
import info.nightscout.androidaps.database.entities.TherapyEvent
import info.nightscout.androidaps.extensions.toMainUnit
import info.nightscout.plugins.sync.nsclient.extensions.toMainUnit
import info.nightscout.androidaps.utils.DateUtil
import java.util.*

View file

@ -1,4 +1,4 @@
package info.nightscout.androidaps.plugins.general.tidepool.elements
package info.nightscout.androidaps.plugins.sync.tidepool.elements
import com.google.gson.annotations.Expose
import info.nightscout.androidaps.database.entities.Bolus

View file

@ -1,13 +1,12 @@
package info.nightscout.androidaps.plugins.general.tidepool.elements
package info.nightscout.androidaps.plugins.sync.tidepool.elements
import com.google.gson.annotations.Expose
import info.nightscout.androidaps.data.ProfileSealed
import info.nightscout.androidaps.database.entities.EffectiveProfileSwitch
import info.nightscout.androidaps.interfaces.Profile
import info.nightscout.androidaps.plugins.general.tidepool.comm.TidepoolUploader
import info.nightscout.androidaps.plugins.sync.tidepool.comm.TidepoolUploader
import info.nightscout.androidaps.utils.DateUtil
import java.util.*
import kotlin.collections.ArrayList
class ProfileElement(ps: EffectiveProfileSwitch, serialNumber: String, dateUtil: DateUtil)
: BaseElement(ps.timestamp, UUID.nameUUIDFromBytes(("AAPS-profile" + ps.timestamp).toByteArray()).toString(), dateUtil) {

View file

@ -1,4 +1,4 @@
package info.nightscout.androidaps.plugins.general.tidepool.elements
package info.nightscout.androidaps.plugins.sync.tidepool.elements
import com.google.gson.annotations.Expose
import info.nightscout.androidaps.database.entities.GlucoseValue

View file

@ -1,4 +1,4 @@
package info.nightscout.androidaps.plugins.general.tidepool.elements
package info.nightscout.androidaps.plugins.sync.tidepool.elements
import com.google.gson.annotations.Expose
import info.nightscout.androidaps.database.entities.Bolus

View file

@ -1,4 +1,4 @@
package info.nightscout.androidaps.plugins.general.tidepool.events
package info.nightscout.androidaps.plugins.sync.tidepool.events
import info.nightscout.rx.events.Event
import java.text.SimpleDateFormat

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