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' plugins {
apply plugin: 'kotlin-android' id 'com.android.library'
apply plugin: 'kotlin-kapt' id 'kotlin-android'
apply plugin: 'kotlin-allopen' id 'kotlin-kapt'
apply plugin: 'com.hiya.jacoco-android' id 'kotlin-allopen'
apply plugin: 'kotlinx-serialization' id 'com.hiya.jacoco-android'
id 'kotlinx-serialization'
}
apply from: "${project.rootDir}/core/android_dependencies.gradle" apply from: "${project.rootDir}/core/android_dependencies.gradle"
apply from: "${project.rootDir}/core/android_module_dependencies.gradle" apply from: "${project.rootDir}/core/android_module_dependencies.gradle"

View file

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

View file

@ -1,12 +1,15 @@
apply plugin: 'com.android.library' plugins {
apply plugin: 'kotlin-android' id 'com.android.library'
apply plugin: 'kotlin-kapt' id 'kotlin-android'
apply plugin: 'kotlin-allopen' id 'kotlin-kapt'
apply plugin: 'com.hiya.jacoco-android' id 'kotlinx-serialization'
apply plugin: 'kotlinx-serialization' id 'kotlin-allopen'
id 'com.hiya.jacoco-android'
}
apply from: "${project.rootDir}/core/android_dependencies.gradle" apply from: "${project.rootDir}/core/android_dependencies.gradle"
apply from: "${project.rootDir}/core/android_module_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/test_dependencies.gradle"
apply from: "${project.rootDir}/core/jacoco_global.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 '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 '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" api "org.apache.commons:commons-lang3:$commonslang3_version"
//RxBus //RxBus

View file

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

View file

