diff --git a/app/src/main/java/info/nightscout/androidaps/MainActivity.kt b/app/src/main/java/info/nightscout/androidaps/MainActivity.kt index 6e3f5de1c2..0a4da54cf1 100644 --- a/app/src/main/java/info/nightscout/androidaps/MainActivity.kt +++ b/app/src/main/java/info/nightscout/androidaps/MainActivity.kt @@ -51,7 +51,6 @@ import info.nightscout.interfaces.aps.Loop import info.nightscout.interfaces.constraints.Constraints import info.nightscout.interfaces.logging.UserEntryLogger import info.nightscout.interfaces.maintenance.PrefFileListProvider -import info.nightscout.interfaces.nsclient.NSSettingsStatus import info.nightscout.interfaces.plugin.ActivePlugin import info.nightscout.interfaces.plugin.PluginBase import info.nightscout.interfaces.profile.ProfileFunction @@ -62,7 +61,6 @@ import info.nightscout.interfaces.versionChecker.VersionCheckerUtils import info.nightscout.plugins.constraints.signatureVerifier.SignatureVerifierPlugin import info.nightscout.rx.AapsSchedulers import info.nightscout.rx.events.EventAppExit -import info.nightscout.rx.events.EventInitializationChanged import info.nightscout.rx.events.EventPreferenceChange import info.nightscout.rx.events.EventRebuildTabs import info.nightscout.rx.logging.LTag @@ -88,7 +86,6 @@ class MainActivity : DaggerAppCompatActivityWithResult() { @Inject lateinit var versionCheckerUtils: VersionCheckerUtils @Inject lateinit var smsCommunicator: SmsCommunicator @Inject lateinit var loop: Loop - @Inject lateinit var nsSettingsStatus: NSSettingsStatus @Inject lateinit var config: Config @Inject lateinit var activePlugin: ActivePlugin @Inject lateinit var fabricPrivacy: FabricPrivacy @@ -347,7 +344,7 @@ class MainActivity : DaggerAppCompatActivityWithResult() { R.id.nav_about -> { var message = "Build: ${BuildConfig.BUILDVERSION}\n" message += "Flavor: ${BuildConfig.FLAVOR}${BuildConfig.BUILD_TYPE}\n" - message += "${rh.gs(info.nightscout.configuration.R.string.configbuilder_nightscoutversion_label)} ${nsSettingsStatus.getVersion()}" + message += "${rh.gs(info.nightscout.configuration.R.string.configbuilder_nightscoutversion_label)} ${activePlugin.activeNsClient?.detectedNsVersion() ?: rh.gs(info.nightscout.plugins.R.string.not_available_full)}" if (config.isEngineeringMode()) message += "\n${rh.gs(info.nightscout.configuration.R.string.engineering_mode_enabled)}" if (config.isUnfinishedMode()) message += "\nUnfinished mode enabled" if (!fabricPrivacy.fabricEnabled()) message += "\n${rh.gs(R.string.fabric_upload_disabled)}" diff --git a/core/interfaces/src/main/java/info/nightscout/interfaces/sync/NsClient.kt b/core/interfaces/src/main/java/info/nightscout/interfaces/sync/NsClient.kt index 56a39beb2e..51eae086c7 100644 --- a/core/interfaces/src/main/java/info/nightscout/interfaces/sync/NsClient.kt +++ b/core/interfaces/src/main/java/info/nightscout/interfaces/sync/NsClient.kt @@ -3,20 +3,44 @@ package info.nightscout.interfaces.sync import android.text.Spanned import info.nightscout.interfaces.nsclient.NSAlarm +/** + * Plugin providing communication with Nightscout server + */ interface NsClient : Sync { - enum class Version { - NONE, V1, V3 - } - val version: Version + /** + * NS URL + */ val address: String + /** + * Set plugin in paused state + */ fun pause(newState: Boolean) + + /** + * Initiate new round of upload/download + */ fun resend(reason: String) + + /** + * @return List last of messages for fragment in HTML format + */ fun textLog(): Spanned + + /** + * Clear list of stored messages displayed in fragment + */ fun clearLog() + /** + * Version of NS server + * @return Returns detected version of NS server + */ + fun detectedNsVersion(): String? + enum class Collection { ENTRIES, TREATMENTS, FOODS, PROFILE } + /** * NSC v3 does first load of all data * next loads are using srvModified property for sync @@ -34,6 +58,7 @@ interface NsClient : Sync { * */ fun updateLatestBgReceivedIfNewer(latestReceived: Long) + /** * Update newest loaded timestamp for treatments collection (first load or NSCv1) * Update newest srvModified (sync loads) @@ -42,10 +67,37 @@ interface NsClient : Sync { * */ fun updateLatestTreatmentReceivedIfNewer(latestReceived: Long) + + /** + * Send alarm confirmation to NS + * + * @param originalAlarm alarm to be cleared + * @param silenceTimeInMilliseconds silence alarm for specified duration + */ fun handleClearAlarm(originalAlarm: NSAlarm, silenceTimeInMilliseconds: Long) + /** + * Clear synchronization status + * + * Next synchronization will start from scratch + */ fun resetToFullSync() + /** + * Upload new record to NS + * + * @param collection target ns collection + * @param dataPair data to upload (data.first) and id of changed record (data.second) + * @param progress progress of sync in format "number/number". Only for display in fragment + */ fun nsAdd(collection: String, dataPair: DataSyncSelector.DataPair, progress: String) + + /** + * Upload updated record to NS + * + * @param collection target ns collection + * @param dataPair data to upload (data.first) and id of changed record (data.second) + * @param progress progress of sync in format "number/number". Only for display in fragment + */ fun nsUpdate(collection: String, dataPair: DataSyncSelector.DataPair, progress: String) } \ No newline at end of file diff --git a/core/ns-sdk/src/main/java/info/nightscout/sdk/NSAndroidClientImpl.kt b/core/ns-sdk/src/main/java/info/nightscout/sdk/NSAndroidClientImpl.kt index 8c3843315d..13c4ecb91f 100644 --- a/core/ns-sdk/src/main/java/info/nightscout/sdk/NSAndroidClientImpl.kt +++ b/core/ns-sdk/src/main/java/info/nightscout/sdk/NSAndroidClientImpl.kt @@ -5,6 +5,7 @@ import com.google.gson.JsonParser import info.nightscout.sdk.exceptions.DateHeaderOutOfToleranceException import info.nightscout.sdk.exceptions.InvalidAccessTokenException import info.nightscout.sdk.exceptions.InvalidFormatNightscoutException +import info.nightscout.sdk.exceptions.InvalidParameterNightscoutException import info.nightscout.sdk.exceptions.UnknownResponseNightscoutException import info.nightscout.sdk.exceptions.UnsuccessfullNightscoutException import info.nightscout.sdk.interfaces.NSAndroidClient @@ -105,9 +106,10 @@ class NSAndroidClientImpl( val response = api.lastModified() if (response.isSuccessful) { return@callWrapper response.body()?.result ?: throw UnsuccessfullNightscoutException() - } else { + } else if (response.code() in 400..499) + throw InvalidParameterNightscoutException(response.errorBody()?.string() ?: response.message()) + else throw UnsuccessfullNightscoutException() - } } override suspend fun getSgvs(): NSAndroidClient.ReadResponse> = callWrapper(dispatcher) { @@ -115,9 +117,10 @@ class NSAndroidClientImpl( val response = api.getSgvs() if (response.isSuccessful) { return@callWrapper NSAndroidClient.ReadResponse(code = response.raw().networkResponse?.code ?: response.code(), lastServerModified = 0, values = response.body()?.result?.map(RemoteEntry::toSgv).toNotNull()) - } else { + } else if (response.code() in 400..499) + throw InvalidParameterNightscoutException(response.errorBody()?.string() ?: response.message()) + else throw UnsuccessfullNightscoutException() - } } override suspend fun getSgvsModifiedSince(from: Long, limit: Long): NSAndroidClient.ReadResponse> = callWrapper(dispatcher) { @@ -127,9 +130,10 @@ class NSAndroidClientImpl( val eTagString = response.headers()["ETag"] val eTag = eTagString?.substring(3, eTagString.length - 1)?.toLong() return@callWrapper NSAndroidClient.ReadResponse(code = response.raw().networkResponse?.code ?: response.code(), lastServerModified = eTag, values = response.body()?.result?.map(RemoteEntry::toSgv).toNotNull()) - } else { + } else if (response.code() in 400..499) + throw InvalidParameterNightscoutException(response.errorBody()?.string() ?: response.message()) + else throw UnsuccessfullNightscoutException() - } } override suspend fun getSgvsNewerThan(from: Long, limit: Long): NSAndroidClient.ReadResponse> = callWrapper(dispatcher) { @@ -137,9 +141,10 @@ class NSAndroidClientImpl( val response = api.getSgvsNewerThan(from, limit) if (response.isSuccessful) { return@callWrapper NSAndroidClient.ReadResponse(code = response.raw().networkResponse?.code ?: response.code(), lastServerModified = 0, values = response.body()?.result?.map(RemoteEntry::toSgv).toNotNull()) - } else { + } else if (response.code() in 400..499) + throw InvalidParameterNightscoutException(response.errorBody()?.string() ?: response.message()) + else throw UnsuccessfullNightscoutException() - } } override suspend fun createSvg(nsSgvV3: NSSgvV3): CreateUpdateResponse = callWrapper(dispatcher) { @@ -176,7 +181,10 @@ class NSAndroidClientImpl( identifier = null, errorResponse = errorResponse ) - } else throw UnknownResponseNightscoutException() + } else if (response.code() in 400..499) + throw InvalidParameterNightscoutException(response.errorBody()?.string() ?: response.message()) + else + throw UnsuccessfullNightscoutException() } override suspend fun updateSvg(nsSgvV3: NSSgvV3): CreateUpdateResponse = callWrapper(dispatcher) { @@ -205,9 +213,10 @@ class NSAndroidClientImpl( deduplicatedIdentifier = null, lastModified = null ) - } else { + } else if (response.code() in 400..499) + throw InvalidParameterNightscoutException(response.errorBody()?.string() ?: response.message()) + else throw UnsuccessfullNightscoutException() - } } override suspend fun getTreatmentsNewerThan(createdAt: String, limit: Long): NSAndroidClient.ReadResponse> = callWrapper(dispatcher) { @@ -215,9 +224,10 @@ class NSAndroidClientImpl( val response = api.getTreatmentsNewerThan(createdAt, limit) if (response.isSuccessful) { return@callWrapper NSAndroidClient.ReadResponse(code = response.raw().networkResponse?.code ?: response.code(), lastServerModified = 0, values = response.body()?.result?.map(RemoteTreatment::toTreatment).toNotNull()) - } else { + } else if (response.code() in 400..499) + throw InvalidParameterNightscoutException(response.errorBody()?.string() ?: response.message()) + else throw UnsuccessfullNightscoutException() - } } override suspend fun getTreatmentsModifiedSince(from: Long, limit: Long): NSAndroidClient.ReadResponse> = callWrapper(dispatcher) { @@ -226,11 +236,14 @@ class NSAndroidClientImpl( if (response.isSuccessful) { val eTagString = response.headers()["ETag"] val eTag = eTagString?.substring(3, eTagString.length - 1)?.toLong() - return@callWrapper NSAndroidClient.ReadResponse(code = response.raw().networkResponse?.code ?: response.code(), lastServerModified = eTag, values = response.body()?.result?.map - (RemoteTreatment::toTreatment).toNotNull()) - } else { + return@callWrapper NSAndroidClient.ReadResponse( + code = response.raw().networkResponse?.code ?: response.code(), lastServerModified = eTag, values = response.body()?.result?.map + (RemoteTreatment::toTreatment).toNotNull() + ) + } else if (response.code() in 400..499) + throw InvalidParameterNightscoutException(response.errorBody()?.string() ?: response.message()) + else throw UnsuccessfullNightscoutException() - } } override suspend fun getDeviceStatusModifiedSince(from: Long): List = callWrapper(dispatcher) { @@ -238,9 +251,10 @@ class NSAndroidClientImpl( val response = api.getDeviceStatusModifiedSince(from) if (response.isSuccessful) { return@callWrapper response.body()?.result?.map(RemoteDeviceStatus::toNSDeviceStatus).toNotNull() - } else { + } else if (response.code() in 400..499) + throw InvalidParameterNightscoutException(response.errorBody()?.string() ?: response.message()) + else throw UnsuccessfullNightscoutException() - } } override suspend fun createDeviceStatus(nsDeviceStatus: NSDeviceStatus): CreateUpdateResponse = callWrapper(dispatcher) { @@ -266,9 +280,10 @@ class NSAndroidClientImpl( lastModified = response.body()?.result?.lastModified ) } else throw UnknownResponseNightscoutException() - } else { + } else if (response.code() in 400..499) + throw InvalidParameterNightscoutException(response.errorBody()?.string() ?: response.message()) + else throw UnsuccessfullNightscoutException() - } } override suspend fun createTreatment(nsTreatment: NSTreatment): CreateUpdateResponse = callWrapper(dispatcher) { @@ -304,7 +319,10 @@ class NSAndroidClientImpl( identifier = null, errorResponse = errorResponse ) - } else throw UnknownResponseNightscoutException() + } else if (response.code() in 400..499) + throw InvalidParameterNightscoutException(response.errorBody()?.string() ?: response.message()) + else + throw UnsuccessfullNightscoutException() } override suspend fun updateTreatment(nsTreatment: NSTreatment): CreateUpdateResponse = callWrapper(dispatcher) { @@ -333,9 +351,10 @@ class NSAndroidClientImpl( deduplicatedIdentifier = null, lastModified = null ) - } else { + } else if (response.code() in 400..499) + throw InvalidParameterNightscoutException(response.errorBody()?.string() ?: response.message()) + else throw UnsuccessfullNightscoutException() - } } override suspend fun getFoods(limit: Long): NSAndroidClient.ReadResponse> = callWrapper(dispatcher) { @@ -343,9 +362,10 @@ class NSAndroidClientImpl( val response = api.getFoods(limit) if (response.isSuccessful) { return@callWrapper NSAndroidClient.ReadResponse(code = response.raw().networkResponse?.code ?: response.code(), lastServerModified = 0, values = response.body()?.result?.map(RemoteFood::toNSFood).toNotNull()) - } else { + } else if (response.code() in 400..499) + throw InvalidParameterNightscoutException(response.errorBody()?.string() ?: response.message()) + else throw UnsuccessfullNightscoutException() - } } /* @@ -412,9 +432,10 @@ class NSAndroidClientImpl( deduplicatedIdentifier = null, lastModified = null ) - } else { + } else if (response.code() in 400..499) + throw InvalidParameterNightscoutException(response.errorBody()?.string() ?: response.message()) + else throw UnsuccessfullNightscoutException() - } } override suspend fun createProfileStore(remoteProfileStore: JSONObject): CreateUpdateResponse = callWrapper(dispatcher) { @@ -438,9 +459,10 @@ class NSAndroidClientImpl( lastModified = response.body()?.result?.lastModified ) } else throw UnsuccessfullNightscoutException() - } else { + } else if (response.code() in 400..499) + throw InvalidParameterNightscoutException(response.errorBody()?.string() ?: response.message()) + else throw UnsuccessfullNightscoutException() - } } override suspend fun getLastProfileStore(): NSAndroidClient.ReadResponse> = callWrapper(dispatcher) { @@ -450,9 +472,10 @@ class NSAndroidClientImpl( val eTagString = response.headers()["ETag"] val eTag = eTagString?.substring(3, eTagString.length - 1)?.toLong() return@callWrapper NSAndroidClient.ReadResponse(code = response.raw().networkResponse?.code ?: response.code(), lastServerModified = eTag, values = response.body()?.result.toNotNull()) - } else { + } else if (response.code() in 400..499) + throw InvalidParameterNightscoutException(response.errorBody()?.string() ?: response.message()) + else throw UnsuccessfullNightscoutException() - } } @@ -463,9 +486,10 @@ class NSAndroidClientImpl( val eTagString = response.headers()["ETag"] val eTag = eTagString?.substring(3, eTagString.length - 1)?.toLong() return@callWrapper NSAndroidClient.ReadResponse(code = response.raw().networkResponse?.code ?: response.code(), lastServerModified = eTag, values = response.body()?.result.toNotNull()) - } else { + } else if (response.code() in 400..499) + throw InvalidParameterNightscoutException(response.errorBody()?.string() ?: response.message()) + else throw UnsuccessfullNightscoutException() - } } diff --git a/core/ns-sdk/src/main/java/info/nightscout/sdk/exceptions/InvalidFormatNightscoutException.kt b/core/ns-sdk/src/main/java/info/nightscout/sdk/exceptions/InvalidFormatNightscoutException.kt index 80ab0f019e..f59a7ae4e6 100644 --- a/core/ns-sdk/src/main/java/info/nightscout/sdk/exceptions/InvalidFormatNightscoutException.kt +++ b/core/ns-sdk/src/main/java/info/nightscout/sdk/exceptions/InvalidFormatNightscoutException.kt @@ -1,3 +1,9 @@ package info.nightscout.sdk.exceptions -class InvalidFormatNightscoutException : NightscoutException() +@Suppress("unused") +class InvalidFormatNightscoutException : NightscoutException { + constructor() : super() + constructor(message: String) : super(message) + constructor(message: String, cause: Throwable) : super(message, cause) + constructor(cause: Throwable?) : super(cause) +} diff --git a/core/ns-sdk/src/main/java/info/nightscout/sdk/exceptions/InvalidParameterNightscoutException.kt b/core/ns-sdk/src/main/java/info/nightscout/sdk/exceptions/InvalidParameterNightscoutException.kt new file mode 100644 index 0000000000..de8e25b8f0 --- /dev/null +++ b/core/ns-sdk/src/main/java/info/nightscout/sdk/exceptions/InvalidParameterNightscoutException.kt @@ -0,0 +1,9 @@ +package info.nightscout.sdk.exceptions + +@Suppress("unused") +class InvalidParameterNightscoutException : NightscoutException { + constructor() : super() + constructor(message: String) : super(message) + constructor(message: String, cause: Throwable) : super(message, cause) + constructor(cause: Throwable?) : super(cause) +} diff --git a/database/impl/src/main/java/info/nightscout/database/impl/transactions/SyncNsTemporaryTargetTransaction.kt b/database/impl/src/main/java/info/nightscout/database/impl/transactions/SyncNsTemporaryTargetTransaction.kt index 49b991439f..6229136192 100644 --- a/database/impl/src/main/java/info/nightscout/database/impl/transactions/SyncNsTemporaryTargetTransaction.kt +++ b/database/impl/src/main/java/info/nightscout/database/impl/transactions/SyncNsTemporaryTargetTransaction.kt @@ -7,7 +7,7 @@ import kotlin.math.abs /** * Sync the TemporaryTarget from NS */ -class SyncNsTemporaryTargetTransaction(private val temporaryTargets: List, private val nsClientMode: Boolean) : +class SyncNsTemporaryTargetTransaction(private val temporaryTargets: List) : Transaction() { override fun run(): TransactionResult { @@ -28,7 +28,7 @@ class SyncNsTemporaryTargetTransaction(private val temporaryTargets: List? = null - when (type) { - PluginType.INSULIN -> pluginsInCategory = activePlugin.getSpecificPluginsListByInterface(Insulin::class.java) - PluginType.SENSITIVITY -> pluginsInCategory = activePlugin.getSpecificPluginsListByInterface(Sensitivity::class.java) - PluginType.SMOOTHING -> pluginsInCategory = activePlugin.getSpecificPluginsListByInterface(Smoothing::class.java) - PluginType.APS -> pluginsInCategory = activePlugin.getSpecificPluginsListByInterface(APS::class.java) - PluginType.PROFILE -> pluginsInCategory = activePlugin.getSpecificPluginsListByInterface(ProfileSource::class.java) - PluginType.BGSOURCE -> pluginsInCategory = activePlugin.getSpecificPluginsListByInterface(BgSource::class.java) - PluginType.PUMP -> pluginsInCategory = activePlugin.getSpecificPluginsListByInterface(Pump::class.java) + when { + type == PluginType.INSULIN -> pluginsInCategory = activePlugin.getSpecificPluginsListByInterface(Insulin::class.java) + type == PluginType.SENSITIVITY -> pluginsInCategory = activePlugin.getSpecificPluginsListByInterface(Sensitivity::class.java) + type == PluginType.SMOOTHING -> pluginsInCategory = activePlugin.getSpecificPluginsListByInterface(Smoothing::class.java) + type == PluginType.APS -> pluginsInCategory = activePlugin.getSpecificPluginsListByInterface(APS::class.java) + type == PluginType.PROFILE -> pluginsInCategory = activePlugin.getSpecificPluginsListByInterface(ProfileSource::class.java) + type == PluginType.BGSOURCE -> pluginsInCategory = activePlugin.getSpecificPluginsListByInterface(BgSource::class.java) + type == PluginType.PUMP -> pluginsInCategory = activePlugin.getSpecificPluginsListByInterface(Pump::class.java) // Process only NSClients - PluginType.SYNC -> pluginsInCategory = activePlugin.getSpecificPluginsListByInterface(NsClient::class.java) + changedPlugin is NsClient -> pluginsInCategory = activePlugin.getSpecificPluginsListByInterface(NsClient::class.java) - else -> { + else -> { } } if (pluginsInCategory != null) { diff --git a/plugins/configuration/src/main/java/info/nightscout/configuration/setupwizard/SWDefinition.kt b/plugins/configuration/src/main/java/info/nightscout/configuration/setupwizard/SWDefinition.kt index c304c05592..34ccaff3df 100644 --- a/plugins/configuration/src/main/java/info/nightscout/configuration/setupwizard/SWDefinition.kt +++ b/plugins/configuration/src/main/java/info/nightscout/configuration/setupwizard/SWDefinition.kt @@ -225,9 +225,9 @@ class SWDefinition @Inject constructor( .add( SWEventListener(injector, EventSWSyncStatus::class.java) .label(R.string.status) - .initialStatus(activePlugin.firstActiveSync?.status ?: "") + .initialStatus(activePlugin.activeNsClient?.status ?: "") ) - .validator { activePlugin.firstActiveSync?.connected == true && activePlugin.firstActiveSync?.hasWritePermission == true } + .validator { activePlugin.activeNsClient?.connected == true && activePlugin.activeNsClient?.hasWritePermission == true } private val screenPatientName get() = SWScreen(injector, R.string.patient_name) .skippable(true) 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 aadc32a8b0..b3736b070e 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 @@ -1,8 +1,6 @@ package info.nightscout.plugins.sync.nsShared import android.os.Bundle -import android.os.Handler -import android.os.HandlerThread import android.view.LayoutInflater import android.view.Menu import android.view.MenuInflater @@ -22,7 +20,6 @@ import info.nightscout.interfaces.plugin.ActivePlugin import info.nightscout.interfaces.plugin.PluginBase import info.nightscout.interfaces.plugin.PluginFragment import info.nightscout.interfaces.sync.DataSyncSelector -import info.nightscout.interfaces.sync.NsClient import info.nightscout.plugins.sync.R import info.nightscout.plugins.sync.databinding.NsClientFragmentBinding import info.nightscout.plugins.sync.nsShared.events.EventNSClientUpdateGUI @@ -60,11 +57,9 @@ class NSClientFragment : DaggerFragment(), MenuProvider, PluginFragment { override var plugin: PluginBase? = null private val nsClientPlugin get() = activePlugin.activeNsClient - private val version: NsClient.Version get() = nsClientPlugin?.version ?: NsClient.Version.NONE private val disposable = CompositeDisposable() - private var handler = Handler(HandlerThread(this::class.simpleName + "Handler").also { it.start() }.looper) private var _binding: NsClientFragmentBinding? = null // This property is only valid between onCreateView and 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 68f4dd170a..445c934835 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 @@ -325,7 +325,7 @@ class StoreDataForDbImpl @Inject constructor( SystemClock.sleep(pause) if (temporaryTargets.isNotEmpty()) - repository.runTransactionForResult(SyncNsTemporaryTargetTransaction(temporaryTargets, config.NSCLIENT)) + repository.runTransactionForResult(SyncNsTemporaryTargetTransaction(temporaryTargets)) .doOnError { aapsLogger.error(LTag.DATABASE, "Error while saving temporary target", it) } 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 0eb8b45715..53ca1d3e73 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 @@ -18,6 +18,7 @@ import info.nightscout.core.validators.ValidatingEditTextPreference import info.nightscout.interfaces.Config import info.nightscout.interfaces.Constants import info.nightscout.interfaces.nsclient.NSAlarm +import info.nightscout.interfaces.nsclient.NSSettingsStatus import info.nightscout.interfaces.plugin.ActivePlugin import info.nightscout.interfaces.plugin.PluginBase import info.nightscout.interfaces.plugin.PluginDescription @@ -71,7 +72,8 @@ class NSClientPlugin @Inject constructor( private val uiInteraction: UiInteraction, private val activePlugin: ActivePlugin, private val dateUtil: DateUtil, - private val profileFunction: ProfileFunction + private val profileFunction: ProfileFunction, + private val nsSettingsStatus: NSSettingsStatus ) : NsClient, Sync, PluginBase( PluginDescription() .mainType(PluginType.SYNC) @@ -154,7 +156,6 @@ class NSClientPlugin @Inject constructor( if (activePlugin.activeBgSource is DoingOwnUploadSource) { preferenceFragment.findPreference(rh.gs(info.nightscout.core.utils.R.string.key_do_ns_upload))?.isVisible = false } - preferenceFragment.findPreference(rh.gs(R.string.key_ns_client_token))?.isVisible = false } override val hasWritePermission: Boolean get() = nsClientService?.hasWriteAuth ?: false @@ -180,6 +181,8 @@ class NSClientPlugin @Inject constructor( } } + override fun detectedNsVersion(): String? = nsSettingsStatus.getVersion() + private fun addToLog(ev: EventNSClientNewLog) { synchronized(listLog) { listLog.add(ev) @@ -213,9 +216,6 @@ class NSClientPlugin @Inject constructor( rxBus.send(EventPreferenceChange(rh.gs(R.string.key_ns_client_paused))) } - override val version: NsClient.Version - get() = NsClient.Version.V1 - override val address: String get() = nsClientService?.nsURL ?: "" override fun handleClearAlarm(originalAlarm: NSAlarm, silenceTimeInMilliseconds: Long) { 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 b319210a3e..894c2ad86a 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 @@ -16,7 +16,6 @@ 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.validators.ValidatingEditTextPreference import info.nightscout.database.ValueWrapper import info.nightscout.database.entities.interfaces.TraceableDBEntry import info.nightscout.database.impl.AppRepository @@ -111,7 +110,7 @@ class NSClientV3Plugin @Inject constructor( .pluginIcon(info.nightscout.core.ui.R.drawable.ic_nightscout_syncs) .pluginName(R.string.ns_client_v3) .shortName(R.string.ns_client_v3_short_name) - .preferencesId(R.xml.pref_ns_client) + .preferencesId(R.xml.pref_ns_client_v3) .description(R.string.description_ns_client_v3), aapsLogger, rh, injector ) { @@ -120,6 +119,7 @@ class NSClientV3Plugin @Inject constructor( val JOB_NAME: String = this::class.java.simpleName val REFRESH_INTERVAL = T.secs(30).msecs() + const val RECORDS_TO_LOAD = 500L } private val disposable = CompositeDisposable() @@ -170,6 +170,7 @@ class NSClientV3Plugin @Inject constructor( .subscribe({ ev -> nsClientReceiverDelegate.onStatusEvent(ev) setClient() + rxBus.send(EventNSClientUpdateGUI()) }, fabricPrivacy::logException) disposable += rxBus .toObservable(EventPreferenceChange::class.java) @@ -195,7 +196,10 @@ class NSClientV3Plugin @Inject constructor( disposable += rxBus .toObservable(EventChargingState::class.java) .observeOn(aapsSchedulers.io) - .subscribe({ ev -> nsClientReceiverDelegate.onStatusEvent(ev) }, fabricPrivacy::logException) + .subscribe({ ev -> + nsClientReceiverDelegate.onStatusEvent(ev) + rxBus.send(EventNSClientUpdateGUI()) + }, fabricPrivacy::logException) disposable += rxBus .toObservable(EventNSClientResend::class.java) .observeOn(aapsSchedulers.io) @@ -216,8 +220,9 @@ class NSClientV3Plugin @Inject constructor( if (it is ValueWrapper.Existing) { if (it.value.timestamp < dateUtil.now() - T.mins(5).plus(T.secs(20)).msecs()) executeLoop("MAIN_LOOP", forceNew = false) - else - rxBus.send(EventNSClientNewLog("RECENT", "No need to load")) + else { + if (isAllowed) rxBus.send(EventNSClientNewLog("RECENT", "No need to load")) + } } else executeLoop("MAIN_LOOP", forceNew = false) } } @@ -241,7 +246,6 @@ class NSClientV3Plugin @Inject constructor( preferenceFragment.findPreference(rh.gs(info.nightscout.core.utils.R.string.key_ns_create_announcements_from_carbs_req))?.isVisible = false } preferenceFragment.findPreference(rh.gs(R.string.key_ns_receive_tbr_eb))?.isVisible = config.isEngineeringMode() - preferenceFragment.findPreference(rh.gs(info.nightscout.core.utils.R.string.key_nsclientinternal_api_secret))?.isVisible = false } override val hasWritePermission: Boolean get() = nsAndroidClient?.lastStatus?.apiPermissions?.isFull() ?: false @@ -291,12 +295,12 @@ class NSClientV3Plugin @Inject constructor( 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))) - } + 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))) + } - override val version: NsClient.Version get() = NsClient.Version.V3 + override fun detectedNsVersion(): String? = nsAndroidClient?.lastStatus?.version override val address: String get() = sp.getString(info.nightscout.core.utils.R.string.key_nsclientinternal_url, "") 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 2b42ea36fd..93afbb4d5f 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 @@ -59,9 +59,9 @@ class LoadBgWorker( if ((nsClientV3Plugin.newestDataOnServer?.collections?.entries ?: Long.MAX_VALUE) > lastLoaded) { val sgvs: List val response: NSAndroidClient.ReadResponse>? - if (isFirstLoad) response = nsAndroidClient.getSgvsNewerThan(lastLoaded, 500) + if (isFirstLoad) response = nsAndroidClient.getSgvsNewerThan(lastLoaded, NSClientV3Plugin.RECORDS_TO_LOAD) else { - response = nsAndroidClient.getSgvsModifiedSince(lastLoaded, 500) + response = nsAndroidClient.getSgvsModifiedSince(lastLoaded, NSClientV3Plugin.RECORDS_TO_LOAD) response.lastServerModified?.let { nsClientV3Plugin.lastLoadedSrvModified.collections.entries = it } nsClientV3Plugin.storeLastLoadedSrvModified() nsClientV3Plugin.scheduleIrregularExecution() // Idea is to run after 5 min after last BG 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 750ad438e5..b5159fa9bf 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 @@ -47,9 +47,9 @@ class LoadTreatmentsWorker( val response: NSAndroidClient.ReadResponse>? if (isFirstLoad) { val lastLoadedIso = dateUtil.toISOString(lastLoaded) - response = nsAndroidClient.getTreatmentsNewerThan(lastLoadedIso, 500) + response = nsAndroidClient.getTreatmentsNewerThan(lastLoadedIso, NSClientV3Plugin.RECORDS_TO_LOAD) } else { - response = nsAndroidClient.getTreatmentsModifiedSince(lastLoaded, 500) + response = nsAndroidClient.getTreatmentsModifiedSince(lastLoaded, NSClientV3Plugin.RECORDS_TO_LOAD) response.lastServerModified?.let { nsClientV3Plugin.lastLoadedSrvModified.collections.treatments = it } nsClientV3Plugin.storeLastLoadedSrvModified() } 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 9f2739ee68..c6f9cdb768 100644 --- a/plugins/sync/src/main/res/xml/pref_ns_client.xml +++ b/plugins/sync/src/main/res/xml/pref_ns_client.xml @@ -26,15 +26,6 @@ validate:minLength="12" validate:testType="minLength"/> - - 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 new file mode 100644 index 0000000000..79f5b522af --- /dev/null +++ b/plugins/sync/src/main/res/xml/pref_ns_client_v3.xml @@ -0,0 +1,217 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + > + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/pump/combov2/src/main/kotlin/info/nightscout/pump/combov2/ComboV2Plugin.kt b/pump/combov2/src/main/kotlin/info/nightscout/pump/combov2/ComboV2Plugin.kt index 95cd290957..c611249569 100644 --- a/pump/combov2/src/main/kotlin/info/nightscout/pump/combov2/ComboV2Plugin.kt +++ b/pump/combov2/src/main/kotlin/info/nightscout/pump/combov2/ComboV2Plugin.kt @@ -251,14 +251,14 @@ class ComboV2Plugin @Inject constructor ( init { ComboCtlLogger.backend = AAPSComboCtlLogger(aapsLogger) - updateComboCtlLogLevel() - _pumpDescription.fillFor(PumpType.ACCU_CHEK_COMBO) } override fun onStart() { super.onStart() + updateComboCtlLogLevel() + // Check if there is a pump state in the internal SP. If not, try to // copy a pump state from the AAPS main SP. It is possible for example // that AAPS was reinstalled, and the previous settings were imported. diff --git a/pump/danar/src/main/java/info/nightscout/androidaps/danar/comm/MsgHistoryAll.kt b/pump/danar/src/main/java/info/nightscout/androidaps/danar/comm/MsgHistoryAll.kt index b7948f9605..d13acf81f0 100644 --- a/pump/danar/src/main/java/info/nightscout/androidaps/danar/comm/MsgHistoryAll.kt +++ b/pump/danar/src/main/java/info/nightscout/androidaps/danar/comm/MsgHistoryAll.kt @@ -7,6 +7,7 @@ import info.nightscout.rx.events.EventDanaRSyncStatus import info.nightscout.rx.logging.LTag import info.nightscout.shared.utils.T +@Suppress("SpellCheckingInspection") open class MsgHistoryAll( injector: HasAndroidInjector ) : MessageBase(injector) { @@ -17,136 +18,143 @@ open class MsgHistoryAll( } override fun handleMessage(bytes: ByteArray) { - val recordCode = intFromBuff(bytes, 0, 1).toByte() - val date = dateFromBuff(bytes, 1) // 3 bytes - val dailyBasal = intFromBuff(bytes, 4, 2) * 0.01 - val dailyBolus = intFromBuff(bytes, 6, 2) * 0.01 - //val paramByte5 = intFromBuff(bytes, 4, 1).toByte() - //val paramByte6 = intFromBuff(bytes, 5, 1).toByte() - val paramByte7 = intFromBuff(bytes, 6, 1).toByte() - val paramByte8 = intFromBuff(bytes, 7, 1).toByte() - val value = intFromBuff(bytes, 8, 2).toDouble() - val danaHistoryRecord = DanaHistoryRecord( - timestamp = date, - code = recordCode - ) - var messageType = "" - when (recordCode) { - RecordTypes.RECORD_TYPE_BOLUS -> { - val datetime = dateTimeFromBuff(bytes, 1) // 5 bytes - danaHistoryRecord.timestamp = datetime - when (0xF0 and paramByte8.toInt()) { - 0xA0 -> { - danaHistoryRecord.bolusType = "DS" - messageType += "DS bolus" - } + try { + val recordCode = intFromBuff(bytes, 0, 1).toByte() + val date = dateFromBuff(bytes, 1) // 3 bytes + val dailyBasal = intFromBuff(bytes, 4, 2) * 0.01 + val dailyBolus = intFromBuff(bytes, 6, 2) * 0.01 + //val paramByte5 = intFromBuff(bytes, 4, 1).toByte() + //val paramByte6 = intFromBuff(bytes, 5, 1).toByte() + val paramByte7 = intFromBuff(bytes, 6, 1).toByte() + val paramByte8 = intFromBuff(bytes, 7, 1).toByte() + val value = intFromBuff(bytes, 8, 2).toDouble() + val danaHistoryRecord = DanaHistoryRecord( + timestamp = date, + code = recordCode + ) + var messageType = "" + when (recordCode) { + RecordTypes.RECORD_TYPE_BOLUS -> { + val datetime = dateTimeFromBuff(bytes, 1) // 5 bytes + danaHistoryRecord.timestamp = datetime + when (0xF0 and paramByte8.toInt()) { + 0xA0 -> { + danaHistoryRecord.bolusType = "DS" + messageType += "DS bolus" + } - 0xC0 -> { - danaHistoryRecord.bolusType = "E" - messageType += "E bolus" - } + 0xC0 -> { + danaHistoryRecord.bolusType = "E" + messageType += "E bolus" + } - 0x80 -> { - danaHistoryRecord.bolusType = "S" - messageType += "S bolus" - } + 0x80 -> { + danaHistoryRecord.bolusType = "S" + messageType += "S bolus" + } - 0x90 -> { - danaHistoryRecord.bolusType = "DE" - messageType += "DE bolus" - } + 0x90 -> { + danaHistoryRecord.bolusType = "DE" + messageType += "DE bolus" + } - else -> danaHistoryRecord.bolusType = "None" + else -> danaHistoryRecord.bolusType = "None" + } + danaHistoryRecord.duration = T.mins((paramByte8.toInt() and 0x0F) * 60 + paramByte7.toLong()).msecs() + danaHistoryRecord.value = value * 0.01 } - danaHistoryRecord.duration = T.mins((paramByte8.toInt() and 0x0F) * 60 + paramByte7.toLong()).msecs() - danaHistoryRecord.value = value * 0.01 - } - RecordTypes.RECORD_TYPE_DAILY -> { - messageType += "dailyinsulin" - danaHistoryRecord.timestamp = date - danaHistoryRecord.dailyBasal = dailyBasal - danaHistoryRecord.dailyBolus = dailyBolus - } - - RecordTypes.RECORD_TYPE_PRIME -> { - messageType += "prime" - val datetimewihtsec = dateTimeSecFromBuff(bytes, 1) // 6 bytes - danaHistoryRecord.timestamp = datetimewihtsec - danaHistoryRecord.value = value * 0.01 - } - - RecordTypes.RECORD_TYPE_ERROR -> { - messageType += "error" - val datetimewihtsec = dateTimeSecFromBuff(bytes, 1) // 6 bytes - danaHistoryRecord.timestamp = datetimewihtsec - danaHistoryRecord.value = value * 0.01 - } - - RecordTypes.RECORD_TYPE_REFILL -> { - messageType += "refill" - val datetimewihtsec = dateTimeSecFromBuff(bytes, 1) // 6 bytes - danaHistoryRecord.timestamp = datetimewihtsec - danaHistoryRecord.value = value * 0.01 - } - - RecordTypes.RECORD_TYPE_BASALHOUR -> { - messageType += "basal hour" - val datetimewihtsec = dateTimeSecFromBuff(bytes, 1) // 6 bytes - danaHistoryRecord.timestamp = datetimewihtsec - danaHistoryRecord.value = value * 0.01 - } - - RecordTypes.RECORD_TYPE_TB -> { - messageType += "tb" - val datetimewihtsec = dateTimeSecFromBuff(bytes, 1) // 6 bytes - danaHistoryRecord.timestamp = datetimewihtsec - danaHistoryRecord.value = value * 0.01 - } - - RecordTypes.RECORD_TYPE_GLUCOSE -> { - messageType += "glucose" - val datetimewihtsec = dateTimeSecFromBuff(bytes, 1) // 6 bytes - danaHistoryRecord.timestamp = datetimewihtsec - danaHistoryRecord.value = value - } - - RecordTypes.RECORD_TYPE_CARBO -> { - messageType += "carbo" - val datetimewihtsec = dateTimeSecFromBuff(bytes, 1) // 6 bytes - danaHistoryRecord.timestamp = datetimewihtsec - danaHistoryRecord.value = value - } - - RecordTypes.RECORD_TYPE_ALARM -> { - messageType += "alarm" - val datetimewihtsec = dateTimeSecFromBuff(bytes, 1) // 6 bytes - danaHistoryRecord.timestamp = datetimewihtsec - var strAlarm = "None" - when (paramByte8.toInt()) { - 67 -> strAlarm = "Check" - 79 -> strAlarm = "Occlusion" - 66 -> strAlarm = "Low Battery" - 83 -> strAlarm = "Shutdown" + RecordTypes.RECORD_TYPE_DAILY -> { + messageType += "dailyinsulin" + danaHistoryRecord.timestamp = date + danaHistoryRecord.dailyBasal = dailyBasal + danaHistoryRecord.dailyBolus = dailyBolus } - danaHistoryRecord.alarm = strAlarm - danaHistoryRecord.value = value * 0.01 - } - RecordTypes.RECORD_TYPE_SUSPEND -> { - messageType += "suspend" - val datetimewihtsec = dateTimeSecFromBuff(bytes, 1) // 6 bytes - danaHistoryRecord.timestamp = datetimewihtsec - var strRecordValue = "Off" - if (paramByte8.toInt() == 79) strRecordValue = "On" - danaHistoryRecord.stringValue = strRecordValue - } + RecordTypes.RECORD_TYPE_PRIME -> { + messageType += "prime" + val datetimewihtsec = dateTimeSecFromBuff(bytes, 1) // 6 bytes + danaHistoryRecord.timestamp = datetimewihtsec + danaHistoryRecord.value = value * 0.01 + } - 17.toByte() -> failed = true + RecordTypes.RECORD_TYPE_ERROR -> { + messageType += "error" + val datetimewihtsec = dateTimeSecFromBuff(bytes, 1) // 6 bytes + danaHistoryRecord.timestamp = datetimewihtsec + danaHistoryRecord.value = value * 0.01 + } + + RecordTypes.RECORD_TYPE_REFILL -> { + messageType += "refill" + val datetimewihtsec = dateTimeSecFromBuff(bytes, 1) // 6 bytes + danaHistoryRecord.timestamp = datetimewihtsec + danaHistoryRecord.value = value * 0.01 + } + + RecordTypes.RECORD_TYPE_BASALHOUR -> { + messageType += "basal hour" + val datetimewihtsec = dateTimeSecFromBuff(bytes, 1) // 6 bytes + danaHistoryRecord.timestamp = datetimewihtsec + danaHistoryRecord.value = value * 0.01 + } + + RecordTypes.RECORD_TYPE_TB -> { + messageType += "tb" + val datetimewihtsec = dateTimeSecFromBuff(bytes, 1) // 6 bytes + danaHistoryRecord.timestamp = datetimewihtsec + danaHistoryRecord.value = value * 0.01 + } + + RecordTypes.RECORD_TYPE_GLUCOSE -> { + messageType += "glucose" + val datetimewihtsec = dateTimeSecFromBuff(bytes, 1) // 6 bytes + danaHistoryRecord.timestamp = datetimewihtsec + danaHistoryRecord.value = value + } + + RecordTypes.RECORD_TYPE_CARBO -> { + messageType += "carbo" + val datetimewihtsec = dateTimeSecFromBuff(bytes, 1) // 6 bytes + danaHistoryRecord.timestamp = datetimewihtsec + danaHistoryRecord.value = value + } + + RecordTypes.RECORD_TYPE_ALARM -> { + messageType += "alarm" + val datetimewihtsec = dateTimeSecFromBuff(bytes, 1) // 6 bytes + danaHistoryRecord.timestamp = datetimewihtsec + var strAlarm = "None" + when (paramByte8.toInt()) { + 67 -> strAlarm = "Check" + 79 -> strAlarm = "Occlusion" + 66 -> strAlarm = "Low Battery" + 83 -> strAlarm = "Shutdown" + } + danaHistoryRecord.alarm = strAlarm + danaHistoryRecord.value = value * 0.01 + } + + RecordTypes.RECORD_TYPE_SUSPEND -> { + messageType += "suspend" + val datetimewihtsec = dateTimeSecFromBuff(bytes, 1) // 6 bytes + danaHistoryRecord.timestamp = datetimewihtsec + var strRecordValue = "Off" + if (paramByte8.toInt() == 79) strRecordValue = "On" + danaHistoryRecord.stringValue = strRecordValue + } + + 17.toByte() -> failed = true + } + danaHistoryRecordDao.createOrUpdate(danaHistoryRecord) + if (recordCode == RecordTypes.RECORD_TYPE_DAILY) + pumpSync.createOrUpdateTotalDailyDose(date, dailyBolus, dailyBasal, dailyBolus + dailyBasal, date, activePlugin.activePump.model(), danaPump.serialNumber) + rxBus.send(EventDanaRSyncStatus(dateUtil.dateAndTimeString(danaHistoryRecord.timestamp) + " " + messageType)) + } catch (e: Exception) { + // DanaR id sometimes producing invalid date in history + // ignore these records + aapsLogger.error(e.stackTraceToString()) + return } - danaHistoryRecordDao.createOrUpdate(danaHistoryRecord) - if (recordCode == RecordTypes.RECORD_TYPE_DAILY) - pumpSync.createOrUpdateTotalDailyDose(date, dailyBolus, dailyBasal, dailyBolus + dailyBasal, date, activePlugin.activePump.model(), danaPump.serialNumber) - rxBus.send(EventDanaRSyncStatus(dateUtil.dateAndTimeString(danaHistoryRecord.timestamp) + " " + messageType)) } } \ No newline at end of file