From 7cafeae1c64c9436401964b4e2e2636b63d276c1 Mon Sep 17 00:00:00 2001 From: Milos Kozak Date: Fri, 20 Jan 2023 10:41:42 +0100 Subject: [PATCH 1/8] NS 15 support --- plugins/sync/build.gradle | 5 +---- .../sync/nsclient/services/NSClientService.kt | 22 +++++-------------- 2 files changed, 6 insertions(+), 21 deletions(-) diff --git a/plugins/sync/build.gradle b/plugins/sync/build.gradle index 2cbb59d236..1194a86950 100644 --- a/plugins/sync/build.gradle +++ b/plugins/sync/build.gradle @@ -32,10 +32,7 @@ dependencies { testImplementation project(':plugins:aps') // NSClient, Tidepool - api("io.socket:socket.io-client:1.0.2") { - // excluding org.json which is provided by Android - exclude group: "org.json", module: "json" - } + api("io.socket:socket.io-client:2.1.0") api "com.squareup.okhttp3:okhttp:$okhttp3_version" api "com.squareup.okhttp3:logging-interceptor:$okhttp3_version" //api "com.squareup.retrofit2:retrofit:$retrofit2_version" diff --git a/plugins/sync/src/main/java/info/nightscout/plugins/sync/nsclient/services/NSClientService.kt b/plugins/sync/src/main/java/info/nightscout/plugins/sync/nsclient/services/NSClientService.kt index e4a5df6141..24aeeaec0b 100644 --- a/plugins/sync/src/main/java/info/nightscout/plugins/sync/nsclient/services/NSClientService.kt +++ b/plugins/sync/src/main/java/info/nightscout/plugins/sync/nsclient/services/NSClientService.kt @@ -49,6 +49,7 @@ import info.nightscout.rx.events.EventConfigBuilderChange import info.nightscout.rx.events.EventDismissNotification import info.nightscout.rx.events.EventNSClientNewLog import info.nightscout.rx.events.EventNSClientRestart +import info.nightscout.rx.events.EventNewHistoryData import info.nightscout.rx.events.EventPreferenceChange import info.nightscout.rx.logging.AAPSLogger import info.nightscout.rx.logging.LTag @@ -165,6 +166,10 @@ class NSClientService : DaggerService() { .toObservable(NSAuthAck::class.java) .observeOn(aapsSchedulers.io) .subscribe({ ack -> processAuthAck(ack) }, fabricPrivacy::logException) + disposable += rxBus + .toObservable(EventNewHistoryData::class.java) + .observeOn(aapsSchedulers.io) + .subscribe({ resend("NEW_DATA") }, fabricPrivacy::logException) } override fun onDestroy() { @@ -231,10 +236,6 @@ class NSClientService : DaggerService() { socket = IO.socket(nsURL, opt).also { socket -> socket.on(Socket.EVENT_CONNECT, onConnect) socket.on(Socket.EVENT_DISCONNECT, onDisconnect) - socket.on(Socket.EVENT_ERROR, onError) - socket.on(Socket.EVENT_CONNECT_ERROR, onError) - socket.on(Socket.EVENT_CONNECT_TIMEOUT, onError) - socket.on(Socket.EVENT_PING, onPing) rxBus.send(EventNSClientNewLog("NSCLIENT", "do connect")) socket.connect() socket.on("dataUpdate", onDataUpdate) @@ -300,7 +301,6 @@ class NSClientService : DaggerService() { @Synchronized fun destroy() { socket?.off(Socket.EVENT_CONNECT) socket?.off(Socket.EVENT_DISCONNECT) - socket?.off(Socket.EVENT_PING) socket?.off("dataUpdate") socket?.off("announcement") socket?.off("alarm") @@ -336,18 +336,6 @@ class NSClientService : DaggerService() { nsDevice = sp.getString("careportal_enteredby", "") } - private val onError = Emitter.Listener { args -> - var msg = "Unknown Error" - if (args.isNotEmpty() && args[0] != null) { - msg = args[0].toString() - } - rxBus.send(EventNSClientNewLog("ERROR", msg)) - } - private val onPing = Emitter.Listener { - rxBus.send(EventNSClientNewLog("PING", "received")) - // send data if there is something waiting - resend("Ping received") - } private val onAnnouncement = Emitter.Listener { args -> /* From aa9684f621dba47691d3ea8c10877756ce9b245b Mon Sep 17 00:00:00 2001 From: Milos Kozak Date: Fri, 20 Jan 2023 17:06:38 +0100 Subject: [PATCH 2/8] set min supported NS to 15.0.0 --- .../info/nightscout/androidaps/implementations/ConfigImpl.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/info/nightscout/androidaps/implementations/ConfigImpl.kt b/app/src/main/java/info/nightscout/androidaps/implementations/ConfigImpl.kt index b3354a1aeb..5c5a09f6a2 100644 --- a/app/src/main/java/info/nightscout/androidaps/implementations/ConfigImpl.kt +++ b/app/src/main/java/info/nightscout/androidaps/implementations/ConfigImpl.kt @@ -15,7 +15,7 @@ class ConfigImpl @Inject constructor( fileListProvider: PrefFileListProvider ) : Config { - override val SUPPORTED_NS_VERSION = 140206 // 14.2.6 + override val SUPPORTED_NS_VERSION = 150000 // 15.0.0 override val APS = BuildConfig.FLAVOR == "full" override val NSCLIENT = BuildConfig.FLAVOR == "aapsclient" || BuildConfig.FLAVOR == "aapsclient2" override val PUMPCONTROL = BuildConfig.FLAVOR == "pumpcontrol" From cef547861f1580a14d802fba92ccdfa8003d9022 Mon Sep 17 00:00:00 2001 From: Milos Kozak Date: Fri, 20 Jan 2023 17:13:06 +0100 Subject: [PATCH 3/8] NSCv3: track changed profile store --- .../info/nightscout/plugins/sync/nsclientV3/NSClientV3Plugin.kt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/plugins/sync/src/main/java/info/nightscout/plugins/sync/nsclientV3/NSClientV3Plugin.kt b/plugins/sync/src/main/java/info/nightscout/plugins/sync/nsclientV3/NSClientV3Plugin.kt index 4204f65c72..b319210a3e 100644 --- a/plugins/sync/src/main/java/info/nightscout/plugins/sync/nsclientV3/NSClientV3Plugin.kt +++ b/plugins/sync/src/main/java/info/nightscout/plugins/sync/nsclientV3/NSClientV3Plugin.kt @@ -178,6 +178,8 @@ class NSClientV3Plugin @Inject constructor( nsClientReceiverDelegate.onStatusEvent(ev) if (ev.isChanged(rh.gs(R.string.key_ns_client_token)) || ev.isChanged(rh.gs(info.nightscout.core.utils.R.string.key_nsclientinternal_url))) setClient() + if (ev.isChanged(rh.gs(info.nightscout.core.utils.R.string.key_local_profile_last_change))) + delayAndScheduleExecution("PROFILE_CHANGE") }, fabricPrivacy::logException) disposable += rxBus .toObservable(EventAppExit::class.java) From 89ad9e21dd8c59d94553a3376367945bf854770a Mon Sep 17 00:00:00 2001 From: Milos Kozak Date: Mon, 23 Jan 2023 23:50:32 +0100 Subject: [PATCH 4/8] NSCv3: websockets support --- .../sdk/mapper/DeviceStatusMapper.kt | 4 + .../info/nightscout/sdk/mapper/FoodMapper.kt | 4 + .../info/nightscout/sdk/mapper/SvgMapper.kt | 4 + .../nightscout/sdk/mapper/TreatmentMapper.kt | 4 + .../sdk/remotemodel/LastModified.kt | 11 + core/utils/src/main/res/values/keys.xml | 1 + .../configBuilder/RunningConfigurationImpl.kt | 2 +- .../nightscout/source/NSClientSourcePlugin.kt | 2 +- .../nightscout/plugins/sync/di/SyncModule.kt | 1 + .../DataSyncSelectorImplementation.kt | 2 +- .../plugins/sync/nsShared/NSClientFragment.kt | 4 +- .../sync/nsShared/StoreDataForDbImpl.kt | 27 +- .../EventNSConnectivityOptionChanged.kt | 5 + .../plugins/sync/nsclient/NSClientPlugin.kt | 21 +- .../sync/nsclient/NsClientReceiverDelegate.kt | 51 +- .../sync/nsclient/services/NSClientService.kt | 19 +- .../sync/nsclientV3/NSClientV3Plugin.kt | 527 ++++++++++++++---- .../sync/nsclientV3/workers/DataSyncWorker.kt | 12 +- .../sync/nsclientV3/workers/LoadBgWorker.kt | 8 +- .../workers/LoadDeviceStatusWorker.kt | 11 +- .../nsclientV3/workers/LoadFoodsWorker.kt | 6 +- .../workers/LoadLastModificationWorker.kt | 2 +- .../workers/LoadProfileStoreWorker.kt | 8 +- .../nsclientV3/workers/LoadStatusWorker.kt | 2 +- .../workers/LoadTreatmentsWorker.kt | 25 +- .../nsclientV3/workers/ProcessFoodWorker.kt | 2 +- .../workers/ProcessTreatmentsWorker.kt | 7 +- plugins/sync/src/main/res/values/strings.xml | 4 +- .../src/main/res/xml/pref_ns_client_v3.xml | 10 +- 29 files changed, 576 insertions(+), 210 deletions(-) create mode 100644 plugins/sync/src/main/java/info/nightscout/plugins/sync/nsShared/events/EventNSConnectivityOptionChanged.kt diff --git a/core/ns-sdk/src/main/java/info/nightscout/sdk/mapper/DeviceStatusMapper.kt b/core/ns-sdk/src/main/java/info/nightscout/sdk/mapper/DeviceStatusMapper.kt index e2ca241a48..2b4334183f 100644 --- a/core/ns-sdk/src/main/java/info/nightscout/sdk/mapper/DeviceStatusMapper.kt +++ b/core/ns-sdk/src/main/java/info/nightscout/sdk/mapper/DeviceStatusMapper.kt @@ -1,5 +1,6 @@ package info.nightscout.sdk.mapper +import com.google.gson.Gson import com.google.gson.JsonParser import info.nightscout.sdk.localmodel.devicestatus.NSDeviceStatus import info.nightscout.sdk.remotemodel.RemoteDeviceStatus @@ -8,6 +9,9 @@ import org.json.JSONObject fun NSDeviceStatus.convertToRemoteAndBack(): NSDeviceStatus = toRemoteDeviceStatus().toNSDeviceStatus() +fun String.toNSDeviceStatus(): NSDeviceStatus = + Gson().fromJson(this, RemoteDeviceStatus::class.java).toNSDeviceStatus() + internal fun RemoteDeviceStatus.toNSDeviceStatus(): NSDeviceStatus = NSDeviceStatus( app = app, diff --git a/core/ns-sdk/src/main/java/info/nightscout/sdk/mapper/FoodMapper.kt b/core/ns-sdk/src/main/java/info/nightscout/sdk/mapper/FoodMapper.kt index 15bb3978c9..49ebe6456c 100644 --- a/core/ns-sdk/src/main/java/info/nightscout/sdk/mapper/FoodMapper.kt +++ b/core/ns-sdk/src/main/java/info/nightscout/sdk/mapper/FoodMapper.kt @@ -1,5 +1,6 @@ package info.nightscout.sdk.mapper +import com.google.gson.Gson import info.nightscout.sdk.localmodel.food.NSFood import info.nightscout.sdk.remotemodel.RemoteFood @@ -12,6 +13,9 @@ import info.nightscout.sdk.remotemodel.RemoteFood fun NSFood.convertToRemoteAndBack(): NSFood? = toRemoteFood().toNSFood() +fun String.toNSFood(): NSFood? = + Gson().fromJson(this, RemoteFood::class.java).toNSFood() + internal fun RemoteFood.toNSFood(): NSFood? { when (type) { "food" -> diff --git a/core/ns-sdk/src/main/java/info/nightscout/sdk/mapper/SvgMapper.kt b/core/ns-sdk/src/main/java/info/nightscout/sdk/mapper/SvgMapper.kt index b37a600a86..bc08e4e6f2 100644 --- a/core/ns-sdk/src/main/java/info/nightscout/sdk/mapper/SvgMapper.kt +++ b/core/ns-sdk/src/main/java/info/nightscout/sdk/mapper/SvgMapper.kt @@ -1,5 +1,6 @@ package info.nightscout.sdk.mapper +import com.google.gson.Gson import info.nightscout.sdk.localmodel.entry.Direction import info.nightscout.sdk.localmodel.entry.NSSgvV3 import info.nightscout.sdk.localmodel.entry.NsUnits @@ -8,6 +9,9 @@ import info.nightscout.sdk.remotemodel.RemoteEntry fun NSSgvV3.convertToRemoteAndBack(): NSSgvV3? = toRemoteEntry().toSgv() +fun String.toNSSgvV3(): NSSgvV3? = + Gson().fromJson(this, RemoteEntry::class.java).toSgv() + internal fun RemoteEntry.toSgv(): NSSgvV3? { this.sgv ?: return null diff --git a/core/ns-sdk/src/main/java/info/nightscout/sdk/mapper/TreatmentMapper.kt b/core/ns-sdk/src/main/java/info/nightscout/sdk/mapper/TreatmentMapper.kt index 2dbd17f74b..64a500aa81 100644 --- a/core/ns-sdk/src/main/java/info/nightscout/sdk/mapper/TreatmentMapper.kt +++ b/core/ns-sdk/src/main/java/info/nightscout/sdk/mapper/TreatmentMapper.kt @@ -1,5 +1,6 @@ package info.nightscout.sdk.mapper +import com.google.gson.Gson import info.nightscout.sdk.localmodel.entry.NsUnits import info.nightscout.sdk.localmodel.treatment.EventType import info.nightscout.sdk.localmodel.treatment.NSBolus @@ -26,6 +27,9 @@ import java.util.concurrent.TimeUnit fun NSTreatment.convertToRemoteAndBack(): NSTreatment? = toRemoteTreatment()?.toTreatment() +fun String.toNSTreatment(): NSTreatment? = + Gson().fromJson(this, RemoteTreatment::class.java).toTreatment() + internal fun RemoteTreatment.toTreatment(): NSTreatment? { val treatmentTimestamp = timestamp() when { diff --git a/core/ns-sdk/src/main/java/info/nightscout/sdk/remotemodel/LastModified.kt b/core/ns-sdk/src/main/java/info/nightscout/sdk/remotemodel/LastModified.kt index 2a9716adc6..4d48a5f46d 100644 --- a/core/ns-sdk/src/main/java/info/nightscout/sdk/remotemodel/LastModified.kt +++ b/core/ns-sdk/src/main/java/info/nightscout/sdk/remotemodel/LastModified.kt @@ -22,4 +22,15 @@ data class LastModified( @SerializedName("foods") var foods: Long = 0, // foods collection @SerializedName("settings") var settings: Long = 0 // settings collection ) + + fun set(colName: String, value: Long) { + when (colName) { + "devicestatus" -> collections.devicestatus = value + "entries" -> collections.entries = value + "profile" -> collections.profile = value + "treatments" -> collections.treatments = value + "foods" -> collections.foods = value + "settings" -> collections.settings = value + } + } } diff --git a/core/utils/src/main/res/values/keys.xml b/core/utils/src/main/res/values/keys.xml index 8377c4b5d7..2ea8eb2c02 100644 --- a/core/utils/src/main/res/values/keys.xml +++ b/core/utils/src/main/res/values/keys.xml @@ -85,6 +85,7 @@ ns_receive_profile_store nsclientinternal_url nsclientinternal_api_secret + ns_use_ws ns_receive_insulin ns_receive_carbs ns_receive_therapy_events diff --git a/plugins/configuration/src/main/java/info/nightscout/configuration/configBuilder/RunningConfigurationImpl.kt b/plugins/configuration/src/main/java/info/nightscout/configuration/configBuilder/RunningConfigurationImpl.kt index 81643a8d2d..1696e5c6a0 100644 --- a/plugins/configuration/src/main/java/info/nightscout/configuration/configBuilder/RunningConfigurationImpl.kt +++ b/plugins/configuration/src/main/java/info/nightscout/configuration/configBuilder/RunningConfigurationImpl.kt @@ -75,7 +75,7 @@ class RunningConfigurationImpl @Inject constructor( assert(config.NSCLIENT) configuration.version?.let { - rxBus.send(EventNSClientNewLog("VERSION", "Received AAPS version $it")) + rxBus.send(EventNSClientNewLog("◄ VERSION", "Received AAPS version $it")) if (config.VERSION_NAME.startsWith(it).not()) uiInteraction.addNotification(Notification.NSCLIENT_VERSION_DOES_NOT_MATCH, rh.gs(R.string.nsclient_version_does_not_match), Notification.NORMAL) } diff --git a/plugins/source/src/main/java/info/nightscout/source/NSClientSourcePlugin.kt b/plugins/source/src/main/java/info/nightscout/source/NSClientSourcePlugin.kt index 9863eff071..b5ccfe6387 100644 --- a/plugins/source/src/main/java/info/nightscout/source/NSClientSourcePlugin.kt +++ b/plugins/source/src/main/java/info/nightscout/source/NSClientSourcePlugin.kt @@ -116,7 +116,7 @@ class NSClientSourcePlugin @Inject constructor( return TransactionGlucoseValue( timestamp = sgv.date ?: throw InvalidParameterException(), value = sgv.sgv, - noise = sgv.noise?.toDouble(), + noise = sgv.noise, raw = sgv.filtered, trendArrow = GlucoseValue.TrendArrow.fromString(sgv.direction?.nsName), nightscoutId = sgv.identifier, diff --git a/plugins/sync/src/main/java/info/nightscout/plugins/sync/di/SyncModule.kt b/plugins/sync/src/main/java/info/nightscout/plugins/sync/di/SyncModule.kt index 731d4b729a..f1ef1bece4 100644 --- a/plugins/sync/src/main/java/info/nightscout/plugins/sync/di/SyncModule.kt +++ b/plugins/sync/src/main/java/info/nightscout/plugins/sync/di/SyncModule.kt @@ -60,6 +60,7 @@ abstract class SyncModule { @ContributesAndroidInjector abstract fun contributesLoadProfileStoreWorker(): LoadProfileStoreWorker @ContributesAndroidInjector abstract fun contributesStoreBgWorker(): StoreDataForDbImpl.StoreBgWorker @ContributesAndroidInjector abstract fun contributesStoreFoodWorker(): StoreDataForDbImpl.StoreFoodWorker + @ContributesAndroidInjector abstract fun contributesStoreTreatmentsWorker(): StoreDataForDbImpl.StoreTreatmentsWorker @ContributesAndroidInjector abstract fun contributesTreatmentWorker(): LoadTreatmentsWorker @ContributesAndroidInjector abstract fun contributesProcessTreatmentsWorker(): ProcessTreatmentsWorker @ContributesAndroidInjector abstract fun contributesLoadDeviceStatusWorker(): LoadDeviceStatusWorker diff --git a/plugins/sync/src/main/java/info/nightscout/plugins/sync/nsShared/DataSyncSelectorImplementation.kt b/plugins/sync/src/main/java/info/nightscout/plugins/sync/nsShared/DataSyncSelectorImplementation.kt index 60562c323c..91ec86fca5 100644 --- a/plugins/sync/src/main/java/info/nightscout/plugins/sync/nsShared/DataSyncSelectorImplementation.kt +++ b/plugins/sync/src/main/java/info/nightscout/plugins/sync/nsShared/DataSyncSelectorImplementation.kt @@ -57,7 +57,7 @@ class DataSyncSelectorImplementation @Inject constructor( } private val queueCounter = QueueCounter() - private val isPaused get() = sp.getBoolean(R.string.key_ns_client_paused, false) + private val isPaused get() = sp.getBoolean(R.string.key_ns_paused, false) override fun queueSize(): Long = queueCounter.size() diff --git a/plugins/sync/src/main/java/info/nightscout/plugins/sync/nsShared/NSClientFragment.kt b/plugins/sync/src/main/java/info/nightscout/plugins/sync/nsShared/NSClientFragment.kt index b3736b070e..ecd92f2270 100644 --- a/plugins/sync/src/main/java/info/nightscout/plugins/sync/nsShared/NSClientFragment.kt +++ b/plugins/sync/src/main/java/info/nightscout/plugins/sync/nsShared/NSClientFragment.kt @@ -81,7 +81,7 @@ class NSClientFragment : DaggerFragment(), MenuProvider, PluginFragment { updateGui() } - binding.paused.isChecked = sp.getBoolean(R.string.key_ns_client_paused, false) + binding.paused.isChecked = sp.getBoolean(R.string.key_ns_paused, false) binding.paused.setOnCheckedChangeListener { _, isChecked -> uel.log(if (isChecked) UserEntry.Action.NS_PAUSED else UserEntry.Action.NS_RESUME, UserEntry.Sources.NSClient) nsClientPlugin?.pause(isChecked) @@ -143,7 +143,7 @@ class NSClientFragment : DaggerFragment(), MenuProvider, PluginFragment { private fun updateGui() { if (_binding == null) return - binding.paused.isChecked = sp.getBoolean(R.string.key_ns_client_paused, false) + binding.paused.isChecked = sp.getBoolean(R.string.key_ns_paused, false) binding.log.text = nsClientPlugin?.textLog() if (sp.getBoolean(R.string.key_ns_client_autoscroll, true)) binding.logScrollview.fullScroll(ScrollView.FOCUS_DOWN) binding.url.text = nsClientPlugin?.address diff --git a/plugins/sync/src/main/java/info/nightscout/plugins/sync/nsShared/StoreDataForDbImpl.kt b/plugins/sync/src/main/java/info/nightscout/plugins/sync/nsShared/StoreDataForDbImpl.kt index 445c934835..e47281cd5e 100644 --- a/plugins/sync/src/main/java/info/nightscout/plugins/sync/nsShared/StoreDataForDbImpl.kt +++ b/plugins/sync/src/main/java/info/nightscout/plugins/sync/nsShared/StoreDataForDbImpl.kt @@ -147,13 +147,24 @@ class StoreDataForDbImpl @Inject constructor( } } + class StoreTreatmentsWorker( + context: Context, + params: WorkerParameters + ) : LoggingWorker(context, params, Dispatchers.Default) { + + @Inject lateinit var storeDataForDb: StoreDataForDb + + override suspend fun doWorkAndLog(): Result { + storeDataForDb.storeTreatmentsToDb() + return Result.success() + } + } + fun HashMap.inc(key: T) = if (containsKey(key)) merge(key, 1, Long::plus) else put(key, 1) override fun storeGlucoseValuesToDb() { - rxBus.send(EventNSClientNewLog("PROCESSING BG", "")) - if (glucoseValues.isNotEmpty()) repository.runTransactionForResult(CgmSourceTransaction(glucoseValues, emptyList(), null)) .doOnError { @@ -184,12 +195,10 @@ class StoreDataForDbImpl @Inject constructor( sendLog("GlucoseValue", GlucoseValue::class.java.simpleName) SystemClock.sleep(pause) - rxBus.send(EventNSClientNewLog("DONE BG", "")) + rxBus.send(EventNSClientNewLog("● DONE PROCESSING BG", "")) } override fun storeFoodsToDb() { - rxBus.send(EventNSClientNewLog("PROCESSING FOOD", "")) - if (foods.isNotEmpty()) repository.runTransactionForResult(SyncNsFoodTransaction(foods)) .doOnError { @@ -214,12 +223,10 @@ class StoreDataForDbImpl @Inject constructor( sendLog("Food", Food::class.java.simpleName) SystemClock.sleep(pause) - rxBus.send(EventNSClientNewLog("DONE FOOD", "")) + rxBus.send(EventNSClientNewLog("● DONE PROCESSING FOOD", "")) } override fun storeTreatmentsToDb() { - rxBus.send(EventNSClientNewLog("PROCESSING TR", "")) - if (boluses.isNotEmpty()) repository.runTransactionForResult(SyncNsBolusTransaction(boluses)) .doOnError { @@ -796,7 +803,7 @@ class StoreDataForDbImpl @Inject constructor( SystemClock.sleep(pause) uel.log(userEntries) - rxBus.send(EventNSClientNewLog("DONE TR", "")) + rxBus.send(EventNSClientNewLog("● DONE PROCESSING TR", "")) } private val eventWorker = Executors.newSingleThreadScheduledExecutor() @@ -996,7 +1003,7 @@ class StoreDataForDbImpl @Inject constructor( sendLog("TherapyEvent", TherapyEvent::class.java.simpleName) sendLog("OfflineEvent", OfflineEvent::class.java.simpleName) sendLog("ExtendedBolus", ExtendedBolus::class.java.simpleName) - rxBus.send(EventNSClientNewLog("DONE NSIDs", "")) + rxBus.send(EventNSClientNewLog("● DONE NSIDs", "")) } private fun sendLog(item: String, clazz: String) { diff --git a/plugins/sync/src/main/java/info/nightscout/plugins/sync/nsShared/events/EventNSConnectivityOptionChanged.kt b/plugins/sync/src/main/java/info/nightscout/plugins/sync/nsShared/events/EventNSConnectivityOptionChanged.kt new file mode 100644 index 0000000000..e5a50ba7d5 --- /dev/null +++ b/plugins/sync/src/main/java/info/nightscout/plugins/sync/nsShared/events/EventNSConnectivityOptionChanged.kt @@ -0,0 +1,5 @@ +package info.nightscout.plugins.sync.nsShared.events + +import info.nightscout.rx.events.Event + +class EventNSConnectivityOptionChanged(val blockingReason: String) : Event() \ No newline at end of file diff --git a/plugins/sync/src/main/java/info/nightscout/plugins/sync/nsclient/NSClientPlugin.kt b/plugins/sync/src/main/java/info/nightscout/plugins/sync/nsclient/NSClientPlugin.kt index 53ca1d3e73..7adc85cf6a 100644 --- a/plugins/sync/src/main/java/info/nightscout/plugins/sync/nsclient/NSClientPlugin.kt +++ b/plugins/sync/src/main/java/info/nightscout/plugins/sync/nsclient/NSClientPlugin.kt @@ -14,7 +14,6 @@ import androidx.preference.SwitchPreference import dagger.android.HasAndroidInjector import info.nightscout.core.extensions.toJson import info.nightscout.core.utils.fabric.FabricPrivacy -import info.nightscout.core.validators.ValidatingEditTextPreference import info.nightscout.interfaces.Config import info.nightscout.interfaces.Constants import info.nightscout.interfaces.nsclient.NSAlarm @@ -41,9 +40,7 @@ import info.nightscout.plugins.sync.nsclient.services.NSClientService import info.nightscout.rx.AapsSchedulers import info.nightscout.rx.bus.RxBus import info.nightscout.rx.events.EventAppExit -import info.nightscout.rx.events.EventChargingState import info.nightscout.rx.events.EventNSClientNewLog -import info.nightscout.rx.events.EventNetworkChange import info.nightscout.rx.events.EventPreferenceChange import info.nightscout.rx.events.EventSWSyncStatus import info.nightscout.rx.logging.AAPSLogger @@ -109,14 +106,6 @@ class NSClientPlugin @Inject constructor( // Pass to setup wizard rxBus.send(EventSWSyncStatus(event.getStatus(context))) }, 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) @@ -128,10 +117,6 @@ class NSClientPlugin @Inject constructor( 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) @@ -181,7 +166,7 @@ class NSClientPlugin @Inject constructor( } } - override fun detectedNsVersion(): String? = nsSettingsStatus.getVersion() + override fun detectedNsVersion(): String = nsSettingsStatus.getVersion() private fun addToLog(ev: EventNSClientNewLog) { synchronized(listLog) { @@ -212,8 +197,8 @@ class NSClientPlugin @Inject constructor( } override fun pause(newState: Boolean) { - sp.putBoolean(R.string.key_ns_client_paused, newState) - rxBus.send(EventPreferenceChange(rh.gs(R.string.key_ns_client_paused))) + sp.putBoolean(R.string.key_ns_paused, newState) + rxBus.send(EventPreferenceChange(rh.gs(R.string.key_ns_paused))) } override val address: String get() = nsClientService?.nsURL ?: "" diff --git a/plugins/sync/src/main/java/info/nightscout/plugins/sync/nsclient/NsClientReceiverDelegate.kt b/plugins/sync/src/main/java/info/nightscout/plugins/sync/nsclient/NsClientReceiverDelegate.kt index b515ee08ab..bae5c3fe4b 100644 --- a/plugins/sync/src/main/java/info/nightscout/plugins/sync/nsclient/NsClientReceiverDelegate.kt +++ b/plugins/sync/src/main/java/info/nightscout/plugins/sync/nsclient/NsClientReceiverDelegate.kt @@ -1,14 +1,19 @@ package info.nightscout.plugins.sync.nsclient import info.nightscout.androidaps.annotations.OpenForTesting +import info.nightscout.core.utils.fabric.FabricPrivacy import info.nightscout.interfaces.receivers.ReceiverStatusStore import info.nightscout.plugins.sync.R +import info.nightscout.plugins.sync.nsShared.events.EventNSConnectivityOptionChanged +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.events.EventPreferenceChange import info.nightscout.shared.interfaces.ResourceHelper import info.nightscout.shared.sharedPreferences.SP +import io.reactivex.rxjava3.disposables.CompositeDisposable +import io.reactivex.rxjava3.kotlin.plusAssign import javax.inject.Inject import javax.inject.Singleton @@ -18,26 +23,45 @@ class NsClientReceiverDelegate @Inject constructor( private val rxBus: RxBus, private val rh: ResourceHelper, private val sp: SP, - private val receiverStatusStore: ReceiverStatusStore + private val receiverStatusStore: ReceiverStatusStore, + aapsSchedulers: AapsSchedulers, + fabricPrivacy: FabricPrivacy ) { - private var allowedChargingState = true - private var allowedNetworkState = true - var allowed = true - var blockingReason = "" + private var allowedChargingState: Boolean? = null + private var allowedNetworkState: Boolean? = null + var allowed: Boolean = false + var blockingReason = "Status not available" + + private val disposable = CompositeDisposable() + + init { + disposable += rxBus + .toObservable(EventPreferenceChange::class.java) + .observeOn(aapsSchedulers.io) + .subscribe({ ev -> onPreferenceChange(ev) }, fabricPrivacy::logException) + disposable += rxBus + .toObservable(EventNetworkChange::class.java) + .observeOn(aapsSchedulers.io) + .subscribe({ ev -> onNetworkChange(ev) }, fabricPrivacy::logException) + disposable += rxBus + .toObservable(EventChargingState::class.java) + .observeOn(aapsSchedulers.io) + .subscribe({ ev -> onChargingStateChange(ev) }, fabricPrivacy::logException) + } fun grabReceiversState() { receiverStatusStore.updateNetworkStatus() } - fun onStatusEvent(ev: EventPreferenceChange) { + private fun onPreferenceChange(ev: EventPreferenceChange) { when { ev.isChanged(rh.gs(R.string.key_ns_wifi)) || ev.isChanged(rh.gs(R.string.key_ns_cellular)) || ev.isChanged(rh.gs(R.string.key_ns_wifi_ssids)) || ev.isChanged(rh.gs(R.string.key_ns_allow_roaming)) -> { receiverStatusStore.updateNetworkStatus() - receiverStatusStore.lastNetworkEvent?.let { onStatusEvent(it) } + receiverStatusStore.lastNetworkEvent?.let { onNetworkChange(it) } } ev.isChanged(rh.gs(R.string.key_ns_charging)) || @@ -47,29 +71,30 @@ class NsClientReceiverDelegate @Inject constructor( } } - fun onStatusEvent(ev: EventChargingState) { + private fun onChargingStateChange(ev: EventChargingState) { val newChargingState = calculateStatus(ev) if (newChargingState != allowedChargingState) { allowedChargingState = newChargingState - blockingReason = rh.gs(R.string.blocked_by_charging) + if (!newChargingState) blockingReason = rh.gs(R.string.blocked_by_charging) processStateChange() } } - fun onStatusEvent(ev: EventNetworkChange) { + private fun onNetworkChange(ev: EventNetworkChange) { val newNetworkState = calculateStatus(ev) if (newNetworkState != allowedNetworkState) { allowedNetworkState = newNetworkState - blockingReason = rh.gs(R.string.blocked_by_connectivity) + if (!newNetworkState) blockingReason = rh.gs(R.string.blocked_by_connectivity) processStateChange() } } private fun processStateChange() { - val newAllowedState = allowedChargingState && allowedNetworkState + val newAllowedState = allowedChargingState == true && allowedNetworkState == true if (newAllowedState != allowed) { allowed = newAllowedState - rxBus.send(EventPreferenceChange(rh.gs(R.string.key_ns_client_paused))) + if (allowed) blockingReason = "" + rxBus.send(EventNSConnectivityOptionChanged(blockingReason)) } } diff --git a/plugins/sync/src/main/java/info/nightscout/plugins/sync/nsclient/services/NSClientService.kt b/plugins/sync/src/main/java/info/nightscout/plugins/sync/nsclient/services/NSClientService.kt index 24aeeaec0b..affb7e1ab2 100644 --- a/plugins/sync/src/main/java/info/nightscout/plugins/sync/nsclient/services/NSClientService.kt +++ b/plugins/sync/src/main/java/info/nightscout/plugins/sync/nsclient/services/NSClientService.kt @@ -33,6 +33,7 @@ import info.nightscout.plugins.sync.R import info.nightscout.plugins.sync.nsShared.StoreDataForDbImpl import info.nightscout.plugins.sync.nsShared.events.EventNSClientStatus import info.nightscout.plugins.sync.nsShared.events.EventNSClientUpdateGUI +import info.nightscout.plugins.sync.nsShared.events.EventNSConnectivityOptionChanged import info.nightscout.plugins.sync.nsclient.NSClientPlugin import info.nightscout.plugins.sync.nsclient.acks.NSAddAck import info.nightscout.plugins.sync.nsclient.acks.NSAuthAck @@ -140,13 +141,21 @@ class NSClientService : DaggerService() { .subscribe({ event: EventPreferenceChange -> if (event.isChanged(rh.gs(info.nightscout.core.utils.R.string.key_nsclientinternal_url)) || event.isChanged(rh.gs(info.nightscout.core.utils.R.string.key_nsclientinternal_api_secret)) || - event.isChanged(rh.gs(R.string.key_ns_client_paused)) + event.isChanged(rh.gs(R.string.key_ns_paused)) ) { latestDateInReceivedData = 0 destroy() initialize() } }, fabricPrivacy::logException) + disposable += rxBus + .toObservable(EventNSConnectivityOptionChanged::class.java) + .observeOn(aapsSchedulers.io) + .subscribe({ + latestDateInReceivedData = 0 + destroy() + initialize() + }, fabricPrivacy::logException) disposable += rxBus .toObservable(EventAppExit::class.java) .observeOn(aapsSchedulers.io) @@ -218,10 +227,10 @@ class NSClientService : DaggerService() { @Suppress("DEPRECATION") if (nsAPISecret != "") nsApiHashCode = Hashing.sha1().hashString(nsAPISecret, Charsets.UTF_8).toString() rxBus.send(EventNSClientStatus("Initializing")) - if (!nsClientPlugin.isAllowed) { + if (nsClientPlugin.isAllowed != true) { rxBus.send(EventNSClientNewLog("NSCLIENT", nsClientPlugin.blockingReason)) rxBus.send(EventNSClientStatus(nsClientPlugin.blockingReason)) - } else if (sp.getBoolean(R.string.key_ns_client_paused, false)) { + } else if (sp.getBoolean(R.string.key_ns_paused, false)) { rxBus.send(EventNSClientNewLog("NSCLIENT", "paused")) rxBus.send(EventNSClientStatus("Paused")) } else if (!nsEnabled) { @@ -230,9 +239,7 @@ class NSClientService : DaggerService() { } else if (nsURL != "" && (nsURL.lowercase(Locale.getDefault()).startsWith("https://"))) { try { rxBus.send(EventNSClientStatus("Connecting ...")) - val opt = IO.Options() - opt.forceNew = true - opt.reconnection = true + val opt = IO.Options().also { it.forceNew = true } socket = IO.socket(nsURL, opt).also { socket -> socket.on(Socket.EVENT_CONNECT, onConnect) socket.on(Socket.EVENT_DISCONNECT, onDisconnect) diff --git a/plugins/sync/src/main/java/info/nightscout/plugins/sync/nsclientV3/NSClientV3Plugin.kt b/plugins/sync/src/main/java/info/nightscout/plugins/sync/nsclientV3/NSClientV3Plugin.kt index 894c2ad86a..b80cb08de1 100644 --- a/plugins/sync/src/main/java/info/nightscout/plugins/sync/nsclientV3/NSClientV3Plugin.kt +++ b/plugins/sync/src/main/java/info/nightscout/plugins/sync/nsclientV3/NSClientV3Plugin.kt @@ -3,6 +3,7 @@ package info.nightscout.plugins.sync.nsclientV3 import android.content.Context import android.os.Handler import android.os.HandlerThread +import android.os.SystemClock import android.text.Spanned import androidx.preference.PreferenceFragmentCompat import androidx.preference.PreferenceScreen @@ -16,26 +17,34 @@ import com.google.gson.GsonBuilder import dagger.android.HasAndroidInjector import info.nightscout.androidaps.annotations.OpenForTesting import info.nightscout.core.utils.fabric.FabricPrivacy +import info.nightscout.core.utils.receivers.DataWorkerStorage import info.nightscout.database.ValueWrapper import info.nightscout.database.entities.interfaces.TraceableDBEntry import info.nightscout.database.impl.AppRepository import info.nightscout.interfaces.Config import info.nightscout.interfaces.Constants +import info.nightscout.interfaces.notifications.Notification import info.nightscout.interfaces.nsclient.NSAlarm import info.nightscout.interfaces.plugin.PluginBase import info.nightscout.interfaces.plugin.PluginDescription import info.nightscout.interfaces.plugin.PluginType import info.nightscout.interfaces.profile.ProfileFunction +import info.nightscout.interfaces.source.NSClientSource import info.nightscout.interfaces.sync.DataSyncSelector import info.nightscout.interfaces.sync.NsClient import info.nightscout.interfaces.sync.Sync import info.nightscout.interfaces.ui.UiInteraction import info.nightscout.interfaces.utils.HtmlHelper +import info.nightscout.interfaces.utils.JsonHelper +import info.nightscout.interfaces.workflow.WorkerClasses import info.nightscout.plugins.sync.R import info.nightscout.plugins.sync.nsShared.NSClientFragment +import info.nightscout.plugins.sync.nsShared.StoreDataForDbImpl import info.nightscout.plugins.sync.nsShared.events.EventNSClientResend import info.nightscout.plugins.sync.nsShared.events.EventNSClientUpdateGUI +import info.nightscout.plugins.sync.nsShared.events.EventNSConnectivityOptionChanged import info.nightscout.plugins.sync.nsclient.NsClientReceiverDelegate +import info.nightscout.plugins.sync.nsclient.data.NSDeviceStatusHandler import info.nightscout.plugins.sync.nsclientV3.extensions.toNSBolus import info.nightscout.plugins.sync.nsclientV3.extensions.toNSBolusWizard import info.nightscout.plugins.sync.nsclientV3.extensions.toNSCarbs @@ -49,16 +58,17 @@ import info.nightscout.plugins.sync.nsclientV3.extensions.toNSSvgV3 import info.nightscout.plugins.sync.nsclientV3.extensions.toNSTemporaryBasal import info.nightscout.plugins.sync.nsclientV3.extensions.toNSTemporaryTarget import info.nightscout.plugins.sync.nsclientV3.extensions.toNSTherapyEvent +import info.nightscout.plugins.sync.nsclientV3.workers.DataSyncWorker import info.nightscout.plugins.sync.nsclientV3.workers.LoadBgWorker import info.nightscout.plugins.sync.nsclientV3.workers.LoadLastModificationWorker import info.nightscout.plugins.sync.nsclientV3.workers.LoadStatusWorker +import info.nightscout.plugins.sync.nsclientV3.workers.ProcessFoodWorker +import info.nightscout.plugins.sync.nsclientV3.workers.ProcessTreatmentsWorker import info.nightscout.rx.AapsSchedulers import info.nightscout.rx.bus.RxBus import info.nightscout.rx.events.EventAppExit -import info.nightscout.rx.events.EventChargingState +import info.nightscout.rx.events.EventDismissNotification import info.nightscout.rx.events.EventNSClientNewLog -import info.nightscout.rx.events.EventNetworkChange -import info.nightscout.rx.events.EventNewBG import info.nightscout.rx.events.EventNewHistoryData import info.nightscout.rx.events.EventPreferenceChange import info.nightscout.rx.events.EventSWSyncStatus @@ -66,6 +76,10 @@ 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.mapper.toNSDeviceStatus +import info.nightscout.sdk.mapper.toNSFood +import info.nightscout.sdk.mapper.toNSSgvV3 +import info.nightscout.sdk.mapper.toNSTreatment import info.nightscout.sdk.remotemodel.LastModified import info.nightscout.shared.interfaces.ResourceHelper import info.nightscout.shared.sharedPreferences.SP @@ -73,15 +87,19 @@ import info.nightscout.shared.utils.DateUtil import info.nightscout.shared.utils.T import io.reactivex.rxjava3.disposables.CompositeDisposable import io.reactivex.rxjava3.kotlin.plusAssign +import io.socket.client.Ack +import io.socket.client.IO +import io.socket.client.Socket +import io.socket.emitter.Emitter import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.SupervisorJob import kotlinx.coroutines.launch import kotlinx.serialization.decodeFromString import kotlinx.serialization.json.Json -import java.util.concurrent.Executors -import java.util.concurrent.ScheduledFuture -import java.util.concurrent.TimeUnit +import org.json.JSONArray +import org.json.JSONObject +import java.net.URISyntaxException import javax.inject.Inject import javax.inject.Singleton @@ -102,7 +120,12 @@ class NSClientV3Plugin @Inject constructor( private val uiInteraction: UiInteraction, private val dataSyncSelector: DataSyncSelector, private val profileFunction: ProfileFunction, - private val repository: AppRepository + private val repository: AppRepository, + private val nsDeviceStatusHandler: NSDeviceStatusHandler, + private val workManager: WorkManager, + private val workerClasses: WorkerClasses, + private val dataWorkerStorage: DataWorkerStorage, + private val nsClientSource: NSClientSource ) : NsClient, Sync, PluginBase( PluginDescription() .mainType(PluginType.SYNC) @@ -118,7 +141,6 @@ class NSClientV3Plugin @Inject constructor( companion object { val JOB_NAME: String = this::class.java.simpleName - val REFRESH_INTERVAL = T.secs(30).msecs() const val RECORDS_TO_LOAD = 500L } @@ -130,14 +152,16 @@ class NSClientV3Plugin @Inject constructor( override val status get() = when { - sp.getBoolean(R.string.key_ns_client_paused, false) -> rh.gs(info.nightscout.core.ui.R.string.paused) - isAllowed.not() -> blockingReason - lastOperationError != null -> rh.gs(info.nightscout.core.ui.R.string.error) - nsAndroidClient?.lastStatus == null -> rh.gs(R.string.not_connected) - workIsRunning(arrayOf(JOB_NAME)) -> rh.gs(R.string.working) - nsAndroidClient?.lastStatus?.apiPermissions?.isFull() == true -> rh.gs(info.nightscout.shared.R.string.connected) - nsAndroidClient?.lastStatus?.apiPermissions?.isRead() == true -> rh.gs(R.string.read_only) - else -> rh.gs(info.nightscout.core.ui.R.string.unknown) + sp.getBoolean(R.string.key_ns_paused, false) -> rh.gs(info.nightscout.core.ui.R.string.paused) + isAllowed.not() -> blockingReason + sp.getBoolean(info.nightscout.core.utils.R.string.key_ns_use_ws, true) && wsConnected -> "WS: " + rh.gs(info.nightscout.shared.R.string.connected) + sp.getBoolean(info.nightscout.core.utils.R.string.key_ns_use_ws, true) && !wsConnected -> "WS: " + rh.gs(R.string.not_connected) + lastOperationError != null -> rh.gs(info.nightscout.core.ui.R.string.error) + nsAndroidClient?.lastStatus == null -> rh.gs(R.string.not_connected) + workIsRunning(arrayOf(JOB_NAME)) -> rh.gs(R.string.working) + nsAndroidClient?.lastStatus?.apiPermissions?.isFull() == true -> rh.gs(info.nightscout.shared.R.string.connected) + nsAndroidClient?.lastStatus?.apiPermissions?.isRead() == true -> rh.gs(R.string.read_only) + else -> rh.gs(info.nightscout.core.ui.R.string.unknown) } var lastOperationError: String? = null @@ -161,26 +185,30 @@ class NSClientV3Plugin @Inject constructor( ) ) - setClient() + setClient("START") nsClientReceiverDelegate.grabReceiversState() disposable += rxBus - .toObservable(EventNetworkChange::class.java) + .toObservable(EventNSConnectivityOptionChanged::class.java) .observeOn(aapsSchedulers.io) .subscribe({ ev -> - nsClientReceiverDelegate.onStatusEvent(ev) - setClient() - rxBus.send(EventNSClientUpdateGUI()) + rxBus.send(EventNSClientNewLog("● CONNECTIVITY CHANGE", ev.blockingReason)) + setClient("CONNECTIVITY_CHANGE") + if (isAllowed) executeLoop("CONNECTIVITY_CHANGE", forceNew = false) }, fabricPrivacy::logException) disposable += rxBus .toObservable(EventPreferenceChange::class.java) .observeOn(aapsSchedulers.io) .subscribe({ ev -> - nsClientReceiverDelegate.onStatusEvent(ev) - if (ev.isChanged(rh.gs(R.string.key_ns_client_token)) || ev.isChanged(rh.gs(info.nightscout.core.utils.R.string.key_nsclientinternal_url))) - setClient() + if (ev.isChanged(rh.gs(R.string.key_ns_client_token)) || + ev.isChanged(rh.gs(info.nightscout.core.utils.R.string.key_nsclientinternal_url)) || + ev.isChanged(rh.gs(info.nightscout.core.utils.R.string.key_ns_use_ws)) || + ev.isChanged(rh.gs(R.string.key_ns_paused)) + ) + setClient("SETTING CHANGE") if (ev.isChanged(rh.gs(info.nightscout.core.utils.R.string.key_local_profile_last_change))) - delayAndScheduleExecution("PROFILE_CHANGE") + executeUpload("PROFILE_CHANGE", forceNew = true) + }, fabricPrivacy::logException) disposable += rxBus .toObservable(EventAppExit::class.java) @@ -193,47 +221,55 @@ class NSClientV3Plugin @Inject constructor( 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) - rxBus.send(EventNSClientUpdateGUI()) - }, fabricPrivacy::logException) disposable += rxBus .toObservable(EventNSClientResend::class.java) .observeOn(aapsSchedulers.io) .subscribe({ event -> resend(event.reason) }, fabricPrivacy::logException) - disposable += rxBus - .toObservable(EventNewBG::class.java) - .observeOn(aapsSchedulers.io) - .subscribe({ delayAndScheduleExecution("NEW_BG") }, fabricPrivacy::logException) disposable += rxBus .toObservable(EventNewHistoryData::class.java) .observeOn(aapsSchedulers.io) - .subscribe({ delayAndScheduleExecution("NEW_DATA") }, fabricPrivacy::logException) + .subscribe({ executeUpload("NEW_DATA", forceNew = false) }, fabricPrivacy::logException) runLoop = Runnable { - handler.postDelayed(runLoop, REFRESH_INTERVAL) + var refreshInterval = T.mins(5).msecs() repository.getLastGlucoseValueWrapped().blockingGet().let { // if last value is older than 5 min or there is no bg if (it is ValueWrapper.Existing) { - if (it.value.timestamp < dateUtil.now() - T.mins(5).plus(T.secs(20)).msecs()) + if (it.value.timestamp < dateUtil.now() - T.mins(5).plus(T.secs(20)).msecs()) { + refreshInterval = T.mins(1).msecs() executeLoop("MAIN_LOOP", forceNew = false) - else { - if (isAllowed) rxBus.send(EventNSClientNewLog("RECENT", "No need to load")) } } else executeLoop("MAIN_LOOP", forceNew = false) } + handler.postDelayed(runLoop, refreshInterval) + rxBus.send(EventNSClientNewLog("● TICK", "")) + } + handler.postDelayed(runLoop, T.mins(2).msecs()) + } + + fun scheduleIrregularExecution(refreshToken: Boolean = false) { + if (refreshToken) { + handler.post { executeLoop("REFRESH TOKEN", forceNew = true) } + return + } + if (config.NSCLIENT || nsClientSource.isEnabled()) { + var origin = "5_MIN_AFTER_BG" + var forceNew = true + var toTime = lastLoadedSrvModified.collections.entries + T.mins(5).plus(T.secs(10)).msecs() + if (toTime < dateUtil.now()) { + toTime = dateUtil.now() + T.mins(1).plus(T.secs(0)).msecs() + origin = "1_MIN_OLD_DATA" + forceNew = false + } + handler.postDelayed({ executeLoop(origin, forceNew = forceNew) }, toTime - dateUtil.now()) + rxBus.send(EventNSClientNewLog("● NEXT", dateUtil.dateAndTimeAndSecondsString(toTime))) } - handler.postDelayed(runLoop, REFRESH_INTERVAL) - executeLoop("START", forceNew = false) } override fun onStop() { - // context.applicationContext.unbindService(mConnection) handler.removeCallbacksAndMessages(null) disposable.clear() + socket?.disconnect() super.onStop() } @@ -257,16 +293,269 @@ class NSClientV3Plugin @Inject constructor( } } - private fun setClient() { + private fun setClient(reason: String) { nsAndroidClient = NSAndroidClientImpl( baseUrl = sp.getString(info.nightscout.core.utils.R.string.key_nsclientinternal_url, "").lowercase().replace("https://", "").replace(Regex("/$"), ""), accessToken = sp.getString(R.string.key_ns_client_token, ""), context = context, logging = true ) + if (wsConnected) + socket?.disconnect() + SystemClock.sleep(2000) + initializeWebSockets(reason) rxBus.send(EventSWSyncStatus(status)) } + /********************** + WS code + **********************/ + private var connectCounter = 0 + private var socket: Socket? = null + var wsConnected = false + internal var initialLoadFinished = false + private fun initializeWebSockets(reason: String) { + if (!sp.getBoolean(info.nightscout.core.utils.R.string.key_ns_use_ws, true)) return + val url = sp.getString(info.nightscout.core.utils.R.string.key_nsclientinternal_url, "").lowercase().replace(Regex("/$"), "") + "/storage" + if (!isAllowed) { + rxBus.send(EventNSClientNewLog("● WS", blockingReason)) + } else if (sp.getBoolean(R.string.key_ns_paused, false)) { + rxBus.send(EventNSClientNewLog("● WS", "paused")) + } else if (url != "") { + try { + //rxBus.send(EventNSClientStatus("Connecting ...")) + val opt = IO.Options().also { + it.forceNew = true + //it.webSocketFactory = nsAndroidClient. + } + socket = IO.socket(url, opt).also { socket -> + socket.on(Socket.EVENT_CONNECT, onConnect) + socket.on(Socket.EVENT_DISCONNECT, onDisconnect) + rxBus.send(EventNSClientNewLog("► WS", "do connect $reason")) + socket.connect() + socket.on("create", onDataCreateUpdate) + socket.on("update", onDataCreateUpdate) + socket.on("delete", onDataDelete) + socket.on("announcement", onAnnouncement) + socket.on("alarm", onAlarm) + socket.on("urgent_alarm", onUrgentAlarm) + socket.on("clear_alarm", onClearAlarm) + } + } catch (e: URISyntaxException) { + rxBus.send(EventNSClientNewLog("● WS", "Wrong URL syntax")) + } catch (e: RuntimeException) { + rxBus.send(EventNSClientNewLog("● WS", "RuntimeException")) + } + } else { + rxBus.send(EventNSClientNewLog("● WS", "No NS URL specified")) + } + } + + private val onConnect = Emitter.Listener { + connectCounter++ + val socketId = socket?.id() ?: "NULL" + rxBus.send(EventNSClientNewLog("◄ WS", "connect #$connectCounter event. ID: $socketId")) + if (socket != null) { + val authMessage = JSONObject().also { + it.put("accessToken", sp.getString(R.string.key_ns_client_token, "")) + it.put("collections", JSONArray(arrayOf("devicestatus", "entries", "profile", "treatments", "foods", "settings"))) + } + rxBus.send(EventNSClientNewLog("► WS", "requesting auth")) + socket?.emit("subscribe", authMessage, Ack { args -> + val response = args[0] as JSONObject + wsConnected = if (response.optBoolean("success")) { + rxBus.send(EventNSClientNewLog("◄ WS", "Subscribed for: ${response.optString("collections")}")) + true + } else { + rxBus.send(EventNSClientNewLog("◄ WS", "Auth failed")) + false + } + }) + } + } + + private val onDisconnect = Emitter.Listener { args -> + aapsLogger.debug(LTag.NSCLIENT, "disconnect reason: ${args[0]}") + rxBus.send(EventNSClientNewLog("◄ WS", "disconnect event")) + wsConnected = false + initialLoadFinished = false + socket = null + } + + private val onDataCreateUpdate = Emitter.Listener { args -> + val response = args[0] as JSONObject + aapsLogger.debug(LTag.NSCLIENT, "onDataCreateUpdate: $response") + val collection = response.getString("colName") + val docJson = response.getJSONObject("doc") + val docString = response.getString("doc") + rxBus.send(EventNSClientNewLog("◄ WS CREATE/UPDATE", "$collection $docString")) + val srvModified = docJson.getLong("srvModified") + lastLoadedSrvModified.set(collection, srvModified) + storeLastLoadedSrvModified() + when (collection) { + "devicestatus" -> docString.toNSDeviceStatus().let { nsDeviceStatusHandler.handleNewData(arrayOf(it)) } + "entries" -> docString.toNSSgvV3()?.let { + workManager.beginUniqueWork( + JOB_NAME + collection, + ExistingWorkPolicy.APPEND_OR_REPLACE, + OneTimeWorkRequest.Builder(workerClasses.nsClientSourceWorker).setInputData(dataWorkerStorage.storeInputData(listOf(it))).build() + ) + .then(OneTimeWorkRequest.Builder(StoreDataForDbImpl.StoreBgWorker::class.java).build()) + .enqueue() + } + + "profile" -> + workManager.enqueueUniqueWork( + JOB_NAME + collection, + ExistingWorkPolicy.APPEND_OR_REPLACE, + OneTimeWorkRequest.Builder(workerClasses.nsProfileWorker).setInputData(dataWorkerStorage.storeInputData(docJson)).build() + ) + + "treatments" -> docString.toNSTreatment()?.let { + workManager.beginUniqueWork( + JOB_NAME + collection, + ExistingWorkPolicy.APPEND_OR_REPLACE, + OneTimeWorkRequest.Builder(ProcessTreatmentsWorker::class.java).setInputData(dataWorkerStorage.storeInputData(listOf(it))).build() + ) + .then(OneTimeWorkRequest.Builder(StoreDataForDbImpl.StoreTreatmentsWorker::class.java).build()) + .enqueue() + } + + "foods" -> docString.toNSFood()?.let { + workManager.beginUniqueWork( + JOB_NAME + collection, + ExistingWorkPolicy.APPEND_OR_REPLACE, + OneTimeWorkRequest.Builder(ProcessFoodWorker::class.java).setInputData(dataWorkerStorage.storeInputData(listOf(it))).build() + ) + .then(OneTimeWorkRequest.Builder(StoreDataForDbImpl.StoreFoodWorker::class.java).build()) + .enqueue() + } + + "settings" -> {} + } + } + + private val onDataDelete = Emitter.Listener { args -> + val response = args[0] as JSONObject + aapsLogger.debug(LTag.NSCLIENT, "onDataDelete: $response") + rxBus.send(EventNSClientNewLog("◄ WS DELETE", "${response.optString("collection")} ${response.optString("doc")}")) + } + + private val onAnnouncement = Emitter.Listener { args -> + + /* + { + "level":0, + "title":"Announcement", + "message":"test", + "plugin":{"name":"treatmentnotify","label":"Treatment Notifications","pluginType":"notification","enabled":true}, + "group":"Announcement", + "isAnnouncement":true, + "key":"9ac46ad9a1dcda79dd87dae418fce0e7955c68da" + } + */ + val data: JSONObject + try { + data = args[0] as JSONObject + handleAnnouncement(data) + } catch (e: Exception) { + aapsLogger.error("Unhandled exception", e) + } + } + private val onAlarm = Emitter.Listener { args -> + + /* + { + "level":1, + "title":"Warning HIGH", + "message":"BG Now: 5 -0.2 → mmol\/L\nRaw BG: 4.8 mmol\/L Čistý\nBG 15m: 4.8 mmol\/L\nIOB: -0.02U\nCOB: 0g", + "eventName":"high", + "plugin":{"name":"simplealarms","label":"Simple Alarms","pluginType":"notification","enabled":true}, + "pushoverSound":"climb", + "debug":{"lastSGV":5,"thresholds":{"bgHigh":180,"bgTargetTop":75,"bgTargetBottom":72,"bgLow":70}}, + "group":"default", + "key":"simplealarms_1" + } + */ + val data: JSONObject + try { + data = args[0] as JSONObject + handleAlarm(data) + } catch (e: Exception) { + aapsLogger.error("Unhandled exception", e) + } + } + private val onUrgentAlarm = Emitter.Listener { args: Array -> + val data: JSONObject + try { + data = args[0] as JSONObject + handleUrgentAlarm(data) + } catch (e: Exception) { + aapsLogger.error("Unhandled exception", e) + } + } + private val onClearAlarm = Emitter.Listener { args -> + + /* + { + "clear":true, + "title":"All Clear", + "message":"default - Urgent was ack'd", + "group":"default" + } + */ + val data: JSONObject + try { + data = args[0] as JSONObject + rxBus.send(EventNSClientNewLog("CLEARALARM", "received")) + rxBus.send(EventDismissNotification(Notification.NS_ALARM)) + rxBus.send(EventDismissNotification(Notification.NS_URGENT_ALARM)) + aapsLogger.debug(LTag.NSCLIENT, data.toString()) + } catch (e: Exception) { + aapsLogger.error("Unhandled exception", e) + } + } + + private fun handleAnnouncement(announcement: JSONObject) { + val defaultVal = config.NSCLIENT + if (sp.getBoolean(info.nightscout.core.utils.R.string.key_ns_announcements, defaultVal)) { + val nsAlarm = NSAlarm(announcement) + uiInteraction.addNotificationWithAction(injector, nsAlarm) + rxBus.send(EventNSClientNewLog("ANNOUNCEMENT", JsonHelper.safeGetString(announcement, "message", "received"))) + aapsLogger.debug(LTag.NSCLIENT, announcement.toString()) + } + } + + private fun handleAlarm(alarm: JSONObject) { + val defaultVal = config.NSCLIENT + if (sp.getBoolean(info.nightscout.core.utils.R.string.key_ns_alarms, defaultVal)) { + val snoozedTo = sp.getLong(info.nightscout.core.utils.R.string.key_snoozed_to, 0L) + if (snoozedTo == 0L || System.currentTimeMillis() > snoozedTo) { + val nsAlarm = NSAlarm(alarm) + uiInteraction.addNotificationWithAction(injector, nsAlarm) + } + rxBus.send(EventNSClientNewLog("ALARM", JsonHelper.safeGetString(alarm, "message", "received"))) + aapsLogger.debug(LTag.NSCLIENT, alarm.toString()) + } + } + + private fun handleUrgentAlarm(alarm: JSONObject) { + val defaultVal = config.NSCLIENT + if (sp.getBoolean(info.nightscout.core.utils.R.string.key_ns_alarms, defaultVal)) { + val snoozedTo = sp.getLong(info.nightscout.core.utils.R.string.key_snoozed_to, 0L) + if (snoozedTo == 0L || System.currentTimeMillis() > snoozedTo) { + val nsAlarm = NSAlarm(alarm) + uiInteraction.addNotificationWithAction(injector, nsAlarm) + } + rxBus.send(EventNSClientNewLog("URGENTALARM", JsonHelper.safeGetString(alarm, "message", "received"))) + aapsLogger.debug(LTag.NSCLIENT, alarm.toString()) + } + } + + /********************** + WS code end + **********************/ + private fun addToLog(ev: EventNSClientNewLog) { synchronized(listLog) { listLog.add(ev) @@ -292,12 +581,15 @@ class NSClientV3Plugin @Inject constructor( } override fun resend(reason: String) { - executeLoop("RESEND", forceNew = false) + if (sp.getBoolean(info.nightscout.core.utils.R.string.key_ns_use_ws, true)) + executeUpload("RESEND", forceNew = false) + else + executeLoop("RESEND", forceNew = false) } override fun pause(newState: Boolean) { - sp.putBoolean(R.string.key_ns_client_paused, newState) - rxBus.send(EventPreferenceChange(rh.gs(R.string.key_ns_client_paused))) + sp.putBoolean(R.string.key_ns_paused, newState) + rxBus.send(EventPreferenceChange(rh.gs(R.string.key_ns_paused))) } override fun detectedNsVersion(): String? = nsAndroidClient?.lastStatus?.version @@ -337,6 +629,7 @@ class NSClientV3Plugin @Inject constructor( override fun resetToFullSync() { firstLoadContinueTimestamp = LastModified(LastModified.Collections()) lastLoadedSrvModified = LastModified(LastModified.Collections()) + initialLoadFinished = false storeLastLoadedSrvModified() } @@ -355,15 +648,15 @@ class NSClientV3Plugin @Inject constructor( val data = (dataPair as DataSyncSelector.PairProfileStore).value scope.launch { try { - rxBus.send(EventNSClientNewLog("ADD $collection", "Sent ${dataPair.javaClass.simpleName} $data $progress")) + rxBus.send(EventNSClientNewLog("► ADD $collection", "Sent ${dataPair.javaClass.simpleName} $data $progress")) nsAndroidClient?.createProfileStore(data)?.let { result -> when (result.response) { - 200 -> rxBus.send(EventNSClientNewLog("UPDATED", "OK ProfileStore")) - 201 -> rxBus.send(EventNSClientNewLog("ADDED", "OK ProfileStore")) - 404 -> rxBus.send(EventNSClientNewLog("NOT_FOUND", "${dataPair.value.javaClass.simpleName} ${result.errorResponse}")) + 200 -> rxBus.send(EventNSClientNewLog("◄ UPDATED", "OK ProfileStore")) + 201 -> rxBus.send(EventNSClientNewLog("◄ ADDED", "OK ProfileStore")) + 404 -> rxBus.send(EventNSClientNewLog("◄ NOT_FOUND", "${dataPair.value.javaClass.simpleName} ${result.errorResponse}")) else -> { - rxBus.send(EventNSClientNewLog("ERROR", "ProfileStore")) + rxBus.send(EventNSClientNewLog("◄ ERROR", "ProfileStore")) return@launch } } @@ -385,15 +678,15 @@ class NSClientV3Plugin @Inject constructor( val data = (dataPair as DataSyncSelector.PairDeviceStatus).value.toNSDeviceStatus() scope.launch { try { - rxBus.send(EventNSClientNewLog("ADD $collection", "Sent ${dataPair.javaClass.simpleName} ${gson.toJson(data)} $progress")) + rxBus.send(EventNSClientNewLog("► ADD $collection", "Sent ${dataPair.javaClass.simpleName} ${gson.toJson(data)} $progress")) nsAndroidClient?.createDeviceStatus(data)?.let { result -> when (result.response) { - 200 -> rxBus.send(EventNSClientNewLog("UPDATED", "OK ${dataPair.value.javaClass.simpleName}")) - 201 -> rxBus.send(EventNSClientNewLog("ADDED", "OK ${dataPair.value.javaClass.simpleName} ${result.identifier}")) - 404 -> rxBus.send(EventNSClientNewLog("NOT_FOUND", "${dataPair.value.javaClass.simpleName} ${result.errorResponse}")) + 200 -> rxBus.send(EventNSClientNewLog("◄ UPDATED", "OK ${dataPair.value.javaClass.simpleName}")) + 201 -> rxBus.send(EventNSClientNewLog("◄ ADDED", "OK ${dataPair.value.javaClass.simpleName} ${result.identifier}")) + 404 -> rxBus.send(EventNSClientNewLog("◄ NOT_FOUND", "${dataPair.value.javaClass.simpleName} ${result.errorResponse}")) else -> { - rxBus.send(EventNSClientNewLog("ERROR", "${dataPair.value.javaClass.simpleName} ")) + rxBus.send(EventNSClientNewLog("◄ ERROR", "${dataPair.value.javaClass.simpleName} ")) return@launch } } @@ -426,24 +719,24 @@ class NSClientV3Plugin @Inject constructor( rxBus.send( EventNSClientNewLog( when (operation) { - Operation.CREATE -> "ADD $collection" - Operation.UPDATE -> "UPDATE $collection" + Operation.CREATE -> "► ADD $collection" + Operation.UPDATE -> "► UPDATE $collection" }, when (operation) { - Operation.CREATE -> "Sent ${dataPair.javaClass.simpleName} ${gson.toJson(data)} $progress" - Operation.UPDATE -> "Sent ${dataPair.javaClass.simpleName} $id ${gson.toJson(data)} $progress" + Operation.CREATE -> "Sent ${dataPair.javaClass.simpleName} ${gson.toJson(data)} $progress" + Operation.UPDATE -> "Sent ${dataPair.javaClass.simpleName} $id ${gson.toJson(data)} $progress" } ) ) call?.let { it(data) }?.let { result -> when (result.response) { - 200 -> rxBus.send(EventNSClientNewLog("UPDATED", "OK ${dataPair.value.javaClass.simpleName}")) - 201 -> rxBus.send(EventNSClientNewLog("ADDED", "OK ${dataPair.value.javaClass.simpleName}")) - 400 -> rxBus.send(EventNSClientNewLog("FAIL", "${dataPair.value.javaClass.simpleName} ${result.errorResponse}")) - 404 -> rxBus.send(EventNSClientNewLog("NOT_FOUND", "${dataPair.value.javaClass.simpleName} ${result.errorResponse}")) + 200 -> rxBus.send(EventNSClientNewLog("◄ UPDATED", "OK ${dataPair.value.javaClass.simpleName}")) + 201 -> rxBus.send(EventNSClientNewLog("◄ ADDED", "OK ${dataPair.value.javaClass.simpleName}")) + 400 -> rxBus.send(EventNSClientNewLog("◄ FAIL", "${dataPair.value.javaClass.simpleName} ${result.errorResponse}")) + 404 -> rxBus.send(EventNSClientNewLog("◄ NOT_FOUND", "${dataPair.value.javaClass.simpleName} ${result.errorResponse}")) else -> { - rxBus.send(EventNSClientNewLog("ERROR", "${dataPair.value.javaClass.simpleName} ")) + rxBus.send(EventNSClientNewLog("◄ ERROR", "${dataPair.value.javaClass.simpleName} ")) return@launch } } @@ -481,24 +774,24 @@ class NSClientV3Plugin @Inject constructor( rxBus.send( EventNSClientNewLog( when (operation) { - Operation.CREATE -> "ADD $collection" - Operation.UPDATE -> "UPDATE $collection" + Operation.CREATE -> "► ADD $collection" + Operation.UPDATE -> "► UPDATE $collection" }, when (operation) { - Operation.CREATE -> "Sent ${dataPair.javaClass.simpleName} ${gson.toJson(data)} $progress" - Operation.UPDATE -> "Sent ${dataPair.javaClass.simpleName} $id ${gson.toJson(data)} $progress" + Operation.CREATE -> "Sent ${dataPair.javaClass.simpleName} ${gson.toJson(data)} $progress" + Operation.UPDATE -> "Sent ${dataPair.javaClass.simpleName} $id ${gson.toJson(data)} $progress" } ) ) call?.let { it(data) }?.let { result -> when (result.response) { - 200 -> rxBus.send(EventNSClientNewLog("UPDATED", "OK ${dataPair.value.javaClass.simpleName}")) - 201 -> rxBus.send(EventNSClientNewLog("ADDED", "OK ${dataPair.value.javaClass.simpleName}")) - 400 -> rxBus.send(EventNSClientNewLog("FAIL", "${dataPair.value.javaClass.simpleName} ${result.errorResponse}")) - 404 -> rxBus.send(EventNSClientNewLog("NOT_FOUND", "${dataPair.value.javaClass.simpleName} ${result.errorResponse}")) + 200 -> rxBus.send(EventNSClientNewLog("◄ UPDATED", "OK ${dataPair.value.javaClass.simpleName}")) + 201 -> rxBus.send(EventNSClientNewLog("◄ ADDED", "OK ${dataPair.value.javaClass.simpleName}")) + 400 -> rxBus.send(EventNSClientNewLog("◄ FAIL", "${dataPair.value.javaClass.simpleName} ${result.errorResponse}")) + 404 -> rxBus.send(EventNSClientNewLog("◄ NOT_FOUND", "${dataPair.value.javaClass.simpleName} ${result.errorResponse}")) else -> { - rxBus.send(EventNSClientNewLog("ERROR", "${dataPair.value.javaClass.simpleName} ")) + rxBus.send(EventNSClientNewLog("◄ ERROR", "${dataPair.value.javaClass.simpleName} ")) return@launch } } @@ -564,24 +857,24 @@ class NSClientV3Plugin @Inject constructor( rxBus.send( EventNSClientNewLog( when (operation) { - Operation.CREATE -> "ADD $collection" - Operation.UPDATE -> "UPDATE $collection" + Operation.CREATE -> "► ADD $collection" + Operation.UPDATE -> "► UPDATE $collection" }, when (operation) { - Operation.CREATE -> "Sent ${dataPair.javaClass.simpleName} ${gson.toJson(data)} $progress" - Operation.UPDATE -> "Sent ${dataPair.javaClass.simpleName} $id ${gson.toJson(data)} $progress" + Operation.CREATE -> "Sent ${dataPair.javaClass.simpleName} ${gson.toJson(data)} $progress" + Operation.UPDATE -> "Sent ${dataPair.javaClass.simpleName} $id ${gson.toJson(data)} $progress" } ) ) call?.let { it(data) }?.let { result -> when (result.response) { - 200 -> rxBus.send(EventNSClientNewLog("UPDATED", "OK ${dataPair.value.javaClass.simpleName}")) - 201 -> rxBus.send(EventNSClientNewLog("ADDED", "OK ${dataPair.value.javaClass.simpleName}")) - 400 -> rxBus.send(EventNSClientNewLog("FAIL", "${dataPair.value.javaClass.simpleName} ${result.errorResponse}")) - 404 -> rxBus.send(EventNSClientNewLog("NOT_FOUND", "${dataPair.value.javaClass.simpleName} ${result.errorResponse}")) + 200 -> rxBus.send(EventNSClientNewLog("◄ UPDATED", "OK ${dataPair.value.javaClass.simpleName}")) + 201 -> rxBus.send(EventNSClientNewLog("◄ ADDED", "OK ${dataPair.value.javaClass.simpleName}")) + 400 -> rxBus.send(EventNSClientNewLog("◄ FAIL", "${dataPair.value.javaClass.simpleName} ${result.errorResponse}")) + 404 -> rxBus.send(EventNSClientNewLog("◄ NOT_FOUND", "${dataPair.value.javaClass.simpleName} ${result.errorResponse}")) else -> { - rxBus.send(EventNSClientNewLog("ERROR", "${dataPair.value.javaClass.simpleName} ")) + rxBus.send(EventNSClientNewLog("◄ ERROR", "${dataPair.value.javaClass.simpleName} ")) return@launch } } @@ -708,35 +1001,23 @@ class NSClientV3Plugin @Inject constructor( sp.putString(R.string.key_ns_client_v3_last_modified, Json.encodeToString(LastModified.serializer(), lastLoadedSrvModified)) } - fun scheduleIrregularExecution() { - var origin = "5_MIN_AFTER_BG" - var forceNew = true - var toTime = lastLoadedSrvModified.collections.entries + T.mins(5).plus(T.secs(10)).msecs() - if (toTime < dateUtil.now()) { - toTime = dateUtil.now() + T.mins(1).plus(T.secs(0)).msecs() - origin = "1_MIN_OLD_DATA" - forceNew = false - } - handler.postDelayed({ executeLoop(origin, forceNew = forceNew) }, toTime - dateUtil.now()) - rxBus.send(EventNSClientNewLog("NEXT", dateUtil.dateAndTimeAndSecondsString(toTime))) - } - private fun executeLoop(origin: String, forceNew: Boolean) { - if (sp.getBoolean(R.string.key_ns_client_paused, false)) { - rxBus.send(EventNSClientNewLog("RUN", "paused")) + if (sp.getBoolean(info.nightscout.core.utils.R.string.key_ns_use_ws, true) && initialLoadFinished) return + if (sp.getBoolean(R.string.key_ns_paused, false)) { + rxBus.send(EventNSClientNewLog("● RUN", "paused $origin")) return } if (!isAllowed) { - rxBus.send(EventNSClientNewLog("RUN", blockingReason)) + rxBus.send(EventNSClientNewLog("● RUN", "$blockingReason $origin")) return } if (workIsRunning(arrayOf(JOB_NAME))) { - rxBus.send(EventNSClientNewLog("RUN", "Already running $origin")) + rxBus.send(EventNSClientNewLog("● RUN", "Already running $origin")) if (!forceNew) return // Wait for end and start new cycle while (workIsRunning(arrayOf(JOB_NAME))) Thread.sleep(5000) } - rxBus.send(EventNSClientNewLog("RUN", "Starting next round $origin")) + rxBus.send(EventNSClientNewLog("● RUN", "Starting next round $origin")) WorkManager.getInstance(context) .beginUniqueWork( JOB_NAME, @@ -754,6 +1035,30 @@ class NSClientV3Plugin @Inject constructor( .enqueue() } + private fun executeUpload(origin: String, forceNew: Boolean) { + if (sp.getBoolean(R.string.key_ns_paused, false)) { + rxBus.send(EventNSClientNewLog("● RUN", "paused")) + return + } + if (!isAllowed) { + rxBus.send(EventNSClientNewLog("● RUN", blockingReason)) + return + } + if (workIsRunning(arrayOf(JOB_NAME))) { + rxBus.send(EventNSClientNewLog("● RUN", "Already running $origin")) + if (!forceNew) return + // Wait for end and start new cycle + while (workIsRunning(arrayOf(JOB_NAME))) Thread.sleep(5000) + } + rxBus.send(EventNSClientNewLog("● RUN", "Starting upload $origin")) + WorkManager.getInstance(context) + .enqueueUniqueWork( + JOB_NAME, + ExistingWorkPolicy.REPLACE, + OneTimeWorkRequest.Builder(DataSyncWorker::class.java).build() + ) + } + private fun workIsRunning(workNames: Array): Boolean { for (workName in workNames) for (workInfo in WorkManager.getInstance(context).getWorkInfosForUniqueWork(workName).get()) @@ -761,20 +1066,4 @@ class NSClientV3Plugin @Inject constructor( return true return false } - - private val eventWorker = Executors.newSingleThreadScheduledExecutor() - private var scheduledEventPost: ScheduledFuture<*>? = null - private fun delayAndScheduleExecution(origin: String) { - class PostRunnable : Runnable { - - override fun run() { - scheduledEventPost = null - executeLoop(origin, forceNew = true) - } - } - // cancel waiting task to prevent sending multiple posts - scheduledEventPost?.cancel(false) - val task: Runnable = PostRunnable() - scheduledEventPost = eventWorker.schedule(task, 10, TimeUnit.SECONDS) - } } \ No newline at end of file diff --git a/plugins/sync/src/main/java/info/nightscout/plugins/sync/nsclientV3/workers/DataSyncWorker.kt b/plugins/sync/src/main/java/info/nightscout/plugins/sync/nsclientV3/workers/DataSyncWorker.kt index 0c446063b6..69b1d5204f 100644 --- a/plugins/sync/src/main/java/info/nightscout/plugins/sync/nsclientV3/workers/DataSyncWorker.kt +++ b/plugins/sync/src/main/java/info/nightscout/plugins/sync/nsclientV3/workers/DataSyncWorker.kt @@ -7,6 +7,7 @@ import info.nightscout.core.utils.worker.LoggingWorker import info.nightscout.interfaces.plugin.ActivePlugin import info.nightscout.interfaces.sync.DataSyncSelector import info.nightscout.plugins.sync.nsShared.events.EventNSClientUpdateGUI +import info.nightscout.plugins.sync.nsclientV3.NSClientV3Plugin import info.nightscout.rx.bus.RxBus import info.nightscout.rx.events.EventNSClientNewLog import kotlinx.coroutines.Dispatchers @@ -20,12 +21,17 @@ class DataSyncWorker( @Inject lateinit var dataSyncSelector: DataSyncSelector @Inject lateinit var activePlugin: ActivePlugin @Inject lateinit var rxBus: RxBus + @Inject lateinit var nsClientV3Plugin: NSClientV3Plugin override suspend fun doWorkAndLog(): Result { - if (activePlugin.activeNsClient?.hasWritePermission == true) { - rxBus.send(EventNSClientNewLog("UPL", "Start")) + if (activePlugin.activeNsClient?.hasWritePermission == true || nsClientV3Plugin.wsConnected) { + rxBus.send(EventNSClientNewLog("► UPL", "Start")) dataSyncSelector.doUpload() - rxBus.send(EventNSClientNewLog("UPL", "End")) + rxBus.send(EventNSClientNewLog("► UPL", "End")) + } else { + rxBus.send(EventNSClientNewLog("► ERROR", "Not connected or write permission")) + // refresh token + nsClientV3Plugin.scheduleIrregularExecution(refreshToken = true) } rxBus.send(EventNSClientUpdateGUI()) return Result.success() diff --git a/plugins/sync/src/main/java/info/nightscout/plugins/sync/nsclientV3/workers/LoadBgWorker.kt b/plugins/sync/src/main/java/info/nightscout/plugins/sync/nsclientV3/workers/LoadBgWorker.kt index 93afbb4d5f..3c1451eee8 100644 --- a/plugins/sync/src/main/java/info/nightscout/plugins/sync/nsclientV3/workers/LoadBgWorker.kt +++ b/plugins/sync/src/main/java/info/nightscout/plugins/sync/nsclientV3/workers/LoadBgWorker.kt @@ -70,7 +70,7 @@ class LoadBgWorker( aapsLogger.debug(LTag.NSCLIENT, "SGVS: $sgvs") if (sgvs.isNotEmpty()) { val action = if (isFirstLoad) "RCV-FIRST" else "RCV" - rxBus.send(EventNSClientNewLog(action, "${sgvs.size} SVGs from ${dateUtil.dateAndTimeAndSecondsString(lastLoaded)}")) + rxBus.send(EventNSClientNewLog("◄ $action", "${sgvs.size} SVGs from ${dateUtil.dateAndTimeAndSecondsString(lastLoaded)}")) // Objective0 sp.putBoolean(info.nightscout.core.utils.R.string.key_objectives_bg_is_available_in_ns, true) // Schedule processing of fetched data and continue of loading @@ -90,7 +90,7 @@ class LoadBgWorker( nsClientV3Plugin.lastLoadedSrvModified.collections.entries = lastLoaded nsClientV3Plugin.storeLastLoadedSrvModified() } - rxBus.send(EventNSClientNewLog("RCV END", "No SGVs from ${dateUtil.dateAndTimeAndSecondsString(lastLoaded)}")) + rxBus.send(EventNSClientNewLog("◄ RCV BG END", "No data from ${dateUtil.dateAndTimeAndSecondsString(lastLoaded)}")) workManager .beginUniqueWork( NSClientV3Plugin.JOB_NAME, @@ -106,7 +106,7 @@ class LoadBgWorker( nsClientV3Plugin.lastLoadedSrvModified.collections.entries = lastLoaded nsClientV3Plugin.storeLastLoadedSrvModified() } - rxBus.send(EventNSClientNewLog("RCV END", "No new SGVs from ${dateUtil.dateAndTimeAndSecondsString(lastLoaded)}")) + rxBus.send(EventNSClientNewLog("◄ RCV BG END", "No new data from ${dateUtil.dateAndTimeAndSecondsString(lastLoaded)}")) workManager .beginUniqueWork( NSClientV3Plugin.JOB_NAME, @@ -118,7 +118,7 @@ class LoadBgWorker( } } catch (error: Exception) { aapsLogger.error("Error: ", error) - rxBus.send(EventNSClientNewLog("ERROR", error.localizedMessage)) + rxBus.send(EventNSClientNewLog("◄ ERROR", error.localizedMessage)) nsClientV3Plugin.lastOperationError = error.localizedMessage return Result.failure(workDataOf("Error" to error.localizedMessage)) } diff --git a/plugins/sync/src/main/java/info/nightscout/plugins/sync/nsclientV3/workers/LoadDeviceStatusWorker.kt b/plugins/sync/src/main/java/info/nightscout/plugins/sync/nsclientV3/workers/LoadDeviceStatusWorker.kt index 437f2acae2..4a3acdfce1 100644 --- a/plugins/sync/src/main/java/info/nightscout/plugins/sync/nsclientV3/workers/LoadDeviceStatusWorker.kt +++ b/plugins/sync/src/main/java/info/nightscout/plugins/sync/nsclientV3/workers/LoadDeviceStatusWorker.kt @@ -33,15 +33,18 @@ class LoadDeviceStatusWorker( val nsAndroidClient = nsClientV3Plugin.nsAndroidClient ?: return Result.failure(workDataOf("Error" to "AndroidClient is null")) try { + // Notify plugin we loaded al missed data + nsClientV3Plugin.initialLoadFinished = true + val from = dateUtil.now() - T.mins(7).msecs() val deviceStatuses = nsAndroidClient.getDeviceStatusModifiedSince(from) aapsLogger.debug("DEVICESTATUSES: $deviceStatuses") if (deviceStatuses.isNotEmpty()) { - rxBus.send(EventNSClientNewLog("RCV", "${deviceStatuses.size} DSs from ${dateUtil.dateAndTimeAndSecondsString(from)}")) + rxBus.send(EventNSClientNewLog("◄ RCV", "${deviceStatuses.size} DSs from ${dateUtil.dateAndTimeAndSecondsString(from)}")) nsDeviceStatusHandler.handleNewData(deviceStatuses.toTypedArray()) - rxBus.send(EventNSClientNewLog("DONE DS", "")) + rxBus.send(EventNSClientNewLog("● DONE PROCESSING DS", "")) } else { - rxBus.send(EventNSClientNewLog("RCV END", "No DSs from ${dateUtil.dateAndTimeAndSecondsString(from)}")) + rxBus.send(EventNSClientNewLog("◄ RCV DS END", "No data from ${dateUtil.dateAndTimeAndSecondsString(from)}")) } WorkManager.getInstance(context) .enqueueUniqueWork( @@ -51,7 +54,7 @@ class LoadDeviceStatusWorker( ) } catch (error: Exception) { aapsLogger.error("Error: ", error) - rxBus.send(EventNSClientNewLog("ERROR", error.localizedMessage)) + rxBus.send(EventNSClientNewLog("◄ ERROR", error.localizedMessage)) nsClientV3Plugin.lastOperationError = error.localizedMessage return Result.failure(workDataOf("Error" to error.localizedMessage)) } diff --git a/plugins/sync/src/main/java/info/nightscout/plugins/sync/nsclientV3/workers/LoadFoodsWorker.kt b/plugins/sync/src/main/java/info/nightscout/plugins/sync/nsclientV3/workers/LoadFoodsWorker.kt index 8a92a1f703..74b3b5ff25 100644 --- a/plugins/sync/src/main/java/info/nightscout/plugins/sync/nsclientV3/workers/LoadFoodsWorker.kt +++ b/plugins/sync/src/main/java/info/nightscout/plugins/sync/nsclientV3/workers/LoadFoodsWorker.kt @@ -40,7 +40,7 @@ class LoadFoodsWorker( if (nsClientV3Plugin.lastLoadedSrvModified.collections.foods++ % 5 == 0L) { val foods: List = nsAndroidClient.getFoods(1000).values aapsLogger.debug(LTag.NSCLIENT, "FOODS: $foods") - rxBus.send(EventNSClientNewLog("RCV", "${foods.size} FOODs")) + rxBus.send(EventNSClientNewLog("◄ RCV", "${foods.size} FOODs")) // Schedule processing of fetched data WorkManager.getInstance(context) .beginUniqueWork( @@ -53,7 +53,7 @@ class LoadFoodsWorker( .then(OneTimeWorkRequest.Builder(LoadProfileStoreWorker::class.java).build()) .enqueue() } else { - rxBus.send(EventNSClientNewLog("RCV", "FOOD skipped")) + rxBus.send(EventNSClientNewLog("● RCV FOOD", "skipped")) WorkManager.getInstance(context) .enqueueUniqueWork( NSClientV3Plugin.JOB_NAME, @@ -63,7 +63,7 @@ class LoadFoodsWorker( } } catch (error: Exception) { aapsLogger.error("Error: ", error) - rxBus.send(EventNSClientNewLog("ERROR", error.localizedMessage)) + rxBus.send(EventNSClientNewLog("◄ ERROR", error.localizedMessage)) nsClientV3Plugin.lastOperationError = error.localizedMessage return Result.failure(workDataOf("Error" to error.localizedMessage)) } diff --git a/plugins/sync/src/main/java/info/nightscout/plugins/sync/nsclientV3/workers/LoadLastModificationWorker.kt b/plugins/sync/src/main/java/info/nightscout/plugins/sync/nsclientV3/workers/LoadLastModificationWorker.kt index c4333ab28b..addcf27ce6 100644 --- a/plugins/sync/src/main/java/info/nightscout/plugins/sync/nsclientV3/workers/LoadLastModificationWorker.kt +++ b/plugins/sync/src/main/java/info/nightscout/plugins/sync/nsclientV3/workers/LoadLastModificationWorker.kt @@ -27,7 +27,7 @@ class LoadLastModificationWorker( aapsLogger.debug(LTag.NSCLIENT, "LAST MODIFIED: ${nsClientV3Plugin.newestDataOnServer}") } catch (error: Exception) { aapsLogger.error(LTag.NSCLIENT, "Error: ", error) - rxBus.send(EventNSClientNewLog("ERROR", error.localizedMessage)) + rxBus.send(EventNSClientNewLog("◄ ERROR", error.localizedMessage)) nsClientV3Plugin.lastOperationError = error.localizedMessage return Result.failure(workDataOf("Error" to error.localizedMessage)) } diff --git a/plugins/sync/src/main/java/info/nightscout/plugins/sync/nsclientV3/workers/LoadProfileStoreWorker.kt b/plugins/sync/src/main/java/info/nightscout/plugins/sync/nsclientV3/workers/LoadProfileStoreWorker.kt index 0acae4ffc4..84b3cf245d 100644 --- a/plugins/sync/src/main/java/info/nightscout/plugins/sync/nsclientV3/workers/LoadProfileStoreWorker.kt +++ b/plugins/sync/src/main/java/info/nightscout/plugins/sync/nsclientV3/workers/LoadProfileStoreWorker.kt @@ -57,7 +57,7 @@ class LoadProfileStoreWorker( { nsClientV3Plugin.lastLoadedSrvModified.collections.profile = dateUtil.now() } nsClientV3Plugin.storeLastLoadedSrvModified() aapsLogger.debug(LTag.NSCLIENT, "PROFILE: $profile") - rxBus.send(EventNSClientNewLog("RCV", "1 PROFILE from ${dateUtil.dateAndTimeAndSecondsString(lastLoaded)}")) + rxBus.send(EventNSClientNewLog("◄ RCV", "1 PROFILE from ${dateUtil.dateAndTimeAndSecondsString(lastLoaded)}")) WorkManager.getInstance(context) .beginUniqueWork( NSClientV3Plugin.JOB_NAME, @@ -68,7 +68,7 @@ class LoadProfileStoreWorker( ).then(OneTimeWorkRequest.Builder(LoadDeviceStatusWorker::class.java).build()) .enqueue() } else { - rxBus.send(EventNSClientNewLog("RCV END", "No new PROFILE from ${dateUtil.dateAndTimeAndSecondsString(lastLoaded)}")) + rxBus.send(EventNSClientNewLog("◄ RCV PROFILE END", "No new data from ${dateUtil.dateAndTimeAndSecondsString(lastLoaded)}")) WorkManager.getInstance(context) .enqueueUniqueWork( NSClientV3Plugin.JOB_NAME, @@ -77,7 +77,7 @@ class LoadProfileStoreWorker( ) } } else { - rxBus.send(EventNSClientNewLog("RCV END", "No PROFILE from ${dateUtil.dateAndTimeAndSecondsString(lastLoaded)}")) + rxBus.send(EventNSClientNewLog("◄ RCV PROFILE END", "No data from ${dateUtil.dateAndTimeAndSecondsString(lastLoaded)}")) WorkManager.getInstance(context) .enqueueUniqueWork( NSClientV3Plugin.JOB_NAME, @@ -87,7 +87,7 @@ class LoadProfileStoreWorker( } } catch (error: Exception) { aapsLogger.error("Error: ", error) - rxBus.send(EventNSClientNewLog("ERROR", error.localizedMessage)) + rxBus.send(EventNSClientNewLog("◄ ERROR", error.localizedMessage)) return Result.failure(workDataOf("Error" to error.localizedMessage)) } diff --git a/plugins/sync/src/main/java/info/nightscout/plugins/sync/nsclientV3/workers/LoadStatusWorker.kt b/plugins/sync/src/main/java/info/nightscout/plugins/sync/nsclientV3/workers/LoadStatusWorker.kt index d51a286306..806e743f1d 100644 --- a/plugins/sync/src/main/java/info/nightscout/plugins/sync/nsclientV3/workers/LoadStatusWorker.kt +++ b/plugins/sync/src/main/java/info/nightscout/plugins/sync/nsclientV3/workers/LoadStatusWorker.kt @@ -26,7 +26,7 @@ class LoadStatusWorker( aapsLogger.debug(LTag.NSCLIENT, "STATUS: $status") } catch (error: Exception) { aapsLogger.error("Error: ", error) - rxBus.send(EventNSClientNewLog("ERROR", error.localizedMessage)) + rxBus.send(EventNSClientNewLog("◄ ERROR", error.localizedMessage)) nsClientV3Plugin.lastOperationError = error.localizedMessage return Result.failure(workDataOf("Error" to error.localizedMessage)) } diff --git a/plugins/sync/src/main/java/info/nightscout/plugins/sync/nsclientV3/workers/LoadTreatmentsWorker.kt b/plugins/sync/src/main/java/info/nightscout/plugins/sync/nsclientV3/workers/LoadTreatmentsWorker.kt index b5159fa9bf..7e91ed9281 100644 --- a/plugins/sync/src/main/java/info/nightscout/plugins/sync/nsclientV3/workers/LoadTreatmentsWorker.kt +++ b/plugins/sync/src/main/java/info/nightscout/plugins/sync/nsclientV3/workers/LoadTreatmentsWorker.kt @@ -11,6 +11,7 @@ import info.nightscout.core.utils.worker.LoggingWorker import info.nightscout.core.utils.worker.then import info.nightscout.interfaces.nsclient.StoreDataForDb import info.nightscout.interfaces.sync.NsClient +import info.nightscout.plugins.sync.nsShared.StoreDataForDbImpl import info.nightscout.plugins.sync.nsclientV3.NSClientV3Plugin import info.nightscout.rx.bus.RxBus import info.nightscout.rx.events.EventNSClientNewLog @@ -57,14 +58,14 @@ class LoadTreatmentsWorker( aapsLogger.debug(LTag.NSCLIENT, "TREATMENTS: $treatments") if (treatments.isNotEmpty()) { val action = if (isFirstLoad) "RCV-FIRST" else "RCV" - rxBus.send(EventNSClientNewLog(action, "${treatments.size} TRs from ${dateUtil.dateAndTimeAndSecondsString(lastLoaded)}")) + rxBus.send(EventNSClientNewLog("◄ $action", "${treatments.size} TRs from ${dateUtil.dateAndTimeAndSecondsString(lastLoaded)}")) // 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(response)) + .setInputData(dataWorkerStorage.storeInputData(response.values)) .build() ) // response 304 == Not modified (happens when date > srvModified => bad time on phone or server during upload @@ -77,14 +78,15 @@ class LoadTreatmentsWorker( nsClientV3Plugin.lastLoadedSrvModified.collections.treatments = lastLoaded nsClientV3Plugin.storeLastLoadedSrvModified() } - rxBus.send(EventNSClientNewLog("RCV END", "No TRs from ${dateUtil.dateAndTimeAndSecondsString(lastLoaded)}")) - storeDataForDb.storeTreatmentsToDb() + rxBus.send(EventNSClientNewLog("◄ RCV TR END", "No data from ${dateUtil.dateAndTimeAndSecondsString(lastLoaded)}")) WorkManager.getInstance(context) - .enqueueUniqueWork( + .beginUniqueWork( NSClientV3Plugin.JOB_NAME, ExistingWorkPolicy.APPEND_OR_REPLACE, - OneTimeWorkRequest.Builder(LoadFoodsWorker::class.java).build() + OneTimeWorkRequest.Builder(StoreDataForDbImpl.StoreTreatmentsWorker::class.java).build() ) + .then(OneTimeWorkRequest.Builder(LoadFoodsWorker::class.java).build()) + .enqueue() } } else { // End first load @@ -92,18 +94,19 @@ class LoadTreatmentsWorker( nsClientV3Plugin.lastLoadedSrvModified.collections.treatments = lastLoaded nsClientV3Plugin.storeLastLoadedSrvModified() } - rxBus.send(EventNSClientNewLog("RCV END", "No new TRs from ${dateUtil.dateAndTimeAndSecondsString(lastLoaded)}")) - storeDataForDb.storeTreatmentsToDb() + rxBus.send(EventNSClientNewLog("◄ RCV TR END", "No new data from ${dateUtil.dateAndTimeAndSecondsString(lastLoaded)}")) WorkManager.getInstance(context) - .enqueueUniqueWork( + .beginUniqueWork( NSClientV3Plugin.JOB_NAME, ExistingWorkPolicy.APPEND_OR_REPLACE, - OneTimeWorkRequest.Builder(LoadFoodsWorker::class.java).build() + OneTimeWorkRequest.Builder(StoreDataForDbImpl.StoreTreatmentsWorker::class.java).build() ) + .then(OneTimeWorkRequest.Builder(LoadFoodsWorker::class.java).build()) + .enqueue() } } catch (error: Exception) { aapsLogger.error("Error: ", error) - rxBus.send(EventNSClientNewLog("ERROR", error.localizedMessage)) + rxBus.send(EventNSClientNewLog("◄ ERROR", error.localizedMessage)) nsClientV3Plugin.lastOperationError = error.localizedMessage return Result.failure(workDataOf("Error" to error.localizedMessage)) } diff --git a/plugins/sync/src/main/java/info/nightscout/plugins/sync/nsclientV3/workers/ProcessFoodWorker.kt b/plugins/sync/src/main/java/info/nightscout/plugins/sync/nsclientV3/workers/ProcessFoodWorker.kt index 32bdc3ac54..b6254b7931 100644 --- a/plugins/sync/src/main/java/info/nightscout/plugins/sync/nsclientV3/workers/ProcessFoodWorker.kt +++ b/plugins/sync/src/main/java/info/nightscout/plugins/sync/nsclientV3/workers/ProcessFoodWorker.kt @@ -72,7 +72,7 @@ class ProcessFoodWorker( storeDataForDb.foods.addAll(foods) } catch (error: Exception) { aapsLogger.error("Error: ", error) - rxBus.send(EventNSClientNewLog("ERROR", error.localizedMessage)) + rxBus.send(EventNSClientNewLog("◄ ERROR", error.localizedMessage)) return Result.failure(workDataOf("Error" to error.localizedMessage)) } diff --git a/plugins/sync/src/main/java/info/nightscout/plugins/sync/nsclientV3/workers/ProcessTreatmentsWorker.kt b/plugins/sync/src/main/java/info/nightscout/plugins/sync/nsclientV3/workers/ProcessTreatmentsWorker.kt index 3f96ad4922..fb1e1e3cde 100644 --- a/plugins/sync/src/main/java/info/nightscout/plugins/sync/nsclientV3/workers/ProcessTreatmentsWorker.kt +++ b/plugins/sync/src/main/java/info/nightscout/plugins/sync/nsclientV3/workers/ProcessTreatmentsWorker.kt @@ -24,7 +24,6 @@ import info.nightscout.plugins.sync.nsclientV3.extensions.toTherapyEvent import info.nightscout.rx.bus.RxBus import info.nightscout.rx.events.EventNSClientNewLog import info.nightscout.rx.logging.LTag -import info.nightscout.sdk.interfaces.NSAndroidClient import info.nightscout.sdk.localmodel.treatment.NSBolus import info.nightscout.sdk.localmodel.treatment.NSBolusWizard import info.nightscout.sdk.localmodel.treatment.NSCarbs @@ -57,12 +56,12 @@ class ProcessTreatmentsWorker( override suspend fun doWorkAndLog(): Result { @Suppress("UNCHECKED_CAST") - val treatments = dataWorkerStorage.pickupObject(inputData.getLong(DataWorkerStorage.STORE_KEY, -1)) as NSAndroidClient.ReadResponse>? + val treatments = dataWorkerStorage.pickupObject(inputData.getLong(DataWorkerStorage.STORE_KEY, -1)) as List? ?: return Result.failure(workDataOf("Error" to "missing input data")) try { var latestDateInReceivedData: Long = 0 - for (treatment in treatments.values) { + for (treatment in treatments) { aapsLogger.debug(LTag.DATABASE, "Received NS treatment: $treatment") val date = treatment.date ?: continue if (date > latestDateInReceivedData) latestDateInReceivedData = date @@ -139,7 +138,7 @@ class ProcessTreatmentsWorker( // xDripBroadcast.sendTreatments(treatments) } catch (error: Exception) { aapsLogger.error("Error: ", error) - rxBus.send(EventNSClientNewLog("ERROR", error.localizedMessage)) + rxBus.send(EventNSClientNewLog("◄ ERROR", error.localizedMessage)) return Result.failure(workDataOf("Error" to error.localizedMessage)) } return Result.success() diff --git a/plugins/sync/src/main/res/values/strings.xml b/plugins/sync/src/main/res/values/strings.xml index ce19f868b7..44263daa2d 100644 --- a/plugins/sync/src/main/res/values/strings.xml +++ b/plugins/sync/src/main/res/values/strings.xml @@ -48,7 +48,7 @@ ns_client_autoscroll - ns_client_paused + ns_client_paused ns_log_app_started_event NSCLIENT has no write permission. Wrong API secret? @@ -171,5 +171,7 @@ Data Broadcaster + Connect to websockets + Enabling means: faster updates, receiving alarms and announcements and higher battery consumption similar to v1. All other uploaderds to NS must use v3 protocol. \ No newline at end of file diff --git a/plugins/sync/src/main/res/xml/pref_ns_client_v3.xml b/plugins/sync/src/main/res/xml/pref_ns_client_v3.xml index 79f5b522af..974a2b89d9 100644 --- a/plugins/sync/src/main/res/xml/pref_ns_client_v3.xml +++ b/plugins/sync/src/main/res/xml/pref_ns_client_v3.xml @@ -9,7 +9,7 @@ app:initialExpandedChildrenCount="0"> + validate:testType="minLength" /> + + Date: Tue, 24 Jan 2023 22:32:07 +0100 Subject: [PATCH 5/8] NSCv3: Connect to new alarm socket.io --- .../notifications/NotificationWithAction.kt | 4 +- .../sync/nsclient/services/NSClientService.kt | 4 +- .../sync/nsclientV3/NSClientV3Plugin.kt | 207 ++++++++---------- 3 files changed, 100 insertions(+), 115 deletions(-) diff --git a/plugins/main/src/main/java/info/nightscout/plugins/general/overview/notifications/NotificationWithAction.kt b/plugins/main/src/main/java/info/nightscout/plugins/general/overview/notifications/NotificationWithAction.kt index fe25a9823c..27c2be99fe 100644 --- a/plugins/main/src/main/java/info/nightscout/plugins/general/overview/notifications/NotificationWithAction.kt +++ b/plugins/main/src/main/java/info/nightscout/plugins/general/overview/notifications/NotificationWithAction.kt @@ -4,7 +4,6 @@ import dagger.android.HasAndroidInjector import info.nightscout.interfaces.notifications.Notification import info.nightscout.interfaces.nsclient.NSAlarm import info.nightscout.interfaces.plugin.ActivePlugin -import info.nightscout.interfaces.profile.DefaultValueHelper import info.nightscout.plugins.R import info.nightscout.rx.logging.AAPSLogger import info.nightscout.rx.logging.LTag @@ -21,7 +20,6 @@ class NotificationWithAction constructor( @Inject lateinit var aapsLogger: AAPSLogger @Inject lateinit var rh: ResourceHelper @Inject lateinit var sp: SP - @Inject lateinit var defaultValueHelper: DefaultValueHelper @Inject lateinit var activePlugin: ActivePlugin init { @@ -66,7 +64,7 @@ class NotificationWithAction constructor( aapsLogger.debug(LTag.NOTIFICATION, "Notification text is: $text") val msToSnooze = sp.getInt(info.nightscout.core.utils.R.string.key_ns_alarm_stale_data_value, 15) * 60 * 1000L aapsLogger.debug(LTag.NOTIFICATION, "snooze nsalarm_staledatavalue in minutes is ${T.msecs(msToSnooze).mins()} currentTimeMillis is: ${System.currentTimeMillis()}") - sp.putLong(info.nightscout.core.utils.R.string.key_snoozed_to, System.currentTimeMillis() + msToSnooze) + sp.putLong(rh.gs(info.nightscout.core.utils.R.string.key_snoozed_to) + nsAlarm.level(), System.currentTimeMillis() + msToSnooze) } } diff --git a/plugins/sync/src/main/java/info/nightscout/plugins/sync/nsclient/services/NSClientService.kt b/plugins/sync/src/main/java/info/nightscout/plugins/sync/nsclient/services/NSClientService.kt index affb7e1ab2..d130ad3d05 100644 --- a/plugins/sync/src/main/java/info/nightscout/plugins/sync/nsclient/services/NSClientService.kt +++ b/plugins/sync/src/main/java/info/nightscout/plugins/sync/nsclient/services/NSClientService.kt @@ -646,7 +646,7 @@ class NSClientService : DaggerService() { private fun handleAlarm(alarm: JSONObject) { val defaultVal = config.NSCLIENT if (sp.getBoolean(info.nightscout.core.utils.R.string.key_ns_alarms, defaultVal)) { - val snoozedTo = sp.getLong(info.nightscout.core.utils.R.string.key_snoozed_to, 0L) + val snoozedTo = sp.getLong(rh.gs(info.nightscout.core.utils.R.string.key_snoozed_to) + alarm.optString("level"), 0L) if (snoozedTo == 0L || System.currentTimeMillis() > snoozedTo) { val nsAlarm = NSAlarm(alarm) uiInteraction.addNotificationWithAction(injector, nsAlarm) @@ -659,7 +659,7 @@ class NSClientService : DaggerService() { private fun handleUrgentAlarm(alarm: JSONObject) { val defaultVal = config.NSCLIENT if (sp.getBoolean(info.nightscout.core.utils.R.string.key_ns_alarms, defaultVal)) { - val snoozedTo = sp.getLong(info.nightscout.core.utils.R.string.key_snoozed_to, 0L) + val snoozedTo = sp.getLong(rh.gs(info.nightscout.core.utils.R.string.key_snoozed_to) + alarm.optString("level"), 0L) if (snoozedTo == 0L || System.currentTimeMillis() > snoozedTo) { val nsAlarm = NSAlarm(alarm) uiInteraction.addNotificationWithAction(injector, nsAlarm) diff --git a/plugins/sync/src/main/java/info/nightscout/plugins/sync/nsclientV3/NSClientV3Plugin.kt b/plugins/sync/src/main/java/info/nightscout/plugins/sync/nsclientV3/NSClientV3Plugin.kt index b80cb08de1..889e053f6b 100644 --- a/plugins/sync/src/main/java/info/nightscout/plugins/sync/nsclientV3/NSClientV3Plugin.kt +++ b/plugins/sync/src/main/java/info/nightscout/plugins/sync/nsclientV3/NSClientV3Plugin.kt @@ -35,7 +35,6 @@ import info.nightscout.interfaces.sync.NsClient import info.nightscout.interfaces.sync.Sync import info.nightscout.interfaces.ui.UiInteraction import info.nightscout.interfaces.utils.HtmlHelper -import info.nightscout.interfaces.utils.JsonHelper import info.nightscout.interfaces.workflow.WorkerClasses import info.nightscout.plugins.sync.R import info.nightscout.plugins.sync.nsShared.NSClientFragment @@ -192,9 +191,9 @@ class NSClientV3Plugin @Inject constructor( .toObservable(EventNSConnectivityOptionChanged::class.java) .observeOn(aapsSchedulers.io) .subscribe({ ev -> - rxBus.send(EventNSClientNewLog("● CONNECTIVITY CHANGE", ev.blockingReason)) - setClient("CONNECTIVITY_CHANGE") - if (isAllowed) executeLoop("CONNECTIVITY_CHANGE", forceNew = false) + rxBus.send(EventNSClientNewLog("● CONNECTIVITY", ev.blockingReason)) + setClient("CONNECTIVITY") + if (isAllowed) executeLoop("CONNECTIVITY", forceNew = false) }, fabricPrivacy::logException) disposable += rxBus .toObservable(EventPreferenceChange::class.java) @@ -269,7 +268,8 @@ class NSClientV3Plugin @Inject constructor( override fun onStop() { handler.removeCallbacksAndMessages(null) disposable.clear() - socket?.disconnect() + storageSocket?.disconnect() + alarmSocket?.disconnect() super.onStop() } @@ -300,8 +300,10 @@ class NSClientV3Plugin @Inject constructor( context = context, logging = true ) - if (wsConnected) - socket?.disconnect() + if (wsConnected) { + storageSocket?.disconnect() + alarmSocket?.disconnect() + } SystemClock.sleep(2000) initializeWebSockets(reason) rxBus.send(EventSWSyncStatus(status)) @@ -310,32 +312,36 @@ class NSClientV3Plugin @Inject constructor( /********************** WS code **********************/ - private var connectCounter = 0 - private var socket: Socket? = null + private var storageSocket: Socket? = null + private var alarmSocket: Socket? = null var wsConnected = false internal var initialLoadFinished = false private fun initializeWebSockets(reason: String) { if (!sp.getBoolean(info.nightscout.core.utils.R.string.key_ns_use_ws, true)) return - val url = sp.getString(info.nightscout.core.utils.R.string.key_nsclientinternal_url, "").lowercase().replace(Regex("/$"), "") + "/storage" + if (sp.getString(info.nightscout.core.utils.R.string.key_nsclientinternal_url, "").isEmpty()) return + val urlStorage = sp.getString(info.nightscout.core.utils.R.string.key_nsclientinternal_url, "").lowercase().replace(Regex("/$"), "") + "/storage" + val urlAlarm = sp.getString(info.nightscout.core.utils.R.string.key_nsclientinternal_url, "").lowercase().replace(Regex("/$"), "") + "/alarm" if (!isAllowed) { rxBus.send(EventNSClientNewLog("● WS", blockingReason)) } else if (sp.getBoolean(R.string.key_ns_paused, false)) { rxBus.send(EventNSClientNewLog("● WS", "paused")) - } else if (url != "") { + } else { try { - //rxBus.send(EventNSClientStatus("Connecting ...")) - val opt = IO.Options().also { - it.forceNew = true - //it.webSocketFactory = nsAndroidClient. - } - socket = IO.socket(url, opt).also { socket -> - socket.on(Socket.EVENT_CONNECT, onConnect) - socket.on(Socket.EVENT_DISCONNECT, onDisconnect) - rxBus.send(EventNSClientNewLog("► WS", "do connect $reason")) + // java io.client doesn't support multiplexing. create 2 sockets + storageSocket = IO.socket(urlStorage).also { socket -> + socket.on(Socket.EVENT_CONNECT, onConnectStorage) + socket.on(Socket.EVENT_DISCONNECT, onDisconnectStorage) + rxBus.send(EventNSClientNewLog("► WS", "do connect storage $reason")) socket.connect() socket.on("create", onDataCreateUpdate) socket.on("update", onDataCreateUpdate) socket.on("delete", onDataDelete) + } + alarmSocket = IO.socket(urlAlarm).also { socket -> + socket.on(Socket.EVENT_CONNECT, onConnectAlarms) + socket.on(Socket.EVENT_DISCONNECT, onDisconnectAlarm) + rxBus.send(EventNSClientNewLog("► WS", "do connect alarm $reason")) + socket.connect() socket.on("announcement", onAnnouncement) socket.on("alarm", onAlarm) socket.on("urgent_alarm", onUrgentAlarm) @@ -346,22 +352,19 @@ class NSClientV3Plugin @Inject constructor( } catch (e: RuntimeException) { rxBus.send(EventNSClientNewLog("● WS", "RuntimeException")) } - } else { - rxBus.send(EventNSClientNewLog("● WS", "No NS URL specified")) } } - private val onConnect = Emitter.Listener { - connectCounter++ - val socketId = socket?.id() ?: "NULL" - rxBus.send(EventNSClientNewLog("◄ WS", "connect #$connectCounter event. ID: $socketId")) - if (socket != null) { + private val onConnectStorage = Emitter.Listener { + val socketId = storageSocket?.id() ?: "NULL" + rxBus.send(EventNSClientNewLog("◄ WS", "connected storage ID: $socketId")) + if (storageSocket != null) { val authMessage = JSONObject().also { it.put("accessToken", sp.getString(R.string.key_ns_client_token, "")) - it.put("collections", JSONArray(arrayOf("devicestatus", "entries", "profile", "treatments", "foods", "settings"))) + it.put("collections", JSONArray(arrayOf("devicestatus", "entries", "profile", "treatments", "foods", "settings"))) } - rxBus.send(EventNSClientNewLog("► WS", "requesting auth")) - socket?.emit("subscribe", authMessage, Ack { args -> + rxBus.send(EventNSClientNewLog("► WS", "requesting auth for storage")) + storageSocket?.emit("subscribe", authMessage, Ack { args -> val response = args[0] as JSONObject wsConnected = if (response.optBoolean("success")) { rxBus.send(EventNSClientNewLog("◄ WS", "Subscribed for: ${response.optString("collections")}")) @@ -374,12 +377,39 @@ class NSClientV3Plugin @Inject constructor( } } - private val onDisconnect = Emitter.Listener { args -> - aapsLogger.debug(LTag.NSCLIENT, "disconnect reason: ${args[0]}") - rxBus.send(EventNSClientNewLog("◄ WS", "disconnect event")) + private val onConnectAlarms = Emitter.Listener { + val socketId = alarmSocket?.id() ?: "NULL" + rxBus.send(EventNSClientNewLog("◄ WS", "connected alarms ID: $socketId")) + if (alarmSocket != null) { + val authMessage = JSONObject().also { + it.put("accessToken", sp.getString(R.string.key_ns_client_token, "")) + } + rxBus.send(EventNSClientNewLog("► WS", "requesting auth for alarms")) + alarmSocket?.emit("subscribe", authMessage, Ack { args -> + val response = args[0] as JSONObject + wsConnected = if (response.optBoolean("success")) { + rxBus.send(EventNSClientNewLog("◄ WS", response.optString("message"))) + true + } else { + rxBus.send(EventNSClientNewLog("◄ WS", "Auth failed")) + false + } + }) + } + } + + private val onDisconnectStorage = Emitter.Listener { args -> + aapsLogger.debug(LTag.NSCLIENT, "disconnect storage reason: ${args[0]}") + rxBus.send(EventNSClientNewLog("◄ WS", "disconnect storage event")) wsConnected = false initialLoadFinished = false - socket = null + storageSocket = null + } + + private val onDisconnectAlarm = Emitter.Listener { args -> + aapsLogger.debug(LTag.NSCLIENT, "disconnect alarm reason: ${args[0]}") + rxBus.send(EventNSClientNewLog("◄ WS", "disconnect alarm event")) + alarmSocket = null } private val onDataCreateUpdate = Emitter.Listener { args -> @@ -454,13 +484,11 @@ class NSClientV3Plugin @Inject constructor( "key":"9ac46ad9a1dcda79dd87dae418fce0e7955c68da" } */ - val data: JSONObject - try { - data = args[0] as JSONObject - handleAnnouncement(data) - } catch (e: Exception) { - aapsLogger.error("Unhandled exception", e) - } + val data = args[0] as JSONObject + rxBus.send(EventNSClientNewLog("◄ ANNOUNCEMENT", data.optString("message"))) + aapsLogger.debug(LTag.NSCLIENT, data.toString()) + if (sp.getBoolean(info.nightscout.core.utils.R.string.key_ns_announcements, config.NSCLIENT)) + uiInteraction.addNotificationWithAction(injector, NSAlarm(data)) } private val onAlarm = Emitter.Listener { args -> @@ -477,23 +505,27 @@ class NSClientV3Plugin @Inject constructor( "key":"simplealarms_1" } */ - val data: JSONObject - try { - data = args[0] as JSONObject - handleAlarm(data) - } catch (e: Exception) { - aapsLogger.error("Unhandled exception", e) + val data = args[0] as JSONObject + rxBus.send(EventNSClientNewLog("◄ ALARM", data.optString("message"))) + aapsLogger.debug(LTag.NSCLIENT, data.toString()) + if (sp.getBoolean(info.nightscout.core.utils.R.string.key_ns_alarms, config.NSCLIENT)) { + val snoozedTo = sp.getLong(rh.gs(info.nightscout.core.utils.R.string.key_snoozed_to) + data.optString("level"), 0L) + if (snoozedTo == 0L || System.currentTimeMillis() > snoozedTo) + uiInteraction.addNotificationWithAction(injector, NSAlarm(data)) } } + private val onUrgentAlarm = Emitter.Listener { args: Array -> - val data: JSONObject - try { - data = args[0] as JSONObject - handleUrgentAlarm(data) - } catch (e: Exception) { - aapsLogger.error("Unhandled exception", e) + val data = args[0] as JSONObject + rxBus.send(EventNSClientNewLog("◄ URGENT ALARM", data.optString("message"))) + aapsLogger.debug(LTag.NSCLIENT, data.toString()) + if (sp.getBoolean(info.nightscout.core.utils.R.string.key_ns_alarms, config.NSCLIENT)) { + val snoozedTo = sp.getLong(rh.gs(info.nightscout.core.utils.R.string.key_snoozed_to) + data.optString("level"), 0L) + if (snoozedTo == 0L || System.currentTimeMillis() > snoozedTo) + uiInteraction.addNotificationWithAction(injector, NSAlarm(data)) } } + private val onClearAlarm = Emitter.Listener { args -> /* @@ -504,52 +536,21 @@ class NSClientV3Plugin @Inject constructor( "group":"default" } */ - val data: JSONObject - try { - data = args[0] as JSONObject - rxBus.send(EventNSClientNewLog("CLEARALARM", "received")) - rxBus.send(EventDismissNotification(Notification.NS_ALARM)) - rxBus.send(EventDismissNotification(Notification.NS_URGENT_ALARM)) - aapsLogger.debug(LTag.NSCLIENT, data.toString()) - } catch (e: Exception) { - aapsLogger.error("Unhandled exception", e) - } + val data = args[0] as JSONObject + rxBus.send(EventNSClientNewLog("◄ CLEARALARM", data.optString("title"))) + aapsLogger.debug(LTag.NSCLIENT, data.toString()) + rxBus.send(EventDismissNotification(Notification.NS_ALARM)) + rxBus.send(EventDismissNotification(Notification.NS_URGENT_ALARM)) } - private fun handleAnnouncement(announcement: JSONObject) { - val defaultVal = config.NSCLIENT - if (sp.getBoolean(info.nightscout.core.utils.R.string.key_ns_announcements, defaultVal)) { - val nsAlarm = NSAlarm(announcement) - uiInteraction.addNotificationWithAction(injector, nsAlarm) - rxBus.send(EventNSClientNewLog("ANNOUNCEMENT", JsonHelper.safeGetString(announcement, "message", "received"))) - aapsLogger.debug(LTag.NSCLIENT, announcement.toString()) - } - } - - private fun handleAlarm(alarm: JSONObject) { - val defaultVal = config.NSCLIENT - if (sp.getBoolean(info.nightscout.core.utils.R.string.key_ns_alarms, defaultVal)) { - val snoozedTo = sp.getLong(info.nightscout.core.utils.R.string.key_snoozed_to, 0L) - if (snoozedTo == 0L || System.currentTimeMillis() > snoozedTo) { - val nsAlarm = NSAlarm(alarm) - uiInteraction.addNotificationWithAction(injector, nsAlarm) - } - rxBus.send(EventNSClientNewLog("ALARM", JsonHelper.safeGetString(alarm, "message", "received"))) - aapsLogger.debug(LTag.NSCLIENT, alarm.toString()) - } - } - - private fun handleUrgentAlarm(alarm: JSONObject) { - val defaultVal = config.NSCLIENT - if (sp.getBoolean(info.nightscout.core.utils.R.string.key_ns_alarms, defaultVal)) { - val snoozedTo = sp.getLong(info.nightscout.core.utils.R.string.key_snoozed_to, 0L) - if (snoozedTo == 0L || System.currentTimeMillis() > snoozedTo) { - val nsAlarm = NSAlarm(alarm) - uiInteraction.addNotificationWithAction(injector, nsAlarm) - } - rxBus.send(EventNSClientNewLog("URGENTALARM", JsonHelper.safeGetString(alarm, "message", "received"))) - aapsLogger.debug(LTag.NSCLIENT, alarm.toString()) + override 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 } + alarmSocket?.emit("ack", originalAlarm.level(), originalAlarm.group(), silenceTimeInMilliseconds) + rxBus.send(EventNSClientNewLog("► ALARMACK ", "${originalAlarm.level()} ${originalAlarm.group()} $silenceTimeInMilliseconds")) } /********************** @@ -596,20 +597,6 @@ class NSClientV3Plugin @Inject constructor( override val address: String get() = sp.getString(info.nightscout.core.utils.R.string.key_nsclientinternal_url, "") - override 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 isFirstLoad(collection: NsClient.Collection) = when (collection) { NsClient.Collection.ENTRIES -> lastLoadedSrvModified.collections.entries == 0L From 2b49778697fb302d37d50041f18b132f7ac5099b Mon Sep 17 00:00:00 2001 From: Milos Kozak Date: Wed, 25 Jan 2023 13:55:56 +0100 Subject: [PATCH 6/8] NSCv3: use alarm socket only when needed --- .../nsclient/data/NSDeviceStatusHandler.kt | 2 + .../sync/nsclientV3/NSClientV3Plugin.kt | 27 +++++---- .../nsclient/NsClientReceiverDelegateTest.kt | 55 ++++++++++--------- .../sync/nsclientV3/NSClientV3PluginTest.kt | 11 +++- .../nsclientV3/workers/DataSyncWorkerTest.kt | 3 + .../nsclientV3/workers/LoadBgWorkerTest.kt | 11 ++-- 6 files changed, 66 insertions(+), 43 deletions(-) diff --git a/plugins/sync/src/main/java/info/nightscout/plugins/sync/nsclient/data/NSDeviceStatusHandler.kt b/plugins/sync/src/main/java/info/nightscout/plugins/sync/nsclient/data/NSDeviceStatusHandler.kt index ce92e64b82..ad1244872c 100644 --- a/plugins/sync/src/main/java/info/nightscout/plugins/sync/nsclient/data/NSDeviceStatusHandler.kt +++ b/plugins/sync/src/main/java/info/nightscout/plugins/sync/nsclient/data/NSDeviceStatusHandler.kt @@ -1,5 +1,6 @@ package info.nightscout.plugins.sync.nsclient.data +import info.nightscout.androidaps.annotations.OpenForTesting import info.nightscout.interfaces.Config import info.nightscout.interfaces.configBuilder.RunningConfiguration import info.nightscout.interfaces.nsclient.ProcessedDeviceStatusData @@ -65,6 +66,7 @@ import javax.inject.Singleton */ @Suppress("SpellCheckingInspection") @Singleton +@OpenForTesting class NSDeviceStatusHandler @Inject constructor( private val sp: SP, private val config: Config, diff --git a/plugins/sync/src/main/java/info/nightscout/plugins/sync/nsclientV3/NSClientV3Plugin.kt b/plugins/sync/src/main/java/info/nightscout/plugins/sync/nsclientV3/NSClientV3Plugin.kt index 889e053f6b..fb9de2267d 100644 --- a/plugins/sync/src/main/java/info/nightscout/plugins/sync/nsclientV3/NSClientV3Plugin.kt +++ b/plugins/sync/src/main/java/info/nightscout/plugins/sync/nsclientV3/NSClientV3Plugin.kt @@ -202,7 +202,9 @@ class NSClientV3Plugin @Inject constructor( if (ev.isChanged(rh.gs(R.string.key_ns_client_token)) || ev.isChanged(rh.gs(info.nightscout.core.utils.R.string.key_nsclientinternal_url)) || ev.isChanged(rh.gs(info.nightscout.core.utils.R.string.key_ns_use_ws)) || - ev.isChanged(rh.gs(R.string.key_ns_paused)) + ev.isChanged(rh.gs(R.string.key_ns_paused)) || + ev.isChanged(rh.gs(info.nightscout.core.utils.R.string.key_ns_alarms)) || + ev.isChanged(rh.gs(info.nightscout.core.utils.R.string.key_ns_announcements)) ) setClient("SETTING CHANGE") if (ev.isChanged(rh.gs(info.nightscout.core.utils.R.string.key_local_profile_last_change))) @@ -337,16 +339,19 @@ class NSClientV3Plugin @Inject constructor( socket.on("update", onDataCreateUpdate) socket.on("delete", onDataDelete) } - alarmSocket = IO.socket(urlAlarm).also { socket -> - socket.on(Socket.EVENT_CONNECT, onConnectAlarms) - socket.on(Socket.EVENT_DISCONNECT, onDisconnectAlarm) - rxBus.send(EventNSClientNewLog("► WS", "do connect alarm $reason")) - socket.connect() - socket.on("announcement", onAnnouncement) - socket.on("alarm", onAlarm) - socket.on("urgent_alarm", onUrgentAlarm) - socket.on("clear_alarm", onClearAlarm) - } + if (sp.getBoolean(info.nightscout.core.utils.R.string.key_ns_announcements, config.NSCLIENT) || + sp.getBoolean(info.nightscout.core.utils.R.string.key_ns_alarms, config.NSCLIENT) + ) + alarmSocket = IO.socket(urlAlarm).also { socket -> + socket.on(Socket.EVENT_CONNECT, onConnectAlarms) + socket.on(Socket.EVENT_DISCONNECT, onDisconnectAlarm) + rxBus.send(EventNSClientNewLog("► WS", "do connect alarm $reason")) + socket.connect() + socket.on("announcement", onAnnouncement) + socket.on("alarm", onAlarm) + socket.on("urgent_alarm", onUrgentAlarm) + socket.on("clear_alarm", onClearAlarm) + } } catch (e: URISyntaxException) { rxBus.send(EventNSClientNewLog("● WS", "Wrong URL syntax")) } catch (e: RuntimeException) { diff --git a/plugins/sync/src/test/java/info/nightscout/plugins/sync/nsclient/NsClientReceiverDelegateTest.kt b/plugins/sync/src/test/java/info/nightscout/plugins/sync/nsclient/NsClientReceiverDelegateTest.kt index 363f41b5ee..62b990ea56 100644 --- a/plugins/sync/src/test/java/info/nightscout/plugins/sync/nsclient/NsClientReceiverDelegateTest.kt +++ b/plugins/sync/src/test/java/info/nightscout/plugins/sync/nsclient/NsClientReceiverDelegateTest.kt @@ -1,6 +1,7 @@ package info.nightscout.plugins.sync.nsclient import info.nightscout.androidaps.TestBase +import info.nightscout.core.utils.fabric.FabricPrivacy import info.nightscout.interfaces.receivers.ReceiverStatusStore import info.nightscout.plugins.sync.R import info.nightscout.rx.bus.RxBus @@ -8,7 +9,7 @@ import info.nightscout.rx.events.EventChargingState import info.nightscout.rx.events.EventNetworkChange import info.nightscout.shared.interfaces.ResourceHelper import info.nightscout.shared.sharedPreferences.SP -import org.junit.Assert +import org.junit.jupiter.api.Assertions import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.Test import org.mockito.Mock @@ -18,28 +19,28 @@ class NsClientReceiverDelegateTest : TestBase() { @Mock lateinit var sp: SP @Mock lateinit var rh: ResourceHelper - val rxBus = RxBus(aapsSchedulers, aapsLogger) + @Mock lateinit var fabricPrivacy: FabricPrivacy + private val rxBus = RxBus(aapsSchedulers, aapsLogger) @Mock private lateinit var receiverStatusStore: ReceiverStatusStore private lateinit var sut: NsClientReceiverDelegate - @BeforeEach fun prepare() { //receiverStatusStore = ReceiverStatusStore(context, rxBus) - sut = NsClientReceiverDelegate(rxBus, rh, sp, receiverStatusStore) + sut = NsClientReceiverDelegate(rxBus, rh, sp, receiverStatusStore, aapsSchedulers, fabricPrivacy) } @Test fun testCalculateStatusChargingState() { `when`(sp.getBoolean(R.string.key_ns_battery, true)).thenReturn(true) `when`(sp.getBoolean(R.string.key_ns_charging, true)).thenReturn(false) - Assert.assertTrue(sut.calculateStatus(EventChargingState(false, 0))) - Assert.assertFalse(sut.calculateStatus(EventChargingState(true, 0))) + Assertions.assertTrue(sut.calculateStatus(EventChargingState(false, 0))) + Assertions.assertFalse(sut.calculateStatus(EventChargingState(true, 0))) `when`(sp.getBoolean(R.string.key_ns_battery, true)).thenReturn(false) `when`(sp.getBoolean(R.string.key_ns_charging, true)).thenReturn(true) - Assert.assertTrue(sut.calculateStatus(EventChargingState(true, 0))) - Assert.assertFalse(sut.calculateStatus(EventChargingState(false, 0))) + Assertions.assertTrue(sut.calculateStatus(EventChargingState(true, 0))) + Assertions.assertFalse(sut.calculateStatus(EventChargingState(false, 0))) } @Test @@ -48,41 +49,41 @@ class NsClientReceiverDelegateTest : TestBase() { `when`(sp.getBoolean(R.string.key_ns_allow_roaming, true)).thenReturn(true) `when`(sp.getBoolean(R.string.key_ns_wifi, true)).thenReturn(true) `when`(sp.getString(R.string.key_ns_wifi_ssids, "")).thenReturn("") - Assert.assertTrue(sut.calculateStatus(EventNetworkChange(mobileConnected = true, wifiConnected = false, roaming = true))) - Assert.assertTrue(sut.calculateStatus(EventNetworkChange(mobileConnected = true, wifiConnected = false, roaming = false))) - Assert.assertTrue(sut.calculateStatus(EventNetworkChange(ssid = "", mobileConnected = true, wifiConnected = true))) - Assert.assertTrue(sut.calculateStatus(EventNetworkChange(ssid = "", mobileConnected = false, wifiConnected = true))) - Assert.assertFalse(sut.calculateStatus(EventNetworkChange())) + Assertions.assertTrue(sut.calculateStatus(EventNetworkChange(mobileConnected = true, wifiConnected = false, roaming = true))) + Assertions.assertTrue(sut.calculateStatus(EventNetworkChange(mobileConnected = true, wifiConnected = false, roaming = false))) + Assertions.assertTrue(sut.calculateStatus(EventNetworkChange(ssid = "", mobileConnected = true, wifiConnected = true))) + Assertions.assertTrue(sut.calculateStatus(EventNetworkChange(ssid = "", mobileConnected = false, wifiConnected = true))) + Assertions.assertFalse(sut.calculateStatus(EventNetworkChange())) `when`(sp.getString(R.string.key_ns_wifi_ssids, "")).thenReturn("test") - Assert.assertTrue(sut.calculateStatus(EventNetworkChange(mobileConnected = true, wifiConnected = false, roaming = true))) - Assert.assertTrue(sut.calculateStatus(EventNetworkChange(mobileConnected = true, wifiConnected = false, roaming = false))) - Assert.assertTrue(sut.calculateStatus(EventNetworkChange(ssid = "", mobileConnected = true, wifiConnected = true))) - Assert.assertFalse(sut.calculateStatus(EventNetworkChange(ssid = "", mobileConnected = false, wifiConnected = true))) - Assert.assertTrue(sut.calculateStatus(EventNetworkChange(ssid = "test", mobileConnected = true, wifiConnected = true))) - Assert.assertTrue(sut.calculateStatus(EventNetworkChange(ssid = "test", mobileConnected = false, wifiConnected = true))) - Assert.assertFalse(sut.calculateStatus(EventNetworkChange())) + Assertions.assertTrue(sut.calculateStatus(EventNetworkChange(mobileConnected = true, wifiConnected = false, roaming = true))) + Assertions.assertTrue(sut.calculateStatus(EventNetworkChange(mobileConnected = true, wifiConnected = false, roaming = false))) + Assertions.assertTrue(sut.calculateStatus(EventNetworkChange(ssid = "", mobileConnected = true, wifiConnected = true))) + Assertions.assertFalse(sut.calculateStatus(EventNetworkChange(ssid = "", mobileConnected = false, wifiConnected = true))) + Assertions.assertTrue(sut.calculateStatus(EventNetworkChange(ssid = "test", mobileConnected = true, wifiConnected = true))) + Assertions.assertTrue(sut.calculateStatus(EventNetworkChange(ssid = "test", mobileConnected = false, wifiConnected = true))) + Assertions.assertFalse(sut.calculateStatus(EventNetworkChange())) `when`(sp.getBoolean(R.string.key_ns_cellular, true)).thenReturn(false) `when`(sp.getBoolean(R.string.key_ns_wifi, true)).thenReturn(true) `when`(sp.getBoolean(R.string.key_ns_allow_roaming, true)).thenReturn(true) `when`(sp.getString(R.string.key_ns_wifi_ssids, "")).thenReturn("") - Assert.assertTrue(sut.calculateStatus(EventNetworkChange(wifiConnected = true))) - Assert.assertFalse(sut.calculateStatus(EventNetworkChange())) - Assert.assertFalse(sut.calculateStatus(EventNetworkChange(mobileConnected = true))) + Assertions.assertTrue(sut.calculateStatus(EventNetworkChange(wifiConnected = true))) + Assertions.assertFalse(sut.calculateStatus(EventNetworkChange())) + Assertions.assertFalse(sut.calculateStatus(EventNetworkChange(mobileConnected = true))) `when`(sp.getBoolean(R.string.key_ns_cellular, true)).thenReturn(true) `when`(sp.getBoolean(R.string.key_ns_wifi, true)).thenReturn(true) `when`(sp.getBoolean(R.string.key_ns_allow_roaming, true)).thenReturn(false) `when`(sp.getString(R.string.key_ns_wifi_ssids, "")).thenReturn("") - Assert.assertTrue(sut.calculateStatus(EventNetworkChange(mobileConnected = true, roaming = false))) - Assert.assertFalse(sut.calculateStatus(EventNetworkChange(mobileConnected = true, roaming = true))) + Assertions.assertTrue(sut.calculateStatus(EventNetworkChange(mobileConnected = true, roaming = false))) + Assertions.assertFalse(sut.calculateStatus(EventNetworkChange(mobileConnected = true, roaming = true))) `when`(sp.getBoolean(R.string.key_ns_cellular, true)).thenReturn(true) `when`(sp.getBoolean(R.string.key_ns_wifi, true)).thenReturn(true) `when`(sp.getBoolean(R.string.key_ns_allow_roaming, true)).thenReturn(true) `when`(sp.getString(R.string.key_ns_wifi_ssids, "")).thenReturn("") - Assert.assertTrue(sut.calculateStatus(EventNetworkChange(mobileConnected = true, roaming = false))) - Assert.assertTrue(sut.calculateStatus(EventNetworkChange(mobileConnected = true, roaming = true))) + Assertions.assertTrue(sut.calculateStatus(EventNetworkChange(mobileConnected = true, roaming = false))) + Assertions.assertTrue(sut.calculateStatus(EventNetworkChange(mobileConnected = true, roaming = true))) } } \ No newline at end of file diff --git a/plugins/sync/src/test/java/info/nightscout/plugins/sync/nsclientV3/NSClientV3PluginTest.kt b/plugins/sync/src/test/java/info/nightscout/plugins/sync/nsclientV3/NSClientV3PluginTest.kt index b6bd808f5f..3d9e788eaa 100644 --- a/plugins/sync/src/test/java/info/nightscout/plugins/sync/nsclientV3/NSClientV3PluginTest.kt +++ b/plugins/sync/src/test/java/info/nightscout/plugins/sync/nsclientV3/NSClientV3PluginTest.kt @@ -1,9 +1,11 @@ package info.nightscout.plugins.sync.nsclientV3 +import androidx.work.WorkManager import dagger.android.AndroidInjector import dagger.android.HasAndroidInjector import info.nightscout.androidaps.TestBaseWithProfile import info.nightscout.core.extensions.fromConstant +import info.nightscout.core.utils.receivers.DataWorkerStorage import info.nightscout.database.entities.Bolus import info.nightscout.database.entities.BolusCalculatorResult import info.nightscout.database.entities.Carbs @@ -26,8 +28,10 @@ import info.nightscout.interfaces.pump.VirtualPump import info.nightscout.interfaces.source.NSClientSource import info.nightscout.interfaces.sync.DataSyncSelector import info.nightscout.interfaces.ui.UiInteraction +import info.nightscout.interfaces.workflow.WorkerClasses import info.nightscout.plugins.sync.nsShared.StoreDataForDbImpl import info.nightscout.plugins.sync.nsclient.NsClientReceiverDelegate +import info.nightscout.plugins.sync.nsclient.data.NSDeviceStatusHandler import info.nightscout.plugins.sync.nsclient.extensions.fromConstant import info.nightscout.sdk.interfaces.NSAndroidClient import info.nightscout.sdk.localmodel.treatment.CreateUpdateResponse @@ -54,6 +58,10 @@ internal class NSClientV3PluginTest : TestBaseWithProfile() { @Mock lateinit var xDripBroadcast: XDripBroadcast @Mock lateinit var virtualPump: VirtualPump @Mock lateinit var mockedProfileFunction: ProfileFunction + @Mock lateinit var nsDeviceStatusHandler: NSDeviceStatusHandler + @Mock lateinit var workManager: WorkManager + @Mock lateinit var workerClasses: WorkerClasses + @Mock lateinit var dataWorkerStorage: DataWorkerStorage private lateinit var storeDataForDb: StoreDataForDb private lateinit var sut: NSClientV3Plugin @@ -69,7 +77,8 @@ internal class NSClientV3PluginTest : TestBaseWithProfile() { sut = NSClientV3Plugin( injector, aapsLogger, aapsSchedulers, rxBus, rh, context, fabricPrivacy, - sp, nsClientReceiverDelegate, config, dateUtil, uiInteraction, dataSyncSelector, mockedProfileFunction, repository + sp, nsClientReceiverDelegate, config, dateUtil, uiInteraction, dataSyncSelector, mockedProfileFunction, repository, + nsDeviceStatusHandler, workManager, workerClasses, dataWorkerStorage, nsClientSource ) sut.nsAndroidClient = nsAndroidClient `when`(mockedProfileFunction.getProfile(anyLong())).thenReturn(validProfile) diff --git a/plugins/sync/src/test/java/info/nightscout/plugins/sync/nsclientV3/workers/DataSyncWorkerTest.kt b/plugins/sync/src/test/java/info/nightscout/plugins/sync/nsclientV3/workers/DataSyncWorkerTest.kt index b32f80ba70..ba7cc4cf9b 100644 --- a/plugins/sync/src/test/java/info/nightscout/plugins/sync/nsclientV3/workers/DataSyncWorkerTest.kt +++ b/plugins/sync/src/test/java/info/nightscout/plugins/sync/nsclientV3/workers/DataSyncWorkerTest.kt @@ -9,6 +9,7 @@ import info.nightscout.core.utils.fabric.FabricPrivacy import info.nightscout.interfaces.plugin.ActivePlugin import info.nightscout.interfaces.sync.DataSyncSelector import info.nightscout.interfaces.sync.NsClient +import info.nightscout.plugins.sync.nsclientV3.NSClientV3Plugin import info.nightscout.rx.bus.RxBus import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.test.runTest @@ -27,6 +28,7 @@ internal class DataSyncWorkerTest : TestBase() { @Mock lateinit var activePlugin: ActivePlugin @Mock lateinit var nsClient: NsClient @Mock lateinit var rxBus: RxBus + @Mock lateinit var nsClientV3Plugin: NSClientV3Plugin private lateinit var sut: DataSyncWorker @@ -38,6 +40,7 @@ internal class DataSyncWorkerTest : TestBase() { it.dataSyncSelector = dataSyncSelector it.activePlugin = activePlugin it.rxBus = rxBus + it.nsClientV3Plugin = nsClientV3Plugin } } } diff --git a/plugins/sync/src/test/java/info/nightscout/plugins/sync/nsclientV3/workers/LoadBgWorkerTest.kt b/plugins/sync/src/test/java/info/nightscout/plugins/sync/nsclientV3/workers/LoadBgWorkerTest.kt index a6b0483b54..a909367a83 100644 --- a/plugins/sync/src/test/java/info/nightscout/plugins/sync/nsclientV3/workers/LoadBgWorkerTest.kt +++ b/plugins/sync/src/test/java/info/nightscout/plugins/sync/nsclientV3/workers/LoadBgWorkerTest.kt @@ -23,6 +23,7 @@ import info.nightscout.interfaces.sync.DataSyncSelector import info.nightscout.interfaces.ui.UiInteraction import info.nightscout.interfaces.workflow.WorkerClasses import info.nightscout.plugins.sync.nsclient.NsClientReceiverDelegate +import info.nightscout.plugins.sync.nsclient.data.NSDeviceStatusHandler import info.nightscout.plugins.sync.nsclientV3.NSClientV3Plugin import info.nightscout.plugins.sync.nsclientV3.extensions.toNSSvgV3 import info.nightscout.rx.bus.RxBus @@ -49,7 +50,6 @@ internal class LoadBgWorkerTest : TestBase() { @Mock lateinit var workerClasses: WorkerClasses @Mock lateinit var sp: SP @Mock lateinit var fabricPrivacy: FabricPrivacy - @Mock lateinit var rxBus: RxBus @Mock lateinit var dateUtil: DateUtil @Mock lateinit var nsAndroidClient: NSAndroidClient @Mock lateinit var rh: ResourceHelper @@ -62,7 +62,9 @@ internal class LoadBgWorkerTest : TestBase() { @Mock lateinit var nsClientSource: NSClientSource @Mock lateinit var workManager: WorkManager @Mock lateinit var workContinuation: WorkContinuation + @Mock lateinit var nsDeviceStatusHandler: NSDeviceStatusHandler + private val rxBus: RxBus = RxBus(aapsSchedulers, aapsLogger) private lateinit var nsClientV3Plugin: NSClientV3Plugin private lateinit var nsClientReceiverDelegate: NsClientReceiverDelegate private lateinit var dataWorkerStorage: DataWorkerStorage @@ -95,10 +97,11 @@ internal class LoadBgWorkerTest : TestBase() { Mockito.`when`(dateUtil.now()).thenReturn(now) Mockito.`when`(nsClientSource.isEnabled()).thenReturn(true) dataWorkerStorage = DataWorkerStorage(context) - nsClientReceiverDelegate = NsClientReceiverDelegate(rxBus, rh, sp, receiverStatusStore) + nsClientReceiverDelegate = NsClientReceiverDelegate(rxBus, rh, sp, receiverStatusStore, aapsSchedulers, fabricPrivacy) nsClientV3Plugin = NSClientV3Plugin( - injector, aapsLogger, aapsSchedulers, rxBus, rh, context, fabricPrivacy, sp, nsClientReceiverDelegate, config, dateUtil, uiInteraction, dataSyncSelector, - profileFunction, repository + injector, aapsLogger, aapsSchedulers, rxBus, rh, context, fabricPrivacy, + sp, nsClientReceiverDelegate, config, dateUtil, uiInteraction, dataSyncSelector, profileFunction, repository, + nsDeviceStatusHandler, workManager, workerClasses, dataWorkerStorage, nsClientSource ) nsClientV3Plugin.newestDataOnServer = LastModified(LastModified.Collections()) } From 26c0b7c896664a2f5763c30d74c95aea70a2d5d2 Mon Sep 17 00:00:00 2001 From: Milos Kozak Date: Sun, 29 Jan 2023 22:33:23 +0100 Subject: [PATCH 7/8] Tidepool: improve settings, upload & and enable --- .../nightscout/androidaps/di/AppModule.kt | 4 +- .../androidaps/di/PluginsListModule.kt | 2 +- core/ui/src/main/res/values/strings.xml | 2 +- .../aps/src/main/res/xml/pref_openapsama.xml | 2 +- .../aps/src/main/res/xml/pref_openapssmb.xml | 2 +- .../res/xml/pref_openapssmbdynamicisf.xml | 2 +- .../main/src/main/res/xml/pref_overview.xml | 2 +- .../src/main/res/xml/pref_absorption_aaps.xml | 2 +- .../main/res/xml/pref_absorption_oref1.xml | 2 +- ...d.kt => EventConnectivityOptionChanged.kt} | 2 +- .../plugins/sync/nsclient/NSClientPlugin.kt | 8 +- ...eceiverDelegate.kt => ReceiverDelegate.kt} | 6 +- .../sync/nsclient/services/NSClientService.kt | 4 +- .../sync/nsclientV3/NSClientV3Plugin.kt | 14 +-- .../plugins/sync/tidepool/TidepoolFragment.kt | 74 ++++++++++---- .../plugins/sync/tidepool/TidepoolPlugin.kt | 40 ++++---- .../sync/tidepool/comm/TidepoolUploader.kt | 26 +++-- .../plugins/sync/tidepool/comm/UploadChunk.kt | 15 +-- .../sync/tidepool/elements/ProfileElement.kt | 23 +++-- .../main/res/layout/ns_client_fragment.xml | 2 +- .../src/main/res/layout/tidepool_fragment.xml | 96 ++++++------------- plugins/sync/src/main/res/values/strings.xml | 7 -- .../sync/src/main/res/xml/pref_ns_client.xml | 5 +- .../src/main/res/xml/pref_ns_client_v3.xml | 5 +- .../sync/src/main/res/xml/pref_tidepool.xml | 80 +++++++++------- ...elegateTest.kt => ReceiverDelegateTest.kt} | 6 +- .../sync/nsclientV3/NSClientV3PluginTest.kt | 6 +- .../nsclientV3/workers/LoadBgWorkerTest.kt | 8 +- 28 files changed, 234 insertions(+), 213 deletions(-) rename plugins/sync/src/main/java/info/nightscout/plugins/sync/nsShared/events/{EventNSConnectivityOptionChanged.kt => EventConnectivityOptionChanged.kt} (55%) rename plugins/sync/src/main/java/info/nightscout/plugins/sync/nsclient/{NsClientReceiverDelegate.kt => ReceiverDelegate.kt} (95%) rename plugins/sync/src/test/java/info/nightscout/plugins/sync/nsclient/{NsClientReceiverDelegateTest.kt => ReceiverDelegateTest.kt} (96%) diff --git a/app/src/main/java/info/nightscout/androidaps/di/AppModule.kt b/app/src/main/java/info/nightscout/androidaps/di/AppModule.kt index 5c38128af0..a02cf5afc2 100644 --- a/app/src/main/java/info/nightscout/androidaps/di/AppModule.kt +++ b/app/src/main/java/info/nightscout/androidaps/di/AppModule.kt @@ -34,14 +34,14 @@ open class AppModule { @PluginsListModule.PumpDriver pumpDrivers: Lazy>, @PluginsListModule.NotNSClient notNsClient: Lazy>, @PluginsListModule.APS aps: Lazy>, - @PluginsListModule.Unfinished unfinished: Lazy> + //@PluginsListModule.Unfinished unfinished: Lazy> ) : List<@JvmSuppressWildcards PluginBase> { val plugins = allConfigs.toMutableMap() if (config.PUMPDRIVERS) plugins += pumpDrivers.get() if (config.APS) plugins += aps.get() if (!config.NSCLIENT) plugins += notNsClient.get() - if (config.isUnfinishedMode()) plugins += unfinished.get() + //if (config.isUnfinishedMode()) plugins += unfinished.get() return plugins.toList().sortedBy { it.first }.map { it.second } } diff --git a/app/src/main/java/info/nightscout/androidaps/di/PluginsListModule.kt b/app/src/main/java/info/nightscout/androidaps/di/PluginsListModule.kt index 7e1b89f547..e300898224 100644 --- a/app/src/main/java/info/nightscout/androidaps/di/PluginsListModule.kt +++ b/app/src/main/java/info/nightscout/androidaps/di/PluginsListModule.kt @@ -318,7 +318,7 @@ abstract class PluginsListModule { abstract fun bindNSClientV3Plugin(plugin: NSClientV3Plugin): PluginBase @Binds - @Unfinished + @NotNSClient @IntoMap @IntKey(360) abstract fun bindTidepoolPlugin(plugin: TidepoolPlugin): PluginBase diff --git a/core/ui/src/main/res/values/strings.xml b/core/ui/src/main/res/values/strings.xml index 4f5f9b7ff3..a0e6dd9b13 100644 --- a/core/ui/src/main/res/values/strings.xml +++ b/core/ui/src/main/res/values/strings.xml @@ -45,7 +45,7 @@ Mute for 5 minutes Mute Success - Advanced Settings + Advanced Settings Extended bolus delivery error APS Mode Extended bolus diff --git a/plugins/aps/src/main/res/xml/pref_openapsama.xml b/plugins/aps/src/main/res/xml/pref_openapsama.xml index e1d6444080..155b434ef0 100644 --- a/plugins/aps/src/main/res/xml/pref_openapsama.xml +++ b/plugins/aps/src/main/res/xml/pref_openapsama.xml @@ -52,7 +52,7 @@ + android:title="@string/advanced_settings_title"> + android:title="@string/advanced_settings_title"> + android:title="@string/advanced_settings_title"> + android:title="@string/advanced_settings_title"> + android:title="@string/advanced_settings_title"> + android:title="@string/advanced_settings_title"> rxBus.send(EventNSClientNewLog("● CONNECTIVITY", ev.blockingReason)) diff --git a/plugins/sync/src/main/java/info/nightscout/plugins/sync/tidepool/TidepoolFragment.kt b/plugins/sync/src/main/java/info/nightscout/plugins/sync/tidepool/TidepoolFragment.kt index eb4eeef486..827d8c5a2c 100644 --- a/plugins/sync/src/main/java/info/nightscout/plugins/sync/tidepool/TidepoolFragment.kt +++ b/plugins/sync/src/main/java/info/nightscout/plugins/sync/tidepool/TidepoolFragment.kt @@ -2,9 +2,14 @@ package info.nightscout.plugins.sync.tidepool import android.os.Bundle import android.view.LayoutInflater +import android.view.Menu +import android.view.MenuInflater +import android.view.MenuItem import android.view.View import android.view.ViewGroup import android.widget.ScrollView +import androidx.core.view.MenuProvider +import androidx.lifecycle.Lifecycle import dagger.android.support.DaggerFragment import info.nightscout.core.utils.fabric.FabricPrivacy import info.nightscout.plugins.sync.R @@ -15,12 +20,13 @@ import info.nightscout.plugins.sync.tidepool.events.EventTidepoolResetData import info.nightscout.plugins.sync.tidepool.events.EventTidepoolUpdateGUI import info.nightscout.rx.AapsSchedulers import info.nightscout.rx.bus.RxBus +import info.nightscout.shared.interfaces.ResourceHelper import info.nightscout.shared.sharedPreferences.SP import io.reactivex.rxjava3.disposables.CompositeDisposable import io.reactivex.rxjava3.kotlin.plusAssign import javax.inject.Inject -class TidepoolFragment : DaggerFragment() { +class TidepoolFragment : DaggerFragment(), MenuProvider { @Inject lateinit var rxBus: RxBus @Inject lateinit var tidepoolPlugin: TidepoolPlugin @@ -28,6 +34,15 @@ class TidepoolFragment : DaggerFragment() { @Inject lateinit var sp: SP @Inject lateinit var fabricPrivacy: FabricPrivacy @Inject lateinit var aapsSchedulers: AapsSchedulers + @Inject lateinit var rh: ResourceHelper + + companion object { + + const val ID_MENU_LOGIN = 530 + const val ID_MENU_SEND_NOW = 531 + const val ID_MENU_REMOVE_ALL = 532 + const val ID_MENU_FULL_SYNC = 533 + } private var disposable: CompositeDisposable = CompositeDisposable() @@ -39,31 +54,59 @@ class TidepoolFragment : DaggerFragment() { override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View { _binding = TidepoolFragmentBinding.inflate(inflater, container, false) + requireActivity().addMenuProvider(this, viewLifecycleOwner, Lifecycle.State.RESUMED) return binding.root } - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { - super.onViewCreated(view, savedInstanceState) - binding.login.setOnClickListener { tidepoolUploader.doLogin(false) } - binding.uploadnow.setOnClickListener { rxBus.send(EventTidepoolDoUpload()) } - binding.removeall.setOnClickListener { rxBus.send(EventTidepoolResetData()) } - binding.resertstart.setOnClickListener { sp.putLong(R.string.key_tidepool_last_end, 0) } + override fun onCreateMenu(menu: Menu, inflater: MenuInflater) { + menu.add(Menu.FIRST, ID_MENU_LOGIN, 0, rh.gs(info.nightscout.core.ui.R.string.login)).setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER) + menu.add(Menu.FIRST, ID_MENU_SEND_NOW, 0, rh.gs(R.string.upload_now)).setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER) + menu.add(Menu.FIRST, ID_MENU_REMOVE_ALL, 0, rh.gs(R.string.remove_all)).setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER) + menu.add(Menu.FIRST, ID_MENU_FULL_SYNC, 0, rh.gs(R.string.full_sync)).setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER) + menu.setGroupDividerEnabled(true) } + override fun onMenuItemSelected(item: MenuItem): Boolean = + when (item.itemId) { + ID_MENU_LOGIN -> { + tidepoolUploader.doLogin(false) + true + } + + ID_MENU_SEND_NOW -> { + rxBus.send(EventTidepoolDoUpload()) + true + } + + ID_MENU_REMOVE_ALL -> { + rxBus.send(EventTidepoolResetData()) + true + } + + ID_MENU_FULL_SYNC -> { + sp.putLong(R.string.key_tidepool_last_end, 0) + true + } + + else -> false + } + @Synchronized override fun onResume() { super.onResume() disposable += rxBus .toObservable(EventTidepoolUpdateGUI::class.java) .observeOn(aapsSchedulers.main) - .subscribe({ - if (_binding == null) return@subscribe - tidepoolPlugin.updateLog() - binding.log.text = tidepoolPlugin.textLog - binding.status.text = tidepoolUploader.connectionStatus.name - binding.log.text = tidepoolPlugin.textLog - binding.logscrollview.fullScroll(ScrollView.FOCUS_DOWN) - }, fabricPrivacy::logException) + .subscribe({ updateGui() }, fabricPrivacy::logException) + updateGui() + } + + private fun updateGui() { + tidepoolPlugin.updateLog() + _binding?.log?.text = tidepoolPlugin.textLog + _binding?.status?.text = tidepoolUploader.connectionStatus.name + _binding?.log?.text = tidepoolPlugin.textLog + _binding?.logScrollview?.fullScroll(ScrollView.FOCUS_DOWN) } @Synchronized @@ -77,5 +120,4 @@ class TidepoolFragment : DaggerFragment() { super.onDestroyView() _binding = null } - } diff --git a/plugins/sync/src/main/java/info/nightscout/plugins/sync/tidepool/TidepoolPlugin.kt b/plugins/sync/src/main/java/info/nightscout/plugins/sync/tidepool/TidepoolPlugin.kt index 549c0e6f8f..521d21e66f 100644 --- a/plugins/sync/src/main/java/info/nightscout/plugins/sync/tidepool/TidepoolPlugin.kt +++ b/plugins/sync/src/main/java/info/nightscout/plugins/sync/tidepool/TidepoolPlugin.kt @@ -10,11 +10,12 @@ import info.nightscout.interfaces.Constants import info.nightscout.interfaces.plugin.PluginBase import info.nightscout.interfaces.plugin.PluginDescription import info.nightscout.interfaces.plugin.PluginType -import info.nightscout.interfaces.receivers.ReceiverStatusStore import info.nightscout.interfaces.sync.Sync import info.nightscout.interfaces.ui.UiInteraction import info.nightscout.interfaces.utils.HtmlHelper import info.nightscout.plugins.sync.R +import info.nightscout.plugins.sync.nsShared.events.EventConnectivityOptionChanged +import info.nightscout.plugins.sync.nsclient.ReceiverDelegate import info.nightscout.plugins.sync.tidepool.comm.TidepoolUploader import info.nightscout.plugins.sync.tidepool.comm.UploadChunk import info.nightscout.plugins.sync.tidepool.events.EventTidepoolDoUpload @@ -24,7 +25,7 @@ import info.nightscout.plugins.sync.tidepool.events.EventTidepoolUpdateGUI import info.nightscout.plugins.sync.tidepool.utils.RateLimit import info.nightscout.rx.AapsSchedulers import info.nightscout.rx.bus.RxBus -import info.nightscout.rx.events.EventNetworkChange +import info.nightscout.rx.events.EventNSClientNewLog import info.nightscout.rx.events.EventNewBG import info.nightscout.rx.events.EventPreferenceChange import info.nightscout.rx.logging.AAPSLogger @@ -50,7 +51,7 @@ class TidepoolPlugin @Inject constructor( private val uploadChunk: UploadChunk, private val sp: SP, private val rateLimit: RateLimit, - private val receiverStatusStore: ReceiverStatusStore, + private val receiverDelegate: ReceiverDelegate, private val uiInteraction: UiInteraction ) : Sync, PluginBase( PluginDescription() @@ -67,10 +68,18 @@ class TidepoolPlugin @Inject constructor( private val listLog = ArrayList() var textLog: Spanned = HtmlHelper.fromHtml("") + private val isAllowed get() = receiverDelegate.allowed - @Suppress("UNNECESSARY_NOT_NULL_ASSERTION") override fun onStart() { super.onStart() + disposable += rxBus + .toObservable(EventConnectivityOptionChanged::class.java) + .observeOn(aapsSchedulers.io) + .subscribe({ ev -> + rxBus.send(EventNSClientNewLog("● CONNECTIVITY", ev.blockingReason)) + tidepoolUploader.resetInstance() + if (isAllowed) doUpload() + }, fabricPrivacy::logException) disposable += rxBus .toObservable(EventTidepoolDoUpload::class.java) .observeOn(aapsSchedulers.io) @@ -94,17 +103,13 @@ class TidepoolPlugin @Inject constructor( disposable += rxBus .toObservable(EventNewBG::class.java) .observeOn(aapsSchedulers.io) - .filter { it.glucoseValueTimestamp != null } // better would be optional in API level >24 - .map { it.glucoseValueTimestamp!! } - .subscribe({ bgReadingTimestamp -> - if (bgReadingTimestamp < uploadChunk.getLastEnd()) - uploadChunk.setLastEnd(bgReadingTimestamp) - if (isEnabled() - && (!sp.getBoolean(R.string.key_tidepool_only_while_charging, false) || receiverStatusStore.isCharging) - && (!sp.getBoolean(R.string.key_tidepool_only_while_unmetered, false) || receiverStatusStore.isWifiConnected) - && rateLimit.rateLimit("tidepool-new-data-upload", T.mins(4).secs().toInt()) - ) - doUpload() + .subscribe({ + it.glucoseValueTimestamp?.let { bgReadingTimestamp -> + if (bgReadingTimestamp < uploadChunk.getLastEnd()) + uploadChunk.setLastEnd(bgReadingTimestamp) + if (isAllowed && rateLimit.rateLimit("tidepool-new-data-upload", T.mins(4).secs().toInt())) + doUpload() + } }, fabricPrivacy::logException) disposable += rxBus .toObservable(EventPreferenceChange::class.java) @@ -116,11 +121,6 @@ class TidepoolPlugin @Inject constructor( ) tidepoolUploader.resetInstance() }, fabricPrivacy::logException) - disposable += rxBus - .toObservable(EventNetworkChange::class.java) - .observeOn(aapsSchedulers.io) - .subscribe({}, fabricPrivacy::logException) // TODO start upload on wifi connect - } override fun onStop() { diff --git a/plugins/sync/src/main/java/info/nightscout/plugins/sync/tidepool/comm/TidepoolUploader.kt b/plugins/sync/src/main/java/info/nightscout/plugins/sync/tidepool/comm/TidepoolUploader.kt index bb1e8e930f..0e7b5374af 100644 --- a/plugins/sync/src/main/java/info/nightscout/plugins/sync/tidepool/comm/TidepoolUploader.kt +++ b/plugins/sync/src/main/java/info/nightscout/plugins/sync/tidepool/comm/TidepoolUploader.kt @@ -5,8 +5,8 @@ import android.os.PowerManager import android.os.SystemClock import info.nightscout.core.ui.dialogs.OKDialog import info.nightscout.interfaces.Config -import info.nightscout.interfaces.plugin.ActivePlugin import info.nightscout.plugins.sync.R +import info.nightscout.plugins.sync.nsclient.ReceiverDelegate import info.nightscout.plugins.sync.tidepool.events.EventTidepoolStatus import info.nightscout.plugins.sync.tidepool.messages.AuthReplyMessage import info.nightscout.plugins.sync.tidepool.messages.AuthRequestMessage @@ -37,11 +37,12 @@ class TidepoolUploader @Inject constructor( private val rh: ResourceHelper, private val sp: SP, private val uploadChunk: UploadChunk, - private val activePlugin: ActivePlugin, private val dateUtil: DateUtil, + private val receiverDelegate: ReceiverDelegate, private val config: Config ) { + private val isAllowed get() = receiverDelegate.allowed private var wl: PowerManager.WakeLock? = null companion object { @@ -57,7 +58,7 @@ class TidepoolUploader @Inject constructor( private var session: Session? = null enum class ConnectionStatus { - DISCONNECTED, CONNECTING, CONNECTED, FAILED + BLOCKED, DISCONNECTED, CONNECTING, CONNECTED, FAILED } var connectionStatus: ConnectionStatus = ConnectionStatus.DISCONNECTED @@ -87,7 +88,6 @@ class TidepoolUploader @Inject constructor( return Session(AuthRequestMessage.getAuthRequestHeader(sp), SESSION_TOKEN_HEADER, service) } - // TODO: call on preference change fun resetInstance() { retrofit = null aapsLogger.debug(LTag.TIDEPOOL, "Instance reset") @@ -96,6 +96,11 @@ class TidepoolUploader @Inject constructor( @Synchronized fun doLogin(doUpload: Boolean = false) { + if (!isAllowed) { + connectionStatus = ConnectionStatus.BLOCKED + aapsLogger.debug(LTag.TIDEPOOL, "Blocked by connectivity settings") + return + } if (connectionStatus == ConnectionStatus.CONNECTED || connectionStatus == ConnectionStatus.CONNECTING) { aapsLogger.debug(LTag.TIDEPOOL, "Already connected") return @@ -139,7 +144,6 @@ class TidepoolUploader @Inject constructor( "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") @@ -197,6 +201,11 @@ class TidepoolUploader @Inject constructor( @Synchronized fun doUpload() { + if (!isAllowed) { + connectionStatus = ConnectionStatus.BLOCKED + aapsLogger.debug(LTag.TIDEPOOL, "Blocked by connectivity settings") + return + } session.let { session -> if (session == null) { aapsLogger.error("Session is null, cannot proceed") @@ -231,7 +240,7 @@ class TidepoolUploader @Inject constructor( releaseWakeLock() uploadNext() }, { - connectionStatus = ConnectionStatus.FAILED + connectionStatus = ConnectionStatus.DISCONNECTED rxBus.send(EventTidepoolStatus(("Upload FAILED"))) releaseWakeLock() })) @@ -242,6 +251,11 @@ class TidepoolUploader @Inject constructor( } private fun uploadNext() { + if (!isAllowed) { + connectionStatus = ConnectionStatus.BLOCKED + aapsLogger.debug(LTag.TIDEPOOL, "Blocked by connectivity settings") + return + } if (uploadChunk.getLastEnd() < dateUtil.now() - T.mins(1).msecs()) { SystemClock.sleep(3000) aapsLogger.debug(LTag.TIDEPOOL, "Restarting doUpload. Last: " + dateUtil.dateAndTimeString(uploadChunk.getLastEnd())) diff --git a/plugins/sync/src/main/java/info/nightscout/plugins/sync/tidepool/comm/UploadChunk.kt b/plugins/sync/src/main/java/info/nightscout/plugins/sync/tidepool/comm/UploadChunk.kt index dc962f0f83..7f33da685b 100644 --- a/plugins/sync/src/main/java/info/nightscout/plugins/sync/tidepool/comm/UploadChunk.kt +++ b/plugins/sync/src/main/java/info/nightscout/plugins/sync/tidepool/comm/UploadChunk.kt @@ -69,16 +69,11 @@ class UploadChunk @Inject constructor( val records = LinkedList() - if (sp.getBoolean(R.string.key_tidepool_upload_bolus, true)) - records.addAll(getTreatments(start, end)) - if (sp.getBoolean(R.string.key_tidepool_upload_bg, true)) - records.addAll(getBloodTests(start, end)) - if (sp.getBoolean(R.string.key_tidepool_upload_tbr, true)) - records.addAll(getBasals(start, end)) - if (sp.getBoolean(R.string.key_tidepool_upload_cgm, true)) - records.addAll(getBgReadings(start, end)) - if (sp.getBoolean(R.string.key_tidepool_upload_profile, true)) - records.addAll(getProfiles(start, end)) + records.addAll(getTreatments(start, end)) + records.addAll(getBloodTests(start, end)) + records.addAll(getBasals(start, end)) + records.addAll(getBgReadings(start, end)) + records.addAll(getProfiles(start, end)) return GsonInstance.defaultGsonInstance().toJson(records) } diff --git a/plugins/sync/src/main/java/info/nightscout/plugins/sync/tidepool/elements/ProfileElement.kt b/plugins/sync/src/main/java/info/nightscout/plugins/sync/tidepool/elements/ProfileElement.kt index 297bee3ca5..ea6ed877fb 100644 --- a/plugins/sync/src/main/java/info/nightscout/plugins/sync/tidepool/elements/ProfileElement.kt +++ b/plugins/sync/src/main/java/info/nightscout/plugins/sync/tidepool/elements/ProfileElement.kt @@ -35,14 +35,21 @@ class ProfileElement(ps: EffectiveProfileSwitch, serialNumber: String, dateUtil: init { type = "pumpSettings" val profile: Profile = ProfileSealed.EPS(ps) - for (br in profile.getBasalValues()) - basalSchedules.Normal.add(BasalRate(br.timeAsSeconds * 1000, br.value)) - for (target in profile.getSingleTargetsMgdl()) - bgTargets.Normal.add(Target(target.timeAsSeconds * 1000, target.value.toInt())) - for (ic in profile.getIcsValues()) - carbRatios.Normal.add(Ratio(ic.timeAsSeconds * 1000, ic.value.toInt())) - for (isf in profile.getIsfsMgdlValues()) - insulinSensitivities.Normal.add(Ratio(isf.timeAsSeconds * 1000, isf.value.toInt())) + // for (br in profile.getBasalValues()) + // basalSchedules.Normal.add(BasalRate(br.timeAsSeconds * 1000, br.value)) + // for (target in profile.getSingleTargetsMgdl()) + // bgTargets.Normal.add(Target(target.timeAsSeconds * 1000, target.value.toInt())) + // for (ic in profile.getIcsValues()) + // carbRatios.Normal.add(Ratio(ic.timeAsSeconds * 1000, ic.value.toInt())) + // for (isf in profile.getIsfsMgdlValues()) + // insulinSensitivities.Normal.add(Ratio(isf.timeAsSeconds * 1000, isf.value.toInt())) + for (hour in 0..23) { + val seconds = hour * 3600 + basalSchedules.Normal.add(BasalRate(seconds * 1000, profile.getBasalTimeFromMidnight(seconds))) + bgTargets.Normal.add(Target(seconds * 1000, Profile.toMgdl((((profile.getTargetLowMgdlTimeFromMidnight(seconds) + profile.getTargetLowMgdlTimeFromMidnight(seconds))) / 2)).toInt())) + carbRatios.Normal.add(Ratio(seconds * 1000, profile.getIcTimeFromMidnight(seconds).toInt())) + insulinSensitivities.Normal.add(Ratio(seconds * 1000, profile.getIsfMgdlTimeFromMidnight(seconds).toInt())) + } } inner class BasalProfile internal constructor( diff --git a/plugins/sync/src/main/res/layout/ns_client_fragment.xml b/plugins/sync/src/main/res/layout/ns_client_fragment.xml index 3a92d3f400..8663f67361 100644 --- a/plugins/sync/src/main/res/layout/ns_client_fragment.xml +++ b/plugins/sync/src/main/res/layout/ns_client_fragment.xml @@ -3,7 +3,7 @@ android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" - tools:context=".sync.nsShared.NSClientFragment"> + tools:context="info.nightscout.plugins.sync.nsShared.NSClientFragment"> - + android:layout_height="match_parent" + tools:context="info.nightscout.plugins.sync.tidepool.TidepoolFragment"> - + android:layout_marginBottom="10dp" + android:layout_marginStart="5dp" + android:layout_marginEnd="5dp" + android:orientation="horizontal"> - + - + - - - + + android:id="@+id/log_scrollview" + android:layout_width="fill_parent" + android:layout_height="fill_parent" + android:layout_marginStart="5dp" + android:layout_marginEnd="5dp"> - + android:text="" /> - + diff --git a/plugins/sync/src/main/res/values/strings.xml b/plugins/sync/src/main/res/values/strings.xml index 44263daa2d..3e2635dacf 100644 --- a/plugins/sync/src/main/res/values/strings.xml +++ b/plugins/sync/src/main/res/values/strings.xml @@ -115,14 +115,7 @@ tidepool_password tidepool_dev_servers tidepool_test_login - tidepool_only_while_charging - tidepool_only_while_unmetered tidepool_last_end - tidepool_upload_profile - tidepool_upload_tbr - tidepool_upload_cgm - tidepool_upload_bolus - tidepool_upload_bg Your Tidepool login user name, normally your email address Login User Name diff --git a/plugins/sync/src/main/res/xml/pref_ns_client.xml b/plugins/sync/src/main/res/xml/pref_ns_client.xml index c6f9cdb768..a3657bcad7 100644 --- a/plugins/sync/src/main/res/xml/pref_ns_client.xml +++ b/plugins/sync/src/main/res/xml/pref_ns_client.xml @@ -178,14 +178,13 @@ + android:title="@string/advanced_settings_title"> + android:summary="@string/ns_log_app_started_event" /> + android:title="@string/advanced_settings_title"> + android:summary="@string/ns_log_app_started_event" /> - + - + - + - + - + - + - + - + + + + + + + + diff --git a/plugins/sync/src/test/java/info/nightscout/plugins/sync/nsclient/NsClientReceiverDelegateTest.kt b/plugins/sync/src/test/java/info/nightscout/plugins/sync/nsclient/ReceiverDelegateTest.kt similarity index 96% rename from plugins/sync/src/test/java/info/nightscout/plugins/sync/nsclient/NsClientReceiverDelegateTest.kt rename to plugins/sync/src/test/java/info/nightscout/plugins/sync/nsclient/ReceiverDelegateTest.kt index 62b990ea56..6aa5d4f192 100644 --- a/plugins/sync/src/test/java/info/nightscout/plugins/sync/nsclient/NsClientReceiverDelegateTest.kt +++ b/plugins/sync/src/test/java/info/nightscout/plugins/sync/nsclient/ReceiverDelegateTest.kt @@ -15,7 +15,7 @@ import org.junit.jupiter.api.Test import org.mockito.Mock import org.mockito.Mockito.`when` -class NsClientReceiverDelegateTest : TestBase() { +class ReceiverDelegateTest : TestBase() { @Mock lateinit var sp: SP @Mock lateinit var rh: ResourceHelper @@ -23,12 +23,12 @@ class NsClientReceiverDelegateTest : TestBase() { private val rxBus = RxBus(aapsSchedulers, aapsLogger) @Mock private lateinit var receiverStatusStore: ReceiverStatusStore - private lateinit var sut: NsClientReceiverDelegate + private lateinit var sut: ReceiverDelegate @BeforeEach fun prepare() { //receiverStatusStore = ReceiverStatusStore(context, rxBus) - sut = NsClientReceiverDelegate(rxBus, rh, sp, receiverStatusStore, aapsSchedulers, fabricPrivacy) + sut = ReceiverDelegate(rxBus, rh, sp, receiverStatusStore, aapsSchedulers, fabricPrivacy) } @Test diff --git a/plugins/sync/src/test/java/info/nightscout/plugins/sync/nsclientV3/NSClientV3PluginTest.kt b/plugins/sync/src/test/java/info/nightscout/plugins/sync/nsclientV3/NSClientV3PluginTest.kt index 3d9e788eaa..dbc95ceff0 100644 --- a/plugins/sync/src/test/java/info/nightscout/plugins/sync/nsclientV3/NSClientV3PluginTest.kt +++ b/plugins/sync/src/test/java/info/nightscout/plugins/sync/nsclientV3/NSClientV3PluginTest.kt @@ -30,7 +30,7 @@ import info.nightscout.interfaces.sync.DataSyncSelector import info.nightscout.interfaces.ui.UiInteraction import info.nightscout.interfaces.workflow.WorkerClasses import info.nightscout.plugins.sync.nsShared.StoreDataForDbImpl -import info.nightscout.plugins.sync.nsclient.NsClientReceiverDelegate +import info.nightscout.plugins.sync.nsclient.ReceiverDelegate import info.nightscout.plugins.sync.nsclient.data.NSDeviceStatusHandler import info.nightscout.plugins.sync.nsclient.extensions.fromConstant import info.nightscout.sdk.interfaces.NSAndroidClient @@ -49,7 +49,7 @@ import org.mockito.internal.verification.Times @Suppress("SpellCheckingInspection") internal class NSClientV3PluginTest : TestBaseWithProfile() { - @Mock lateinit var nsClientReceiverDelegate: NsClientReceiverDelegate + @Mock lateinit var receiverDelegate: ReceiverDelegate @Mock lateinit var uiInteraction: UiInteraction @Mock lateinit var dataSyncSelector: DataSyncSelector @Mock lateinit var nsAndroidClient: NSAndroidClient @@ -77,7 +77,7 @@ internal class NSClientV3PluginTest : TestBaseWithProfile() { sut = NSClientV3Plugin( injector, aapsLogger, aapsSchedulers, rxBus, rh, context, fabricPrivacy, - sp, nsClientReceiverDelegate, config, dateUtil, uiInteraction, dataSyncSelector, mockedProfileFunction, repository, + sp, receiverDelegate, config, dateUtil, uiInteraction, dataSyncSelector, mockedProfileFunction, repository, nsDeviceStatusHandler, workManager, workerClasses, dataWorkerStorage, nsClientSource ) sut.nsAndroidClient = nsAndroidClient diff --git a/plugins/sync/src/test/java/info/nightscout/plugins/sync/nsclientV3/workers/LoadBgWorkerTest.kt b/plugins/sync/src/test/java/info/nightscout/plugins/sync/nsclientV3/workers/LoadBgWorkerTest.kt index a909367a83..33c7a48775 100644 --- a/plugins/sync/src/test/java/info/nightscout/plugins/sync/nsclientV3/workers/LoadBgWorkerTest.kt +++ b/plugins/sync/src/test/java/info/nightscout/plugins/sync/nsclientV3/workers/LoadBgWorkerTest.kt @@ -22,7 +22,7 @@ import info.nightscout.interfaces.source.NSClientSource import info.nightscout.interfaces.sync.DataSyncSelector import info.nightscout.interfaces.ui.UiInteraction import info.nightscout.interfaces.workflow.WorkerClasses -import info.nightscout.plugins.sync.nsclient.NsClientReceiverDelegate +import info.nightscout.plugins.sync.nsclient.ReceiverDelegate import info.nightscout.plugins.sync.nsclient.data.NSDeviceStatusHandler import info.nightscout.plugins.sync.nsclientV3.NSClientV3Plugin import info.nightscout.plugins.sync.nsclientV3.extensions.toNSSvgV3 @@ -66,7 +66,7 @@ internal class LoadBgWorkerTest : TestBase() { private val rxBus: RxBus = RxBus(aapsSchedulers, aapsLogger) private lateinit var nsClientV3Plugin: NSClientV3Plugin - private lateinit var nsClientReceiverDelegate: NsClientReceiverDelegate + private lateinit var receiverDelegate: ReceiverDelegate private lateinit var dataWorkerStorage: DataWorkerStorage private lateinit var sut: LoadBgWorker @@ -97,10 +97,10 @@ internal class LoadBgWorkerTest : TestBase() { Mockito.`when`(dateUtil.now()).thenReturn(now) Mockito.`when`(nsClientSource.isEnabled()).thenReturn(true) dataWorkerStorage = DataWorkerStorage(context) - nsClientReceiverDelegate = NsClientReceiverDelegate(rxBus, rh, sp, receiverStatusStore, aapsSchedulers, fabricPrivacy) + receiverDelegate = ReceiverDelegate(rxBus, rh, sp, receiverStatusStore, aapsSchedulers, fabricPrivacy) nsClientV3Plugin = NSClientV3Plugin( injector, aapsLogger, aapsSchedulers, rxBus, rh, context, fabricPrivacy, - sp, nsClientReceiverDelegate, config, dateUtil, uiInteraction, dataSyncSelector, profileFunction, repository, + sp, receiverDelegate, config, dateUtil, uiInteraction, dataSyncSelector, profileFunction, repository, nsDeviceStatusHandler, workManager, workerClasses, dataWorkerStorage, nsClientSource ) nsClientV3Plugin.newestDataOnServer = LastModified(LastModified.Collections()) From 50c1234630e7cf5149b6467facb6afa0eda796f4 Mon Sep 17 00:00:00 2001 From: Milos Kozak Date: Wed, 1 Feb 2023 07:49:23 +0100 Subject: [PATCH 8/8] Tidepool: cleanup, send data older than 3h --- .../database/entities/OfflineEvent.kt | 4 +- .../sync/tidepool/comm/InfoInterceptor.kt | 2 +- .../plugins/sync/tidepool/comm/Session.kt | 29 ++- .../sync/tidepool/comm/TidepoolCallback.kt | 9 +- .../sync/tidepool/comm/TidepoolUploader.kt | 170 ++++++++++-------- .../plugins/sync/tidepool/comm/UploadChunk.kt | 25 +-- .../sync/tidepool/elements/BasalElement.kt | 2 +- plugins/sync/src/main/res/values/strings.xml | 2 +- 8 files changed, 123 insertions(+), 120 deletions(-) diff --git a/database/entities/src/main/java/info/nightscout/database/entities/OfflineEvent.kt b/database/entities/src/main/java/info/nightscout/database/entities/OfflineEvent.kt index 3ba6a14b14..36c4281960 100644 --- a/database/entities/src/main/java/info/nightscout/database/entities/OfflineEvent.kt +++ b/database/entities/src/main/java/info/nightscout/database/entities/OfflineEvent.kt @@ -8,6 +8,7 @@ import androidx.room.PrimaryKey import info.nightscout.database.entities.embedments.InterfaceIDs import info.nightscout.database.entities.interfaces.DBEntryWithTimeAndDuration import info.nightscout.database.entities.interfaces.TraceableDBEntry +import info.nightscout.database.entities.interfaces.end import java.util.TimeZone @Entity( @@ -53,9 +54,6 @@ data class OfflineEvent( previous.interfaceIDs.nightscoutId == null && interfaceIDs.nightscoutId != null - fun isRecordDeleted(other: OfflineEvent): Boolean = - isValid && !other.isValid - enum class Reason { DISCONNECT_PUMP, SUSPEND, diff --git a/plugins/sync/src/main/java/info/nightscout/plugins/sync/tidepool/comm/InfoInterceptor.kt b/plugins/sync/src/main/java/info/nightscout/plugins/sync/tidepool/comm/InfoInterceptor.kt index 71987129f0..2eec303461 100644 --- a/plugins/sync/src/main/java/info/nightscout/plugins/sync/tidepool/comm/InfoInterceptor.kt +++ b/plugins/sync/src/main/java/info/nightscout/plugins/sync/tidepool/comm/InfoInterceptor.kt @@ -8,7 +8,7 @@ import okhttp3.Response import okio.Buffer import java.io.IOException -class InfoInterceptor(val tag: String = "interceptor", val aapsLogger: AAPSLogger) : Interceptor { +class InfoInterceptor(val aapsLogger: AAPSLogger) : Interceptor { @Throws(IOException::class) override fun intercept(chain: Interceptor.Chain): Response { diff --git a/plugins/sync/src/main/java/info/nightscout/plugins/sync/tidepool/comm/Session.kt b/plugins/sync/src/main/java/info/nightscout/plugins/sync/tidepool/comm/Session.kt index 4c425899b7..1d47adfd78 100644 --- a/plugins/sync/src/main/java/info/nightscout/plugins/sync/tidepool/comm/Session.kt +++ b/plugins/sync/src/main/java/info/nightscout/plugins/sync/tidepool/comm/Session.kt @@ -4,38 +4,37 @@ import info.nightscout.plugins.sync.tidepool.messages.AuthReplyMessage import info.nightscout.plugins.sync.tidepool.messages.DatasetReplyMessage import okhttp3.Headers -class Session(val authHeader: String?, - private val sessionTokenHeader: String, - val service: TidepoolApiService?) { +class Session( + val authHeader: String?, + private val sessionTokenHeader: String, + val service: TidepoolApiService? +) { internal var token: String? = null internal var authReply: AuthReplyMessage? = null internal var datasetReply: DatasetReplyMessage? = null internal var start: Long = 0 internal var end: Long = 0 + @Volatile internal var iterations: Int = 0 fun populateHeaders(headers: Headers) { if (this.token == null) { - this.token = headers.get(sessionTokenHeader) + this.token = headers[sessionTokenHeader] } } fun populateBody(obj: Any?) { - if (obj == null) return - if (obj is AuthReplyMessage) { - authReply = obj - } else if (obj is List<*>) { - val list = obj as? List<*>? + when (obj) { + is AuthReplyMessage -> authReply = obj - list?.getOrNull(0)?.let { - if (it is DatasetReplyMessage) { - datasetReply = it + is List<*> -> + (obj as? List<*>?)?.getOrNull(0)?.let { + if (it is DatasetReplyMessage) datasetReply = it } - } - } else if (obj is DatasetReplyMessage) { - datasetReply = obj + + is DatasetReplyMessage -> datasetReply = obj } } } diff --git a/plugins/sync/src/main/java/info/nightscout/plugins/sync/tidepool/comm/TidepoolCallback.kt b/plugins/sync/src/main/java/info/nightscout/plugins/sync/tidepool/comm/TidepoolCallback.kt index 9b06e3367a..b39c955fb8 100644 --- a/plugins/sync/src/main/java/info/nightscout/plugins/sync/tidepool/comm/TidepoolCallback.kt +++ b/plugins/sync/src/main/java/info/nightscout/plugins/sync/tidepool/comm/TidepoolCallback.kt @@ -8,7 +8,14 @@ import retrofit2.Call import retrofit2.Callback import retrofit2.Response -internal class TidepoolCallback(private val aapsLogger: AAPSLogger, private val rxBus: RxBus, private val session: Session, val name: String, val onSuccess: () -> Unit, val onFail: () -> Unit) : +internal class TidepoolCallback( + private val aapsLogger: AAPSLogger, + private val rxBus: RxBus, + private val session: Session, + private val name: String, + private val onSuccess: () -> Unit, + private val onFail: () -> Unit +) : Callback { override fun onResponse(call: Call, response: Response) { diff --git a/plugins/sync/src/main/java/info/nightscout/plugins/sync/tidepool/comm/TidepoolUploader.kt b/plugins/sync/src/main/java/info/nightscout/plugins/sync/tidepool/comm/TidepoolUploader.kt index 0e7b5374af..22066019d1 100644 --- a/plugins/sync/src/main/java/info/nightscout/plugins/sync/tidepool/comm/TidepoolUploader.kt +++ b/plugins/sync/src/main/java/info/nightscout/plugins/sync/tidepool/comm/TidepoolUploader.kt @@ -71,7 +71,7 @@ class TidepoolUploader @Inject constructor( val client = OkHttpClient.Builder() .addInterceptor(httpLoggingInterceptor) - .addInterceptor(InfoInterceptor(TidepoolUploader::class.java.name, aapsLogger)) + .addInterceptor(InfoInterceptor(aapsLogger)) .build() retrofit = Retrofit.Builder() @@ -114,12 +114,15 @@ class TidepoolUploader @Inject constructor( rxBus.send(EventTidepoolStatus(("Connecting"))) val call = session?.service?.getLogin(authHeader) - call?.enqueue(TidepoolCallback(aapsLogger, rxBus, session!!, "Login", { - startSession(session!!, doUpload) - }, { - connectionStatus = ConnectionStatus.FAILED - releaseWakeLock() - })) + call?.enqueue(TidepoolCallback( + aapsLogger, rxBus, session!!, "Login", + { + startSession(session!!, doUpload) + }, { + connectionStatus = ConnectionStatus.FAILED + releaseWakeLock() + }) + ) return } else { aapsLogger.debug(LTag.TIDEPOOL, "Cannot do login as user credentials have not been set correctly") @@ -135,15 +138,14 @@ class TidepoolUploader @Inject constructor( session.authHeader?.let { val call = session.service?.getLogin(it) - call?.enqueue(TidepoolCallback(aapsLogger, rxBus, session, "Login", { - OKDialog.show(rootContext, rh.gs(R.string.tidepool), "Successfully logged into Tidepool.") - }, { - OKDialog.show( - rootContext, - rh.gs(R.string.tidepool), - "Failed to log into Tidepool.\nCheck that your user name and password are correct." - ) - })) + call?.enqueue(TidepoolCallback( + aapsLogger, rxBus, session, "Login", + { + OKDialog.show(rootContext, rh.gs(R.string.tidepool), "Successfully logged into Tidepool.") + }, { + OKDialog.show(rootContext, rh.gs(R.string.tidepool), "Failed to log into Tidepool.\nCheck that your user name and password are correct.") + }) + ) } ?: OKDialog.show(rootContext, rh.gs(R.string.tidepool), "Cannot do login as user credentials have not been set correctly") @@ -158,39 +160,41 @@ class TidepoolUploader @Inject constructor( session.authReply!!.userid!!, "AAPS", 1 ) - datasetCall.enqueue(TidepoolCallback>(aapsLogger, rxBus, session, "Get Open Datasets", { - if (session.datasetReply == null) { - rxBus.send(EventTidepoolStatus(("Creating new dataset"))) - val call = session.service.openDataSet( - session.token!!, session.authReply!!.userid!!, - OpenDatasetRequestMessage(config, dateUtil).getBody() - ) - call.enqueue(TidepoolCallback(aapsLogger, rxBus, session, "Open New Dataset", { - connectionStatus = ConnectionStatus.CONNECTED - rxBus.send(EventTidepoolStatus(("New dataset OK"))) - if (doUpload) doUpload() - else - releaseWakeLock() + datasetCall.enqueue( + TidepoolCallback>( + aapsLogger, rxBus, session, "Get Open Datasets", + { + if (session.datasetReply == null) { + rxBus.send(EventTidepoolStatus(("Creating new dataset"))) + val call = session.service.openDataSet(session.token!!, session.authReply!!.userid!!, OpenDatasetRequestMessage(config, dateUtil).getBody()) + call.enqueue(TidepoolCallback( + aapsLogger, rxBus, session, "Open New Dataset", + { + connectionStatus = ConnectionStatus.CONNECTED + rxBus.send(EventTidepoolStatus(("New dataset OK"))) + if (doUpload) doUpload() + else releaseWakeLock() + }, { + rxBus.send(EventTidepoolStatus(("New dataset FAILED"))) + connectionStatus = ConnectionStatus.FAILED + releaseWakeLock() + }) + ) + } else { + aapsLogger.debug(LTag.TIDEPOOL, "Existing Dataset: " + session.datasetReply!!.getUploadId()) + // TODO: Wouldn't need to do this if we could block on the above `call.enqueue`. + // ie, do the openDataSet conditionally, and then do `doUpload` either way. + connectionStatus = ConnectionStatus.CONNECTED + rxBus.send(EventTidepoolStatus(("Appending to existing dataset"))) + if (doUpload) doUpload() + else releaseWakeLock() + } }, { - rxBus.send(EventTidepoolStatus(("New dataset FAILED"))) - connectionStatus = ConnectionStatus.FAILED - releaseWakeLock() - })) - } else { - aapsLogger.debug(LTag.TIDEPOOL, "Existing Dataset: " + session.datasetReply!!.getUploadId()) - // TODO: Wouldn't need to do this if we could block on the above `call.enqueue`. - // ie, do the openDataSet conditionally, and then do `doUpload` either way. - connectionStatus = ConnectionStatus.CONNECTED - rxBus.send(EventTidepoolStatus(("Appending to existing dataset"))) - if (doUpload) doUpload() - else + connectionStatus = ConnectionStatus.FAILED + rxBus.send(EventTidepoolStatus(("Open dataset FAILED"))) releaseWakeLock() - } - }, { - connectionStatus = ConnectionStatus.FAILED - rxBus.send(EventTidepoolStatus(("Open dataset FAILED"))) - releaseWakeLock() - })) + }) + ) } else { aapsLogger.error("Got login response but cannot determine userId - cannot proceed") connectionStatus = ConnectionStatus.FAILED @@ -234,16 +238,20 @@ class TidepoolUploader @Inject constructor( rxBus.send(EventTidepoolStatus(("Uploading"))) if (session.service != null && session.token != null && session.datasetReply != null) { val call = session.service.doUpload(session.token!!, session.datasetReply!!.getUploadId()!!, body) - call.enqueue(TidepoolCallback(aapsLogger, rxBus, session, "Data Upload", { - uploadChunk.setLastEnd(session.end) - rxBus.send(EventTidepoolStatus(("Upload completed OK"))) - releaseWakeLock() - uploadNext() - }, { - connectionStatus = ConnectionStatus.DISCONNECTED - rxBus.send(EventTidepoolStatus(("Upload FAILED"))) - releaseWakeLock() - })) + call.enqueue(TidepoolCallback( + aapsLogger, rxBus, session, "Data Upload", + { + uploadChunk.setLastEnd(session.end) + connectionStatus = ConnectionStatus.CONNECTED + rxBus.send(EventTidepoolStatus(("Upload completed OK"))) + releaseWakeLock() + uploadNext() + }, { + connectionStatus = ConnectionStatus.DISCONNECTED + rxBus.send(EventTidepoolStatus(("Upload FAILED"))) + releaseWakeLock() + }) + ) } } } @@ -256,7 +264,7 @@ class TidepoolUploader @Inject constructor( aapsLogger.debug(LTag.TIDEPOOL, "Blocked by connectivity settings") return } - if (uploadChunk.getLastEnd() < dateUtil.now() - T.mins(1).msecs()) { + if (uploadChunk.getLastEnd() < dateUtil.now() - T.hours(3).msecs() - T.mins(1).msecs()) { SystemClock.sleep(3000) aapsLogger.debug(LTag.TIDEPOOL, "Restarting doUpload. Last: " + dateUtil.dateAndTimeString(uploadChunk.getLastEnd())) doUpload() @@ -267,15 +275,18 @@ class TidepoolUploader @Inject constructor( if (session?.datasetReply?.id != null) { extendWakeLock(60000) val call = session!!.service?.deleteDataSet(session!!.token!!, session!!.datasetReply!!.id!!) - call?.enqueue(TidepoolCallback(aapsLogger, rxBus, session!!, "Delete Dataset", { - connectionStatus = ConnectionStatus.DISCONNECTED - rxBus.send(EventTidepoolStatus(("Dataset removed OK"))) - releaseWakeLock() - }, { - connectionStatus = ConnectionStatus.DISCONNECTED - rxBus.send(EventTidepoolStatus(("Dataset remove FAILED"))) - releaseWakeLock() - })) + call?.enqueue(TidepoolCallback( + aapsLogger, rxBus, session!!, "Delete Dataset", + { + connectionStatus = ConnectionStatus.DISCONNECTED + rxBus.send(EventTidepoolStatus(("Dataset removed OK"))) + releaseWakeLock() + }, { + connectionStatus = ConnectionStatus.DISCONNECTED + rxBus.send(EventTidepoolStatus(("Dataset remove FAILED"))) + releaseWakeLock() + }) + ) } else { aapsLogger.error("Got login response but cannot determine datasetId - cannot proceed") } @@ -292,15 +303,19 @@ class TidepoolUploader @Inject constructor( requireNotNull(userId) extendWakeLock(60000) val call = session.service?.deleteAllData(token, userId) - call?.enqueue(TidepoolCallback(aapsLogger, rxBus, session, "Delete all data", { - connectionStatus = ConnectionStatus.DISCONNECTED - rxBus.send(EventTidepoolStatus(("All data removed OK"))) - releaseWakeLock() - }, { - connectionStatus = ConnectionStatus.DISCONNECTED - rxBus.send(EventTidepoolStatus(("All data remove FAILED"))) - releaseWakeLock() - })) + call?.enqueue( + TidepoolCallback( + aapsLogger, rxBus, session, "Delete all data", + { + connectionStatus = ConnectionStatus.DISCONNECTED + rxBus.send(EventTidepoolStatus(("All data removed OK"))) + releaseWakeLock() + }, { + connectionStatus = ConnectionStatus.DISCONNECTED + rxBus.send(EventTidepoolStatus(("All data remove FAILED"))) + releaseWakeLock() + }) + ) } catch (e: IllegalArgumentException) { aapsLogger.error("Got login response but cannot determine userId - cannot proceed") } @@ -321,13 +336,12 @@ class TidepoolUploader @Inject constructor( @Synchronized private fun releaseWakeLock() { wl?.let { - if (it.isHeld) { + if (it.isHeld) try { it.release() } catch (e: Exception) { aapsLogger.error("Error releasing wakelock: $e") } - } } } diff --git a/plugins/sync/src/main/java/info/nightscout/plugins/sync/tidepool/comm/UploadChunk.kt b/plugins/sync/src/main/java/info/nightscout/plugins/sync/tidepool/comm/UploadChunk.kt index 7f33da685b..069c78a2f2 100644 --- a/plugins/sync/src/main/java/info/nightscout/plugins/sync/tidepool/comm/UploadChunk.kt +++ b/plugins/sync/src/main/java/info/nightscout/plugins/sync/tidepool/comm/UploadChunk.kt @@ -41,21 +41,21 @@ class UploadChunk @Inject constructor( private val maxUploadSize = T.days(7).msecs() // don't change this fun getNext(session: Session?): String? { - if (session == null) - return null + session ?: return null session.start = getLastEnd() - session.end = min(session.start + maxUploadSize, dateUtil.now()) + // do not upload last 3h, TBR can be still running + session.end = min(session.start + maxUploadSize, dateUtil.now() - T.hours(3).msecs()) val result = get(session.start, session.end) if (result.length < 3) { aapsLogger.debug(LTag.TIDEPOOL, "No records in this time period, setting start to best end time") - setLastEnd(max(session.end, getOldestRecordTimeStamp())) + setLastEnd(session.end) } return result } - operator fun get(start: Long, end: Long): String { + fun get(start: Long, end: Long): String { aapsLogger.debug(LTag.TIDEPOOL, "Syncing data between: " + dateUtil.dateAndTimeString(start) + " -> " + dateUtil.dateAndTimeString(end)) if (end <= start) { @@ -94,21 +94,6 @@ class UploadChunk @Inject constructor( } } - // numeric limits must match max time windows - - private fun getOldestRecordTimeStamp(): Long { - // TODO we could make sure we include records older than the first bg record for completeness - - val start: Long = 0 - val end = dateUtil.now() - - val bgReadingList = repository.compatGetBgReadingsDataFromTime(start, end, true) - .blockingGet() - return if (bgReadingList.isNotEmpty()) - bgReadingList[0].timestamp - else -1 - } - private fun getTreatments(start: Long, end: Long): List { val result = LinkedList() repository.getBolusesDataFromTimeToTime(start, end, true) diff --git a/plugins/sync/src/main/java/info/nightscout/plugins/sync/tidepool/elements/BasalElement.kt b/plugins/sync/src/main/java/info/nightscout/plugins/sync/tidepool/elements/BasalElement.kt index 154b4472f3..3b9b593a7c 100644 --- a/plugins/sync/src/main/java/info/nightscout/plugins/sync/tidepool/elements/BasalElement.kt +++ b/plugins/sync/src/main/java/info/nightscout/plugins/sync/tidepool/elements/BasalElement.kt @@ -7,7 +7,7 @@ import info.nightscout.interfaces.profile.Profile import info.nightscout.shared.utils.DateUtil import java.util.UUID -class BasalElement(tbr: TemporaryBasal, private val profile: Profile, dateUtil: DateUtil) +class BasalElement(tbr: TemporaryBasal, profile: Profile, dateUtil: DateUtil) : BaseElement(tbr.timestamp, UUID.nameUUIDFromBytes(("AAPS-basal" + tbr.timestamp).toByteArray()).toString(), dateUtil) { internal var timestamp: Long = 0 // not exposed diff --git a/plugins/sync/src/main/res/values/strings.xml b/plugins/sync/src/main/res/values/strings.xml index 58692fa694..c72206c238 100644 --- a/plugins/sync/src/main/res/values/strings.xml +++ b/plugins/sync/src/main/res/values/strings.xml @@ -11,7 +11,7 @@ ns_device_status_last_synced_id ns_temporary_basal_last_synced_id ns_extended_bolus_last_synced_id - profile_switch_last_synced_id + ns_profile_switch_last_synced_id ns_effective_profile_switch_last_synced_id ns_offline_event_last_synced_id ns_profile_store_last_synced_timestamp