@ -77,7 +77,7 @@ class RealPumpTest {
configBuilderPlugin.performPluginSwitch(loopPlugin, true, PluginType.LOOP) configBuilderPlugin.performPluginSwitch(loopPlugin, true, PluginType.LOOP)
// Enable common // Enable common
configBuilderPlugin.performPluginSwitch(actionsPlugin, true, PluginType.GENERAL) configBuilderPlugin.performPluginSwitch(actionsPlugin, true, )
// Disable unneeded // Disable unneeded
MainApp.getPluginsList().remove(objectivesPlugin) 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(1.1, p.getBasalTimeFromMidnight(0), 0.0001)
Assert.assertEquals(6.0 * Constants.MMOLL_TO_MGDL, p.targetLowMgdl, 0.0001) Assert.assertEquals(6.0 * Constants.MMOLL_TO_MGDL, p.targetLowMgdl, 0.0001)
Assert.assertTrue(VirtualPumpPlugin.getPlugin().isEnabled(PluginType.PUMP)) 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(LoopPlugin.getPlugin().isEnabled(PluginType.LOOP))
Assert.assertTrue(SensitivityOref1Plugin.getPlugin().isEnabled(PluginType.SENSITIVITY)) Assert.assertTrue(SensitivityOref1Plugin.getPlugin().isEnabled(PluginType.SENSITIVITY))
Assert.assertTrue(ObjectivesPlugin.objectives[0].isStarted) Assert.assertTrue(ObjectivesPlugin.objectives[0].isStarted)

View file

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

View file

@ -51,7 +51,7 @@ import info.nightscout.androidaps.interfaces.ProfileFunction
import info.nightscout.interfaces.SmsCommunicator import info.nightscout.interfaces.SmsCommunicator
import info.nightscout.androidaps.logging.UserEntryLogger import info.nightscout.androidaps.logging.UserEntryLogger
import info.nightscout.androidaps.plugins.constraints.versionChecker.VersionCheckerUtils 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.setupwizard.SetupWizardActivity
import info.nightscout.androidaps.utils.FabricPrivacy import info.nightscout.androidaps.utils.FabricPrivacy
import info.nightscout.androidaps.utils.alertDialogs.OKDialog import info.nightscout.androidaps.utils.alertDialogs.OKDialog

View file

@ -214,6 +214,8 @@ class MainApp : DaggerApplication() {
} }
sp.remove("ns_charginonly") 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> { 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.configBuilder.PluginStore
import info.nightscout.androidaps.plugins.constraints.safety.SafetyPlugin import info.nightscout.androidaps.plugins.constraints.safety.SafetyPlugin
import info.nightscout.androidaps.plugins.general.maintenance.MaintenancePlugin 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.general.wear.WearPlugin
import info.nightscout.androidaps.plugins.pump.combo.ComboPlugin import info.nightscout.androidaps.plugins.pump.combo.ComboPlugin
import info.nightscout.androidaps.plugins.pump.eopatch.EopatchPumpPlugin 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.IntelligoPlugin
import info.nightscout.androidaps.plugins.source.PoctechPlugin import info.nightscout.androidaps.plugins.source.PoctechPlugin
import info.nightscout.androidaps.plugins.source.TomatoPlugin 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.alertDialogs.OKDialog.show
import info.nightscout.androidaps.utils.protection.PasswordCheck import info.nightscout.androidaps.utils.protection.PasswordCheck
import info.nightscout.androidaps.utils.protection.ProtectionCheck.ProtectionType.BIOMETRIC 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 localInsightPlugin: LocalInsightPlugin
@Inject lateinit var medtronicPumpPlugin: MedtronicPumpPlugin @Inject lateinit var medtronicPumpPlugin: MedtronicPumpPlugin
@Inject lateinit var nsClientPlugin: NSClientPlugin @Inject lateinit var nsClientPlugin: NSClientPlugin
@Inject lateinit var nsClientV3Plugin: NSClientV3Plugin
@Inject lateinit var openAPSAMAPlugin: OpenAPSAMAPlugin @Inject lateinit var openAPSAMAPlugin: OpenAPSAMAPlugin
@Inject lateinit var openAPSSMBPlugin: OpenAPSSMBPlugin @Inject lateinit var openAPSSMBPlugin: OpenAPSSMBPlugin
@Inject lateinit var openAPSSMBDynamicISFPlugin: OpenAPSSMBDynamicISFPlugin @Inject lateinit var openAPSSMBDynamicISFPlugin: OpenAPSSMBDynamicISFPlugin
@ -212,6 +214,7 @@ class MyPreferenceFragment : PreferenceFragmentCompat(), OnSharedPreferenceChang
addPreferencesFromResourceIfEnabled(virtualPumpPlugin, rootKey) addPreferencesFromResourceIfEnabled(virtualPumpPlugin, rootKey)
addPreferencesFromResourceIfEnabled(insulinOrefFreePeakPlugin, rootKey) addPreferencesFromResourceIfEnabled(insulinOrefFreePeakPlugin, rootKey)
addPreferencesFromResourceIfEnabled(nsClientPlugin, rootKey) addPreferencesFromResourceIfEnabled(nsClientPlugin, rootKey)
addPreferencesFromResourceIfEnabled(nsClientV3Plugin, rootKey)
addPreferencesFromResourceIfEnabled(tidepoolPlugin, rootKey) addPreferencesFromResourceIfEnabled(tidepoolPlugin, rootKey)
addPreferencesFromResourceIfEnabled(smsCommunicatorPlugin, rootKey) addPreferencesFromResourceIfEnabled(smsCommunicatorPlugin, rootKey)
addPreferencesFromResourceIfEnabled(automationPlugin, rootKey) addPreferencesFromResourceIfEnabled(automationPlugin, rootKey)
@ -328,13 +331,11 @@ class MyPreferenceFragment : PreferenceFragmentCompat(), OnSharedPreferenceChang
var visible = false var visible = false
if (p is PreferenceGroup) { 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 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 { } else {
@Suppress("KotlinConstantConditions")
visible = visible || p.key?.contains(filter, true) == true visible = visible || p.key?.contains(filter, true) == true
visible = visible || p.title?.contains(filter, true) == true visible = visible || p.title?.contains(filter, true) == true
visible = visible || p.summary?.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.configBuilder.ProfileFunctionImpl
import info.nightscout.androidaps.plugins.general.maintenance.ImportExportPrefsImpl import info.nightscout.androidaps.plugins.general.maintenance.ImportExportPrefsImpl
import info.nightscout.androidaps.plugins.general.maintenance.PrefFileListProvider 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.iob.iobCobCalculator.IobCobCalculatorPlugin
import info.nightscout.androidaps.plugins.pump.PumpSyncImplementation 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.DateUtil
import info.nightscout.androidaps.utils.FabricPrivacy import info.nightscout.androidaps.utils.FabricPrivacy
import info.nightscout.androidaps.utils.HardLimits import info.nightscout.androidaps.utils.HardLimits
@ -115,11 +115,11 @@ open class AppModule {
aapsLogger: AAPSLogger, sp: SP, rxBus: RxBus, rh: aapsLogger: AAPSLogger, sp: SP, rxBus: RxBus, rh:
ResourceHelper, activePlugin: ResourceHelper, activePlugin:
ActivePlugin, repository: AppRepository, dateUtil: DateUtil, config: Config, hardLimits: HardLimits, ActivePlugin, repository: AppRepository, dateUtil: DateUtil, config: Config, hardLimits: HardLimits,
aapsSchedulers: AapsSchedulers, fabricPrivacy: FabricPrivacy, deviceStatusData: DeviceStatusData aapsSchedulers: AapsSchedulers, fabricPrivacy: FabricPrivacy, processedDeviceStatusData: ProcessedDeviceStatusData
): ProfileFunction = ): ProfileFunction =
ProfileFunctionImpl( ProfileFunctionImpl(
aapsLogger, sp, rxBus, rh, activePlugin, repository, dateUtil, aapsLogger, sp, rxBus, rh, activePlugin, repository, dateUtil,
config, hardLimits, aapsSchedulers, fabricPrivacy, deviceStatusData config, hardLimits, aapsSchedulers, fabricPrivacy, processedDeviceStatusData
) )
@Provides @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.constraints.objectives.activities.ObjectivesExamDialog
import info.nightscout.androidaps.plugins.general.actions.ActionsFragment import info.nightscout.androidaps.plugins.general.actions.ActionsFragment
import info.nightscout.androidaps.plugins.general.maintenance.MaintenanceFragment 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.OverviewFragment
import info.nightscout.androidaps.plugins.general.overview.dialogs.EditQuickWizardDialog 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.general.wear.WearFragment
import info.nightscout.androidaps.plugins.pump.virtual.VirtualPumpFragment import info.nightscout.androidaps.plugins.pump.virtual.VirtualPumpFragment
import info.nightscout.androidaps.plugins.source.BGSourceFragment 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.androidaps.utils.protection.PasswordCheck
import info.nightscout.plugins.general.autotune.AutotuneFragment 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.actions.ActionsPlugin
import info.nightscout.androidaps.plugins.general.dataBroadcaster.DataBroadcastPlugin import info.nightscout.androidaps.plugins.general.dataBroadcaster.DataBroadcastPlugin
import info.nightscout.androidaps.plugins.general.maintenance.MaintenancePlugin 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.overview.OverviewPlugin
import info.nightscout.androidaps.plugins.general.persistentNotification.PersistentNotificationPlugin 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.general.wear.WearPlugin
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorPlugin import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorPlugin
import info.nightscout.androidaps.plugins.pump.combo.ComboPlugin 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.RandomBgPlugin
import info.nightscout.androidaps.plugins.source.TomatoPlugin import info.nightscout.androidaps.plugins.source.TomatoPlugin
import info.nightscout.androidaps.plugins.source.XdripPlugin 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.automation.AutomationPlugin
import info.nightscout.plugins.constraints.bgQualityCheck.BgQualityCheckPlugin import info.nightscout.plugins.constraints.bgQualityCheck.BgQualityCheckPlugin
import info.nightscout.plugins.constraints.dstHelper.DstHelperPlugin import info.nightscout.plugins.constraints.dstHelper.DstHelperPlugin
@ -316,6 +317,12 @@ abstract class PluginsListModule {
@IntKey(368) @IntKey(368)
abstract fun bindTidepoolPlugin(plugin: TidepoolPlugin): PluginBase abstract fun bindTidepoolPlugin(plugin: TidepoolPlugin): PluginBase
@Binds
@Unfinished
@IntoMap
@IntKey(362)
abstract fun bindNSClientV3Plugin(plugin: NSClientV3Plugin): PluginBase
@Binds @Binds
@AllConfigs @AllConfigs
@IntoMap @IntoMap

View file

@ -2,7 +2,7 @@ package info.nightscout.androidaps.di
import dagger.Module import dagger.Module
import dagger.android.ContributesAndroidInjector 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.overview.notifications.DismissNotificationService
import info.nightscout.androidaps.plugins.general.persistentNotification.DummyService import info.nightscout.androidaps.plugins.general.persistentNotification.DummyService
import info.nightscout.androidaps.plugins.general.wear.wearintegration.DataLayerListenerServiceMobile 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.Module
import dagger.android.ContributesAndroidInjector import dagger.android.ContributesAndroidInjector
import info.nightscout.androidaps.plugins.general.maintenance.ImportExportPrefsImpl 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.AidexPlugin
import info.nightscout.androidaps.plugins.source.DexcomPlugin import info.nightscout.androidaps.plugins.source.DexcomPlugin
import info.nightscout.androidaps.plugins.source.EversensePlugin 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.PoctechPlugin
import info.nightscout.androidaps.plugins.source.TomatoPlugin import info.nightscout.androidaps.plugins.source.TomatoPlugin
import info.nightscout.androidaps.plugins.source.XdripPlugin 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 @Module
@Suppress("unused") @Suppress("unused")
@ -37,4 +44,11 @@ abstract class WorkersModule {
@ContributesAndroidInjector abstract fun contributesNSClientMbgWorker(): NSClientMbgWorker @ContributesAndroidInjector abstract fun contributesNSClientMbgWorker(): NSClientMbgWorker
@ContributesAndroidInjector abstract fun contributesCsvExportWorker(): ImportExportPrefsImpl.CsvExportWorker @ContributesAndroidInjector abstract fun contributesCsvExportWorker(): ImportExportPrefsImpl.CsvExportWorker
@ContributesAndroidInjector abstract fun contributesAidexWorker(): AidexPlugin.AidexWorker @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 androidx.core.app.NotificationCompat
import dagger.android.HasAndroidInjector import dagger.android.HasAndroidInjector
import info.nightscout.androidaps.BuildConfig import info.nightscout.androidaps.BuildConfig
import info.nightscout.interfaces.Constants
import info.nightscout.androidaps.MainActivity import info.nightscout.androidaps.MainActivity
import info.nightscout.androidaps.R import info.nightscout.androidaps.R
import info.nightscout.androidaps.annotations.OpenForTesting 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.entities.ValueWithUnit
import info.nightscout.androidaps.database.transactions.InsertAndCancelCurrentOfflineEventTransaction import info.nightscout.androidaps.database.transactions.InsertAndCancelCurrentOfflineEventTransaction
import info.nightscout.androidaps.database.transactions.InsertTherapyEventAnnouncementTransaction import info.nightscout.androidaps.database.transactions.InsertTherapyEventAnnouncementTransaction
import info.nightscout.androidaps.extensions.buildDeviceStatus
import info.nightscout.androidaps.extensions.convertedToAbsolute import info.nightscout.androidaps.extensions.convertedToAbsolute
import info.nightscout.androidaps.extensions.convertedToPercent import info.nightscout.androidaps.extensions.convertedToPercent
import info.nightscout.androidaps.extensions.plannedRemainingMinutes import info.nightscout.androidaps.extensions.plannedRemainingMinutes
import info.nightscout.androidaps.interfaces.ActivePlugin import info.nightscout.androidaps.interfaces.ActivePlugin
import info.nightscout.interfaces.ActivityNames
import info.nightscout.androidaps.interfaces.CommandQueue import info.nightscout.androidaps.interfaces.CommandQueue
import info.nightscout.interfaces.Config
import info.nightscout.androidaps.interfaces.Constraint import info.nightscout.androidaps.interfaces.Constraint
import info.nightscout.androidaps.interfaces.Constraints import info.nightscout.androidaps.interfaces.Constraints
import info.nightscout.androidaps.interfaces.IobCobCalculator import info.nightscout.androidaps.interfaces.IobCobCalculator
import info.nightscout.androidaps.interfaces.Loop import info.nightscout.androidaps.interfaces.Loop
import info.nightscout.androidaps.interfaces.Loop.LastRun import info.nightscout.androidaps.interfaces.Loop.LastRun
import info.nightscout.androidaps.interfaces.PluginBase 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.Profile
import info.nightscout.androidaps.interfaces.ProfileFunction import info.nightscout.androidaps.interfaces.ProfileFunction
import info.nightscout.androidaps.interfaces.PumpDescription 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.configBuilder.RunningConfiguration
import info.nightscout.androidaps.plugins.general.overview.events.EventDismissNotification import info.nightscout.androidaps.plugins.general.overview.events.EventDismissNotification
import info.nightscout.androidaps.plugins.general.overview.events.EventNewNotification import info.nightscout.androidaps.plugins.general.overview.events.EventNewNotification
import info.nightscout.interfaces.notifications.Notification
import info.nightscout.androidaps.plugins.pump.virtual.VirtualPumpPlugin import info.nightscout.androidaps.plugins.pump.virtual.VirtualPumpPlugin
import info.nightscout.interfaces.queue.Callback
import info.nightscout.androidaps.receivers.ReceiverStatusStore import info.nightscout.androidaps.receivers.ReceiverStatusStore
import info.nightscout.androidaps.utils.DateUtil import info.nightscout.androidaps.utils.DateUtil
import info.nightscout.androidaps.utils.FabricPrivacy import info.nightscout.androidaps.utils.FabricPrivacy
import info.nightscout.androidaps.utils.HardLimits import info.nightscout.androidaps.utils.HardLimits
import info.nightscout.androidaps.utils.T import info.nightscout.androidaps.utils.T
import info.nightscout.androidaps.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.AapsSchedulers
import info.nightscout.rx.bus.RxBus import info.nightscout.rx.bus.RxBus
import info.nightscout.rx.events.EventAcceptOpenLoopChange 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)) aapsLogger.debug(LTag.APS, rh.gs(R.string.noprofileset))
return return
} }
if (!isEnabled(PluginType.APS)) { if (!isEnabled()) {
rxBus.send(EventOpenAPSUpdateResultGui(rh.gs(R.string.openapsma_disabled))) rxBus.send(EventOpenAPSUpdateResultGui(rh.gs(R.string.openapsma_disabled)))
aapsLogger.debug(LTag.APS, rh.gs(R.string.openapsma_disabled)) aapsLogger.debug(LTag.APS, rh.gs(R.string.openapsma_disabled))
return return

View file

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

View file

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

View file

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

View file

@ -1,22 +1,12 @@
package info.nightscout.androidaps.plugins.constraints.objectives 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 dagger.android.HasAndroidInjector
import info.nightscout.androidaps.BuildConfig
import info.nightscout.androidaps.R 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.androidaps.interfaces.ActivePlugin
import info.nightscout.interfaces.Config
import info.nightscout.androidaps.interfaces.Constraint import info.nightscout.androidaps.interfaces.Constraint
import info.nightscout.androidaps.interfaces.Constraints import info.nightscout.androidaps.interfaces.Constraints
import info.nightscout.androidaps.interfaces.PluginBase 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.ResourceHelper
import info.nightscout.androidaps.logging.UserEntryLogger
import info.nightscout.androidaps.plugins.constraints.objectives.objectives.Objective 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.Objective0
import info.nightscout.androidaps.plugins.constraints.objectives.objectives.Objective1 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.Objective6
import info.nightscout.androidaps.plugins.constraints.objectives.objectives.Objective7 import info.nightscout.androidaps.plugins.constraints.objectives.objectives.Objective7
import info.nightscout.androidaps.plugins.constraints.objectives.objectives.Objective9 import info.nightscout.androidaps.plugins.constraints.objectives.objectives.Objective9
import info.nightscout.androidaps.utils.DateUtil import info.nightscout.interfaces.Config
import info.nightscout.androidaps.utils.alertDialogs.OKDialog import info.nightscout.interfaces.PluginDescription
import info.nightscout.interfaces.PluginType
import info.nightscout.rx.logging.AAPSLogger import info.nightscout.rx.logging.AAPSLogger
import info.nightscout.shared.sharedPreferences.SP import info.nightscout.shared.sharedPreferences.SP
import java.util.Locale
import javax.inject.Inject import javax.inject.Inject
import javax.inject.Singleton import javax.inject.Singleton
@ -43,19 +33,17 @@ class ObjectivesPlugin @Inject constructor(
rh: ResourceHelper, rh: ResourceHelper,
private val activePlugin: ActivePlugin, private val activePlugin: ActivePlugin,
private val sp: SP, private val sp: SP,
config: Config, config: Config
private val dateUtil: DateUtil,
private val uel: UserEntryLogger
) : PluginBase( ) : PluginBase(
PluginDescription() PluginDescription()
.mainType(PluginType.CONSTRAINTS) .mainType(PluginType.CONSTRAINTS)
.fragmentClass(ObjectivesFragment::class.qualifiedName) .fragmentClass(ObjectivesFragment::class.qualifiedName)
.alwaysEnabled(config.APS) .alwaysEnabled(config.APS)
.showInList(config.APS) .showInList(config.APS)
.pluginIcon(R.drawable.ic_graduation) .pluginIcon(R.drawable.ic_graduation)
.pluginName(R.string.objectives) .pluginName(R.string.objectives)
.shortName(R.string.objectives_shortname) .shortName(R.string.objectives_shortname)
.description(R.string.description_objectives), .description(R.string.description_objectives),
aapsLogger, rh, injector aapsLogger, rh, injector
), Constraints { ), Constraints {
@ -115,34 +103,6 @@ class ObjectivesPlugin @Inject constructor(
sp.putBoolean(R.string.key_objectiveusescale, false) 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 { fun allPriorAccomplished(position: Int): Boolean {
var accomplished = true var accomplished = true
for (i in 0 until position) { 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.IobCobCalculator
import info.nightscout.androidaps.interfaces.Loop import info.nightscout.androidaps.interfaces.Loop
import info.nightscout.androidaps.interfaces.PluginBase import info.nightscout.androidaps.interfaces.PluginBase
import info.nightscout.androidaps.plugins.general.nsclient.NSClientPlugin
import info.nightscout.androidaps.plugins.pump.virtual.VirtualPumpPlugin import info.nightscout.androidaps.plugins.pump.virtual.VirtualPumpPlugin
import javax.inject.Inject import javax.inject.Inject
@ -18,7 +17,6 @@ class Objective0(injector: HasAndroidInjector) : Objective(injector, "config", R
@Inject lateinit var virtualPumpPlugin: VirtualPumpPlugin @Inject lateinit var virtualPumpPlugin: VirtualPumpPlugin
@Inject lateinit var repository: AppRepository @Inject lateinit var repository: AppRepository
@Inject lateinit var loop: Loop @Inject lateinit var loop: Loop
@Inject lateinit var nsClientPlugin: NSClientPlugin
@Inject lateinit var iobCobCalculator: IobCobCalculator @Inject lateinit var iobCobCalculator: IobCobCalculator
init { init {
@ -27,9 +25,9 @@ class Objective0(injector: HasAndroidInjector) : Objective(injector, "config", R
return sp.getBoolean(R.string.key_ObjectivesbgIsAvailableInNS, false) 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 { override fun isCompleted(): Boolean {
return nsClientPlugin.hasWritePermission() return activePlugin.firstActiveSync?.hasWritePermission == true
} }
}) })
tasks.add(object : Task(this, R.string.virtualpump_uploadstatus_title) { tasks.add(object : Task(this, R.string.virtualpump_uploadstatus_title) {

View file

@ -1,18 +1,15 @@
package info.nightscout.androidaps.plugins.constraints.objectives.objectives package info.nightscout.androidaps.plugins.constraints.objectives.objectives
import androidx.fragment.app.FragmentActivity
import dagger.android.HasAndroidInjector import dagger.android.HasAndroidInjector
import info.nightscout.androidaps.R import info.nightscout.androidaps.R
import info.nightscout.androidaps.plugins.constraints.objectives.ObjectivesPlugin import info.nightscout.androidaps.interfaces.ActivePlugin
import info.nightscout.androidaps.plugins.general.nsclient.NSClientPlugin
import info.nightscout.androidaps.utils.T import info.nightscout.androidaps.utils.T
import javax.inject.Inject import javax.inject.Inject
@Suppress("SpellCheckingInspection") @Suppress("SpellCheckingInspection")
class Objective3 @Inject constructor(injector: HasAndroidInjector) : Objective(injector, "openloop", R.string.objectives_openloop_objective, R.string.objectives_openloop_gate) { 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 activePlugin: ActivePlugin
@Inject lateinit var nsClientPlugin: NSClientPlugin
init { init {
tasks.add(MinimumDurationTask(this, T.days(7).msecs())) tasks.add(MinimumDurationTask(this, T.days(7).msecs()))
@ -22,17 +19,11 @@ class Objective3 @Inject constructor(injector: HasAndroidInjector) : Objective(i
} }
override val progress: String 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 { companion object {
private const val MANUAL_ENACTS_NEEDED = 20 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.safeQueryBroadcastReceivers
import info.nightscout.androidaps.extensions.toStringFull import info.nightscout.androidaps.extensions.toStringFull
import info.nightscout.androidaps.interfaces.ActivePlugin import info.nightscout.androidaps.interfaces.ActivePlugin
import info.nightscout.interfaces.Config
import info.nightscout.androidaps.interfaces.IobCobCalculator import info.nightscout.androidaps.interfaces.IobCobCalculator
import info.nightscout.androidaps.interfaces.Loop import info.nightscout.androidaps.interfaces.Loop
import info.nightscout.androidaps.interfaces.PluginBase 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.ProfileFunction
import info.nightscout.androidaps.interfaces.ResourceHelper import info.nightscout.androidaps.interfaces.ResourceHelper
import info.nightscout.androidaps.plugins.aps.events.EventOpenAPSUpdateGui 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.iob.iobCobCalculator.GlucoseStatusProvider
import info.nightscout.androidaps.plugins.sync.nsclient.data.ProcessedDeviceStatusData
import info.nightscout.androidaps.receivers.Intents import info.nightscout.androidaps.receivers.Intents
import info.nightscout.androidaps.receivers.ReceiverStatusStore import info.nightscout.androidaps.receivers.ReceiverStatusStore
import info.nightscout.androidaps.utils.DateUtil import info.nightscout.androidaps.utils.DateUtil
import info.nightscout.androidaps.utils.DefaultValueHelper import info.nightscout.androidaps.utils.DefaultValueHelper
import info.nightscout.androidaps.utils.FabricPrivacy import info.nightscout.androidaps.utils.FabricPrivacy
import info.nightscout.interfaces.Config
import info.nightscout.interfaces.PluginDescription
import info.nightscout.interfaces.PluginType
import info.nightscout.rx.AapsSchedulers import info.nightscout.rx.AapsSchedulers
import info.nightscout.rx.bus.RxBus import info.nightscout.rx.bus.RxBus
import info.nightscout.rx.events.Event import info.nightscout.rx.events.Event
import info.nightscout.rx.events.EventAutosensCalculationFinished import info.nightscout.rx.events.EventAutosensCalculationFinished
import info.nightscout.rx.events.EventOverviewBolusProgress
import info.nightscout.rx.logging.AAPSLogger import info.nightscout.rx.logging.AAPSLogger
import info.nightscout.rx.logging.LTag import info.nightscout.rx.logging.LTag
import io.reactivex.rxjava3.disposables.CompositeDisposable import io.reactivex.rxjava3.disposables.CompositeDisposable
@ -52,14 +51,12 @@ class DataBroadcastPlugin @Inject constructor(
private val iobCobCalculator: IobCobCalculator, private val iobCobCalculator: IobCobCalculator,
private val profileFunction: ProfileFunction, private val profileFunction: ProfileFunction,
private val defaultValueHelper: DefaultValueHelper, private val defaultValueHelper: DefaultValueHelper,
private val nsDeviceStatus: NSDeviceStatus, private val processedDeviceStatusData: ProcessedDeviceStatusData,
private val deviceStatusData: DeviceStatusData,
private val loop: Loop, private val loop: Loop,
private val activePlugin: ActivePlugin, private val activePlugin: ActivePlugin,
private var receiverStatusStore: ReceiverStatusStore, private var receiverStatusStore: ReceiverStatusStore,
private val config: Config, private val config: Config,
private val glucoseStatusProvider: GlucoseStatusProvider private val glucoseStatusProvider: GlucoseStatusProvider
) : PluginBase( ) : PluginBase(
PluginDescription() PluginDescription()
.mainType(PluginType.GENERAL) .mainType(PluginType.GENERAL)
@ -143,7 +140,7 @@ class DataBroadcastPlugin @Inject constructor(
private fun loopStatus(bundle: Bundle) { private fun loopStatus(bundle: Bundle) {
//batteries //batteries
bundle.putInt("phoneBattery", receiverStatusStore.batteryLevel) 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 if (config.APS && loop.lastRun?.lastTBREnact != 0L) { //we are AndroidAPS
bundle.putLong("suggestedTimeStamp", loop.lastRun?.lastAPSRun ?: -1L) bundle.putLong("suggestedTimeStamp", loop.lastRun?.lastAPSRun ?: -1L)
@ -156,7 +153,7 @@ class DataBroadcastPlugin @Inject constructor(
bundle.putString("enacted", loop.lastRun?.request?.json().toString()) bundle.putString("enacted", loop.lastRun?.request?.json().toString())
} }
} else { //NSClient or remote } else { //NSClient or remote
val data = deviceStatusData.openAPSData val data = processedDeviceStatusData.openAPSData
if (data.clockSuggested != 0L && data.suggested != null) { if (data.clockSuggested != 0L && data.suggested != null) {
bundle.putLong("suggestedTimeStamp", data.clockSuggested) bundle.putLong("suggestedTimeStamp", data.clockSuggested)
bundle.putString("suggested", data.suggested.toString()) 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.PluginDescription
import info.nightscout.interfaces.PluginType import info.nightscout.interfaces.PluginType
import info.nightscout.androidaps.interfaces.ResourceHelper 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.plugins.general.maintenance.LoggerUtils
import info.nightscout.rx.logging.AAPSLogger import info.nightscout.rx.logging.AAPSLogger
import info.nightscout.shared.sharedPreferences.SP 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 com.jjoe64.graphview.GraphView
import dagger.android.HasAndroidInjector import dagger.android.HasAndroidInjector
import dagger.android.support.DaggerFragment import dagger.android.support.DaggerFragment
import info.nightscout.interfaces.Constants
import info.nightscout.androidaps.R import info.nightscout.androidaps.R
import info.nightscout.androidaps.data.ProfileSealed import info.nightscout.androidaps.data.ProfileSealed
import info.nightscout.androidaps.database.AppRepository 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.toVisibility
import info.nightscout.androidaps.extensions.valueToUnitsString import info.nightscout.androidaps.extensions.valueToUnitsString
import info.nightscout.androidaps.interfaces.ActivePlugin import info.nightscout.androidaps.interfaces.ActivePlugin
import info.nightscout.interfaces.BuildHelper
import info.nightscout.androidaps.interfaces.CommandQueue import info.nightscout.androidaps.interfaces.CommandQueue
import info.nightscout.interfaces.Config
import info.nightscout.androidaps.interfaces.Constraint import info.nightscout.androidaps.interfaces.Constraint
import info.nightscout.androidaps.interfaces.Constraints import info.nightscout.androidaps.interfaces.Constraints
import info.nightscout.androidaps.interfaces.GlucoseUnit 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.logging.UserEntryLogger
import info.nightscout.androidaps.plugins.aps.loop.events.EventNewOpenLoopNotification import info.nightscout.androidaps.plugins.aps.loop.events.EventNewOpenLoopNotification
import info.nightscout.androidaps.plugins.aps.openAPSSMB.DetermineBasalResultSMB 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.activities.QuickWizardListActivity
import info.nightscout.androidaps.plugins.general.overview.events.EventUpdateOverviewCalcProgress import info.nightscout.androidaps.plugins.general.overview.events.EventUpdateOverviewCalcProgress
import info.nightscout.androidaps.plugins.general.overview.events.EventUpdateOverviewGraph 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.pump.omnipod.eros.OmnipodErosPumpPlugin
import info.nightscout.androidaps.plugins.source.DexcomPlugin import info.nightscout.androidaps.plugins.source.DexcomPlugin
import info.nightscout.androidaps.plugins.source.XdripPlugin 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.skins.SkinProvider
import info.nightscout.androidaps.utils.DateUtil import info.nightscout.androidaps.utils.DateUtil
import info.nightscout.androidaps.utils.DefaultValueHelper import info.nightscout.androidaps.utils.DefaultValueHelper
import info.nightscout.androidaps.utils.FabricPrivacy import info.nightscout.androidaps.utils.FabricPrivacy
import info.nightscout.interfaces.utils.JsonHelper
import info.nightscout.androidaps.utils.ToastUtils import info.nightscout.androidaps.utils.ToastUtils
import info.nightscout.androidaps.utils.alertDialogs.OKDialog import info.nightscout.androidaps.utils.alertDialogs.OKDialog
import info.nightscout.androidaps.utils.protection.ProtectionCheck 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.ui.UIRunnable
import info.nightscout.androidaps.utils.wizard.QuickWizard import info.nightscout.androidaps.utils.wizard.QuickWizard
import info.nightscout.automation.AutomationPlugin 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.plugins.constraints.bgQualityCheck.BgQualityCheckPlugin
import info.nightscout.rx.AapsSchedulers import info.nightscout.rx.AapsSchedulers
import info.nightscout.rx.bus.RxBus import info.nightscout.rx.bus.RxBus
@ -128,7 +129,8 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
@Inject lateinit var profileFunction: ProfileFunction @Inject lateinit var profileFunction: ProfileFunction
@Inject lateinit var constraintChecker: Constraints @Inject lateinit var constraintChecker: Constraints
@Inject lateinit var statusLightHandler: StatusLightHandler @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 loop: Loop
@Inject lateinit var activePlugin: ActivePlugin @Inject lateinit var activePlugin: ActivePlugin
@Inject lateinit var iobCobCalculator: IobCobCalculator @Inject lateinit var iobCobCalculator: IobCobCalculator
@ -722,16 +724,16 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
} }
// pump status from ns // pump status from ns
binding.pump.text = nsDeviceStatus.pumpStatus binding.pump.text = processedDeviceStatusData.pumpStatus(nsSettingsStatus)
binding.pump.setOnClickListener { activity?.let { OKDialog.show(it, rh.gs(R.string.pump), nsDeviceStatus.extendedPumpStatus) } } binding.pump.setOnClickListener { activity?.let { OKDialog.show(it, rh.gs(R.string.pump), processedDeviceStatusData.extendedPumpStatus) } }
// OpenAPS status from ns // OpenAPS status from ns
binding.openaps.text = nsDeviceStatus.openApsStatus binding.openaps.text = processedDeviceStatusData.openApsStatus
binding.openaps.setOnClickListener { activity?.let { OKDialog.show(it, rh.gs(R.string.openaps), nsDeviceStatus.extendedOpenApsStatus) } } binding.openaps.setOnClickListener { activity?.let { OKDialog.show(it, rh.gs(R.string.openaps), processedDeviceStatusData.extendedOpenApsStatus) } }
// Uploader status from ns // Uploader status from ns
binding.uploader.text = nsDeviceStatus.uploaderStatusSpanned binding.uploader.text = processedDeviceStatusData.uploaderStatusSpanned
binding.uploader.setOnClickListener { activity?.let { OKDialog.show(it, rh.gs(R.string.uploader), nsDeviceStatus.extendedUploaderStatus) } } 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 isfMgdl = profile?.getIsfMgdl()
val variableSens = val variableSens =
if (config.APS && request is DetermineBasalResultSMB) request.variableSens ?: 0.0 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 else 0.0
if (variableSens != isfMgdl && variableSens != 0.0 && isfMgdl != null) { 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.AppRepository
import info.nightscout.androidaps.database.ValueWrapper import info.nightscout.androidaps.database.ValueWrapper
import info.nightscout.androidaps.database.entities.TherapyEvent 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.androidaps.interfaces.ActivePlugin
import info.nightscout.interfaces.Config import info.nightscout.interfaces.Config
import info.nightscout.androidaps.plugins.pump.common.defs.PumpType 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.OmnipodErosPumpPlugin
import info.nightscout.androidaps.plugins.pump.omnipod.eros.driver.definition.OmnipodConstants
import info.nightscout.androidaps.utils.DateUtil import info.nightscout.androidaps.utils.DateUtil
import info.nightscout.androidaps.utils.DecimalFormatter import info.nightscout.androidaps.utils.DecimalFormatter
import info.nightscout.androidaps.utils.WarnColors import info.nightscout.androidaps.utils.WarnColors
import info.nightscout.androidaps.interfaces.ResourceHelper import info.nightscout.androidaps.interfaces.ResourceHelper
import info.nightscout.androidaps.plugins.pump.eopatch.AppConstant
import info.nightscout.shared.sharedPreferences.SP import info.nightscout.shared.sharedPreferences.SP
import javax.inject.Inject import javax.inject.Inject
import javax.inject.Singleton import javax.inject.Singleton

View file

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

View file

@ -6,7 +6,7 @@ import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import dagger.android.support.DaggerFragment import dagger.android.support.DaggerFragment
import info.nightscout.androidaps.databinding.WearFragmentBinding 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.DateUtil
import info.nightscout.androidaps.utils.FabricPrivacy import info.nightscout.androidaps.utils.FabricPrivacy
import info.nightscout.rx.AapsSchedulers import info.nightscout.rx.AapsSchedulers
@ -65,7 +65,7 @@ class WearFragment : DaggerFragment() {
_binding = null _binding = null
} }
fun updateGui() { private fun updateGui() {
_binding ?: return _binding ?: return
binding.connectedDevice.text = wearPlugin.connectedDevice 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.app.NotificationManager
import android.content.Context import android.content.Context
import dagger.android.HasAndroidInjector import dagger.android.HasAndroidInjector
import info.nightscout.interfaces.Constants
import info.nightscout.androidaps.R import info.nightscout.androidaps.R
import info.nightscout.androidaps.data.DetailedBolusInfo import info.nightscout.androidaps.data.DetailedBolusInfo
import info.nightscout.androidaps.database.AppRepository import info.nightscout.androidaps.database.AppRepository
import info.nightscout.androidaps.database.ValueWrapper 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.interfaces.end
import info.nightscout.androidaps.database.transactions.CancelCurrentTemporaryTargetIfAnyTransaction import info.nightscout.androidaps.database.transactions.CancelCurrentTemporaryTargetIfAnyTransaction
import info.nightscout.androidaps.database.transactions.InsertAndCancelCurrentTemporaryTargetTransaction 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.total
import info.nightscout.androidaps.extensions.valueToUnits import info.nightscout.androidaps.extensions.valueToUnits
import info.nightscout.androidaps.extensions.valueToUnitsString 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.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.general.overview.graphExtensions.GlucoseValueDataPoint
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.GlucoseStatusProvider 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.receivers.ReceiverStatusStore
import info.nightscout.androidaps.services.AlarmSoundServiceHelper 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.BolusWizard
import info.nightscout.androidaps.utils.wizard.QuickWizard import info.nightscout.androidaps.utils.wizard.QuickWizard
import info.nightscout.androidaps.utils.wizard.QuickWizardEntry import info.nightscout.androidaps.utils.wizard.QuickWizardEntry
import info.nightscout.interfaces.Config 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.AapsSchedulers
import info.nightscout.rx.bus.RxBus import info.nightscout.rx.bus.RxBus
import info.nightscout.rx.events.EventMobileToWear import info.nightscout.rx.events.EventMobileToWear
@ -43,7 +66,9 @@ import io.reactivex.rxjava3.disposables.CompositeDisposable
import io.reactivex.rxjava3.kotlin.plusAssign import io.reactivex.rxjava3.kotlin.plusAssign
import java.text.DateFormat import java.text.DateFormat
import java.text.SimpleDateFormat 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.concurrent.TimeUnit
import java.util.stream.Collectors import java.util.stream.Collectors
import javax.inject.Inject import javax.inject.Inject
@ -66,7 +91,7 @@ class DataHandlerMobile @Inject constructor(
private val glucoseStatusProvider: GlucoseStatusProvider, private val glucoseStatusProvider: GlucoseStatusProvider,
private val profileFunction: ProfileFunction, private val profileFunction: ProfileFunction,
private val loop: Loop, private val loop: Loop,
private val nsDeviceStatus: NSDeviceStatus, private val processedDeviceStatusData: ProcessedDeviceStatusData,
private val receiverStatusStore: ReceiverStatusStore, private val receiverStatusStore: ReceiverStatusStore,
private val quickWizard: QuickWizard, private val quickWizard: QuickWizard,
private val defaultValueHelper: DefaultValueHelper, private val defaultValueHelper: DefaultValueHelper,
@ -872,11 +897,11 @@ class DataHandlerMobile @Inject constructor(
//batteries //batteries
val phoneBattery = receiverStatusStore.batteryLevel val phoneBattery = receiverStatusStore.batteryLevel
val rigBattery = nsDeviceStatus.uploaderStatus.trim { it <= ' ' } val rigBattery = processedDeviceStatusData.uploaderStatus.trim { it <= ' ' }
//OpenAPS status //OpenAPS status
val openApsStatus = val openApsStatus =
if (config.APS) loop.lastRun?.let { if (it.lastTBREnact != 0L) it.lastTBREnact else -1 } ?: -1 if (config.APS) loop.lastRun?.let { if (it.lastTBREnact != 0L) it.lastTBREnact else -1 } ?: -1
else nsDeviceStatus.openApsTimestamp else processedDeviceStatusData.openApsTimestamp
rxBus.send( rxBus.send(
EventMobileToWear( EventMobileToWear(

View file

@ -1,26 +1,25 @@
package info.nightscout.androidaps.plugins.sensitivity package info.nightscout.androidaps.plugins.sensitivity
import dagger.android.HasAndroidInjector import dagger.android.HasAndroidInjector
import info.nightscout.interfaces.Constants
import info.nightscout.androidaps.R import info.nightscout.androidaps.R
import info.nightscout.androidaps.annotations.OpenForTesting import info.nightscout.androidaps.annotations.OpenForTesting
import info.nightscout.androidaps.database.AppRepository import info.nightscout.androidaps.database.AppRepository
import info.nightscout.androidaps.database.entities.TherapyEvent import info.nightscout.androidaps.database.entities.TherapyEvent
import info.nightscout.androidaps.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.Profile
import info.nightscout.androidaps.interfaces.ProfileFunction import info.nightscout.androidaps.interfaces.ProfileFunction
import info.nightscout.androidaps.interfaces.ResourceHelper import info.nightscout.androidaps.interfaces.ResourceHelper
import info.nightscout.androidaps.interfaces.Sensitivity.SensitivityType import info.nightscout.androidaps.interfaces.Sensitivity.SensitivityType
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.AutosensDataStore import info.nightscout.androidaps.plugins.iob.iobCobCalculator.AutosensDataStore
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.AutosensResult 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.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.plugins.utils.Percentile
import info.nightscout.rx.logging.AAPSLogger import info.nightscout.rx.logging.AAPSLogger
import info.nightscout.rx.logging.LTag import info.nightscout.rx.logging.LTag
import info.nightscout.shared.sharedPreferences.SP import info.nightscout.shared.sharedPreferences.SP
import org.json.JSONException import org.json.JSONException
import org.json.JSONObject import org.json.JSONObject

View file

@ -1,27 +1,26 @@
package info.nightscout.androidaps.plugins.sensitivity package info.nightscout.androidaps.plugins.sensitivity
import dagger.android.HasAndroidInjector import dagger.android.HasAndroidInjector
import info.nightscout.interfaces.Constants
import info.nightscout.androidaps.R import info.nightscout.androidaps.R
import info.nightscout.androidaps.annotations.OpenForTesting import info.nightscout.androidaps.annotations.OpenForTesting
import info.nightscout.androidaps.database.AppRepository import info.nightscout.androidaps.database.AppRepository
import info.nightscout.androidaps.database.entities.TherapyEvent import info.nightscout.androidaps.database.entities.TherapyEvent
import info.nightscout.androidaps.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.Profile
import info.nightscout.androidaps.interfaces.ProfileFunction import info.nightscout.androidaps.interfaces.ProfileFunction
import info.nightscout.androidaps.interfaces.ResourceHelper import info.nightscout.androidaps.interfaces.ResourceHelper
import info.nightscout.androidaps.interfaces.Sensitivity.SensitivityType 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.AutosensDataStore
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.AutosensResult 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.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.plugins.utils.Percentile
import info.nightscout.rx.logging.AAPSLogger import info.nightscout.rx.logging.AAPSLogger
import info.nightscout.rx.logging.LTag import info.nightscout.rx.logging.LTag
import info.nightscout.shared.sharedPreferences.SP import info.nightscout.shared.sharedPreferences.SP
import org.json.JSONException import org.json.JSONException
import org.json.JSONObject import org.json.JSONObject

View file

@ -2,22 +2,22 @@ package info.nightscout.androidaps.plugins.sensitivity
import androidx.collection.LongSparseArray import androidx.collection.LongSparseArray
import dagger.android.HasAndroidInjector import dagger.android.HasAndroidInjector
import info.nightscout.interfaces.Constants
import info.nightscout.androidaps.R import info.nightscout.androidaps.R
import info.nightscout.androidaps.annotations.OpenForTesting import info.nightscout.androidaps.annotations.OpenForTesting
import info.nightscout.androidaps.database.AppRepository import info.nightscout.androidaps.database.AppRepository
import info.nightscout.androidaps.database.entities.TherapyEvent import info.nightscout.androidaps.database.entities.TherapyEvent
import info.nightscout.androidaps.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.Profile
import info.nightscout.androidaps.interfaces.ProfileFunction import info.nightscout.androidaps.interfaces.ProfileFunction
import info.nightscout.androidaps.interfaces.ResourceHelper import info.nightscout.androidaps.interfaces.ResourceHelper
import info.nightscout.androidaps.interfaces.Sensitivity.SensitivityType import info.nightscout.androidaps.interfaces.Sensitivity.SensitivityType
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.AutosensDataStore import info.nightscout.androidaps.plugins.iob.iobCobCalculator.AutosensDataStore
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.AutosensResult 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.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.AAPSLogger
import info.nightscout.rx.logging.LTag import info.nightscout.rx.logging.LTag
import info.nightscout.shared.sharedPreferences.SP import info.nightscout.shared.sharedPreferences.SP
@ -147,13 +147,16 @@ class SensitivityWeightedAveragePlugin @Inject constructor(
else -> "Sensitivity normal" else -> "Sensitivity normal"
} }
aapsLogger.debug(LTag.AUTOSENS, sensResult) aapsLogger.debug(LTag.AUTOSENS, sensResult)
val output = fillResult(ratio, current.cob, pastSensitivity, ratioLimit, val output = fillResult(
sensResult, data.size()) ratio, current.cob, pastSensitivity, ratioLimit,
sensResult, data.size()
)
aapsLogger.debug( aapsLogger.debug(
LTag.AUTOSENS, "Sensitivity to: " LTag.AUTOSENS, "Sensitivity to: "
+ dateUtil.dateAndTimeString(toTime) + + dateUtil.dateAndTimeString(toTime) +
" ratio: " + output.ratio " ratio: " + output.ratio
+ " mealCOB: " + current.cob) + " mealCOB: " + current.cob
)
return output return output
} }
@ -178,7 +181,10 @@ class SensitivityWeightedAveragePlugin @Inject constructor(
override fun applyConfiguration(configuration: JSONObject) { override fun applyConfiguration(configuration: JSONObject) {
try { 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_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_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))) 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) { } 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.AppRepository
import info.nightscout.androidaps.database.entities.GlucoseValue import info.nightscout.androidaps.database.entities.GlucoseValue
import info.nightscout.androidaps.database.transactions.CgmSourceTransaction import info.nightscout.androidaps.database.transactions.CgmSourceTransaction
import info.nightscout.androidaps.interfaces.ActivePlugin
import info.nightscout.androidaps.interfaces.BgSource import info.nightscout.androidaps.interfaces.BgSource
import info.nightscout.interfaces.Config
import info.nightscout.androidaps.interfaces.PluginBase 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.ResourceHelper
import info.nightscout.androidaps.interfaces.XDripBroadcast 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.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.receivers.DataWorkerStorage
import info.nightscout.androidaps.utils.DateUtil import info.nightscout.androidaps.utils.DateUtil
import info.nightscout.androidaps.utils.T import info.nightscout.androidaps.utils.T
import info.nightscout.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.bus.RxBus
import info.nightscout.rx.logging.AAPSLogger import info.nightscout.rx.logging.AAPSLogger
import info.nightscout.rx.logging.LTag import info.nightscout.rx.logging.LTag
import info.nightscout.sdk.localmodel.entry.NSSgvV3
import info.nightscout.shared.sharedPreferences.SP import info.nightscout.shared.sharedPreferences.SP
import org.json.JSONArray
import org.json.JSONObject import org.json.JSONObject
import javax.inject.Inject import javax.inject.Inject
import javax.inject.Singleton import javax.inject.Singleton
@ -39,12 +42,12 @@ class NSClientSourcePlugin @Inject constructor(
config: Config config: Config
) : PluginBase( ) : PluginBase(
PluginDescription() PluginDescription()
.mainType(PluginType.BGSOURCE) .mainType(PluginType.BGSOURCE)
.fragmentClass(BGSourceFragment::class.java.name) .fragmentClass(BGSourceFragment::class.java.name)
.pluginIcon(R.drawable.ic_nsclient_bg) .pluginIcon(R.drawable.ic_nsclient_bg)
.pluginName(R.string.nsclientbg) .pluginName(R.string.nsclientbg)
.shortName(R.string.nsclientbgshort) .shortName(R.string.nsclientbgshort)
.description(R.string.description_source_ns_client), .description(R.string.description_source_ns_client),
aapsLogger, rh, injector aapsLogger, rh, injector
), BgSource { ), BgSource {
@ -65,7 +68,7 @@ class NSClientSourcePlugin @Inject constructor(
override fun shouldUploadToNs(glucoseValue: GlucoseValue): Boolean = false override fun shouldUploadToNs(glucoseValue: GlucoseValue): Boolean = false
private fun detectSource(glucoseValue: GlucoseValue) { internal fun detectSource(glucoseValue: GlucoseValue) {
if (glucoseValue.timestamp > lastBGTimeStamp) { if (glucoseValue.timestamp > lastBGTimeStamp) {
isAdvancedFilteringEnabled = arrayOf( isAdvancedFilteringEnabled = arrayOf(
GlucoseValue.SourceSensor.DEXCOM_NATIVE_UNKNOWN, GlucoseValue.SourceSensor.DEXCOM_NATIVE_UNKNOWN,
@ -93,8 +96,8 @@ class NSClientSourcePlugin @Inject constructor(
@Inject lateinit var dataWorkerStorage: DataWorkerStorage @Inject lateinit var dataWorkerStorage: DataWorkerStorage
@Inject lateinit var repository: AppRepository @Inject lateinit var repository: AppRepository
@Inject lateinit var xDripBroadcast: XDripBroadcast @Inject lateinit var xDripBroadcast: XDripBroadcast
@Inject lateinit var dexcomPlugin: DexcomPlugin @Inject lateinit var activePlugin: ActivePlugin
@Inject lateinit var nsClientPlugin: NSClientPlugin @Inject lateinit var storeDataForDb: StoreDataForDb
init { init {
(context.applicationContext as HasAndroidInjector).androidInjector().inject(this) (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") @Suppress("SpellCheckingInspection")
override fun doWork(): Result { override fun doWork(): Result {
var ret = Result.success() 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")) ?: return Result.failure(workDataOf("Error" to "missing input data"))
xDripBroadcast.sendSgvs(sgvs)
if (!nsClientSourcePlugin.isEnabled() && !sp.getBoolean(R.string.key_ns_receive_cgm, false)) if (!nsClientSourcePlugin.isEnabled() && !sp.getBoolean(R.string.key_ns_receive_cgm, false))
return Result.success(workDataOf("Result" to "Sync not enabled")) 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") try {
val glucoseValues = mutableListOf<CgmSourceTransaction.TransactionGlucoseValue>() if (sgvs is JSONArray) { // V1 client
for (i in 0 until sgvs.length()) { xDripBroadcast.sendSgvs(sgvs)
val sgv = toGv(sgvs.getJSONObject(i)) ?: continue
if (sgv.timestamp < dateUtil.now() && sgv.timestamp > latestDateInReceivedData) latestDateInReceivedData = sgv.timestamp for (i in 0 until sgvs.length()) {
glucoseValues += sgv 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 ? // Was that sgv more less 5 mins ago ?
if (T.msecs(dateUtil.now() - latestDateInReceivedData).mins() < 5L) { if (T.msecs(dateUtil.now() - latestDateInReceivedData).mins() < 5L) {
rxBus.send(EventDismissNotification(Notification.NS_ALARM)) rxBus.send(EventDismissNotification(Notification.NS_ALARM))
rxBus.send(EventDismissNotification(Notification.NS_URGENT_ALARM)) rxBus.send(EventDismissNotification(Notification.NS_URGENT_ALARM))
} }
nsClientPlugin.updateLatestDateReceivedIfNewer(latestDateInReceivedData) storeDataForDb.glucoseValues.addAll(glucoseValues)
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")
}
}
} catch (e: Exception) { } catch (e: Exception) {
aapsLogger.error("Unhandled exception", e) aapsLogger.error("Unhandled exception", e)
ret = Result.failure(workDataOf("Error" to e.toString())) 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.entities.GlucoseValue
import info.nightscout.androidaps.database.transactions.CgmSourceTransaction import info.nightscout.androidaps.database.transactions.CgmSourceTransaction
import info.nightscout.androidaps.interfaces.BgSource import info.nightscout.androidaps.interfaces.BgSource
import info.nightscout.interfaces.BuildHelper
import info.nightscout.androidaps.interfaces.PluginBase 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.ResourceHelper
import info.nightscout.androidaps.interfaces.XDripBroadcast import info.nightscout.androidaps.interfaces.XDripBroadcast
import info.nightscout.androidaps.plugins.pump.virtual.VirtualPumpPlugin import info.nightscout.androidaps.plugins.pump.virtual.VirtualPumpPlugin
import info.nightscout.androidaps.utils.T import info.nightscout.androidaps.utils.T
import info.nightscout.androidaps.utils.extensions.isRunningTest 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.AAPSLogger
import info.nightscout.rx.logging.LTag import info.nightscout.rx.logging.LTag
import info.nightscout.shared.sharedPreferences.SP 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.Bundle
import android.os.Handler
import android.os.HandlerThread
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.Menu import android.view.Menu
import android.view.MenuInflater import android.view.MenuInflater
@ -12,26 +14,30 @@ import androidx.core.view.MenuProvider
import androidx.lifecycle.Lifecycle import androidx.lifecycle.Lifecycle
import dagger.android.support.DaggerFragment import dagger.android.support.DaggerFragment
import info.nightscout.androidaps.R import info.nightscout.androidaps.R
import info.nightscout.androidaps.database.entities.UserEntry.Action import info.nightscout.androidaps.database.entities.UserEntry
import info.nightscout.androidaps.database.entities.UserEntry.Sources
import info.nightscout.androidaps.databinding.NsClientFragmentBinding import info.nightscout.androidaps.databinding.NsClientFragmentBinding
import info.nightscout.androidaps.interfaces.ActivePlugin
import info.nightscout.androidaps.interfaces.DataSyncSelector 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.interfaces.ResourceHelper
import info.nightscout.androidaps.logging.UserEntryLogger 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.FabricPrivacy
import info.nightscout.androidaps.utils.alertDialogs.OKDialog import info.nightscout.androidaps.utils.alertDialogs.OKDialog
import info.nightscout.rx.AapsSchedulers import info.nightscout.rx.AapsSchedulers
import info.nightscout.rx.bus.RxBus import info.nightscout.rx.bus.RxBus
import info.nightscout.rx.events.EventNSClientRestart import info.nightscout.rx.events.EventNSClientRestart
import info.nightscout.rx.logging.AAPSLogger
import info.nightscout.shared.sharedPreferences.SP import info.nightscout.shared.sharedPreferences.SP
import io.reactivex.rxjava3.disposables.CompositeDisposable import io.reactivex.rxjava3.disposables.CompositeDisposable
import io.reactivex.rxjava3.kotlin.plusAssign import io.reactivex.rxjava3.kotlin.plusAssign
import javax.inject.Inject 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 sp: SP
@Inject lateinit var rh: ResourceHelper @Inject lateinit var rh: ResourceHelper
@Inject lateinit var rxBus: RxBus @Inject lateinit var rxBus: RxBus
@ -39,6 +45,8 @@ class NSClientFragment : DaggerFragment(), MenuProvider {
@Inject lateinit var aapsSchedulers: AapsSchedulers @Inject lateinit var aapsSchedulers: AapsSchedulers
@Inject lateinit var dataSyncSelector: DataSyncSelector @Inject lateinit var dataSyncSelector: DataSyncSelector
@Inject lateinit var uel: UserEntryLogger @Inject lateinit var uel: UserEntryLogger
@Inject lateinit var aapsLogger: AAPSLogger
@Inject lateinit var activePlugin: ActivePlugin
companion object { companion object {
@ -46,10 +54,17 @@ class NSClientFragment : DaggerFragment(), MenuProvider {
const val ID_MENU_RESTART = 508 const val ID_MENU_RESTART = 508
const val ID_MENU_SEND_NOW = 509 const val ID_MENU_SEND_NOW = 509
const val ID_MENU_FULL_SYNC = 510 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 val disposable = CompositeDisposable()
private var handler = Handler(HandlerThread(this::class.simpleName + "Handler").also { it.start() }.looper)
private var _binding: NsClientFragmentBinding? = null private var _binding: NsClientFragmentBinding? = null
// This property is only valid between onCreateView and // This property is only valid between onCreateView and
@ -65,22 +80,22 @@ class NSClientFragment : DaggerFragment(), MenuProvider {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState) super.onViewCreated(view, savedInstanceState)
binding.autoscroll.isChecked = nsClientPlugin.autoscroll binding.autoscroll.isChecked = sp.getBoolean(R.string.key_nsclientinternal_autoscroll, true)
binding.autoscroll.setOnCheckedChangeListener { _, isChecked -> binding.autoscroll.setOnCheckedChangeListener { _, isChecked ->
sp.putBoolean(R.string.key_nsclientinternal_autoscroll, isChecked) sp.putBoolean(R.string.key_nsclientinternal_autoscroll, isChecked)
nsClientPlugin.autoscroll = isChecked
updateGui() updateGui()
} }
binding.paused.isChecked = nsClientPlugin.paused binding.paused.isChecked = sp.getBoolean(R.string.key_nsclientinternal_paused, false)
binding.paused.setOnCheckedChangeListener { _, isChecked -> binding.paused.setOnCheckedChangeListener { _, isChecked ->
uel.log(if (isChecked) Action.NS_PAUSED else Action.NS_RESUME, Sources.NSClient) uel.log(if (isChecked) UserEntry.Action.NS_PAUSED else UserEntry.Action.NS_RESUME, UserEntry.Sources.NSClient)
nsClientPlugin.pause(isChecked) nsClientPlugin?.pause(isChecked)
updateGui() updateGui()
} }
} }
override fun onCreateMenu(menu: Menu, inflater: MenuInflater) { 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_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_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) 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 = override fun onMenuItemSelected(item: MenuItem): Boolean =
when (item.itemId) { when (item.itemId) {
ID_MENU_CLEAR_LOG -> { ID_MENU_CLEAR_LOG -> {
nsClientPlugin.clearLog() nsClientPlugin?.clearLog()
true true
} }
@ -101,7 +116,7 @@ class NSClientFragment : DaggerFragment(), MenuProvider {
} }
ID_MENU_SEND_NOW -> { ID_MENU_SEND_NOW -> {
nsClientPlugin.resend("GUI") nsClientPlugin?.resend("GUI")
true true
} }
@ -109,12 +124,17 @@ class NSClientFragment : DaggerFragment(), MenuProvider {
context?.let { context -> context?.let { context ->
OKDialog.showConfirmation( OKDialog.showConfirmation(
context, rh.gs(R.string.nsclientinternal), rh.gs(R.string.full_sync_comment), context, rh.gs(R.string.nsclientinternal), rh.gs(R.string.full_sync_comment),
Runnable { dataSyncSelector.resetToNextFullSync() } Runnable { nsClientPlugin?.resetToFullSync() }
) )
} }
true true
} }
ID_MENU_TEST -> {
nsClientPlugin?.let { plugin -> if (plugin is NSClientV3Plugin) handler.post { plugin.test() } }
true
}
else -> false else -> false
} }
@ -134,12 +154,11 @@ class NSClientFragment : DaggerFragment(), MenuProvider {
private fun updateGui() { private fun updateGui() {
if (_binding == null) return if (_binding == null) return
nsClientPlugin.updateLog()
binding.paused.isChecked = sp.getBoolean(R.string.key_nsclientinternal_paused, false) binding.paused.isChecked = sp.getBoolean(R.string.key_nsclientinternal_paused, false)
binding.log.text = nsClientPlugin.textLog binding.log.text = nsClientPlugin?.textLog()
if (nsClientPlugin.autoscroll) binding.logScrollview.fullScroll(ScrollView.FOCUS_DOWN) if (sp.getBoolean(R.string.key_nsclientinternal_autoscroll, true)) binding.logScrollview.fullScroll(ScrollView.FOCUS_DOWN)
binding.url.text = nsClientPlugin.url() binding.url.text = nsClientPlugin?.address
binding.status.text = nsClientPlugin.status binding.status.text = nsClientPlugin?.status
val size = dataSyncSelector.queueSize() val size = dataSyncSelector.queueSize()
binding.queue.text = if (size >= 0) size.toString() else rh.gs(R.string.value_unavailable_short) 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 info.nightscout.rx.events.Event
import java.text.SimpleDateFormat import java.text.SimpleDateFormat
import java.util.Locale 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() var date = System.currentTimeMillis()
private var timeFormat = SimpleDateFormat("HH:mm:ss", Locale.getDefault()) 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 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.R
import info.nightscout.androidaps.database.AppRepository 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.ActivePlugin
import info.nightscout.androidaps.interfaces.DataSyncSelector import info.nightscout.androidaps.interfaces.DataSyncSelector
import info.nightscout.androidaps.interfaces.ProfileFunction import info.nightscout.androidaps.interfaces.ProfileFunction
import info.nightscout.plugins.sync.nsclient.extensions.toJson
import info.nightscout.androidaps.utils.DateUtil import info.nightscout.androidaps.utils.DateUtil
import info.nightscout.androidaps.utils.extensions.toJson
import info.nightscout.plugins.profile.ProfilePlugin import info.nightscout.plugins.profile.ProfilePlugin
import info.nightscout.rx.logging.AAPSLogger import info.nightscout.rx.logging.AAPSLogger
import info.nightscout.rx.logging.LTag import info.nightscout.rx.logging.LTag
@ -34,7 +36,6 @@ class DataSyncSelectorImplementation @Inject constructor(
private val aapsLogger: AAPSLogger, private val aapsLogger: AAPSLogger,
private val dateUtil: DateUtil, private val dateUtil: DateUtil,
private val profileFunction: ProfileFunction, private val profileFunction: ProfileFunction,
private val nsClientPlugin: NSClientPlugin,
private val activePlugin: ActivePlugin, private val activePlugin: ActivePlugin,
private val appRepository: AppRepository, private val appRepository: AppRepository,
private val profilePlugin: ProfilePlugin private val profilePlugin: ProfilePlugin
@ -96,30 +97,10 @@ class DataSyncSelectorImplementation @Inject constructor(
} }
override fun resetToNextFullSync() { 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) 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) 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) 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_extended_bolus_last_synced_id)
sp.remove(R.string.key_ns_food_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_bolus_last_synced_id)
sp.remove(R.string.key_ns_carbs_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) { override fun confirmLastBolusIdIfGreater(lastSynced: Long) {
if (lastSynced > sp.getLong(R.string.key_ns_bolus_last_synced_id, 0)) { 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) sp.putLong(R.string.key_ns_bolus_last_synced_id, lastSynced)
} }
} }
@ -153,9 +134,7 @@ class DataSyncSelectorImplementation @Inject constructor(
} }
} }
//private var lastBolusId = -1L override tailrec fun processChangedBolusesCompat() {
//private var lastBolusTime = -1L
override fun processChangedBolusesCompat(): Boolean {
val lastDbIdWrapped = appRepository.getLastBolusIdWrapped().blockingGet() val lastDbIdWrapped = appRepository.getLastBolusIdWrapped().blockingGet()
val lastDbId = if (lastDbIdWrapped is ValueWrapper.Existing) lastDbIdWrapped.value else 0L val lastDbId = if (lastDbIdWrapped is ValueWrapper.Existing) lastDbIdWrapped.value else 0L
var startId = sp.getLong(R.string.key_ns_bolus_last_synced_id, 0) 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) sp.putLong(R.string.key_ns_bolus_last_synced_id, 0)
startId = 0 startId = 0
} }
//if (startId == lastBolusId && dateUtil.now() - lastBolusTime < 5000) return false
//lastBolusId = startId
//lastBolusTime = dateUtil.now()
queueCounter.bolusesRemaining = lastDbId - startId queueCounter.bolusesRemaining = lastDbId - startId
appRepository.getNextSyncElementBolus(startId).blockingGet()?.let { bolus -> appRepository.getNextSyncElementBolus(startId).blockingGet()?.let { bolus ->
aapsLogger.info(LTag.NSCLIENT, "Loading Bolus data Start: $startId ID: ${bolus.first.id} HistoryID: ${bolus.second.id} ") aapsLogger.info(LTag.NSCLIENT, "Loading Bolus data Start: $startId ID: ${bolus.first.id} HistoryID: ${bolus.second.id} ")
when { when {
// only NsId changed, no need to upload // new record with existing NS id => must be coming from NS => ignore
bolus.first.onlyNsIdAdded(bolus.second) -> { 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) confirmLastBolusIdIfGreater(bolus.second.id)
//lastBolusId = -1
processChangedBolusesCompat() 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} ") 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 // without nsId = create new
bolus.first.interfaceIDs.nightscoutId == null -> bolus.first.interfaceIDs.nightscoutId == null ->
nsClientPlugin.nsClientService?.dbAdd("treatments", bolus.first.toJson(true, dateUtil), DataSyncSelector.PairBolus(bolus.first, bolus.second.id), "$startId/$lastDbId") activePlugin.activeNsClient?.nsClientService?.dbAdd(
// with nsId = update "treatments",
bolus.first.interfaceIDs.nightscoutId != null -> bolus.first.toJson(true, dateUtil),
nsClientPlugin.nsClientService?.dbUpdate( 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", "treatments",
bolus.first.interfaceIDs.nightscoutId, bolus.first.interfaceIDs.nightscoutId,
bolus.first.toJson(false, dateUtil), bolus.first.toJson(false, dateUtil),
@ -191,14 +178,13 @@ class DataSyncSelectorImplementation @Inject constructor(
"$startId/$lastDbId" "$startId/$lastDbId"
) )
} }
return true return
} }
return false
} }
override fun confirmLastCarbsIdIfGreater(lastSynced: Long) { override fun confirmLastCarbsIdIfGreater(lastSynced: Long) {
if (lastSynced > sp.getLong(R.string.key_ns_carbs_last_synced_id, 0)) { 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) sp.putLong(R.string.key_ns_carbs_last_synced_id, lastSynced)
} }
} }
@ -211,9 +197,7 @@ class DataSyncSelectorImplementation @Inject constructor(
} }
} }
//private var lastCarbsId = -1L override tailrec fun processChangedCarbsCompat() {
//private var lastCarbsTime = -1L
override fun processChangedCarbsCompat(): Boolean {
val lastDbIdWrapped = appRepository.getLastCarbsIdWrapped().blockingGet() val lastDbIdWrapped = appRepository.getLastCarbsIdWrapped().blockingGet()
val lastDbId = if (lastDbIdWrapped is ValueWrapper.Existing) lastDbIdWrapped.value else 0L val lastDbId = if (lastDbIdWrapped is ValueWrapper.Existing) lastDbIdWrapped.value else 0L
var startId = sp.getLong(R.string.key_ns_carbs_last_synced_id, 0) 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) sp.putLong(R.string.key_ns_carbs_last_synced_id, 0)
startId = 0 startId = 0
} }
//if (startId == lastCarbsId && dateUtil.now() - lastCarbsTime < 5000) return false
//lastCarbsId = startId
//lastCarbsTime = dateUtil.now()
queueCounter.carbsRemaining = lastDbId - startId queueCounter.carbsRemaining = lastDbId - startId
appRepository.getNextSyncElementCarbs(startId).blockingGet()?.let { carb -> appRepository.getNextSyncElementCarbs(startId).blockingGet()?.let { carb ->
aapsLogger.info(LTag.NSCLIENT, "Loading Carbs data Start: $startId ID: ${carb.first.id} HistoryID: ${carb.second.id} ") aapsLogger.info(LTag.NSCLIENT, "Loading Carbs data Start: $startId ID: ${carb.first.id} HistoryID: ${carb.second.id} ")
when { when {
// only NsId changed, no need to upload // new record with existing NS id => must be coming from NS => ignore
carb.first.onlyNsIdAdded(carb.second) -> { 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) confirmLastCarbsIdIfGreater(carb.second.id)
//lastCarbsId = -1
processChangedCarbsCompat() 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} ") 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 // without nsId = create new
carb.first.interfaceIDs.nightscoutId == null -> carb.first.interfaceIDs.nightscoutId == null ->
nsClientPlugin.nsClientService?.dbAdd("treatments", carb.first.toJson(true, dateUtil), DataSyncSelector.PairCarbs(carb.first, carb.second.id), "$startId/$lastDbId") activePlugin.activeNsClient?.nsClientService?.dbAdd("treatments", carb.first.toJson(true, dateUtil), DataSyncSelector.PairCarbs(carb.first, carb.second.id), "$startId/$lastDbId")
// with nsId = update // with nsId = update if it's modified record
carb.first.interfaceIDs.nightscoutId != null -> carb.first.interfaceIDs.nightscoutId != null && carb.first.id != carb.second.id ->
nsClientPlugin.nsClientService?.dbUpdate( activePlugin.activeNsClient?.nsClientService?.dbUpdate(
"treatments", "treatments",
carb.first.interfaceIDs.nightscoutId, carb.first.interfaceIDs.nightscoutId,
carb.first.toJson(false, dateUtil), carb.first.toJson(false, dateUtil),
@ -249,14 +236,13 @@ class DataSyncSelectorImplementation @Inject constructor(
"$startId/$lastDbId" "$startId/$lastDbId"
) )
} }
return true return
} }
return false
} }
override fun confirmLastBolusCalculatorResultsIdIfGreater(lastSynced: Long) { override fun confirmLastBolusCalculatorResultsIdIfGreater(lastSynced: Long) {
if (lastSynced > sp.getLong(R.string.key_ns_bolus_calculator_result_last_synced_id, 0)) { 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) 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 override tailrec fun processChangedBolusCalculatorResultsCompat() {
//private var lastBcrTime = -1L
override fun processChangedBolusCalculatorResultsCompat(): Boolean {
val lastDbIdWrapped = appRepository.getLastBolusCalculatorResultIdWrapped().blockingGet() val lastDbIdWrapped = appRepository.getLastBolusCalculatorResultIdWrapped().blockingGet()
val lastDbId = if (lastDbIdWrapped is ValueWrapper.Existing) lastDbIdWrapped.value else 0L 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) 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) sp.putLong(R.string.key_ns_bolus_calculator_result_last_synced_id, 0)
startId = 0 startId = 0
} }
//if (startId == lastBcrId && dateUtil.now() - lastBcrTime < 5000) return false
//lastBcrId = startId
//lastBcrTime = dateUtil.now()
queueCounter.bcrRemaining = lastDbId - startId queueCounter.bcrRemaining = lastDbId - startId
appRepository.getNextSyncElementBolusCalculatorResult(startId).blockingGet()?.let { bolusCalculatorResult -> appRepository.getNextSyncElementBolusCalculatorResult(startId).blockingGet()?.let { bolusCalculatorResult ->
aapsLogger.info(LTag.NSCLIENT, "Loading BolusCalculatorResult data Start: $startId ID: ${bolusCalculatorResult.first.id} HistoryID: ${bolusCalculatorResult.second.id} ") aapsLogger.info(LTag.NSCLIENT, "Loading BolusCalculatorResult data Start: $startId ID: ${bolusCalculatorResult.first.id} HistoryID: ${bolusCalculatorResult.second.id} ")
when { when {
// only NsId changed, no need to upload // new record with existing NS id => must be coming from NS => ignore
bolusCalculatorResult.first.onlyNsIdAdded(bolusCalculatorResult.second) -> { 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) confirmLastBolusCalculatorResultsIdIfGreater(bolusCalculatorResult.second.id)
//lastBcrId = -1
processChangedBolusCalculatorResultsCompat() 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} ") 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 // without nsId = create new
bolusCalculatorResult.first.interfaceIDs.nightscoutId == null -> bolusCalculatorResult.first.interfaceIDs.nightscoutId == null ->
nsClientPlugin.nsClientService?.dbAdd( activePlugin.activeNsClient?.nsClientService?.dbAdd(
"treatments", "treatments",
bolusCalculatorResult.first.toJson(true, dateUtil, profileFunction), bolusCalculatorResult.first.toJson(true, dateUtil, profileFunction),
DataSyncSelector.PairBolusCalculatorResult(bolusCalculatorResult.first, bolusCalculatorResult.second.id), DataSyncSelector.PairBolusCalculatorResult(bolusCalculatorResult.first, bolusCalculatorResult.second.id),
"$startId/$lastDbId" "$startId/$lastDbId"
) )
// with nsId = update // with nsId = update if it's modified record
bolusCalculatorResult.first.interfaceIDs.nightscoutId != null -> bolusCalculatorResult.first.interfaceIDs.nightscoutId != null && bolusCalculatorResult.first.id != bolusCalculatorResult.second.id ->
nsClientPlugin.nsClientService?.dbUpdate( activePlugin.activeNsClient?.nsClientService?.dbUpdate(
"treatments", bolusCalculatorResult.first.interfaceIDs.nightscoutId, bolusCalculatorResult.first.toJson(false, dateUtil, profileFunction), "treatments", bolusCalculatorResult.first.interfaceIDs.nightscoutId, bolusCalculatorResult.first.toJson(false, dateUtil, profileFunction),
DataSyncSelector.PairBolusCalculatorResult(bolusCalculatorResult.first, bolusCalculatorResult.second.id), "$startId/$lastDbId" DataSyncSelector.PairBolusCalculatorResult(bolusCalculatorResult.first, bolusCalculatorResult.second.id), "$startId/$lastDbId"
) )
} }
return true return
} }
return false
} }
override fun confirmLastTempTargetsIdIfGreater(lastSynced: Long) { override fun confirmLastTempTargetsIdIfGreater(lastSynced: Long) {
if (lastSynced > sp.getLong(R.string.key_ns_temporary_target_last_synced_id, 0)) { 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) sp.putLong(R.string.key_ns_temporary_target_last_synced_id, lastSynced)
} }
} }
@ -329,9 +315,7 @@ class DataSyncSelectorImplementation @Inject constructor(
} }
} }
//private var lastTtId = -1L override tailrec fun processChangedTempTargetsCompat() {
//private var lastTtTime = -1L
override fun processChangedTempTargetsCompat(): Boolean {
val lastDbIdWrapped = appRepository.getLastTempTargetIdWrapped().blockingGet() val lastDbIdWrapped = appRepository.getLastTempTargetIdWrapped().blockingGet()
val lastDbId = if (lastDbIdWrapped is ValueWrapper.Existing) lastDbIdWrapped.value else 0L 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) 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) sp.putLong(R.string.key_ns_temporary_target_last_synced_id, 0)
startId = 0 startId = 0
} }
//if (startId == lastTtId && dateUtil.now() - lastTtTime < 5000) return false
//lastTtId = startId
//lastTtTime = dateUtil.now()
queueCounter.ttsRemaining = lastDbId - startId queueCounter.ttsRemaining = lastDbId - startId
appRepository.getNextSyncElementTemporaryTarget(startId).blockingGet()?.let { tt -> appRepository.getNextSyncElementTemporaryTarget(startId).blockingGet()?.let { tt ->
aapsLogger.info(LTag.NSCLIENT, "Loading TemporaryTarget data Start: $startId ID: ${tt.first.id} HistoryID: ${tt.second.id} ") aapsLogger.info(LTag.NSCLIENT, "Loading TemporaryTarget data Start: $startId ID: ${tt.first.id} HistoryID: ${tt.second.id} ")
when { when {
// record is not valid record and we are within first sync, no need to upload // new record with existing NS id => must be coming from NS => ignore
tt.first.id != tt.second.id && tt.second.id <= sp.getLong(R.string.key_ns_temporary_target_new_data_id, 0) -> { 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) confirmLastTempTargetsIdIfGreater(tt.second.id)
//lastTbrId = -1
processChangedTempTargetsCompat() processChangedTempTargetsCompat()
aapsLogger.info(LTag.NSCLIENT, "Ignoring TemporaryTarget. Change within first sync ID: ${tt.first.id} HistoryID: ${tt.second.id} ") return
return false
} }
// only NsId changed, no need to upload // only NsId changed, no need to upload
tt.first.onlyNsIdAdded(tt.second) -> { tt.first.onlyNsIdAdded(tt.second) -> {
confirmLastTempTargetsIdIfGreater(tt.second.id)
//lastTtId = -1
processChangedTempTargetsCompat()
aapsLogger.info(LTag.NSCLIENT, "Ignoring TemporaryTarget. Only NS id changed ID: ${tt.first.id} HistoryID: ${tt.second.id} ") 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 // without nsId = create new
tt.first.interfaceIDs.nightscoutId == null -> tt.first.interfaceIDs.nightscoutId == null ->
nsClientPlugin.nsClientService?.dbAdd( activePlugin.activeNsClient?.nsClientService?.dbAdd(
"treatments", "treatments",
tt.first.toJson(true, profileFunction.getUnits(), dateUtil), tt.first.toJson(true, profileFunction.getUnits(), dateUtil),
DataSyncSelector.PairTemporaryTarget(tt.first, tt.second.id), DataSyncSelector.PairTemporaryTarget(tt.first, tt.second.id),
"$startId/$lastDbId" "$startId/$lastDbId"
) )
// existing with nsId = update // existing with nsId = update
tt.first.interfaceIDs.nightscoutId != null -> tt.first.interfaceIDs.nightscoutId != null ->
nsClientPlugin.nsClientService?.dbUpdate( activePlugin.activeNsClient?.nsClientService?.dbUpdate(
"treatments", "treatments",
tt.first.interfaceIDs.nightscoutId, tt.first.interfaceIDs.nightscoutId,
tt.first.toJson(false, profileFunction.getUnits(), dateUtil), tt.first.toJson(false, profileFunction.getUnits(), dateUtil),
@ -380,14 +359,13 @@ class DataSyncSelectorImplementation @Inject constructor(
"$startId/$lastDbId" "$startId/$lastDbId"
) )
} }
return true return
} }
return false
} }
override fun confirmLastFoodIdIfGreater(lastSynced: Long) { override fun confirmLastFoodIdIfGreater(lastSynced: Long) {
if (lastSynced > sp.getLong(R.string.key_ns_food_last_synced_id, 0)) { 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) sp.putLong(R.string.key_ns_food_last_synced_id, lastSynced)
} }
} }
@ -400,9 +378,7 @@ class DataSyncSelectorImplementation @Inject constructor(
} }
} }
//private var lastFoodId = -1L override tailrec fun processChangedFoodsCompat() {
//private var lastFoodTime = -1L
override fun processChangedFoodsCompat(): Boolean {
val lastDbIdWrapped = appRepository.getLastFoodIdWrapped().blockingGet() val lastDbIdWrapped = appRepository.getLastFoodIdWrapped().blockingGet()
val lastDbId = if (lastDbIdWrapped is ValueWrapper.Existing) lastDbIdWrapped.value else 0L val lastDbId = if (lastDbIdWrapped is ValueWrapper.Existing) lastDbIdWrapped.value else 0L
var startId = sp.getLong(R.string.key_ns_food_last_synced_id, 0) 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) sp.putLong(R.string.key_ns_food_last_synced_id, 0)
startId = 0 startId = 0
} }
//if (startId == lastFoodId && dateUtil.now() - lastFoodTime < 5000) return false
//lastFoodId = startId
//lastFoodTime = dateUtil.now()
queueCounter.foodsRemaining = lastDbId - startId queueCounter.foodsRemaining = lastDbId - startId
appRepository.getNextSyncElementFood(startId).blockingGet()?.let { food -> appRepository.getNextSyncElementFood(startId).blockingGet()?.let { food ->
aapsLogger.info(LTag.NSCLIENT, "Loading Food data Start: $startId ID: ${food.first.id} HistoryID: ${food.second} ") aapsLogger.info(LTag.NSCLIENT, "Loading Food data Start: $startId ID: ${food.first.id} HistoryID: ${food.second} ")
when { when {
// only NsId changed, no need to upload // new record with existing NS id => must be coming from NS => ignore
food.first.onlyNsIdAdded(food.second) -> { 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) confirmLastFoodIdIfGreater(food.second.id)
//lastFoodId = -1
processChangedFoodsCompat() 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} ") 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 // without nsId = create new
food.first.interfaceIDs.nightscoutId == null -> food.first.interfaceIDs.nightscoutId == null ->
nsClientPlugin.nsClientService?.dbAdd("food", food.first.toJson(true), DataSyncSelector.PairFood(food.first, food.second.id), "$startId/$lastDbId") activePlugin.activeNsClient?.nsClientService?.dbAdd("food", food.first.toJson(true), DataSyncSelector.PairFood(food.first, food.second.id), "$startId/$lastDbId")
// with nsId = update // with nsId = update
food.first.interfaceIDs.nightscoutId != null -> food.first.interfaceIDs.nightscoutId != null ->
nsClientPlugin.nsClientService?.dbUpdate( activePlugin.activeNsClient?.nsClientService?.dbUpdate(
"food", "food",
food.first.interfaceIDs.nightscoutId, food.first.interfaceIDs.nightscoutId,
food.first.toJson(false), food.first.toJson(false),
@ -438,14 +417,13 @@ class DataSyncSelectorImplementation @Inject constructor(
"$startId/$lastDbId" "$startId/$lastDbId"
) )
} }
return true return
} }
return false
} }
override fun confirmLastGlucoseValueIdIfGreater(lastSynced: Long) { override fun confirmLastGlucoseValueIdIfGreater(lastSynced: Long) {
if (lastSynced > sp.getLong(R.string.key_ns_glucose_value_last_synced_id, 0)) { 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) 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() { override tailrec fun processChangedGlucoseValuesCompat() {
val lastDbIdWrapped = appRepository.getLastGlucoseValueIdWrapped().blockingGet() val lastDbIdWrapped = appRepository.getLastGlucoseValueIdWrapped().blockingGet()
val lastDbId = if (lastDbIdWrapped is ValueWrapper.Existing) lastDbIdWrapped.value else 0L 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) sp.putLong(R.string.key_ns_glucose_value_last_synced_id, 0)
startId = 0 startId = 0
} }
//if (startId == lastGvId && dateUtil.now() - lastGvTime < 5000) return false
//lastGvId = startId
//lastGvTime = dateUtil.now()
queueCounter.gvsRemaining = lastDbId - startId queueCounter.gvsRemaining = lastDbId - startId
var tailCall = false
appRepository.getNextSyncElementGlucoseValue(startId).blockingGet()?.let { gv -> appRepository.getNextSyncElementGlucoseValue(startId).blockingGet()?.let { gv ->
aapsLogger.info(LTag.NSCLIENT, "Loading GlucoseValue data ID: ${gv.first.id} HistoryID: ${gv.second.id} ") aapsLogger.info(LTag.NSCLIENT, "Loading GlucoseValue data ID: ${gv.first.id} HistoryID: ${gv.second.id} ")
if (activePlugin.activeBgSource.shouldUploadToNs(gv.first)) { if (activePlugin.activeBgSource.shouldUploadToNs(gv.first)) {
when { when {
// record is not valid record and we are within first sync, no need to upload // new record with existing NS id => must be coming from NS => ignore
gv.first.id != gv.second.id && gv.second.id <= sp.getLong(R.string.key_ns_glucose_value_new_data_id, 0) -> { 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) confirmLastGlucoseValueIdIfGreater(gv.second.id)
//lastGvId = -1 processChangedGlucoseValuesCompat()
aapsLogger.info(LTag.NSCLIENT, "Ignoring GlucoseValue. Change within first sync ID: ${gv.first.id} HistoryID: ${gv.second.id} ") return
tailCall = true
} }
// only NsId changed, no need to upload // only NsId changed, no need to upload
gv.first.onlyNsIdAdded(gv.second) -> { gv.first.onlyNsIdAdded(gv.second) -> {
confirmLastGlucoseValueIdIfGreater(gv.second.id)
//lastGvId = -1
aapsLogger.info(LTag.NSCLIENT, "Ignoring GlucoseValue. Only NS id changed ID: ${gv.first.id} HistoryID: ${gv.second.id} ") 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 // without nsId = create new
gv.first.interfaceIDs.nightscoutId == null -> gv.first.interfaceIDs.nightscoutId == null ->
nsClientPlugin.nsClientService?.dbAdd("entries", gv.first.toJson(true, dateUtil), DataSyncSelector.PairGlucoseValue(gv.first, gv.second.id), "$startId/$lastDbId") activePlugin.activeNsClient?.nsClientService?.dbAdd("entries", gv.first.toJson(true, dateUtil), DataSyncSelector.PairGlucoseValue(gv.first, gv.second.id), "$startId/$lastDbId")
// with nsId = update // with nsId = update
else -> // gv.first.interfaceIDs.nightscoutId != null else -> // gv.first.interfaceIDs.nightscoutId != null
nsClientPlugin.nsClientService?.dbUpdate( activePlugin.activeNsClient?.nsClientService?.dbUpdate(
"entries", "entries",
gv.first.interfaceIDs.nightscoutId, gv.first.interfaceIDs.nightscoutId,
gv.first.toJson(false, dateUtil), gv.first.toJson(false, dateUtil),
@ -506,18 +478,15 @@ class DataSyncSelectorImplementation @Inject constructor(
} }
} else { } else {
confirmLastGlucoseValueIdIfGreater(gv.second.id) confirmLastGlucoseValueIdIfGreater(gv.second.id)
//lastGvId = -1 processChangedGlucoseValuesCompat()
tailCall = true return
} }
} }
if (tailCall) {
processChangedGlucoseValuesCompat()
}
} }
override fun confirmLastTherapyEventIdIfGreater(lastSynced: Long) { override fun confirmLastTherapyEventIdIfGreater(lastSynced: Long) {
if (lastSynced > sp.getLong(R.string.key_ns_therapy_event_last_synced_id, 0)) { 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) sp.putLong(R.string.key_ns_therapy_event_last_synced_id, lastSynced)
} }
} }
@ -530,9 +499,7 @@ class DataSyncSelectorImplementation @Inject constructor(
} }
} }
//private var lastTeId = -1L override tailrec fun processChangedTherapyEventsCompat() {
//private var lastTeTime = -1L
override fun processChangedTherapyEventsCompat(): Boolean {
val lastDbIdWrapped = appRepository.getLastTherapyEventIdWrapped().blockingGet() val lastDbIdWrapped = appRepository.getLastTherapyEventIdWrapped().blockingGet()
val lastDbId = if (lastDbIdWrapped is ValueWrapper.Existing) lastDbIdWrapped.value else 0L 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) 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) sp.putLong(R.string.key_ns_therapy_event_last_synced_id, 0)
startId = 0 startId = 0
} }
//if (startId == lastTeId && dateUtil.now() - lastTeTime < 5000) return false
//lastTeId = startId
//lastTeTime = dateUtil.now()
queueCounter.tesRemaining = lastDbId - startId queueCounter.tesRemaining = lastDbId - startId
appRepository.getNextSyncElementTherapyEvent(startId).blockingGet()?.let { te -> appRepository.getNextSyncElementTherapyEvent(startId).blockingGet()?.let { te ->
aapsLogger.info(LTag.NSCLIENT, "Loading TherapyEvents data Start: $startId ID: ${te.first.id} HistoryID: ${te.second} ") aapsLogger.info(LTag.NSCLIENT, "Loading TherapyEvents data Start: $startId ID: ${te.first.id} HistoryID: ${te.second} ")
when { when {
// only NsId changed, no need to upload // new record with existing NS id => must be coming from NS => ignore
te.first.onlyNsIdAdded(te.second) -> { 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) confirmLastTherapyEventIdIfGreater(te.second.id)
//lastTeId = -1
processChangedTherapyEventsCompat() processChangedTherapyEventsCompat()
aapsLogger.info(LTag.NSCLIENT, "Ignoring TherapyEvents. Only NS id changed ID: ${te.first.id} HistoryID: ${te.second.id} ") return
return false }
// 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 // without nsId = create new
te.first.interfaceIDs.nightscoutId == null -> te.first.interfaceIDs.nightscoutId == null ->
nsClientPlugin.nsClientService?.dbAdd("treatments", te.first.toJson(true, dateUtil), DataSyncSelector.PairTherapyEvent(te.first, te.second.id), "$startId/$lastDbId") activePlugin.activeNsClient?.nsClientService?.dbAdd("treatments", te.first.toJson(true, dateUtil), DataSyncSelector.PairTherapyEvent(te.first, te.second.id), "$startId/$lastDbId")
// nsId = update // nsId = update
te.first.interfaceIDs.nightscoutId != null -> te.first.interfaceIDs.nightscoutId != null ->
nsClientPlugin.nsClientService?.dbUpdate( activePlugin.activeNsClient?.nsClientService?.dbUpdate(
"treatments", "treatments",
te.first.interfaceIDs.nightscoutId, te.first.interfaceIDs.nightscoutId,
te.first.toJson(false, dateUtil), te.first.toJson(false, dateUtil),
@ -568,14 +538,13 @@ class DataSyncSelectorImplementation @Inject constructor(
"$startId/$lastDbId" "$startId/$lastDbId"
) )
} }
return true return
} }
return false
} }
override fun confirmLastDeviceStatusIdIfGreater(lastSynced: Long) { override fun confirmLastDeviceStatusIdIfGreater(lastSynced: Long) {
if (lastSynced > sp.getLong(R.string.key_ns_device_status_last_synced_id, 0)) { 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) sp.putLong(R.string.key_ns_device_status_last_synced_id, lastSynced)
} }
} }
@ -587,9 +556,7 @@ class DataSyncSelectorImplementation @Inject constructor(
} }
} }
//private var lastDsId = -1L override fun processChangedDeviceStatusesCompat() {
//private var lastDsTime = -1L
override fun processChangedDeviceStatusesCompat(): Boolean {
val lastDbIdWrapped = appRepository.getLastDeviceStatusIdWrapped().blockingGet() val lastDbIdWrapped = appRepository.getLastDeviceStatusIdWrapped().blockingGet()
val lastDbId = if (lastDbIdWrapped is ValueWrapper.Existing) lastDbIdWrapped.value else 0L 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) 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) sp.putLong(R.string.key_ns_device_status_last_synced_id, 0)
startId = 0 startId = 0
} }
//if (startId == lastDsId && dateUtil.now() - lastDsTime < 5000) return false
//lastDsId = startId
//lastDsTime = dateUtil.now()
queueCounter.dssRemaining = lastDbId - startId queueCounter.dssRemaining = lastDbId - startId
appRepository.getNextSyncElementDeviceStatus(startId).blockingGet()?.let { deviceStatus -> appRepository.getNextSyncElementDeviceStatus(startId).blockingGet()?.let { deviceStatus ->
aapsLogger.info(LTag.NSCLIENT, "Loading DeviceStatus data Start: $startId ID: ${deviceStatus.id}") aapsLogger.info(LTag.NSCLIENT, "Loading DeviceStatus data Start: $startId ID: ${deviceStatus.id}")
when { when {
// without nsId = create new // without nsId = create new
deviceStatus.interfaceIDs.nightscoutId == null -> 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 // with nsId = ignore
deviceStatus.interfaceIDs.nightscoutId != null -> Any() deviceStatus.interfaceIDs.nightscoutId != null -> Any()
} }
return true return
} }
return false
} }
override fun confirmLastTemporaryBasalIdIfGreater(lastSynced: Long) { override fun confirmLastTemporaryBasalIdIfGreater(lastSynced: Long) {
if (lastSynced > sp.getLong(R.string.key_ns_temporary_basal_last_synced_id, 0)) { 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) sp.putLong(R.string.key_ns_temporary_basal_last_synced_id, lastSynced)
} }
} }
@ -630,9 +593,7 @@ class DataSyncSelectorImplementation @Inject constructor(
} }
} }
//private var lastTbrId = -1L override tailrec fun processChangedTemporaryBasalsCompat() {
//private var lastTbrTime = -1L
override fun processChangedTemporaryBasalsCompat(): Boolean {
val lastDbIdWrapped = appRepository.getLastTemporaryBasalIdWrapped().blockingGet() val lastDbIdWrapped = appRepository.getLastTemporaryBasalIdWrapped().blockingGet()
val lastDbId = if (lastDbIdWrapped is ValueWrapper.Existing) lastDbIdWrapped.value else 0L 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) 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) sp.putLong(R.string.key_ns_temporary_basal_last_synced_id, 0)
startId = 0 startId = 0
} }
//if (startId == lastTbrId && dateUtil.now() - lastTbrTime < 5000) return false
//lastTbrId = startId
//lastTbrTime = dateUtil.now()
queueCounter.tbrsRemaining = lastDbId - startId queueCounter.tbrsRemaining = lastDbId - startId
appRepository.getNextSyncElementTemporaryBasal(startId).blockingGet()?.let { tb -> appRepository.getNextSyncElementTemporaryBasal(startId).blockingGet()?.let { tb ->
aapsLogger.info(LTag.NSCLIENT, "Loading TemporaryBasal data Start: $startId ID: ${tb.first.id} HistoryID: ${tb.second} ") aapsLogger.info(LTag.NSCLIENT, "Loading TemporaryBasal data Start: $startId ID: ${tb.first.id} HistoryID: ${tb.second} ")
val profile = profileFunction.getProfile(tb.first.timestamp) val profile = profileFunction.getProfile(tb.first.timestamp)
if (profile != null) { if (profile != null) {
when { when {
// record is not valid record and we are within first sync, no need to upload // new record with existing NS id => must be coming from NS => ignore
tb.first.id != tb.second.id && tb.second.id <= sp.getLong(R.string.key_ns_temporary_basal_new_data_id, 0) -> { 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) confirmLastTemporaryBasalIdIfGreater(tb.second.id)
//lastTbrId = -1
processChangedTemporaryBasalsCompat() processChangedTemporaryBasalsCompat()
aapsLogger.info(LTag.NSCLIENT, "Ignoring TemporaryBasal. Change within first sync ID: ${tb.first.id} HistoryID: ${tb.second.id} ") return
return false
} }
// only NsId changed, no need to upload // only NsId changed, no need to upload
tb.first.onlyNsIdAdded(tb.second) -> { tb.first.onlyNsIdAdded(tb.second) -> {
confirmLastTemporaryBasalIdIfGreater(tb.second.id)
//lastTbrId = -1
processChangedTemporaryBasalsCompat()
aapsLogger.info(LTag.NSCLIENT, "Ignoring TemporaryBasal. Only NS id changed ID: ${tb.first.id} HistoryID: ${tb.second.id} ") 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 // without nsId = create new
tb.first.interfaceIDs.nightscoutId == null -> tb.first.interfaceIDs.nightscoutId == null ->
nsClientPlugin.nsClientService?.dbAdd( activePlugin.activeNsClient?.nsClientService?.dbAdd(
"treatments", "treatments",
tb.first.toJson(true, profile, dateUtil), tb.first.toJson(true, profile, dateUtil),
DataSyncSelector.PairTemporaryBasal(tb.first, tb.second.id), DataSyncSelector.PairTemporaryBasal(tb.first, tb.second.id),
"$startId/$lastDbId" "$startId/$lastDbId"
) )
// with nsId = update // with nsId = update
tb.first.interfaceIDs.nightscoutId != null -> tb.first.interfaceIDs.nightscoutId != null ->
nsClientPlugin.nsClientService?.dbUpdate( activePlugin.activeNsClient?.nsClientService?.dbUpdate(
"treatments", "treatments",
tb.first.interfaceIDs.nightscoutId, tb.first.interfaceIDs.nightscoutId,
tb.first.toJson(false, profile, dateUtil), tb.first.toJson(false, profile, dateUtil),
@ -683,19 +639,19 @@ class DataSyncSelectorImplementation @Inject constructor(
"$startId/$lastDbId" "$startId/$lastDbId"
) )
} }
return true return
} else { } else {
aapsLogger.info(LTag.NSCLIENT, "Ignoring TemporaryBasal. No profile: ${tb.first.id} HistoryID: ${tb.second.id} ")
confirmLastTemporaryBasalIdIfGreater(tb.second.id) confirmLastTemporaryBasalIdIfGreater(tb.second.id)
//lastTbrId = -1
processChangedTemporaryBasalsCompat() processChangedTemporaryBasalsCompat()
return
} }
} }
return false
} }
override fun confirmLastExtendedBolusIdIfGreater(lastSynced: Long) { override fun confirmLastExtendedBolusIdIfGreater(lastSynced: Long) {
if (lastSynced > sp.getLong(R.string.key_ns_extended_bolus_last_synced_id, 0)) { 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) sp.putLong(R.string.key_ns_extended_bolus_last_synced_id, lastSynced)
} }
} }
@ -708,9 +664,7 @@ class DataSyncSelectorImplementation @Inject constructor(
} }
} }
//private var lastEbId = -1L override tailrec fun processChangedExtendedBolusesCompat() {
//private var lastEbTime = -1L
override fun processChangedExtendedBolusesCompat(): Boolean {
val lastDbIdWrapped = appRepository.getLastExtendedBolusIdWrapped().blockingGet() val lastDbIdWrapped = appRepository.getLastExtendedBolusIdWrapped().blockingGet()
val lastDbId = if (lastDbIdWrapped is ValueWrapper.Existing) lastDbIdWrapped.value else 0L 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) 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) sp.putLong(R.string.key_ns_extended_bolus_last_synced_id, 0)
startId = 0 startId = 0
} }
//if (startId == lastEbId && dateUtil.now() - lastEbTime < 5000) return false
//lastEbId = startId
//lastEbTime = dateUtil.now()
queueCounter.ebsRemaining = lastDbId - startId queueCounter.ebsRemaining = lastDbId - startId
appRepository.getNextSyncElementExtendedBolus(startId).blockingGet()?.let { eb -> appRepository.getNextSyncElementExtendedBolus(startId).blockingGet()?.let { eb ->
aapsLogger.info(LTag.NSCLIENT, "Loading ExtendedBolus data Start: $startId ID: ${eb.first.id} HistoryID: ${eb.second} ") aapsLogger.info(LTag.NSCLIENT, "Loading ExtendedBolus data Start: $startId ID: ${eb.first.id} HistoryID: ${eb.second} ")
val profile = profileFunction.getProfile(eb.first.timestamp) val profile = profileFunction.getProfile(eb.first.timestamp)
if (profile != null) { if (profile != null) {
when { when {
// record is not valid record and we are within first sync, no need to upload // new record with existing NS id => must be coming from NS => ignore
eb.first.id != eb.second.id && eb.second.id <= sp.getLong(R.string.key_ns_extended_bolus_new_data_id, 0) -> { 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) confirmLastExtendedBolusIdIfGreater(eb.second.id)
//lastTbrId = -1
processChangedExtendedBolusesCompat() processChangedExtendedBolusesCompat()
aapsLogger.info(LTag.NSCLIENT, "Ignoring ExtendedBolus. Change within first sync ID: ${eb.first.id} HistoryID: ${eb.second.id} ") return
return false
} }
// only NsId changed, no need to upload // only NsId changed, no need to upload
eb.first.onlyNsIdAdded(eb.second) -> { eb.first.onlyNsIdAdded(eb.second) -> {
confirmLastExtendedBolusIdIfGreater(eb.second.id)
//lastEbId = -1
processChangedExtendedBolusesCompat()
aapsLogger.info(LTag.NSCLIENT, "Ignoring ExtendedBolus. Only NS id changed ID: ${eb.first.id} HistoryID: ${eb.second.id} ") 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 // without nsId = create new
eb.first.interfaceIDs.nightscoutId == null -> eb.first.interfaceIDs.nightscoutId == null ->
nsClientPlugin.nsClientService?.dbAdd( activePlugin.activeNsClient?.nsClientService?.dbAdd(
"treatments", "treatments",
eb.first.toJson(true, profile, dateUtil), eb.first.toJson(true, profile, dateUtil),
DataSyncSelector.PairExtendedBolus(eb.first, eb.second.id), DataSyncSelector.PairExtendedBolus(eb.first, eb.second.id),
"$startId/$lastDbId" "$startId/$lastDbId"
) )
// with nsId = update // with nsId = update
eb.first.interfaceIDs.nightscoutId != null -> eb.first.interfaceIDs.nightscoutId != null ->
nsClientPlugin.nsClientService?.dbUpdate( activePlugin.activeNsClient?.nsClientService?.dbUpdate(
"treatments", "treatments",
eb.first.interfaceIDs.nightscoutId, eb.first.interfaceIDs.nightscoutId,
eb.first.toJson(false, profile, dateUtil), eb.first.toJson(false, profile, dateUtil),
@ -761,19 +710,19 @@ class DataSyncSelectorImplementation @Inject constructor(
"$startId/$lastDbId" "$startId/$lastDbId"
) )
} }
return true return
} else { } else {
aapsLogger.info(LTag.NSCLIENT, "Ignoring ExtendedBolus. No profile: ${eb.first.id} HistoryID: ${eb.second.id} ")
confirmLastExtendedBolusIdIfGreater(eb.second.id) confirmLastExtendedBolusIdIfGreater(eb.second.id)
//lastEbId = -1
processChangedExtendedBolusesCompat() processChangedExtendedBolusesCompat()
return
} }
} }
return false
} }
override fun confirmLastProfileSwitchIdIfGreater(lastSynced: Long) { override fun confirmLastProfileSwitchIdIfGreater(lastSynced: Long) {
if (lastSynced > sp.getLong(R.string.key_ns_profile_switch_last_synced_id, 0)) { 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) sp.putLong(R.string.key_ns_profile_switch_last_synced_id, lastSynced)
} }
} }
@ -785,9 +734,7 @@ class DataSyncSelectorImplementation @Inject constructor(
} }
} }
//private var lastPsId = -1L override tailrec fun processChangedProfileSwitchesCompat() {
//private var lastPsTime = -1L
override fun processChangedProfileSwitchesCompat(): Boolean {
val lastDbIdWrapped = appRepository.getLastProfileSwitchIdWrapped().blockingGet() val lastDbIdWrapped = appRepository.getLastProfileSwitchIdWrapped().blockingGet()
val lastDbId = if (lastDbIdWrapped is ValueWrapper.Existing) lastDbIdWrapped.value else 0L 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) 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) sp.putLong(R.string.key_ns_profile_switch_last_synced_id, 0)
startId = 0 startId = 0
} }
//if (startId == lastPsId && dateUtil.now() - lastPsTime < 5000) return false
//lastPsId = startId
//lastPsTime = dateUtil.now()
queueCounter.pssRemaining = lastDbId - startId queueCounter.pssRemaining = lastDbId - startId
appRepository.getNextSyncElementProfileSwitch(startId).blockingGet()?.let { ps -> appRepository.getNextSyncElementProfileSwitch(startId).blockingGet()?.let { ps ->
aapsLogger.info(LTag.NSCLIENT, "Loading ProfileSwitch data Start: $startId ID: ${ps.first.id} HistoryID: ${ps.second} ") aapsLogger.info(LTag.NSCLIENT, "Loading ProfileSwitch data Start: $startId ID: ${ps.first.id} HistoryID: ${ps.second} ")
when { when {
// only NsId changed, no need to upload // new record with existing NS id => must be coming from NS => ignore
ps.first.onlyNsIdAdded(ps.second) -> { 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) confirmLastProfileSwitchIdIfGreater(ps.second.id)
//lastPsId = -1
processChangedProfileSwitchesCompat() 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} ") 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 // without nsId = create new
ps.first.interfaceIDs.nightscoutId == null -> ps.first.interfaceIDs.nightscoutId == null ->
nsClientPlugin.nsClientService?.dbAdd("treatments", ps.first.toJson(true, dateUtil), DataSyncSelector.PairProfileSwitch(ps.first, ps.second.id), "$startId/$lastDbId") activePlugin.activeNsClient?.nsClientService?.dbAdd("treatments", ps.first.toJson(true, dateUtil), DataSyncSelector.PairProfileSwitch(ps.first, ps.second.id), "$startId/$lastDbId")
// with nsId = update // with nsId = update
ps.first.interfaceIDs.nightscoutId != null -> ps.first.interfaceIDs.nightscoutId != null ->
nsClientPlugin.nsClientService?.dbUpdate( activePlugin.activeNsClient?.nsClientService?.dbUpdate(
"treatments", "treatments",
ps.first.interfaceIDs.nightscoutId, ps.first.interfaceIDs.nightscoutId,
ps.first.toJson(false, dateUtil), ps.first.toJson(false, dateUtil),
@ -823,14 +773,13 @@ class DataSyncSelectorImplementation @Inject constructor(
"$startId/$lastDbId" "$startId/$lastDbId"
) )
} }
return true return
} }
return false
} }
override fun confirmLastEffectiveProfileSwitchIdIfGreater(lastSynced: Long) { override fun confirmLastEffectiveProfileSwitchIdIfGreater(lastSynced: Long) {
if (lastSynced > sp.getLong(R.string.key_ns_effective_profile_switch_last_synced_id, 0)) { 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) 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 override tailrec fun processChangedEffectiveProfileSwitchesCompat() {
//private var lastEpsTime = -1L
override fun processChangedEffectiveProfileSwitchesCompat(): Boolean {
val lastDbIdWrapped = appRepository.getLastEffectiveProfileSwitchIdWrapped().blockingGet() val lastDbIdWrapped = appRepository.getLastEffectiveProfileSwitchIdWrapped().blockingGet()
val lastDbId = if (lastDbIdWrapped is ValueWrapper.Existing) lastDbIdWrapped.value else 0L 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) 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) sp.putLong(R.string.key_ns_effective_profile_switch_last_synced_id, 0)
startId = 0 startId = 0
} }
//if (startId == lastEpsId && dateUtil.now() - lastEpsTime < 5000) return false
//lastEpsId = startId
//lastEpsTime = dateUtil.now()
queueCounter.epssRemaining = lastDbId - startId queueCounter.epssRemaining = lastDbId - startId
appRepository.getNextSyncElementEffectiveProfileSwitch(startId).blockingGet()?.let { ps -> appRepository.getNextSyncElementEffectiveProfileSwitch(startId).blockingGet()?.let { ps ->
aapsLogger.info(LTag.NSCLIENT, "Loading EffectiveProfileSwitch data Start: $startId ID: ${ps.first.id} HistoryID: ${ps.second} ") aapsLogger.info(LTag.NSCLIENT, "Loading EffectiveProfileSwitch data Start: $startId ID: ${ps.first.id} HistoryID: ${ps.second} ")
when { when {
// only NsId changed, no need to upload // new record with existing NS id => must be coming from NS => ignore
ps.first.onlyNsIdAdded(ps.second) -> { 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) confirmLastEffectiveProfileSwitchIdIfGreater(ps.second.id)
//lastEpsId = -1
processChangedEffectiveProfileSwitchesCompat() 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} ") 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 // without nsId = create new
ps.first.interfaceIDs.nightscoutId == null -> ps.first.interfaceIDs.nightscoutId == null ->
nsClientPlugin.nsClientService?.dbAdd("treatments", ps.first.toJson(true, dateUtil), DataSyncSelector.PairEffectiveProfileSwitch(ps.first, ps.second.id), "$startId/$lastDbId") activePlugin.activeNsClient?.nsClientService?.dbAdd(
"treatments",
ps.first.toJson(true, dateUtil),
DataSyncSelector.PairEffectiveProfileSwitch(ps.first, ps.second.id),
"$startId/$lastDbId"
)
// with nsId = update // with nsId = update
ps.first.interfaceIDs.nightscoutId != null -> ps.first.interfaceIDs.nightscoutId != null ->
nsClientPlugin.nsClientService?.dbUpdate( activePlugin.activeNsClient?.nsClientService?.dbUpdate(
"treatments", "treatments",
ps.first.interfaceIDs.nightscoutId, ps.first.interfaceIDs.nightscoutId,
ps.first.toJson(false, dateUtil), ps.first.toJson(false, dateUtil),
@ -880,14 +835,13 @@ class DataSyncSelectorImplementation @Inject constructor(
"$startId/$lastDbId" "$startId/$lastDbId"
) )
} }
return true return
} }
return false
} }
override fun confirmLastOfflineEventIdIfGreater(lastSynced: Long) { override fun confirmLastOfflineEventIdIfGreater(lastSynced: Long) {
if (lastSynced > sp.getLong(R.string.key_ns_offline_event_last_synced_id, 0)) { 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) sp.putLong(R.string.key_ns_offline_event_last_synced_id, lastSynced)
} }
} }
@ -900,9 +854,7 @@ class DataSyncSelectorImplementation @Inject constructor(
} }
} }
//private var lastOeId = -1L override tailrec fun processChangedOfflineEventsCompat() {
//private var lastOeTime = -1L
override fun processChangedOfflineEventsCompat(): Boolean {
val lastDbIdWrapped = appRepository.getLastOfflineEventIdWrapped().blockingGet() val lastDbIdWrapped = appRepository.getLastOfflineEventIdWrapped().blockingGet()
val lastDbId = if (lastDbIdWrapped is ValueWrapper.Existing) lastDbIdWrapped.value else 0L 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) 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) sp.putLong(R.string.key_ns_offline_event_last_synced_id, 0)
startId = 0 startId = 0
} }
//if (startId == lastOeId && dateUtil.now() - lastOeTime < 5000) return false
//lastOeId = startId
//lastOeTime = dateUtil.now()
queueCounter.oesRemaining = lastDbId - startId queueCounter.oesRemaining = lastDbId - startId
appRepository.getNextSyncElementOfflineEvent(startId).blockingGet()?.let { oe -> appRepository.getNextSyncElementOfflineEvent(startId).blockingGet()?.let { oe ->
aapsLogger.info(LTag.NSCLIENT, "Loading OfflineEvent data Start: $startId ID: ${oe.first.id} HistoryID: ${oe.second} ") aapsLogger.info(LTag.NSCLIENT, "Loading OfflineEvent data Start: $startId ID: ${oe.first.id} HistoryID: ${oe.second} ")
when { when {
// only NsId changed, no need to upload // new record with existing NS id => must be coming from NS => ignore
oe.first.onlyNsIdAdded(oe.second) -> { 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) confirmLastOfflineEventIdIfGreater(oe.second.id)
//lastOeId = -1
processChangedOfflineEventsCompat() 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} ") 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 // without nsId = create new
oe.first.interfaceIDs.nightscoutId == null -> oe.first.interfaceIDs.nightscoutId == null ->
nsClientPlugin.nsClientService?.dbAdd("treatments", oe.first.toJson(true, dateUtil), DataSyncSelector.PairOfflineEvent(oe.first, oe.second.id), "$startId/$lastDbId") activePlugin.activeNsClient?.nsClientService?.dbAdd("treatments", oe.first.toJson(true, dateUtil), DataSyncSelector.PairOfflineEvent(oe.first, oe.second.id), "$startId/$lastDbId")
// existing with nsId = update // existing with nsId = update
oe.first.interfaceIDs.nightscoutId != null -> oe.first.interfaceIDs.nightscoutId != null ->
nsClientPlugin.nsClientService?.dbUpdate( activePlugin.activeNsClient?.nsClientService?.dbUpdate(
"treatments", "treatments",
oe.first.interfaceIDs.nightscoutId, oe.first.interfaceIDs.nightscoutId,
oe.first.toJson(false, dateUtil), oe.first.toJson(false, dateUtil),
@ -938,9 +893,8 @@ class DataSyncSelectorImplementation @Inject constructor(
"$startId/$lastDbId" "$startId/$lastDbId"
) )
} }
return true return
} }
return false
} }
override fun confirmLastProfileStore(lastSynced: Long) { override fun confirmLastProfileStore(lastSynced: Long) {
@ -954,7 +908,7 @@ class DataSyncSelectorImplementation @Inject constructor(
if (lastChange > lastSync) { if (lastChange > lastSync) {
if (profilePlugin.profile?.allProfilesValid != true) return if (profilePlugin.profile?.allProfilesValid != true) return
val profileJson = profilePlugin.profile?.data ?: 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.content.Context
import android.os.SystemClock 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.PairTemporaryBasal
import info.nightscout.androidaps.interfaces.DataSyncSelector.PairTemporaryTarget import info.nightscout.androidaps.interfaces.DataSyncSelector.PairTemporaryTarget
import info.nightscout.androidaps.interfaces.DataSyncSelector.PairTherapyEvent import info.nightscout.androidaps.interfaces.DataSyncSelector.PairTherapyEvent
import info.nightscout.androidaps.plugins.general.nsclient.acks.NSAddAck import info.nightscout.androidaps.interfaces.NsClient
import info.nightscout.androidaps.plugins.general.nsclient.events.EventNSClientNewLog 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.androidaps.receivers.DataWorkerStorage
import info.nightscout.rx.AapsSchedulers import info.nightscout.rx.AapsSchedulers
import info.nightscout.rx.bus.RxBus 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) if (sp.getBoolean(R.string.key_ns_sync_slow, false)) SystemClock.sleep(1000)
when (ack.originalObject) { when (ack.originalObject) {
is PairTemporaryTarget -> { is PairTemporaryTarget -> {
val pair = ack.originalObject val pair = ack.originalObject
pair.value.interfaceIDs.nightscoutId = ack.id pair.value.interfaceIDs.nightscoutId = ack.id
repository.runTransactionForResult(UpdateNsIdTemporaryTargetTransaction(pair.value)) repository.runTransactionForResult(UpdateNsIdTemporaryTargetTransaction(pair.value))
@ -82,12 +83,12 @@ class NSClientAddAckWorker(
dataSyncSelector.confirmLastTempTargetsIdIfGreater(pair.updateRecordId) dataSyncSelector.confirmLastTempTargetsIdIfGreater(pair.updateRecordId)
} }
.blockingGet() .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 // Send new if waiting
dataSyncSelector.processChangedTempTargetsCompat() dataSyncSelector.processChangedTempTargetsCompat()
} }
is PairGlucoseValue -> { is PairGlucoseValue -> {
val pair = ack.originalObject val pair = ack.originalObject
pair.value.interfaceIDs.nightscoutId = ack.id pair.value.interfaceIDs.nightscoutId = ack.id
repository.runTransactionForResult(UpdateNsIdGlucoseValueTransaction(pair.value)) repository.runTransactionForResult(UpdateNsIdGlucoseValueTransaction(pair.value))
@ -101,12 +102,12 @@ class NSClientAddAckWorker(
dataSyncSelector.confirmLastGlucoseValueIdIfGreater(pair.updateRecordId) dataSyncSelector.confirmLastGlucoseValueIdIfGreater(pair.updateRecordId)
} }
.blockingGet() .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 // Send new if waiting
dataSyncSelector.processChangedGlucoseValuesCompat() dataSyncSelector.processChangedGlucoseValuesCompat()
} }
is PairFood -> { is PairFood -> {
val pair = ack.originalObject val pair = ack.originalObject
pair.value.interfaceIDs.nightscoutId = ack.id pair.value.interfaceIDs.nightscoutId = ack.id
repository.runTransactionForResult(UpdateNsIdFoodTransaction(pair.value)) repository.runTransactionForResult(UpdateNsIdFoodTransaction(pair.value))
@ -120,12 +121,12 @@ class NSClientAddAckWorker(
dataSyncSelector.confirmLastFoodIdIfGreater(pair.updateRecordId) dataSyncSelector.confirmLastFoodIdIfGreater(pair.updateRecordId)
} }
.blockingGet() .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 // Send new if waiting
dataSyncSelector.processChangedFoodsCompat() dataSyncSelector.processChangedFoodsCompat()
} }
is PairTherapyEvent -> { is PairTherapyEvent -> {
val pair = ack.originalObject val pair = ack.originalObject
pair.value.interfaceIDs.nightscoutId = ack.id pair.value.interfaceIDs.nightscoutId = ack.id
repository.runTransactionForResult(UpdateNsIdTherapyEventTransaction(pair.value)) repository.runTransactionForResult(UpdateNsIdTherapyEventTransaction(pair.value))
@ -139,12 +140,12 @@ class NSClientAddAckWorker(
dataSyncSelector.confirmLastTherapyEventIdIfGreater(pair.updateRecordId) dataSyncSelector.confirmLastTherapyEventIdIfGreater(pair.updateRecordId)
} }
.blockingGet() .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 // Send new if waiting
dataSyncSelector.processChangedTherapyEventsCompat() dataSyncSelector.processChangedTherapyEventsCompat()
} }
is PairBolus -> { is PairBolus -> {
val pair = ack.originalObject val pair = ack.originalObject
pair.value.interfaceIDs.nightscoutId = ack.id pair.value.interfaceIDs.nightscoutId = ack.id
repository.runTransactionForResult(UpdateNsIdBolusTransaction(pair.value)) repository.runTransactionForResult(UpdateNsIdBolusTransaction(pair.value))
@ -158,12 +159,12 @@ class NSClientAddAckWorker(
dataSyncSelector.confirmLastBolusIdIfGreater(pair.updateRecordId) dataSyncSelector.confirmLastBolusIdIfGreater(pair.updateRecordId)
} }
.blockingGet() .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 // Send new if waiting
dataSyncSelector.processChangedBolusesCompat() dataSyncSelector.processChangedBolusesCompat()
} }
is PairCarbs -> { is PairCarbs -> {
val pair = ack.originalObject val pair = ack.originalObject
pair.value.interfaceIDs.nightscoutId = ack.id pair.value.interfaceIDs.nightscoutId = ack.id
repository.runTransactionForResult(UpdateNsIdCarbsTransaction(pair.value)) repository.runTransactionForResult(UpdateNsIdCarbsTransaction(pair.value))
@ -177,12 +178,12 @@ class NSClientAddAckWorker(
dataSyncSelector.confirmLastCarbsIdIfGreater(pair.updateRecordId) dataSyncSelector.confirmLastCarbsIdIfGreater(pair.updateRecordId)
} }
.blockingGet() .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 // Send new if waiting
dataSyncSelector.processChangedCarbsCompat() dataSyncSelector.processChangedCarbsCompat()
} }
is PairBolusCalculatorResult -> { is PairBolusCalculatorResult -> {
val pair = ack.originalObject val pair = ack.originalObject
pair.value.interfaceIDs.nightscoutId = ack.id pair.value.interfaceIDs.nightscoutId = ack.id
repository.runTransactionForResult(UpdateNsIdBolusCalculatorResultTransaction(pair.value)) repository.runTransactionForResult(UpdateNsIdBolusCalculatorResultTransaction(pair.value))
@ -196,12 +197,12 @@ class NSClientAddAckWorker(
dataSyncSelector.confirmLastBolusCalculatorResultsIdIfGreater(pair.updateRecordId) dataSyncSelector.confirmLastBolusCalculatorResultsIdIfGreater(pair.updateRecordId)
} }
.blockingGet() .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 // Send new if waiting
dataSyncSelector.processChangedBolusCalculatorResultsCompat() dataSyncSelector.processChangedBolusCalculatorResultsCompat()
} }
is PairTemporaryBasal -> { is PairTemporaryBasal -> {
val pair = ack.originalObject val pair = ack.originalObject
pair.value.interfaceIDs.nightscoutId = ack.id pair.value.interfaceIDs.nightscoutId = ack.id
repository.runTransactionForResult(UpdateNsIdTemporaryBasalTransaction(pair.value)) repository.runTransactionForResult(UpdateNsIdTemporaryBasalTransaction(pair.value))
@ -215,12 +216,12 @@ class NSClientAddAckWorker(
dataSyncSelector.confirmLastTemporaryBasalIdIfGreater(pair.updateRecordId) dataSyncSelector.confirmLastTemporaryBasalIdIfGreater(pair.updateRecordId)
} }
.blockingGet() .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 // Send new if waiting
dataSyncSelector.processChangedTemporaryBasalsCompat() dataSyncSelector.processChangedTemporaryBasalsCompat()
} }
is PairExtendedBolus -> { is PairExtendedBolus -> {
val pair = ack.originalObject val pair = ack.originalObject
pair.value.interfaceIDs.nightscoutId = ack.id pair.value.interfaceIDs.nightscoutId = ack.id
repository.runTransactionForResult(UpdateNsIdExtendedBolusTransaction(pair.value)) repository.runTransactionForResult(UpdateNsIdExtendedBolusTransaction(pair.value))
@ -234,12 +235,12 @@ class NSClientAddAckWorker(
dataSyncSelector.confirmLastExtendedBolusIdIfGreater(pair.updateRecordId) dataSyncSelector.confirmLastExtendedBolusIdIfGreater(pair.updateRecordId)
} }
.blockingGet() .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 // Send new if waiting
dataSyncSelector.processChangedExtendedBolusesCompat() dataSyncSelector.processChangedExtendedBolusesCompat()
} }
is PairProfileSwitch -> { is PairProfileSwitch -> {
val pair = ack.originalObject val pair = ack.originalObject
pair.value.interfaceIDs.nightscoutId = ack.id pair.value.interfaceIDs.nightscoutId = ack.id
repository.runTransactionForResult(UpdateNsIdProfileSwitchTransaction(pair.value)) repository.runTransactionForResult(UpdateNsIdProfileSwitchTransaction(pair.value))
@ -253,12 +254,12 @@ class NSClientAddAckWorker(
dataSyncSelector.confirmLastProfileSwitchIdIfGreater(pair.updateRecordId) dataSyncSelector.confirmLastProfileSwitchIdIfGreater(pair.updateRecordId)
} }
.blockingGet() .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 // Send new if waiting
dataSyncSelector.processChangedProfileSwitchesCompat() dataSyncSelector.processChangedProfileSwitchesCompat()
} }
is PairEffectiveProfileSwitch -> { is PairEffectiveProfileSwitch -> {
val pair = ack.originalObject val pair = ack.originalObject
pair.value.interfaceIDs.nightscoutId = ack.id pair.value.interfaceIDs.nightscoutId = ack.id
repository.runTransactionForResult(UpdateNsIdEffectiveProfileSwitchTransaction(pair.value)) repository.runTransactionForResult(UpdateNsIdEffectiveProfileSwitchTransaction(pair.value))
@ -272,12 +273,12 @@ class NSClientAddAckWorker(
dataSyncSelector.confirmLastEffectiveProfileSwitchIdIfGreater(pair.updateRecordId) dataSyncSelector.confirmLastEffectiveProfileSwitchIdIfGreater(pair.updateRecordId)
} }
.blockingGet() .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 // Send new if waiting
dataSyncSelector.processChangedEffectiveProfileSwitchesCompat() dataSyncSelector.processChangedEffectiveProfileSwitchesCompat()
} }
is DeviceStatus -> { is DeviceStatus -> {
val deviceStatus = ack.originalObject val deviceStatus = ack.originalObject
deviceStatus.interfaceIDs.nightscoutId = ack.id deviceStatus.interfaceIDs.nightscoutId = ack.id
repository.runTransactionForResult(UpdateNsIdDeviceStatusTransaction(deviceStatus)) repository.runTransactionForResult(UpdateNsIdDeviceStatusTransaction(deviceStatus))
@ -291,17 +292,17 @@ class NSClientAddAckWorker(
dataSyncSelector.confirmLastDeviceStatusIdIfGreater(deviceStatus.id) dataSyncSelector.confirmLastDeviceStatusIdIfGreater(deviceStatus.id)
} }
.blockingGet() .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 // Send new if waiting
dataSyncSelector.processChangedDeviceStatusesCompat() dataSyncSelector.processChangedDeviceStatusesCompat()
} }
is PairProfileStore -> { is PairProfileStore -> {
dataSyncSelector.confirmLastProfileStore(ack.originalObject.timestampSync) 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 val pair = ack.originalObject
pair.value.interfaceIDs.nightscoutId = ack.id pair.value.interfaceIDs.nightscoutId = ack.id
repository.runTransactionForResult(UpdateNsIdOfflineEventTransaction(pair.value)) repository.runTransactionForResult(UpdateNsIdOfflineEventTransaction(pair.value))
@ -315,7 +316,7 @@ class NSClientAddAckWorker(
dataSyncSelector.confirmLastOfflineEventIdIfGreater(pair.updateRecordId) dataSyncSelector.confirmLastOfflineEventIdIfGreater(pair.updateRecordId)
} }
.blockingGet() .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 // Send new if waiting
dataSyncSelector.processChangedOfflineEventsCompat() 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 android.content.Context
import androidx.work.Worker import androidx.work.Worker
@ -6,15 +6,11 @@ import androidx.work.WorkerParameters
import androidx.work.workDataOf import androidx.work.workDataOf
import dagger.android.HasAndroidInjector import dagger.android.HasAndroidInjector
import info.nightscout.androidaps.R import info.nightscout.androidaps.R
import info.nightscout.androidaps.database.AppRepository import info.nightscout.androidaps.plugins.sync.nsShared.StoreDataForDb
import info.nightscout.androidaps.database.transactions.SyncNsTherapyEventTransaction import info.nightscout.androidaps.plugins.sync.nsclient.data.NSMbg
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.receivers.DataWorkerStorage import info.nightscout.androidaps.receivers.DataWorkerStorage
import info.nightscout.rx.logging.AAPSLogger import info.nightscout.androidaps.utils.extensions.therapyEventFromNsMbg
import info.nightscout.rx.logging.LTag import info.nightscout.interfaces.Config
import info.nightscout.shared.sharedPreferences.SP import info.nightscout.shared.sharedPreferences.SP
import javax.inject.Inject import javax.inject.Inject
@ -23,15 +19,13 @@ class NSClientMbgWorker(
params: WorkerParameters params: WorkerParameters
) : Worker(context, params) { ) : Worker(context, params) {
@Inject lateinit var repository: AppRepository
@Inject lateinit var dataWorkerStorage: DataWorkerStorage @Inject lateinit var dataWorkerStorage: DataWorkerStorage
@Inject lateinit var aapsLogger: AAPSLogger
@Inject lateinit var sp: SP @Inject lateinit var sp: SP
@Inject lateinit var buildHelper: BuildHelper
@Inject lateinit var config: Config @Inject lateinit var config: Config
@Inject lateinit var storeDataForDb: StoreDataForDb
override fun doWork(): Result { 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 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")) if (!acceptNSData) return Result.success(workDataOf("Result" to "Sync not enabled"))
@ -41,16 +35,9 @@ class NSClientMbgWorker(
for (i in 0 until mbgArray.length()) { for (i in 0 until mbgArray.length()) {
val nsMbg = NSMbg(mbgArray.getJSONObject(i)) val nsMbg = NSMbg(mbgArray.getJSONObject(i))
if (!nsMbg.isValid()) continue if (!nsMbg.isValid()) continue
repository.runTransactionForResult(SyncNsTherapyEventTransaction(therapyEventFromNsMbg(nsMbg))) storeDataForDb.therapyEvents.add(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.storeTreatmentsToDb() don't do this. It will be stored along with other treatments
return ret 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.ComponentName
import android.content.Context import android.content.Context
@ -7,29 +7,34 @@ import android.content.ServiceConnection
import android.os.Handler import android.os.Handler
import android.os.HandlerThread import android.os.HandlerThread
import android.os.IBinder import android.os.IBinder
import android.text.Spanned
import androidx.preference.PreferenceFragmentCompat import androidx.preference.PreferenceFragmentCompat
import androidx.preference.PreferenceScreen import androidx.preference.PreferenceScreen
import androidx.preference.SwitchPreference import androidx.preference.SwitchPreference
import dagger.android.HasAndroidInjector import dagger.android.HasAndroidInjector
import info.nightscout.interfaces.Constants
import info.nightscout.androidaps.R import info.nightscout.androidaps.R
import info.nightscout.androidaps.events.EventPreferenceChange 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.BuildHelper
import info.nightscout.interfaces.Config 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.PluginDescription
import info.nightscout.interfaces.PluginType 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.interfaces.utils.HtmlHelper.fromHtml
import info.nightscout.androidaps.utils.ToastUtils
import info.nightscout.rx.AapsSchedulers import info.nightscout.rx.AapsSchedulers
import info.nightscout.rx.bus.RxBus import info.nightscout.rx.bus.RxBus
import info.nightscout.rx.events.EventAppExit import info.nightscout.rx.events.EventAppExit
@ -55,17 +60,16 @@ class NSClientPlugin @Inject constructor(
private val sp: SP, private val sp: SP,
private val nsClientReceiverDelegate: NsClientReceiverDelegate, private val nsClientReceiverDelegate: NsClientReceiverDelegate,
private val config: Config, private val config: Config,
private val buildHelper: BuildHelper private val buildHelper: BuildHelper,
) : PluginBase( private val dataSyncSelector: DataSyncSelector
) : NsClient, Sync, PluginBase(
PluginDescription() PluginDescription()
.mainType(PluginType.GENERAL) .mainType(PluginType.SYNC)
.fragmentClass(NSClientFragment::class.java.name) .fragmentClass(NSClientFragment::class.java.name)
.pluginIcon(R.drawable.ic_nightscout_syncs) .pluginIcon(R.drawable.ic_nightscout_syncs)
.pluginName(R.string.nsclientinternal) .pluginName(R.string.nsclientinternal)
.shortName(R.string.nsclientinternal_shortname) .shortName(R.string.nsclientinternal_shortname)
.preferencesId(R.xml.pref_nsclientinternal) .preferencesId(R.xml.pref_nsclientinternal)
.alwaysEnabled(config.NSCLIENT)
.visibleByDefault(config.NSCLIENT)
.description(R.string.description_ns_client), .description(R.string.description_ns_client),
aapsLogger, rh, injector aapsLogger, rh, injector
) { ) {
@ -73,19 +77,14 @@ class NSClientPlugin @Inject constructor(
private val disposable = CompositeDisposable() private val disposable = CompositeDisposable()
private val handler = Handler(HandlerThread(this::class.simpleName + "Handler").also { it.start() }.looper) private val handler = Handler(HandlerThread(this::class.simpleName + "Handler").also { it.start() }.looper)
private val listLog: MutableList<EventNSClientNewLog> = ArrayList() private val listLog: MutableList<EventNSClientNewLog> = ArrayList()
var textLog = fromHtml("") override var status = ""
var paused = false override var nsClientService: NSClientService? = null
var autoscroll = false
var status = ""
var nsClientService: NSClientService? = null
val isAllowed: Boolean val isAllowed: Boolean
get() = nsClientReceiverDelegate.allowed get() = nsClientReceiverDelegate.allowed
val blockingReason: String val blockingReason: String
get() = nsClientReceiverDelegate.blockingReason get() = nsClientReceiverDelegate.blockingReason
override fun onStart() { 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) context.bindService(Intent(context, NSClientService::class.java), mConnection, Context.BIND_AUTO_CREATE)
super.onStart() super.onStart()
nsClientReceiverDelegate.grabReceiversState() nsClientReceiverDelegate.grabReceiversState()
@ -93,8 +92,10 @@ class NSClientPlugin @Inject constructor(
.toObservable(EventNSClientStatus::class.java) .toObservable(EventNSClientStatus::class.java)
.observeOn(aapsSchedulers.io) .observeOn(aapsSchedulers.io)
.subscribe({ event: EventNSClientStatus -> .subscribe({ event: EventNSClientStatus ->
status = event.getStatus(rh) if (event.version == NsClient.Version.V1) {
rxBus.send(EventNSClientUpdateGUI()) status = event.getStatus(rh)
rxBus.send(EventNSClientUpdateGUI())
}
}, fabricPrivacy::logException) }, fabricPrivacy::logException)
disposable += rxBus disposable += rxBus
.toObservable(EventNetworkChange::class.java) .toObservable(EventNetworkChange::class.java)
@ -112,6 +113,7 @@ class NSClientPlugin @Inject constructor(
.toObservable(EventNSClientNewLog::class.java) .toObservable(EventNSClientNewLog::class.java)
.observeOn(aapsSchedulers.io) .observeOn(aapsSchedulers.io)
.subscribe({ event: EventNSClientNewLog -> .subscribe({ event: EventNSClientNewLog ->
if (event.version != NsClient.Version.V1) return@subscribe
addToLog(event) addToLog(event)
aapsLogger.debug(LTag.NSCLIENT, event.action + " " + event.logText) aapsLogger.debug(LTag.NSCLIENT, event.action + " " + event.logText)
}, fabricPrivacy::logException) }, 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_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_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() 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 { private val mConnection: ServiceConnection = object : ServiceConnection {
override fun onServiceDisconnected(name: ComponentName) { override fun onServiceDisconnected(name: ComponentName) {
aapsLogger.debug(LTag.NSCLIENT, "Service is disconnected") aapsLogger.debug(LTag.NSCLIENT, "Service is disconnected")
@ -162,55 +160,53 @@ class NSClientPlugin @Inject constructor(
} }
} }
@Synchronized fun clearLog() { override fun clearLog() {
handler.post { handler.post {
synchronized(listLog) { listLog.clear() } synchronized(listLog) { listLog.clear() }
rxBus.send(EventNSClientUpdateGUI()) rxBus.send(EventNSClientUpdateGUI())
} }
} }
@Synchronized private fun addToLog(ev: EventNSClientNewLog) { private fun addToLog(ev: EventNSClientNewLog) {
handler.post { synchronized(listLog) {
synchronized(listLog) { listLog.add(ev)
listLog.add(ev) // remove the first line if log is too large
// remove the first line if log is too large if (listLog.size >= Constants.MAX_LOG_LINES) {
if (listLog.size >= Constants.MAX_LOG_LINES) { listLog.removeAt(0)
listLog.removeAt(0)
}
} }
rxBus.send(EventNSClientUpdateGUI())
} }
rxBus.send(EventNSClientUpdateGUI())
} }
@Synchronized fun updateLog() { override fun textLog(): Spanned {
try { try {
val newTextLog = StringBuilder() val newTextLog = StringBuilder()
synchronized(listLog) { synchronized(listLog) {
for (log in listLog) { for (log in listLog) newTextLog.append(log.toPreparedHtml())
newTextLog.append(log.toPreparedHtml())
}
} }
textLog = fromHtml(newTextLog.toString()) return fromHtml(newTextLog.toString())
} catch (e: OutOfMemoryError) { } catch (e: OutOfMemoryError) {
ToastUtils.showToastInUiThread(context, rxBus, "Out of memory!\nStop using this phone !!!", R.raw.error) 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) nsClientService?.resend(reason)
} }
fun pause(newState: Boolean) { override fun pause(newState: Boolean) {
sp.putBoolean(R.string.key_nsclientinternal_paused, newState) sp.putBoolean(R.string.key_nsclientinternal_paused, newState)
paused = newState
rxBus.send(EventPreferenceChange(rh, R.string.key_nsclientinternal_paused)) rxBus.send(EventPreferenceChange(rh, R.string.key_nsclientinternal_paused))
} }
fun url(): String = nsClientService?.nsURL ?: "" override val version: NsClient.Version
fun hasWritePermission(): Boolean = nsClientService?.hasWriteAuth ?: false get() = NsClient.Version.V1
override val address: String get() = nsClientService?.nsURL ?: ""
fun handleClearAlarm(originalAlarm: NSAlarm, silenceTimeInMilliseconds: Long) { fun handleClearAlarm(originalAlarm: NSAlarm, silenceTimeInMilliseconds: Long) {
if (!isEnabled(PluginType.GENERAL)) return if (!isEnabled()) return
if (!sp.getBoolean(R.string.key_ns_upload, true)) { if (!sp.getBoolean(R.string.key_ns_upload, true)) {
aapsLogger.debug(LTag.NSCLIENT, "Upload disabled. Message dropped") aapsLogger.debug(LTag.NSCLIENT, "Upload disabled. Message dropped")
return 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 } 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 android.content.Context
import androidx.work.Worker 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.PairTemporaryBasal
import info.nightscout.androidaps.interfaces.DataSyncSelector.PairTemporaryTarget import info.nightscout.androidaps.interfaces.DataSyncSelector.PairTemporaryTarget
import info.nightscout.androidaps.interfaces.DataSyncSelector.PairTherapyEvent import info.nightscout.androidaps.interfaces.DataSyncSelector.PairTherapyEvent
import info.nightscout.androidaps.plugins.general.nsclient.acks.NSUpdateAck import info.nightscout.androidaps.interfaces.NsClient
import info.nightscout.androidaps.plugins.general.nsclient.events.EventNSClientNewLog 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.androidaps.receivers.DataWorkerStorage
import info.nightscout.rx.AapsSchedulers import info.nightscout.rx.AapsSchedulers
import info.nightscout.rx.bus.RxBus import info.nightscout.rx.bus.RxBus
@ -50,7 +51,7 @@ class NSClientUpdateRemoveAckWorker(
is PairTemporaryTarget -> { is PairTemporaryTarget -> {
val pair = ack.originalObject val pair = ack.originalObject
dataSyncSelector.confirmLastTempTargetsIdIfGreater(pair.updateRecordId) 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 // Send new if waiting
dataSyncSelector.processChangedTempTargetsCompat() dataSyncSelector.processChangedTempTargetsCompat()
ret = Result.success(workDataOf("ProcessedData" to pair.toString())) ret = Result.success(workDataOf("ProcessedData" to pair.toString()))
@ -59,7 +60,7 @@ class NSClientUpdateRemoveAckWorker(
is PairGlucoseValue -> { is PairGlucoseValue -> {
val pair = ack.originalObject val pair = ack.originalObject
dataSyncSelector.confirmLastGlucoseValueIdIfGreater(pair.updateRecordId) 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 // Send new if waiting
dataSyncSelector.processChangedGlucoseValuesCompat() dataSyncSelector.processChangedGlucoseValuesCompat()
ret = Result.success(workDataOf("ProcessedData" to pair.toString())) ret = Result.success(workDataOf("ProcessedData" to pair.toString()))
@ -68,7 +69,7 @@ class NSClientUpdateRemoveAckWorker(
is PairFood -> { is PairFood -> {
val pair = ack.originalObject val pair = ack.originalObject
dataSyncSelector.confirmLastFoodIdIfGreater(pair.updateRecordId) 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 // Send new if waiting
dataSyncSelector.processChangedFoodsCompat() dataSyncSelector.processChangedFoodsCompat()
ret = Result.success(workDataOf("ProcessedData" to pair.toString())) ret = Result.success(workDataOf("ProcessedData" to pair.toString()))
@ -77,7 +78,7 @@ class NSClientUpdateRemoveAckWorker(
is PairTherapyEvent -> { is PairTherapyEvent -> {
val pair = ack.originalObject val pair = ack.originalObject
dataSyncSelector.confirmLastTherapyEventIdIfGreater(pair.updateRecordId) 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 // Send new if waiting
dataSyncSelector.processChangedTherapyEventsCompat() dataSyncSelector.processChangedTherapyEventsCompat()
ret = Result.success(workDataOf("ProcessedData" to pair.toString())) ret = Result.success(workDataOf("ProcessedData" to pair.toString()))
@ -86,7 +87,7 @@ class NSClientUpdateRemoveAckWorker(
is PairBolus -> { is PairBolus -> {
val pair = ack.originalObject val pair = ack.originalObject
dataSyncSelector.confirmLastBolusIdIfGreater(pair.updateRecordId) 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 // Send new if waiting
dataSyncSelector.processChangedBolusesCompat() dataSyncSelector.processChangedBolusesCompat()
ret = Result.success(workDataOf("ProcessedData" to pair.toString())) ret = Result.success(workDataOf("ProcessedData" to pair.toString()))
@ -95,7 +96,7 @@ class NSClientUpdateRemoveAckWorker(
is PairCarbs -> { is PairCarbs -> {
val pair = ack.originalObject val pair = ack.originalObject
dataSyncSelector.confirmLastCarbsIdIfGreater(pair.updateRecordId) 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 // Send new if waiting
dataSyncSelector.processChangedCarbsCompat() dataSyncSelector.processChangedCarbsCompat()
ret = Result.success(workDataOf("ProcessedData" to pair.toString())) ret = Result.success(workDataOf("ProcessedData" to pair.toString()))
@ -104,7 +105,7 @@ class NSClientUpdateRemoveAckWorker(
is PairBolusCalculatorResult -> { is PairBolusCalculatorResult -> {
val pair = ack.originalObject val pair = ack.originalObject
dataSyncSelector.confirmLastBolusCalculatorResultsIdIfGreater(pair.updateRecordId) 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 // Send new if waiting
dataSyncSelector.processChangedBolusCalculatorResultsCompat() dataSyncSelector.processChangedBolusCalculatorResultsCompat()
ret = Result.success(workDataOf("ProcessedData" to pair.toString())) ret = Result.success(workDataOf("ProcessedData" to pair.toString()))
@ -113,7 +114,7 @@ class NSClientUpdateRemoveAckWorker(
is PairTemporaryBasal -> { is PairTemporaryBasal -> {
val pair = ack.originalObject val pair = ack.originalObject
dataSyncSelector.confirmLastTemporaryBasalIdIfGreater(pair.updateRecordId) 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 // Send new if waiting
dataSyncSelector.processChangedTemporaryBasalsCompat() dataSyncSelector.processChangedTemporaryBasalsCompat()
ret = Result.success(workDataOf("ProcessedData" to pair.toString())) ret = Result.success(workDataOf("ProcessedData" to pair.toString()))
@ -122,7 +123,7 @@ class NSClientUpdateRemoveAckWorker(
is PairExtendedBolus -> { is PairExtendedBolus -> {
val pair = ack.originalObject val pair = ack.originalObject
dataSyncSelector.confirmLastExtendedBolusIdIfGreater(pair.updateRecordId) 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 // Send new if waiting
dataSyncSelector.processChangedExtendedBolusesCompat() dataSyncSelector.processChangedExtendedBolusesCompat()
ret = Result.success(workDataOf("ProcessedData" to pair.toString())) ret = Result.success(workDataOf("ProcessedData" to pair.toString()))
@ -131,7 +132,7 @@ class NSClientUpdateRemoveAckWorker(
is PairProfileSwitch -> { is PairProfileSwitch -> {
val pair = ack.originalObject val pair = ack.originalObject
dataSyncSelector.confirmLastProfileSwitchIdIfGreater(pair.updateRecordId) 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 // Send new if waiting
dataSyncSelector.processChangedProfileSwitchesCompat() dataSyncSelector.processChangedProfileSwitchesCompat()
ret = Result.success(workDataOf("ProcessedData" to pair.toString())) ret = Result.success(workDataOf("ProcessedData" to pair.toString()))
@ -140,7 +141,7 @@ class NSClientUpdateRemoveAckWorker(
is PairEffectiveProfileSwitch -> { is PairEffectiveProfileSwitch -> {
val pair = ack.originalObject val pair = ack.originalObject
dataSyncSelector.confirmLastEffectiveProfileSwitchIdIfGreater(pair.updateRecordId) 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 // Send new if waiting
dataSyncSelector.processChangedEffectiveProfileSwitchesCompat() dataSyncSelector.processChangedEffectiveProfileSwitchesCompat()
ret = Result.success(workDataOf("ProcessedData" to pair.toString())) ret = Result.success(workDataOf("ProcessedData" to pair.toString()))
@ -149,7 +150,7 @@ class NSClientUpdateRemoveAckWorker(
is PairOfflineEvent -> { is PairOfflineEvent -> {
val pair = ack.originalObject val pair = ack.originalObject
dataSyncSelector.confirmLastOfflineEventIdIfGreater(pair.updateRecordId) 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 // Send new if waiting
dataSyncSelector.processChangedOfflineEventsCompat() dataSyncSelector.processChangedOfflineEventsCompat()
ret = Result.success(workDataOf("ProcessedData" to pair.toString())) 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.R
import info.nightscout.androidaps.events.EventPreferenceChange 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.bus.RxBus
import info.nightscout.rx.events.Event import info.nightscout.rx.events.Event
@ -16,7 +16,7 @@ class NSAddAck(
) : Event(), Ack { ) : Event(), Ack {
var id: String? = null var id: String? = null
var nsClientID: String? = null private var nsClientID: String? = null
var json: JSONObject? = null var json: JSONObject? = null
override fun call(vararg args: Any) { override fun call(vararg args: Any) {
// Regular response // 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.bus.RxBus
import info.nightscout.rx.events.Event 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.bus.RxBus
import info.nightscout.rx.events.Event 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. * 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 info.nightscout.interfaces.utils.JsonHelper
import org.json.JSONObject 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 info.nightscout.interfaces.utils.JsonHelper
import org.json.JSONObject 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 android.content.Context
import info.nightscout.androidaps.R import info.nightscout.androidaps.R
@ -113,7 +113,6 @@ import javax.inject.Singleton
"activeProfile": "2016 +30%" "activeProfile": "2016 +30%"
} }
*/ */
@Suppress("SpellCheckingInspection")
@OpenForTesting @OpenForTesting
@Singleton @Singleton
class NSSettingsStatus @Inject constructor( class NSSettingsStatus @Inject constructor(
@ -234,11 +233,6 @@ class NSSettingsStatus @Inject constructor(
fun pumpExtendedSettingsFields(): String = fun pumpExtendedSettingsFields(): String =
JsonHelper.safeGetString(extendedPumpSettings(), "fields", "") JsonHelper.safeGetString(extendedPumpSettings(), "fields", "")
fun openAPSEnabledAlerts(): Boolean {
val openaps = JsonHelper.safeGetJSONObject(getExtendedSettings(), "openaps", null)
return JsonHelper.safeGetBoolean(openaps, "enableAlerts")
}
fun copyStatusLightsNsSettings(context: Context?) { fun copyStatusLightsNsSettings(context: Context?) {
val action = Runnable { val action = Runnable {
getExtendedWarnValue("cage", "warn")?.let { sp.putDouble(R.string.key_statuslights_cage_warning, it) } 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 info.nightscout.interfaces.utils.JsonHelper
import org.json.JSONObject 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.annotation.SuppressLint
import android.content.Context import android.content.Context
@ -12,42 +12,47 @@ import android.os.SystemClock
import androidx.work.OneTimeWorkRequest import androidx.work.OneTimeWorkRequest
import com.google.common.base.Charsets import com.google.common.base.Charsets
import com.google.common.hash.Hashing import com.google.common.hash.Hashing
import com.google.gson.GsonBuilder
import com.google.gson.JsonDeserializer
import dagger.android.DaggerService import dagger.android.DaggerService
import dagger.android.HasAndroidInjector import dagger.android.HasAndroidInjector
import info.nightscout.androidaps.R import info.nightscout.androidaps.R
import info.nightscout.androidaps.database.AppRepository import info.nightscout.androidaps.database.AppRepository
import info.nightscout.androidaps.events.EventPreferenceChange 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.DataSyncSelector
import info.nightscout.androidaps.interfaces.NsClient
import info.nightscout.androidaps.interfaces.ResourceHelper import info.nightscout.androidaps.interfaces.ResourceHelper
import info.nightscout.androidaps.plugins.general.nsclient.NSClientAddAckWorker import info.nightscout.androidaps.plugins.sync.nsShared.events.EventNSClientUpdateGUI
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.general.overview.events.EventDismissNotification import info.nightscout.androidaps.plugins.general.overview.events.EventDismissNotification
import info.nightscout.androidaps.plugins.general.overview.events.EventNewNotification import info.nightscout.androidaps.plugins.general.overview.events.EventNewNotification
import info.nightscout.interfaces.notifications.Notification
import info.nightscout.androidaps.plugins.general.overview.notifications.NotificationWithAction 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.receivers.DataWorkerStorage
import info.nightscout.androidaps.utils.DateUtil import info.nightscout.androidaps.utils.DateUtil
import info.nightscout.androidaps.utils.FabricPrivacy 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.safeGetString
import info.nightscout.interfaces.utils.JsonHelper.safeGetStringAllowNull import info.nightscout.interfaces.utils.JsonHelper.safeGetStringAllowNull
import info.nightscout.androidaps.utils.T.Companion.mins import info.nightscout.plugins.general.food.FoodPlugin
import info.nightscout.plugins.general.food.FoodPlugin.FoodWorker
import info.nightscout.plugins.profile.ProfilePlugin import info.nightscout.plugins.profile.ProfilePlugin
import info.nightscout.rx.AapsSchedulers import info.nightscout.rx.AapsSchedulers
import info.nightscout.rx.bus.RxBus 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.events.EventNSClientRestart
import info.nightscout.rx.logging.AAPSLogger import info.nightscout.rx.logging.AAPSLogger
import info.nightscout.rx.logging.LTag import info.nightscout.rx.logging.LTag
import info.nightscout.sdk.remotemodel.RemoteDeviceStatus
import info.nightscout.shared.sharedPreferences.SP import info.nightscout.shared.sharedPreferences.SP
import io.reactivex.rxjava3.disposables.CompositeDisposable import io.reactivex.rxjava3.disposables.CompositeDisposable
import io.reactivex.rxjava3.kotlin.plusAssign import io.reactivex.rxjava3.kotlin.plusAssign
@ -69,13 +75,13 @@ import java.net.URISyntaxException
import java.util.Locale import java.util.Locale
import javax.inject.Inject import javax.inject.Inject
class NSClientService : DaggerService() { class NSClientService : DaggerService(), NsClient.NSClientService {
@Inject lateinit var injector: HasAndroidInjector @Inject lateinit var injector: HasAndroidInjector
@Inject lateinit var aapsLogger: AAPSLogger @Inject lateinit var aapsLogger: AAPSLogger
@Inject lateinit var aapsSchedulers: AapsSchedulers @Inject lateinit var aapsSchedulers: AapsSchedulers
@Inject lateinit var nsSettingsStatus: NSSettingsStatus @Inject lateinit var nsSettingsStatus: NSSettingsStatus
@Inject lateinit var nsDeviceStatus: NSDeviceStatus @Inject lateinit var nsDeviceStatusHandler: NSDeviceStatusHandler
@Inject lateinit var rxBus: RxBus @Inject lateinit var rxBus: RxBus
@Inject lateinit var rh: ResourceHelper @Inject lateinit var rh: ResourceHelper
@Inject lateinit var sp: SP @Inject lateinit var sp: SP
@ -206,13 +212,13 @@ class NSClientService : DaggerService() {
connectionStatus += ')' connectionStatus += ')'
isConnected = true isConnected = true
hasWriteAuth = ack.write && ack.writeTreatment hasWriteAuth = ack.write && ack.writeTreatment
rxBus.send(EventNSClientStatus(connectionStatus)) rxBus.send(EventNSClientStatus(connectionStatus, NsClient.Version.V1))
rxBus.send(EventNSClientNewLog("AUTH", connectionStatus)) rxBus.send(EventNSClientNewLog("AUTH", connectionStatus, NsClient.Version.V1))
if (!ack.write) { 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) { 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) { if (!hasWriteAuth) {
val noWritePerm = Notification(Notification.NSCLIENT_NO_WRITE_PERMISSION, rh.gs(R.string.nowritepermission), Notification.URGENT) val noWritePerm = Notification(Notification.NSCLIENT_NO_WRITE_PERMISSION, rh.gs(R.string.nowritepermission), Notification.URGENT)
@ -235,21 +241,21 @@ class NSClientService : DaggerService() {
fun initialize() { fun initialize() {
dataCounter = 0 dataCounter = 0
readPreferences() readPreferences()
@Suppress("UnstableApiUsage", "DEPRECATION") @Suppress("DEPRECATION")
if (nsAPISecret != "") nsApiHashCode = Hashing.sha1().hashString(nsAPISecret, Charsets.UTF_8).toString() 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) { if (!nsClientPlugin.isAllowed) {
rxBus.send(EventNSClientNewLog("NSCLIENT", nsClientPlugin.blockingReason)) rxBus.send(EventNSClientNewLog("NSCLIENT", nsClientPlugin.blockingReason, NsClient.Version.V1))
rxBus.send(EventNSClientStatus(nsClientPlugin.blockingReason)) rxBus.send(EventNSClientStatus(nsClientPlugin.blockingReason, NsClient.Version.V1))
} else if (nsClientPlugin.paused) { } else if (sp.getBoolean(R.string.key_nsclientinternal_paused, false)) {
rxBus.send(EventNSClientNewLog("NSCLIENT", "paused")) rxBus.send(EventNSClientNewLog("NSCLIENT", "paused", NsClient.Version.V1))
rxBus.send(EventNSClientStatus("Paused")) rxBus.send(EventNSClientStatus("Paused", NsClient.Version.V1))
} else if (!nsEnabled) { } else if (!nsEnabled) {
rxBus.send(EventNSClientNewLog("NSCLIENT", "disabled")) rxBus.send(EventNSClientNewLog("NSCLIENT", "disabled", NsClient.Version.V1))
rxBus.send(EventNSClientStatus("Disabled")) rxBus.send(EventNSClientStatus("Disabled", NsClient.Version.V1))
} else if (nsURL != "" && (buildHelper.isEngineeringMode() || nsURL.lowercase(Locale.getDefault()).startsWith("https://"))) { } else if (nsURL != "" && (buildHelper.isEngineeringMode() || nsURL.lowercase(Locale.getDefault()).startsWith("https://"))) {
try { try {
rxBus.send(EventNSClientStatus("Connecting ...")) rxBus.send(EventNSClientStatus("Connecting ...", NsClient.Version.V1))
val opt = IO.Options() val opt = IO.Options()
opt.forceNew = true opt.forceNew = true
opt.reconnection = true opt.reconnection = true
@ -260,7 +266,7 @@ class NSClientService : DaggerService() {
socket.on(Socket.EVENT_CONNECT_ERROR, onError) socket.on(Socket.EVENT_CONNECT_ERROR, onError)
socket.on(Socket.EVENT_CONNECT_TIMEOUT, onError) socket.on(Socket.EVENT_CONNECT_TIMEOUT, onError)
socket.on(Socket.EVENT_PING, onPing) socket.on(Socket.EVENT_PING, onPing)
rxBus.send(EventNSClientNewLog("NSCLIENT", "do connect")) rxBus.send(EventNSClientNewLog("NSCLIENT", "do connect", NsClient.Version.V1))
socket.connect() socket.connect()
socket.on("dataUpdate", onDataUpdate) socket.on("dataUpdate", onDataUpdate)
socket.on("announcement", onAnnouncement) socket.on("announcement", onAnnouncement)
@ -269,25 +275,25 @@ class NSClientService : DaggerService() {
socket.on("clear_alarm", onClearAlarm) socket.on("clear_alarm", onClearAlarm)
} }
} catch (e: URISyntaxException) { } catch (e: URISyntaxException) {
rxBus.send(EventNSClientNewLog("NSCLIENT", "Wrong URL syntax")) rxBus.send(EventNSClientNewLog("NSCLIENT", "Wrong URL syntax", NsClient.Version.V1))
rxBus.send(EventNSClientStatus("Wrong URL syntax")) rxBus.send(EventNSClientStatus("Wrong URL syntax", NsClient.Version.V1))
} catch (e: RuntimeException) { } catch (e: RuntimeException) {
rxBus.send(EventNSClientNewLog("NSCLIENT", "Wrong URL syntax")) rxBus.send(EventNSClientNewLog("NSCLIENT", "Wrong URL syntax", NsClient.Version.V1))
rxBus.send(EventNSClientStatus("Wrong URL syntax")) rxBus.send(EventNSClientStatus("Wrong URL syntax", NsClient.Version.V1))
} }
} else if (nsURL.lowercase(Locale.getDefault()).startsWith("http://")) { } else if (nsURL.lowercase(Locale.getDefault()).startsWith("http://")) {
rxBus.send(EventNSClientNewLog("NSCLIENT", "NS URL not encrypted")) rxBus.send(EventNSClientNewLog("NSCLIENT", "NS URL not encrypted", NsClient.Version.V1))
rxBus.send(EventNSClientStatus("Not encrypted")) rxBus.send(EventNSClientStatus("Not encrypted", NsClient.Version.V1))
} else { } else {
rxBus.send(EventNSClientNewLog("NSCLIENT", "No NS URL specified")) rxBus.send(EventNSClientNewLog("NSCLIENT", "No NS URL specified", NsClient.Version.V1))
rxBus.send(EventNSClientStatus("Not configured")) rxBus.send(EventNSClientStatus("Not configured", NsClient.Version.V1))
} }
} }
private val onConnect = Emitter.Listener { private val onConnect = Emitter.Listener {
connectCounter++ connectCounter++
val socketId = socket?.id() ?: "NULL" 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)) if (socket != null) sendAuthMessage(NSAuthAck(rxBus))
watchdog() watchdog()
} }
@ -301,16 +307,16 @@ class NSClientService : DaggerService() {
reconnections.remove(r) 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) { if (reconnections.size >= WATCHDOG_MAX_CONNECTIONS) {
val n = Notification(Notification.NS_MALFUNCTION, rh.gs(R.string.nsmalfunction), Notification.URGENT) val n = Notification(Notification.NS_MALFUNCTION, rh.gs(R.string.nsmalfunction), Notification.URGENT)
rxBus.send(EventNewNotification(n)) 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) nsClientPlugin.pause(true)
rxBus.send(EventNSClientUpdateGUI()) rxBus.send(EventNSClientUpdateGUI())
Thread { Thread {
SystemClock.sleep(mins(WATCHDOG_RECONNECT_IN.toLong()).msecs()) 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) nsClientPlugin.pause(false)
}.start() }.start()
} }
@ -319,7 +325,7 @@ class NSClientService : DaggerService() {
private val onDisconnect = Emitter.Listener { args -> private val onDisconnect = Emitter.Listener { args ->
aapsLogger.debug(LTag.NSCLIENT, "disconnect reason: {}", *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() { @Synchronized fun destroy() {
@ -331,7 +337,7 @@ class NSClientService : DaggerService() {
socket?.off("alarm") socket?.off("alarm")
socket?.off("urgent_alarm") socket?.off("urgent_alarm")
socket?.off("clear_alarm") socket?.off("clear_alarm")
rxBus.send(EventNSClientNewLog("NSCLIENT", "destroy")) rxBus.send(EventNSClientNewLog("NSCLIENT", "destroy", NsClient.Version.V1))
isConnected = false isConnected = false
hasWriteAuth = false hasWriteAuth = false
socket?.disconnect() socket?.disconnect()
@ -350,11 +356,11 @@ class NSClientService : DaggerService() {
aapsLogger.error("Unhandled exception", e) aapsLogger.error("Unhandled exception", e)
return return
} }
rxBus.send(EventNSClientNewLog("AUTH", "requesting auth")) rxBus.send(EventNSClientNewLog("AUTH", "requesting auth", NsClient.Version.V1))
socket?.emit("authorize", authMessage, ack) socket?.emit("authorize", authMessage, ack)
} }
fun readPreferences() { private fun readPreferences() {
nsEnabled = nsClientPlugin.isEnabled() nsEnabled = nsClientPlugin.isEnabled()
nsURL = sp.getString(R.string.key_nsclientinternal_url, "") nsURL = sp.getString(R.string.key_nsclientinternal_url, "")
nsAPISecret = sp.getString(R.string.key_nsclientinternal_api_secret, "") nsAPISecret = sp.getString(R.string.key_nsclientinternal_api_secret, "")
@ -366,10 +372,10 @@ class NSClientService : DaggerService() {
if (args.isNotEmpty() && args[0] != null) { if (args.isNotEmpty() && args[0] != null) {
msg = args[0].toString() msg = args[0].toString()
} }
rxBus.send(EventNSClientNewLog("ERROR", msg)) rxBus.send(EventNSClientNewLog("ERROR", msg, NsClient.Version.V1))
} }
private val onPing = Emitter.Listener { 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 // send data if there is something waiting
resend("Ping received") resend("Ping received")
} }
@ -439,7 +445,7 @@ class NSClientService : DaggerService() {
val data: JSONObject val data: JSONObject
try { try {
data = args[0] as JSONObject 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_ALARM))
rxBus.send(EventDismissNotification(Notification.NS_URGENT_ALARM)) rxBus.send(EventDismissNotification(Notification.NS_URGENT_ALARM))
aapsLogger.debug(LTag.NSCLIENT, data.toString()) aapsLogger.debug(LTag.NSCLIENT, data.toString())
@ -458,19 +464,19 @@ class NSClientService : DaggerService() {
try { try {
// delta means only increment/changes are coming // delta means only increment/changes are coming
val isDelta = data.has("delta") 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")) { if (data.has("status")) {
val status = data.getJSONObject("status") val status = data.getJSONObject("status")
nsSettingsStatus.handleNewData(status) nsSettingsStatus.handleNewData(status)
} else if (!isDelta) { } else if (!isDelta) {
rxBus.send(EventNSClientNewLog("ERROR", "Unsupported Nightscout version ")) rxBus.send(EventNSClientNewLog("ERROR", "Unsupported Nightscout version ", NsClient.Version.V1))
} }
if (data.has("profiles")) { if (data.has("profiles")) {
val profiles = data.getJSONArray("profiles") val profiles = data.getJSONArray("profiles")
if (profiles.length() > 0) { if (profiles.length() > 0) {
// take the newest // take the newest
val profileStoreJson = profiles[profiles.length() - 1] as JSONObject 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( dataWorkerStorage.enqueue(
OneTimeWorkRequest.Builder(ProfilePlugin.NSProfileWorker::class.java) OneTimeWorkRequest.Builder(ProfilePlugin.NSProfileWorker::class.java)
.setInputData(dataWorkerStorage.storeInputData(profileStoreJson)) .setInputData(dataWorkerStorage.storeInputData(profileStoreJson))
@ -481,7 +487,7 @@ class NSClientService : DaggerService() {
if (data.has("treatments")) { if (data.has("treatments")) {
val treatments = data.getJSONArray("treatments") val treatments = data.getJSONArray("treatments")
val addedOrUpdatedTreatments = JSONArray() 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()) { for (index in 0 until treatments.length()) {
val jsonTreatment = treatments.getJSONObject(index) val jsonTreatment = treatments.getJSONObject(index)
val action = safeGetStringAllowNull(jsonTreatment, "action", null) val action = safeGetStringAllowNull(jsonTreatment, "action", null)
@ -497,24 +503,31 @@ class NSClientService : DaggerService() {
} }
} }
if (data.has("devicestatus")) { if (data.has("devicestatus")) {
val devicestatuses = data.getJSONArray("devicestatus") val deserializer: JsonDeserializer<JSONObject?> =
if (devicestatuses.length() > 0) { JsonDeserializer<JSONObject?> { json, _, _ ->
rxBus.send(EventNSClientNewLog("DATA", "received " + devicestatuses.length() + " device statuses")) JSONObject(json.asJsonObject.toString())
nsDeviceStatus.handleNewData(devicestatuses) }
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")) { if (data.has("food")) {
val foods = data.getJSONArray("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( dataWorkerStorage.enqueue(
OneTimeWorkRequest.Builder(FoodWorker::class.java) OneTimeWorkRequest.Builder(FoodPlugin.FoodWorker::class.java)
.setInputData(dataWorkerStorage.storeInputData(foods)) .setInputData(dataWorkerStorage.storeInputData(foods))
.build() .build()
) )
} }
if (data.has("mbgs")) { if (data.has("mbgs")) {
val mbgArray = data.getJSONArray("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( dataWorkerStorage.enqueue(
OneTimeWorkRequest.Builder(NSClientMbgWorker::class.java) OneTimeWorkRequest.Builder(NSClientMbgWorker::class.java)
.setInputData(dataWorkerStorage.storeInputData(mbgArray)) .setInputData(dataWorkerStorage.storeInputData(mbgArray))
@ -523,23 +536,26 @@ class NSClientService : DaggerService() {
} }
if (data.has("cals")) { if (data.has("cals")) {
val cals = data.getJSONArray("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 // Calibrations ignored
} }
if (data.has("sgvs")) { if (data.has("sgvs")) {
val sgvs = data.getJSONArray("sgvs") val sgvs = data.getJSONArray("sgvs")
if (sgvs.length() > 0) { if (sgvs.length() > 0) {
rxBus.send(EventNSClientNewLog("DATA", "received " + sgvs.length() + " sgvs")) rxBus.send(EventNSClientNewLog("DATA", "received " + sgvs.length() + " sgvs", NsClient.Version.V1))
// Objective0 // Objective0
sp.putBoolean(R.string.key_ObjectivesbgIsAvailableInNS, true) sp.putBoolean(R.string.key_ObjectivesbgIsAvailableInNS, true)
dataWorkerStorage.enqueue( dataWorkerStorage
OneTimeWorkRequest.Builder(NSClientSourceWorker::class.java) .beginUniqueWork(
.setInputData(dataWorkerStorage.storeInputData(sgvs)) NSClientV3Plugin.JOB_NAME,
.build() 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) { } catch (e: JSONException) {
aapsLogger.error("Unhandled exception", e) 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 { try {
if (_id == null) return if (_id == null) return
if (!isConnected || !hasWriteAuth) return if (!isConnected || !hasWriteAuth) return
@ -562,7 +578,7 @@ class NSClientService : DaggerService() {
rxBus.send( rxBus.send(
EventNSClientNewLog( EventNSClientNewLog(
"DBUPDATE $collection", "Sent " + originalObject.javaClass.simpleName + " " + "DBUPDATE $collection", "Sent " + originalObject.javaClass.simpleName + " " +
"" + _id + " " + data + progress "" + _id + " " + data + progress, NsClient.Version.V1
) )
) )
} catch (e: JSONException) { } 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 { try {
if (!isConnected || !hasWriteAuth) return if (!isConnected || !hasWriteAuth) return
val message = JSONObject() val message = JSONObject()
message.put("collection", collection) message.put("collection", collection)
message.put("data", data) message.put("data", data)
socket?.emit("dbAdd", message, NSAddAck(aapsLogger, rxBus, originalObject)) 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) { } catch (e: JSONException) {
aapsLogger.error("Unhandled exception", e) aapsLogger.error("Unhandled exception", e)
} }
@ -586,7 +602,7 @@ class NSClientService : DaggerService() {
fun sendAlarmAck(alarmAck: AlarmAck) { fun sendAlarmAck(alarmAck: AlarmAck) {
if (!isConnected || !hasWriteAuth) return if (!isConnected || !hasWriteAuth) return
socket?.emit("ack", alarmAck.level, alarmAck.group, alarmAck.silenceTime) 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) { fun resend(reason: String) {
@ -602,9 +618,9 @@ class NSClientService : DaggerService() {
// "AndroidAPS:NSClientService_onDataUpdate") // "AndroidAPS:NSClientService_onDataUpdate")
// wakeLock.acquire(mins(10).msecs()) // wakeLock.acquire(mins(10).msecs())
try { try {
rxBus.send(EventNSClientNewLog("QUEUE", "Resend started: $reason")) rxBus.send(EventNSClientNewLog("QUEUE", "Resend started: $reason", NsClient.Version.V1))
dataSyncSelector.doUpload() dataSyncSelector.doUpload()
rxBus.send(EventNSClientNewLog("QUEUE", "Resend ended: $reason")) rxBus.send(EventNSClientNewLog("QUEUE", "Resend ended: $reason", NsClient.Version.V1))
} finally { } finally {
// if (wakeLock.isHeld) wakeLock.release() // if (wakeLock.isHeld) wakeLock.release()
} }
@ -622,7 +638,7 @@ class NSClientService : DaggerService() {
val nsAlarm = NSAlarm(announcement) val nsAlarm = NSAlarm(announcement)
val notification: Notification = NotificationWithAction(injector, nsAlarm) val notification: Notification = NotificationWithAction(injector, nsAlarm)
rxBus.send(EventNewNotification(notification)) 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()) aapsLogger.debug(LTag.NSCLIENT, announcement.toString())
} }
} }
@ -636,7 +652,7 @@ class NSClientService : DaggerService() {
val notification: Notification = NotificationWithAction(injector, nsAlarm) val notification: Notification = NotificationWithAction(injector, nsAlarm)
rxBus.send(EventNewNotification(notification)) 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()) aapsLogger.debug(LTag.NSCLIENT, alarm.toString())
} }
} }
@ -650,7 +666,7 @@ class NSClientService : DaggerService() {
val notification: Notification = NotificationWithAction(injector, nsAlarm) val notification: Notification = NotificationWithAction(injector, nsAlarm)
rxBus.send(EventNewNotification(notification)) 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()) 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.os.Bundle
import android.view.LayoutInflater import android.view.LayoutInflater
@ -8,10 +8,10 @@ import android.widget.ScrollView
import dagger.android.support.DaggerFragment import dagger.android.support.DaggerFragment
import info.nightscout.androidaps.R import info.nightscout.androidaps.R
import info.nightscout.androidaps.databinding.TidepoolFragmentBinding 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.EventTidepoolDoUpload
import info.nightscout.androidaps.plugins.general.tidepool.events.EventTidepoolResetData 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.androidaps.utils.FabricPrivacy
import info.nightscout.rx.AapsSchedulers import info.nightscout.rx.AapsSchedulers
import info.nightscout.rx.bus.RxBus import info.nightscout.rx.bus.RxBus
@ -57,13 +57,13 @@ class TidepoolFragment : DaggerFragment() {
.toObservable(EventTidepoolUpdateGUI::class.java) .toObservable(EventTidepoolUpdateGUI::class.java)
.observeOn(aapsSchedulers.main) .observeOn(aapsSchedulers.main)
.subscribe({ .subscribe({
if (_binding == null) return@subscribe if (_binding == null) return@subscribe
tidepoolPlugin.updateLog() tidepoolPlugin.updateLog()
binding.log.text = tidepoolPlugin.textLog binding.log.text = tidepoolPlugin.textLog
binding.status.text = tidepoolUploader.connectionStatus.name binding.status.text = tidepoolUploader.connectionStatus.name
binding.log.text = tidepoolPlugin.textLog binding.log.text = tidepoolPlugin.textLog
binding.logscrollview.fullScroll(ScrollView.FOCUS_DOWN) binding.logscrollview.fullScroll(ScrollView.FOCUS_DOWN)
}, fabricPrivacy::logException) }, fabricPrivacy::logException)
} }
@Synchronized @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.content.Context
import android.text.Spanned import android.text.Spanned
import androidx.preference.Preference import androidx.preference.Preference
import androidx.preference.PreferenceFragmentCompat import androidx.preference.PreferenceFragmentCompat
import dagger.android.HasAndroidInjector import dagger.android.HasAndroidInjector
import info.nightscout.interfaces.Constants
import info.nightscout.androidaps.R import info.nightscout.androidaps.R
import info.nightscout.androidaps.events.EventNewBG import info.nightscout.androidaps.events.EventNewBG
import info.nightscout.androidaps.events.EventPreferenceChange import info.nightscout.androidaps.events.EventPreferenceChange
import info.nightscout.androidaps.interfaces.PluginBase 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.ResourceHelper
import info.nightscout.androidaps.plugins.general.tidepool.comm.TidepoolUploader import info.nightscout.androidaps.interfaces.Sync
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.plugins.general.tidepool.events.EventTidepoolDoUpload 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.EventTidepoolResetData
import info.nightscout.androidaps.plugins.general.tidepool.events.EventTidepoolStatus import info.nightscout.androidaps.plugins.sync.tidepool.comm.TidepoolUploader
import info.nightscout.androidaps.plugins.general.tidepool.events.EventTidepoolUpdateGUI import info.nightscout.androidaps.plugins.sync.tidepool.comm.UploadChunk
import info.nightscout.androidaps.plugins.general.tidepool.utils.RateLimit 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.receivers.ReceiverStatusStore
import info.nightscout.androidaps.utils.FabricPrivacy import info.nightscout.androidaps.utils.FabricPrivacy
import info.nightscout.interfaces.utils.HtmlHelper
import info.nightscout.androidaps.utils.T import info.nightscout.androidaps.utils.T
import info.nightscout.androidaps.utils.ToastUtils import info.nightscout.androidaps.utils.ToastUtils
import info.nightscout.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.AapsSchedulers
import info.nightscout.rx.bus.RxBus import info.nightscout.rx.bus.RxBus
import info.nightscout.rx.events.EventNetworkChange import info.nightscout.rx.events.EventNetworkChange
@ -52,14 +51,14 @@ class TidepoolPlugin @Inject constructor(
private val sp: SP, private val sp: SP,
private val rateLimit: RateLimit, private val rateLimit: RateLimit,
private val receiverStatusStore: ReceiverStatusStore private val receiverStatusStore: ReceiverStatusStore
) : PluginBase( ) : Sync, PluginBase(
PluginDescription() PluginDescription()
.mainType(PluginType.GENERAL) .mainType(PluginType.SYNC)
.pluginName(R.string.tidepool) .pluginName(R.string.tidepool)
.shortName(R.string.tidepool_shortname) .shortName(R.string.tidepool_shortname)
.fragmentClass(TidepoolFragment::class.qualifiedName) .fragmentClass(TidepoolFragment::class.qualifiedName)
.preferencesId(R.xml.pref_tidepool) .preferencesId(R.xml.pref_tidepool)
.description(R.string.description_tidepool), .description(R.string.description_tidepool),
aapsLogger, rh, injector aapsLogger, rh, injector
) { ) {
@ -79,14 +78,14 @@ class TidepoolPlugin @Inject constructor(
.toObservable(EventTidepoolResetData::class.java) .toObservable(EventTidepoolResetData::class.java)
.observeOn(aapsSchedulers.io) .observeOn(aapsSchedulers.io)
.subscribe({ .subscribe({
if (tidepoolUploader.connectionStatus != CONNECTED) { if (tidepoolUploader.connectionStatus != TidepoolUploader.ConnectionStatus.CONNECTED) {
aapsLogger.debug(LTag.TIDEPOOL, "Not connected for delete Dataset") aapsLogger.debug(LTag.TIDEPOOL, "Not connected for delete Dataset")
} else { } else {
tidepoolUploader.deleteDataSet() tidepoolUploader.deleteDataSet()
sp.putLong(R.string.key_tidepool_last_end, 0) sp.putLong(R.string.key_tidepool_last_end, 0)
tidepoolUploader.doLogin() tidepoolUploader.doLogin()
} }
}, fabricPrivacy::logException) }, fabricPrivacy::logException)
disposable += rxBus disposable += rxBus
.toObservable(EventTidepoolStatus::class.java) .toObservable(EventTidepoolStatus::class.java)
.observeOn(aapsSchedulers.io) .observeOn(aapsSchedulers.io)
@ -95,26 +94,27 @@ class TidepoolPlugin @Inject constructor(
.toObservable(EventNewBG::class.java) .toObservable(EventNewBG::class.java)
.observeOn(aapsSchedulers.io) .observeOn(aapsSchedulers.io)
.filter { it.glucoseValue != null } // better would be optional in API level >24 .filter { it.glucoseValue != null } // better would be optional in API level >24
.map { it.glucoseValue } .map { it.glucoseValue!! }
.subscribe({ bgReading -> .subscribe({ bgReading ->
if (bgReading!!.timestamp < uploadChunk.getLastEnd()) if (bgReading!!.timestamp < uploadChunk.getLastEnd())
uploadChunk.setLastEnd(bgReading.timestamp ) uploadChunk.setLastEnd(bgReading.timestamp)
if (isEnabled(PluginType.GENERAL) if (isEnabled()
&& (!sp.getBoolean(R.string.key_tidepool_only_while_charging, false) || receiverStatusStore.isCharging) && (!sp.getBoolean(R.string.key_tidepool_only_while_charging, false) || receiverStatusStore.isCharging)
&& (!sp.getBoolean(R.string.key_tidepool_only_while_unmetered, false) || receiverStatusStore.isWifiConnected) && (!sp.getBoolean(R.string.key_tidepool_only_while_unmetered, false) || receiverStatusStore.isWifiConnected)
&& rateLimit.rateLimit("tidepool-new-data-upload", T.mins(4).secs().toInt())) && rateLimit.rateLimit("tidepool-new-data-upload", T.mins(4).secs().toInt())
doUpload() )
}, fabricPrivacy::logException) doUpload()
}, fabricPrivacy::logException)
disposable += rxBus disposable += rxBus
.toObservable(EventPreferenceChange::class.java) .toObservable(EventPreferenceChange::class.java)
.observeOn(aapsSchedulers.io) .observeOn(aapsSchedulers.io)
.subscribe({ event -> .subscribe({ event ->
if (event.isChanged(rh, R.string.key_tidepool_dev_servers) 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_username)
|| event.isChanged(rh, R.string.key_tidepool_password) || event.isChanged(rh, R.string.key_tidepool_password)
) )
tidepoolUploader.resetInstance() tidepoolUploader.resetInstance()
}, fabricPrivacy::logException) }, fabricPrivacy::logException)
disposable += rxBus disposable += rxBus
.toObservable(EventNetworkChange::class.java) .toObservable(EventNetworkChange::class.java)
.observeOn(aapsSchedulers.io) .observeOn(aapsSchedulers.io)
@ -141,10 +141,10 @@ class TidepoolPlugin @Inject constructor(
private fun doUpload() = private fun doUpload() =
when (tidepoolUploader.connectionStatus) { when (tidepoolUploader.connectionStatus) {
DISCONNECTED -> tidepoolUploader.doLogin(true) TidepoolUploader.ConnectionStatus.DISCONNECTED -> tidepoolUploader.doLogin(true)
CONNECTED -> tidepoolUploader.doUpload() 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.AAPSLogger
import info.nightscout.rx.logging.LTag 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.sync.tidepool.messages.AuthReplyMessage
import info.nightscout.androidaps.plugins.general.tidepool.messages.DatasetReplyMessage import info.nightscout.androidaps.plugins.sync.tidepool.messages.DatasetReplyMessage
import okhttp3.Headers import okhttp3.Headers
class Session(val authHeader: String?, 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.BuildConfig
import info.nightscout.androidaps.plugins.general.tidepool.messages.AuthReplyMessage import info.nightscout.androidaps.plugins.sync.tidepool.messages.AuthReplyMessage
import info.nightscout.androidaps.plugins.general.tidepool.messages.DatasetReplyMessage import info.nightscout.androidaps.plugins.sync.tidepool.messages.DatasetReplyMessage
import info.nightscout.androidaps.plugins.general.tidepool.messages.UploadReplyMessage import info.nightscout.androidaps.plugins.sync.tidepool.messages.UploadReplyMessage
import okhttp3.RequestBody import okhttp3.RequestBody
import retrofit2.Call import retrofit2.Call
import retrofit2.http.* 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.bus.RxBus
import info.nightscout.rx.logging.AAPSLogger import info.nightscout.rx.logging.AAPSLogger
import info.nightscout.rx.logging.LTag import info.nightscout.rx.logging.LTag
@ -8,7 +8,8 @@ import retrofit2.Call
import retrofit2.Callback import retrofit2.Callback
import retrofit2.Response 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>) { override fun onResponse(call: Call<T>, response: Response<T>) {
if (response.isSuccessful && response.body() != null) { 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.content.Context
import android.os.PowerManager import android.os.PowerManager
@ -7,12 +7,12 @@ import info.nightscout.androidaps.BuildConfig
import info.nightscout.androidaps.R import info.nightscout.androidaps.R
import info.nightscout.androidaps.interfaces.ActivePlugin import info.nightscout.androidaps.interfaces.ActivePlugin
import info.nightscout.androidaps.interfaces.ResourceHelper import info.nightscout.androidaps.interfaces.ResourceHelper
import info.nightscout.androidaps.plugins.general.tidepool.events.EventTidepoolStatus import info.nightscout.androidaps.plugins.sync.tidepool.events.EventTidepoolStatus
import info.nightscout.androidaps.plugins.general.tidepool.messages.AuthReplyMessage import info.nightscout.androidaps.plugins.sync.tidepool.messages.AuthReplyMessage
import info.nightscout.androidaps.plugins.general.tidepool.messages.AuthRequestMessage import info.nightscout.androidaps.plugins.sync.tidepool.messages.AuthRequestMessage
import info.nightscout.androidaps.plugins.general.tidepool.messages.DatasetReplyMessage import info.nightscout.androidaps.plugins.sync.tidepool.messages.DatasetReplyMessage
import info.nightscout.androidaps.plugins.general.tidepool.messages.OpenDatasetRequestMessage import info.nightscout.androidaps.plugins.sync.tidepool.messages.OpenDatasetRequestMessage
import info.nightscout.androidaps.plugins.general.tidepool.messages.UploadReplyMessage import info.nightscout.androidaps.plugins.sync.tidepool.messages.UploadReplyMessage
import info.nightscout.androidaps.utils.DateUtil import info.nightscout.androidaps.utils.DateUtil
import info.nightscout.androidaps.utils.T import info.nightscout.androidaps.utils.T
import info.nightscout.androidaps.utils.alertDialogs.OKDialog import info.nightscout.androidaps.utils.alertDialogs.OKDialog
@ -111,9 +111,9 @@ class TidepoolUploader @Inject constructor(
call?.enqueue(TidepoolCallback<AuthReplyMessage>(aapsLogger, rxBus, session!!, "Login", { call?.enqueue(TidepoolCallback<AuthReplyMessage>(aapsLogger, rxBus, session!!, "Login", {
startSession(session!!, doUpload) startSession(session!!, doUpload)
}, { }, {
connectionStatus = ConnectionStatus.FAILED connectionStatus = ConnectionStatus.FAILED
releaseWakeLock() releaseWakeLock()
})) }))
return return
} else { } else {
aapsLogger.debug(LTag.TIDEPOOL, "Cannot do login as user credentials have not been set correctly") 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", { 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), "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") ?: 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) extendWakeLock(30000)
if (session.authReply?.userid != null) { if (session.authReply?.userid != null) {
// See if we already have an open data set to write to // See if we already have an open data set to write to
val datasetCall = session.service!!.getOpenDataSets(session.token!!, val datasetCall = session.service!!.getOpenDataSets(
session.authReply!!.userid!!, BuildConfig.APPLICATION_ID, 1) session.token!!,
session.authReply!!.userid!!, BuildConfig.APPLICATION_ID, 1
)
datasetCall.enqueue(TidepoolCallback<List<DatasetReplyMessage>>(aapsLogger, rxBus, session, "Get Open Datasets", { datasetCall.enqueue(TidepoolCallback<List<DatasetReplyMessage>>(aapsLogger, rxBus, session, "Get Open Datasets", {
if (session.datasetReply == null) { if (session.datasetReply == null) {
rxBus.send(EventTidepoolStatus(("Creating new dataset"))) rxBus.send(EventTidepoolStatus(("Creating new dataset")))
val call = session.service.openDataSet(session.token!!, session.authReply!!.userid!!, val call = session.service.openDataSet(
OpenDatasetRequestMessage(activePlugin.activePump.serialNumber(), dateUtil).getBody()) session.token!!, session.authReply!!.userid!!,
OpenDatasetRequestMessage(activePlugin.activePump.serialNumber(), dateUtil).getBody()
)
call.enqueue(TidepoolCallback<DatasetReplyMessage>(aapsLogger, rxBus, session, "Open New Dataset", { call.enqueue(TidepoolCallback<DatasetReplyMessage>(aapsLogger, rxBus, session, "Open New Dataset", {
connectionStatus = ConnectionStatus.CONNECTED connectionStatus = ConnectionStatus.CONNECTED
rxBus.send(EventTidepoolStatus(("New dataset OK"))) rxBus.send(EventTidepoolStatus(("New dataset OK")))
@ -159,10 +167,10 @@ class TidepoolUploader @Inject constructor(
else else
releaseWakeLock() releaseWakeLock()
}, { }, {
rxBus.send(EventTidepoolStatus(("New dataset FAILED"))) rxBus.send(EventTidepoolStatus(("New dataset FAILED")))
connectionStatus = ConnectionStatus.FAILED connectionStatus = ConnectionStatus.FAILED
releaseWakeLock() releaseWakeLock()
})) }))
} else { } else {
aapsLogger.debug(LTag.TIDEPOOL, "Existing Dataset: " + session.datasetReply!!.getUploadId()) 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`. // 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() releaseWakeLock()
} }
}, { }, {
connectionStatus = ConnectionStatus.FAILED connectionStatus = ConnectionStatus.FAILED
rxBus.send(EventTidepoolStatus(("Open dataset FAILED"))) rxBus.send(EventTidepoolStatus(("Open dataset FAILED")))
releaseWakeLock() releaseWakeLock()
})) }))
} else { } else {
aapsLogger.error("Got login response but cannot determine userId - cannot proceed") aapsLogger.error("Got login response but cannot determine userId - cannot proceed")
connectionStatus = ConnectionStatus.FAILED connectionStatus = ConnectionStatus.FAILED
@ -222,9 +230,9 @@ class TidepoolUploader @Inject constructor(
releaseWakeLock() releaseWakeLock()
uploadNext() uploadNext()
}, { }, {
rxBus.send(EventTidepoolStatus(("Upload FAILED"))) rxBus.send(EventTidepoolStatus(("Upload FAILED")))
releaseWakeLock() releaseWakeLock()
})) }))
} }
} }
} }
@ -248,10 +256,10 @@ class TidepoolUploader @Inject constructor(
rxBus.send(EventTidepoolStatus(("Dataset removed OK"))) rxBus.send(EventTidepoolStatus(("Dataset removed OK")))
releaseWakeLock() releaseWakeLock()
}, { }, {
connectionStatus = ConnectionStatus.DISCONNECTED connectionStatus = ConnectionStatus.DISCONNECTED
rxBus.send(EventTidepoolStatus(("Dataset remove FAILED"))) rxBus.send(EventTidepoolStatus(("Dataset remove FAILED")))
releaseWakeLock() releaseWakeLock()
})) }))
} else { } else {
aapsLogger.error("Got login response but cannot determine datasetId - cannot proceed") 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"))) rxBus.send(EventTidepoolStatus(("All data removed OK")))
releaseWakeLock() releaseWakeLock()
}, { }, {
connectionStatus = ConnectionStatus.DISCONNECTED connectionStatus = ConnectionStatus.DISCONNECTED
rxBus.send(EventTidepoolStatus(("All data remove FAILED"))) rxBus.send(EventTidepoolStatus(("All data remove FAILED")))
releaseWakeLock() releaseWakeLock()
})) }))
} catch (e: IllegalArgumentException) { } catch (e: IllegalArgumentException) {
aapsLogger.error("Got login response but cannot determine userId - cannot proceed") 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.R
import info.nightscout.androidaps.database.AppRepository 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.database.entities.TemporaryBasal
import info.nightscout.androidaps.interfaces.ActivePlugin import info.nightscout.androidaps.interfaces.ActivePlugin
import info.nightscout.androidaps.interfaces.ProfileFunction import info.nightscout.androidaps.interfaces.ProfileFunction
import info.nightscout.androidaps.plugins.general.tidepool.elements.BasalElement import info.nightscout.androidaps.plugins.sync.tidepool.elements.BasalElement
import info.nightscout.androidaps.plugins.general.tidepool.elements.BaseElement import info.nightscout.androidaps.plugins.sync.tidepool.elements.BaseElement
import info.nightscout.androidaps.plugins.general.tidepool.elements.BloodGlucoseElement import info.nightscout.androidaps.plugins.sync.tidepool.elements.BloodGlucoseElement
import info.nightscout.androidaps.plugins.general.tidepool.elements.BolusElement import info.nightscout.androidaps.plugins.sync.tidepool.elements.BolusElement
import info.nightscout.androidaps.plugins.general.tidepool.elements.ProfileElement import info.nightscout.androidaps.plugins.sync.tidepool.elements.ProfileElement
import info.nightscout.androidaps.plugins.general.tidepool.elements.SensorGlucoseElement import info.nightscout.androidaps.plugins.sync.tidepool.elements.SensorGlucoseElement
import info.nightscout.androidaps.plugins.general.tidepool.elements.WizardElement import info.nightscout.androidaps.plugins.sync.tidepool.elements.WizardElement
import info.nightscout.androidaps.plugins.general.tidepool.events.EventTidepoolStatus import info.nightscout.androidaps.plugins.sync.tidepool.events.EventTidepoolStatus
import info.nightscout.androidaps.plugins.general.tidepool.utils.GsonInstance import info.nightscout.androidaps.plugins.sync.tidepool.utils.GsonInstance
import info.nightscout.androidaps.utils.DateUtil import info.nightscout.androidaps.utils.DateUtil
import info.nightscout.androidaps.utils.T import info.nightscout.androidaps.utils.T
import info.nightscout.rx.bus.RxBus 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 com.google.gson.annotations.Expose
import info.nightscout.androidaps.interfaces.Profile 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 com.google.gson.annotations.Expose
import info.nightscout.androidaps.utils.DateUtil 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 com.google.gson.annotations.Expose
import info.nightscout.androidaps.interfaces.Profile import info.nightscout.androidaps.interfaces.Profile
import info.nightscout.androidaps.database.entities.TherapyEvent 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 info.nightscout.androidaps.utils.DateUtil
import java.util.* 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 com.google.gson.annotations.Expose
import info.nightscout.androidaps.database.entities.Bolus 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 com.google.gson.annotations.Expose
import info.nightscout.androidaps.data.ProfileSealed import info.nightscout.androidaps.data.ProfileSealed
import info.nightscout.androidaps.database.entities.EffectiveProfileSwitch import info.nightscout.androidaps.database.entities.EffectiveProfileSwitch
import info.nightscout.androidaps.interfaces.Profile 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 info.nightscout.androidaps.utils.DateUtil
import java.util.* import java.util.*
import kotlin.collections.ArrayList
class ProfileElement(ps: EffectiveProfileSwitch, serialNumber: String, dateUtil: DateUtil) class ProfileElement(ps: EffectiveProfileSwitch, serialNumber: String, dateUtil: DateUtil)
: BaseElement(ps.timestamp, UUID.nameUUIDFromBytes(("AAPS-profile" + ps.timestamp).toByteArray()).toString(), 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 com.google.gson.annotations.Expose
import info.nightscout.androidaps.database.entities.GlucoseValue 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 com.google.gson.annotations.Expose
import info.nightscout.androidaps.database.entities.Bolus 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 info.nightscout.rx.events.Event
import java.text.SimpleDateFormat import java.text.SimpleDateFormat

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