Merge pull request #2364 from nightscout/ns15

NS 15.0.0 support
This commit is contained in:
Milos Kozak 2023-02-13 14:48:22 +01:00 committed by GitHub
commit 2c71401418
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
143 changed files with 4090 additions and 2640 deletions

View file

@ -4,6 +4,8 @@
<option name="WRAP_WHEN_TYPING_REACHES_RIGHT_MARGIN" value="true" />
<JetCodeStyleSettings>
<option name="ALIGN_IN_COLUMNS_CASE_BRANCH" value="true" />
<option name="NAME_COUNT_TO_USE_STAR_IMPORT" value="2147483647" />
<option name="NAME_COUNT_TO_USE_STAR_IMPORT_FOR_MEMBERS" value="2147483647" />
<option name="BLANK_LINES_AROUND_BLOCK_WHEN_BRANCHES" value="1" />
<option name="CODE_STYLE_DEFAULTS" value="KOTLIN_OFFICIAL" />
</JetCodeStyleSettings>

View file

@ -15,7 +15,6 @@ class EventNSClientNewLog(val action: String, val logText: String?) : Event() {
stringBuilder.append(action)
stringBuilder.append("</b> ")
stringBuilder.append(logText)
stringBuilder.append("<br>")
return stringBuilder
}
}

View file

@ -0,0 +1,21 @@
package info.nightscout.rx.events
import java.text.SimpleDateFormat
import java.util.Locale
class EventXdripNewLog(val action: String, val logText: String?) : Event() {
var date = System.currentTimeMillis()
private var timeFormat = SimpleDateFormat("HH:mm:ss", Locale.getDefault())
fun toPreparedHtml(): StringBuilder {
val stringBuilder = StringBuilder()
stringBuilder.append(timeFormat.format(date))
stringBuilder.append(" <b>")
stringBuilder.append(action)
stringBuilder.append("</b> ")
stringBuilder.append(logText)
stringBuilder.append("<br>")
return stringBuilder
}
}

View file

@ -28,5 +28,6 @@ enum class LTag(val tag: String, val defaultValue : Boolean = true, val requires
UI("UI", defaultValue = false),
WEAR("WEAR"),
WIDGET("WIDGET"),
WORKER("WORKER")
WORKER("WORKER"),
XDRIP("XDRIP")
}

View file

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

View file

@ -34,14 +34,14 @@ open class AppModule {
@PluginsListModule.PumpDriver pumpDrivers: Lazy<Map<@JvmSuppressWildcards Int, @JvmSuppressWildcards PluginBase>>,
@PluginsListModule.NotNSClient notNsClient: Lazy<Map<@JvmSuppressWildcards Int, @JvmSuppressWildcards PluginBase>>,
@PluginsListModule.APS aps: Lazy<Map<@JvmSuppressWildcards Int, @JvmSuppressWildcards PluginBase>>,
@PluginsListModule.Unfinished unfinished: Lazy<Map<@JvmSuppressWildcards Int, @JvmSuppressWildcards PluginBase>>
//@PluginsListModule.Unfinished unfinished: Lazy<Map<@JvmSuppressWildcards Int, @JvmSuppressWildcards PluginBase>>
)
: 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 }
}

View file

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

View file

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

View file

@ -1,12 +1,9 @@
package info.nightscout.androidaps.workflow
import info.nightscout.interfaces.workflow.WorkerClasses
import info.nightscout.plugins.profile.ProfilePlugin
import info.nightscout.source.NSClientSourcePlugin
import javax.inject.Inject
class WorkerClassesImpl @Inject constructor(): WorkerClasses{
class WorkerClassesImpl @Inject constructor() : WorkerClasses {
override val nsClientSourceWorker = NSClientSourcePlugin.NSClientSourceWorker::class.java
override val nsProfileWorker = ProfilePlugin.NSProfileWorker::class.java
//override val nsProfileWorker = ProfilePlugin.NSProfileWorker::class.java
}

View file

@ -2,6 +2,7 @@ package info.nightscout.core.graph.data
import android.content.Context
import android.graphics.Color
import info.nightscout.database.entities.GlucoseValue
import info.nightscout.interfaces.GlucoseUnit
import info.nightscout.interfaces.iob.InMemoryGlucoseValue
import info.nightscout.interfaces.profile.DefaultValueHelper
@ -35,7 +36,7 @@ internal class InMemoryGlucoseValueDataPointTest {
}
@Test
fun alphaShouldBeAddedForFilledGaps() {
val gv = InMemoryGlucoseValue(1000, 100.0)
val gv = InMemoryGlucoseValue(1000, 100.0, sourceSensor = GlucoseValue.SourceSensor.UNKNOWN)
val sut = InMemoryGlucoseValueDataPoint(gv, defaultValueHelper, profileFunction, rh)
var alpha = sut.color(context).ushr(24)

View file

@ -1,18 +1,6 @@
package info.nightscout.interfaces
import info.nightscout.database.entities.Bolus
import info.nightscout.database.entities.Carbs
import info.nightscout.database.entities.DeviceStatus
import info.nightscout.database.entities.EffectiveProfileSwitch
import info.nightscout.database.entities.ExtendedBolus
import info.nightscout.database.entities.GlucoseValue
import info.nightscout.database.entities.OfflineEvent
import info.nightscout.database.entities.ProfileSwitch
import info.nightscout.database.entities.TemporaryBasal
import info.nightscout.database.entities.TemporaryTarget
import info.nightscout.database.entities.TherapyEvent
import org.json.JSONArray
import org.json.JSONObject
import info.nightscout.interfaces.sync.DataSyncSelector
/**
* Send data to xDrip+ via Inter-app settings
@ -24,64 +12,19 @@ interface XDripBroadcast {
* Accepting must be enabled in Inter-app settings - Accept Calibrations
*/
fun sendCalibration(bg: Double): Boolean
fun sendIn640gMode(glucoseValue: GlucoseValue)
fun sendProfile(profileStoreJson: JSONObject)
fun sendTreatments(addedOrUpdatedTreatments: JSONArray)
fun sendSgvs(sgvs: JSONArray)
/**
* Send data to xDrip+
* Accepting must be enabled in Inter-app settings - Accept Glucose
*
* Accepting must be enabled in Inter-app settings - Accept Glucose/Treatments
*/
fun send(gv: GlucoseValue)
fun sendToXdrip(collection: String, dataPair: DataSyncSelector.DataPair, progress: String)
/**
* Send data to xDrip+
* Accepting must be enabled in Inter-app settings - Accept treatments
*
* Accepting must be enabled in Inter-app settings - Accept Glucose/Treatments
*/
fun send(bolus: Bolus)
/**
* Send data to xDrip+
* Accepting must be enabled in Inter-app settings - Accept treatments
*/
fun send(carbs: Carbs)
/**
* Send data to xDrip+
* Accepting must be enabled in Inter-app settings - Accept treatments
*/
fun send(tt: TemporaryTarget)
/**
* Send data to xDrip+
* Accepting must be enabled in Inter-app settings - Accept treatments
*/
fun send(te: TherapyEvent)
/**
* Send data to xDrip+
* Accepting must be enabled in Inter-app settings - Accept treatments
*/
fun send(deviceStatus: DeviceStatus)
/**
* Send data to xDrip+
* Accepting must be enabled in Inter-app settings - Accept treatments
*/
fun send(tb: TemporaryBasal)
/**
* Send data to xDrip+
* Accepting must be enabled in Inter-app settings - Accept treatments
*/
fun send(eb: ExtendedBolus)
/**
* Send data to xDrip+
* Accepting must be enabled in Inter-app settings - Accept treatments
*/
fun send(ps: ProfileSwitch)
/**
* Send data to xDrip+
* Accepting must be enabled in Inter-app settings - Accept treatments
*/
fun send(ps: EffectiveProfileSwitch)
/**
* Send data to xDrip+
* Accepting must be enabled in Inter-app settings - Accept treatments
*/
fun send(ps: OfflineEvent)
fun sendToXdrip(collection: String, dataPairs: List<DataSyncSelector.DataPair>, progress:
String)
}

View file

@ -47,4 +47,5 @@ interface StoreDataForDb {
fun storeGlucoseValuesToDb()
fun storeFoodsToDb()
fun scheduleNsIdUpdate()
fun updateNsIds()
}

View file

@ -36,5 +36,6 @@ interface ProfileSource {
var currentProfileIndex: Int
fun currentProfile(): SingleProfile?
fun storeSettings(activity: FragmentActivity? = null, emptyCreated: Boolean = false)
fun loadFromStore(store: ProfileStore)
}

View file

@ -8,6 +8,8 @@ interface Intents {
// AAPS -> Xdrip
const val ACTION_NEW_TREATMENT = "info.nightscout.client.NEW_TREATMENT"
const val ACTION_NEW_PROFILE = "info.nightscout.client.NEW_PROFILE"
const val ACTION_NEW_DEVICE_STATUS = "info.nightscout.client.NEW_DEVICESTATUS"
const val ACTION_NEW_FOOD = "info.nightscout.client.NEW_FOOD"
const val ACTION_NEW_SGV = "info.nightscout.client.NEW_SGV"
const val EXTRA_STATUSLINE = "com.eveningoutpost.dexdrip.Extras.Statusline"

View file

@ -17,70 +17,30 @@ import org.json.JSONObject
interface DataSyncSelector {
interface DataPair {
interface DataPair {
val value: Any
val id: Long
}
data class PairTemporaryTarget(override val value: TemporaryTarget, override val id: Long): DataPair
data class PairGlucoseValue(override val value: GlucoseValue, override val id: Long): DataPair
data class PairTherapyEvent(override val value: TherapyEvent, override val id: Long): DataPair
data class PairFood(override val value: Food, override val id: Long): DataPair
data class PairBolus(override val value: Bolus, override val id: Long): DataPair
data class PairCarbs(override val value: Carbs, override val id: Long): DataPair
data class PairBolusCalculatorResult(override val value: BolusCalculatorResult, override val id: Long): DataPair
data class PairTemporaryBasal(override val value: TemporaryBasal, override val id: Long): DataPair
data class PairExtendedBolus(override val value: ExtendedBolus, override val id: Long): DataPair
data class PairProfileSwitch(override val value: ProfileSwitch, override val id: Long): DataPair
data class PairEffectiveProfileSwitch(override val value: EffectiveProfileSwitch, override val id: Long): DataPair
data class PairOfflineEvent(override val value: OfflineEvent, override val id: Long): DataPair
data class PairProfileStore(override val value: JSONObject, override val id: Long): DataPair
data class PairDeviceStatus(override val value: DeviceStatus, override val id: Long): DataPair
data class PairTemporaryTarget(override val value: TemporaryTarget, override val id: Long) : DataPair
data class PairGlucoseValue(override val value: GlucoseValue, override val id: Long) : DataPair
data class PairTherapyEvent(override val value: TherapyEvent, override val id: Long) : DataPair
data class PairFood(override val value: Food, override val id: Long) : DataPair
data class PairBolus(override val value: Bolus, override val id: Long) : DataPair
data class PairCarbs(override val value: Carbs, override val id: Long) : DataPair
data class PairBolusCalculatorResult(override val value: BolusCalculatorResult, override val id: Long) : DataPair
data class PairTemporaryBasal(override val value: TemporaryBasal, override val id: Long) : DataPair
data class PairExtendedBolus(override val value: ExtendedBolus, override val id: Long) : DataPair
data class PairProfileSwitch(override val value: ProfileSwitch, override val id: Long) : DataPair
data class PairEffectiveProfileSwitch(override val value: EffectiveProfileSwitch, override val id: Long) : DataPair
data class PairOfflineEvent(override val value: OfflineEvent, override val id: Long) : DataPair
data class PairProfileStore(override val value: JSONObject, override val id: Long) : DataPair
data class PairDeviceStatus(override val value: DeviceStatus, override val id: Long) : DataPair
fun queueSize(): Long
fun doUpload()
fun resetToNextFullSync()
fun confirmLastBolusIdIfGreater(lastSynced: Long)
fun processChangedBoluses()
fun confirmLastCarbsIdIfGreater(lastSynced: Long)
fun processChangedCarbs()
fun confirmLastBolusCalculatorResultsIdIfGreater(lastSynced: Long)
fun processChangedBolusCalculatorResults()
fun confirmLastTempTargetsIdIfGreater(lastSynced: Long)
fun processChangedTempTargets()
fun confirmLastGlucoseValueIdIfGreater(lastSynced: Long)
fun processChangedGlucoseValues()
fun confirmLastTherapyEventIdIfGreater(lastSynced: Long)
fun processChangedTherapyEvents()
fun confirmLastFoodIdIfGreater(lastSynced: Long)
fun processChangedFoods()
fun confirmLastDeviceStatusIdIfGreater(lastSynced: Long)
fun processChangedDeviceStatuses()
fun confirmLastTemporaryBasalIdIfGreater(lastSynced: Long)
fun processChangedTemporaryBasals()
fun confirmLastExtendedBolusIdIfGreater(lastSynced: Long)
fun processChangedExtendedBoluses()
fun confirmLastProfileSwitchIdIfGreater(lastSynced: Long)
fun processChangedProfileSwitches()
fun confirmLastEffectiveProfileSwitchIdIfGreater(lastSynced: Long)
fun processChangedEffectiveProfileSwitches()
fun confirmLastOfflineEventIdIfGreater(lastSynced: Long)
fun processChangedOfflineEvents()
fun confirmLastProfileStore(lastSynced: Long)
fun processChangedProfileStore()
suspend fun doUpload()
}

View file

@ -0,0 +1,46 @@
package info.nightscout.interfaces.sync
interface DataSyncSelectorV1 : DataSyncSelector {
fun confirmLastBolusIdIfGreater(lastSynced: Long)
suspend fun processChangedBoluses()
fun confirmLastCarbsIdIfGreater(lastSynced: Long)
suspend fun processChangedCarbs()
fun confirmLastBolusCalculatorResultsIdIfGreater(lastSynced: Long)
suspend fun processChangedBolusCalculatorResults()
fun confirmLastTempTargetsIdIfGreater(lastSynced: Long)
suspend fun processChangedTempTargets()
fun confirmLastGlucoseValueIdIfGreater(lastSynced: Long)
suspend fun processChangedGlucoseValues()
fun confirmLastTherapyEventIdIfGreater(lastSynced: Long)
suspend fun processChangedTherapyEvents()
fun confirmLastFoodIdIfGreater(lastSynced: Long)
suspend fun processChangedFoods()
fun confirmLastDeviceStatusIdIfGreater(lastSynced: Long)
suspend fun processChangedDeviceStatuses()
fun confirmLastTemporaryBasalIdIfGreater(lastSynced: Long)
suspend fun processChangedTemporaryBasals()
fun confirmLastExtendedBolusIdIfGreater(lastSynced: Long)
suspend fun processChangedExtendedBoluses()
fun confirmLastProfileSwitchIdIfGreater(lastSynced: Long)
suspend fun processChangedProfileSwitches()
fun confirmLastEffectiveProfileSwitchIdIfGreater(lastSynced: Long)
suspend fun processChangedEffectiveProfileSwitches()
fun confirmLastOfflineEventIdIfGreater(lastSynced: Long)
suspend fun processChangedOfflineEvents()
fun confirmLastProfileStore(lastSynced: Long)
suspend fun processChangedProfileStore()
}

View file

@ -0,0 +1,3 @@
package info.nightscout.interfaces.sync
interface DataSyncSelectorV3 : DataSyncSelector

View file

@ -0,0 +1,3 @@
package info.nightscout.interfaces.sync
interface DataSyncSelectorXdrip : DataSyncSelector

View file

@ -1,7 +1,7 @@
package info.nightscout.interfaces.sync
import android.text.Spanned
import info.nightscout.interfaces.nsclient.NSAlarm
import info.nightscout.rx.events.EventNSClientNewLog
/**
* Plugin providing communication with Nightscout server
@ -24,14 +24,14 @@ interface NsClient : Sync {
fun resend(reason: String)
/**
* @return List last of messages for fragment in HTML format
* List of log messages for fragment
*/
fun textLog(): Spanned
val listLog: MutableList<EventNSClientNewLog>
/**
* Clear list of stored messages displayed in fragment
* Used data sync selector
*/
fun clearLog()
val dataSyncSelector: DataSyncSelector
/**
* Version of NS server
@ -89,8 +89,9 @@ interface NsClient : Sync {
* @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
* @return true for successful upload
*/
fun nsAdd(collection: String, dataPair: DataSyncSelector.DataPair, progress: String)
suspend fun nsAdd(collection: String, dataPair: DataSyncSelector.DataPair, progress: String): Boolean
/**
* Upload updated record to NS
@ -98,6 +99,7 @@ interface NsClient : Sync {
* @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
* @return true for successful upload
*/
fun nsUpdate(collection: String, dataPair: DataSyncSelector.DataPair, progress: String)
suspend fun nsUpdate(collection: String, dataPair: DataSyncSelector.DataPair, progress: String): Boolean
}

View file

@ -1,8 +1,5 @@
package info.nightscout.interfaces.workflow
import androidx.work.ListenableWorker
interface WorkerClasses {
val nsClientSourceWorker: Class<out ListenableWorker>
val nsProfileWorker: Class<out ListenableWorker>
// val nsProfileWorker: Class<out ListenableWorker>
}

View file

@ -119,7 +119,11 @@ 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())
return@callWrapper NSAndroidClient.ReadResponse(
code = response.raw().networkResponse?.code ?: response.code(),
lastServerModified = 0,
values = response.body()?.result?.map(RemoteEntry::toSgv).toNotNull()
)
} else if (response.code() in 400..499)
throw InvalidParameterNightscoutException(response.errorBody()?.string() ?: response.message())
else
@ -132,7 +136,11 @@ 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(RemoteEntry::toSgv).toNotNull())
return@callWrapper NSAndroidClient.ReadResponse(
code = response.raw().networkResponse?.code ?: response.code(),
lastServerModified = eTag,
values = response.body()?.result?.map(RemoteEntry::toSgv).toNotNull()
)
} else if (response.code() in 400..499)
throw InvalidParameterNightscoutException(response.errorBody()?.string() ?: response.message())
else
@ -143,39 +151,37 @@ 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())
return@callWrapper NSAndroidClient.ReadResponse(
code = response.raw().networkResponse?.code ?: response.code(),
lastServerModified = 0,
values = response.body()?.result?.map(RemoteEntry::toSgv).toNotNull()
)
} 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) {
override suspend fun createSgv(nsSgvV3: NSSgvV3): CreateUpdateResponse = callWrapper(dispatcher) {
val remoteEntry = nsSgvV3.toRemoteEntry()
remoteEntry.app = "AAPS"
val response = api.createEntry(remoteEntry)
val responseBody = response.body()
val errorResponse = response.errorBody()?.string()
if (response.code() == 200) {
if (response.code() == 200 || response.code() == 201) {
return@callWrapper CreateUpdateResponse(
response = response.code(),
identifier = null,
isDeduplication = true
)
} else if (response.code() == 201) {
return@callWrapper CreateUpdateResponse(
response = response.code(),
identifier = responseBody?.result?.identifier,
isDeduplication = responseBody?.result?.isDeduplication ?: false,
deduplicatedIdentifier = responseBody?.result?.deduplicatedIdentifier,
lastModified = responseBody?.result?.lastModified
identifier = responseBody?.identifier,
isDeduplication = responseBody?.isDeduplication ?: false,
deduplicatedIdentifier = responseBody?.deduplicatedIdentifier,
lastModified = responseBody?.lastModified
)
} else if (response.code() == 400 && errorResponse?.contains("Bad or missing utcOffset field") == true && nsSgvV3.utcOffset != 0L) {
// Record can be originally uploaded without utcOffset
// because utcOffset is mandatory and cannot be change, try 0
nsSgvV3.utcOffset = 0
return@callWrapper createSvg(nsSgvV3)
return@callWrapper createSgv(nsSgvV3)
} else if (response.code() == 400 && errorResponse?.contains("cannot be modified by the client") == true) {
// there is different field to field in AAPS
// not possible to upload
@ -234,7 +240,11 @@ 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())
return@callWrapper NSAndroidClient.ReadResponse(
code = response.raw().networkResponse?.code ?: response.code(),
lastServerModified = 0,
values = response.body()?.result?.map(RemoteTreatment::toTreatment).toNotNull()
)
} else if (response.code() in 400..499)
throw InvalidParameterNightscoutException(response.errorBody()?.string() ?: response.message())
else
@ -273,22 +283,13 @@ class NSAndroidClientImpl(
nsDeviceStatus.app = "AAPS"
val response = api.createDeviceStatus(nsDeviceStatus.toRemoteDeviceStatus())
if (response.isSuccessful) {
if (response.code() == 200) {
if (response.code() == 200 || response.code() == 201) {
return@callWrapper CreateUpdateResponse(
response = response.code(),
identifier = null,
isDeduplication = true,
deduplicatedIdentifier = null,
lastModified = null
)
} else if (response.code() == 201) {
return@callWrapper CreateUpdateResponse(
response = response.code(),
identifier = response.body()?.result?.identifier
?: throw UnknownResponseNightscoutException(),
isDeduplication = response.body()?.result?.isDeduplication ?: false,
deduplicatedIdentifier = response.body()?.result?.deduplicatedIdentifier,
lastModified = response.body()?.result?.lastModified
identifier = response.body()?.identifier,
isDeduplication = response.body()?.isDeduplication,
deduplicatedIdentifier = response.body()?.deduplicatedIdentifier,
lastModified = response.body()?.lastModified
)
} else throw UnknownResponseNightscoutException()
} else if (response.code() in 400..499) {
@ -307,19 +308,13 @@ class NSAndroidClientImpl(
remoteTreatment.app = "AAPS"
val response = api.createTreatment(remoteTreatment)
val errorResponse = response.errorBody()?.string()
if (response.code() == 200) {
if (response.code() == 200 || response.code() == 201) {
return@callWrapper CreateUpdateResponse(
response = response.code(),
identifier = null,
isDeduplication = true
)
} else if (response.code() == 201) {
return@callWrapper CreateUpdateResponse(
response = response.code(),
identifier = response.body()?.result?.identifier,
isDeduplication = response.body()?.result?.isDeduplication ?: false,
deduplicatedIdentifier = response.body()?.result?.deduplicatedIdentifier,
lastModified = response.body()?.result?.lastModified
identifier = response.body()?.identifier,
isDeduplication = response.body()?.isDeduplication ?: false,
deduplicatedIdentifier = response.body()?.deduplicatedIdentifier,
lastModified = response.body()?.lastModified
)
} else if (response.code() == 400 && errorResponse?.contains("Bad or missing utcOffset field") == true && nsTreatment.utcOffset != 0L) {
// Record can be originally uploaded without utcOffset
@ -384,7 +379,11 @@ 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())
return@callWrapper NSAndroidClient.ReadResponse(
code = response.raw().networkResponse?.code ?: response.code(),
lastServerModified = 0,
values = response.body()?.result?.map(RemoteFood::toNSFood).toNotNull()
)
} else if (response.code() in 400..499)
throw InvalidParameterNightscoutException(response.errorBody()?.string() ?: response.message())
else
@ -410,21 +409,13 @@ class NSAndroidClientImpl(
remoteFood.app = "AAPS"
val response = api.createFood(remoteFood)
if (response.isSuccessful) {
if (response.code() == 200) {
if (response.code() == 200 || response.code() == 201) {
return@callWrapper CreateUpdateResponse(
response = response.code(),
identifier = null,
isDeduplication = true,
deduplicatedIdentifier = null,
lastModified = null
)
} else if (response.code() == 201) {
return@callWrapper CreateUpdateResponse(
response = response.code(),
identifier = response.body()?.result?.identifier,
isDeduplication = response.body()?.result?.isDeduplication ?: false,
deduplicatedIdentifier = response.body()?.result?.deduplicatedIdentifier,
lastModified = response.body()?.result?.lastModified
identifier = response.body()?.identifier,
isDeduplication = response.body()?.isDeduplication,
deduplicatedIdentifier = response.body()?.deduplicatedIdentifier,
lastModified = response.body()?.lastModified
)
} else throw UnsuccessfullNightscoutException()
} else if (response.code() in 400..499) {
@ -474,21 +465,13 @@ class NSAndroidClientImpl(
remoteProfileStore.put("app", "AAPS")
val response = api.createProfile(JsonParser.parseString(remoteProfileStore.toString()).asJsonObject)
if (response.isSuccessful) {
if (response.code() == 200) {
if (response.code() == 200 || response.code() == 201) {
return@callWrapper CreateUpdateResponse(
response = response.code(),
identifier = null,
isDeduplication = true,
deduplicatedIdentifier = null,
lastModified = null
)
} else if (response.code() == 201) {
return@callWrapper CreateUpdateResponse(
response = response.code(),
identifier = response.body()?.result?.identifier,
isDeduplication = response.body()?.result?.isDeduplication ?: false,
deduplicatedIdentifier = response.body()?.result?.deduplicatedIdentifier,
lastModified = response.body()?.result?.lastModified
identifier = response.body()?.identifier,
isDeduplication = response.body()?.isDeduplication,
deduplicatedIdentifier = response.body()?.deduplicatedIdentifier,
lastModified = response.body()?.lastModified
)
} else throw UnsuccessfullNightscoutException()
} else if (response.code() in 400..499) {
@ -514,7 +497,6 @@ class NSAndroidClientImpl(
throw UnsuccessfullNightscoutException()
}
override suspend fun getProfileModifiedSince(from: Long): NSAndroidClient.ReadResponse<List<JSONObject>> = callWrapper(dispatcher) {
val response = api.getProfileModifiedSince(from)
@ -528,7 +510,6 @@ class NSAndroidClientImpl(
throw UnsuccessfullNightscoutException()
}
private suspend fun <T> callWrapper(dispatcher: CoroutineDispatcher, block: suspend () -> T): T =
withContext(dispatcher) {
retry(

View file

@ -25,7 +25,7 @@ interface NSAndroidClient {
suspend fun getSgvs(): ReadResponse<List<NSSgvV3>>
suspend fun getSgvsModifiedSince(from: Long, limit: Int): ReadResponse<List<NSSgvV3>>
suspend fun getSgvsNewerThan(from: Long, limit: Int): ReadResponse<List<NSSgvV3>>
suspend fun createSvg(nsSgvV3: NSSgvV3): CreateUpdateResponse
suspend fun createSgv(nsSgvV3: NSSgvV3): CreateUpdateResponse
suspend fun updateSvg(nsSgvV3: NSSgvV3): CreateUpdateResponse
suspend fun getTreatmentsNewerThan(createdAt: String, limit: Int): ReadResponse<List<NSTreatment>>

View file

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

View file

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

View file

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

View file

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

View file

@ -48,7 +48,7 @@ internal interface NightscoutRemoteService {
suspend fun getSgvsModifiedSince(@Path("from") from: Long, @Query("limit") limit: Int): Response<NSResponse<List<RemoteEntry>>>
@POST("v3/entries")
suspend fun createEntry(@Body remoteEntry: RemoteEntry): Response<NSResponse<RemoteCreateUpdateResponse>>
suspend fun createEntry(@Body remoteEntry: RemoteEntry): Response<RemoteCreateUpdateResponse>
@PATCH("v3/entries/{identifier}")
suspend fun updateEntry(@Body remoteEntry: RemoteEntry, @Path("identifier") identifier: String): Response<NSResponse<RemoteCreateUpdateResponse>>
@ -63,16 +63,16 @@ internal interface NightscoutRemoteService {
suspend fun getTreatmentsModifiedSince(@Path("from") from: Long, @Query("limit") limit: Int): Response<NSResponse<List<RemoteTreatment>>>
@POST("v3/treatments")
suspend fun createTreatment(@Body remoteTreatment: RemoteTreatment): Response<NSResponse<RemoteCreateUpdateResponse>>
suspend fun createTreatment(@Body remoteTreatment: RemoteTreatment): Response<RemoteCreateUpdateResponse>
@PATCH("v3/treatments/{identifier}")
suspend fun updateTreatment(@Body remoteTreatment: RemoteTreatment, @Path("identifier") identifier: String): Response<NSResponse<RemoteCreateUpdateResponse>>
suspend fun updateTreatment(@Body remoteTreatment: RemoteTreatment, @Path("identifier") identifier: String): Response<RemoteCreateUpdateResponse>
@DELETE("v3/treatments/{identifier}")
suspend fun deleteTreatment(@Path("identifier") identifier: String): Response<NSResponse<RemoteCreateUpdateResponse>>
suspend fun deleteTreatment(@Path("identifier") identifier: String): Response<RemoteCreateUpdateResponse>
@POST("v3/devicestatus")
suspend fun createDeviceStatus(@Body remoteDeviceStatus: RemoteDeviceStatus): Response<NSResponse<RemoteCreateUpdateResponse>>
suspend fun createDeviceStatus(@Body remoteDeviceStatus: RemoteDeviceStatus): Response<RemoteCreateUpdateResponse>
@GET("v3/devicestatus/history/{from}")
suspend fun getDeviceStatusModifiedSince(@Path("from") from: Long): Response<NSResponse<List<RemoteDeviceStatus>>>
@ -85,13 +85,13 @@ internal interface NightscoutRemoteService {
suspend fun getFoodsModifiedSince(@Path("from") from: Long, @Query("limit") limit: Int): Response<NSResponse<List<RemoteFood>>>
*/
@POST("v3/food")
suspend fun createFood(@Body remoteFood: RemoteFood): Response<NSResponse<RemoteCreateUpdateResponse>>
suspend fun createFood(@Body remoteFood: RemoteFood): Response<RemoteCreateUpdateResponse>
@PATCH("v3/food")
suspend fun updateFood(@Body remoteFood: RemoteFood, @Path("identifier") identifier: String): Response<NSResponse<RemoteCreateUpdateResponse>>
suspend fun updateFood(@Body remoteFood: RemoteFood, @Path("identifier") identifier: String): Response<RemoteCreateUpdateResponse>
@DELETE("v3/food")
suspend fun deleteFood(@Path("identifier") identifier: String): Response<NSResponse<RemoteCreateUpdateResponse>>
suspend fun deleteFood(@Path("identifier") identifier: String): Response<RemoteCreateUpdateResponse>
@GET("v3/profile/history/{from}")
suspend fun getProfileModifiedSince(@Path("from") from: Long, @Query("limit") limit: Int = 10): Response<NSResponse<List<JSONObject>>>
@ -100,8 +100,7 @@ internal interface NightscoutRemoteService {
@GET("v3/profile?sort\$desc=date&limit=1")
suspend fun getLastProfile(): Response<NSResponse<List<JSONObject>>>
@POST("v3/profile")
suspend fun createProfile(@Body profile: JsonObject): Response<NSResponse<RemoteCreateUpdateResponse>>
suspend fun createProfile(@Body profile: JsonObject): Response<RemoteCreateUpdateResponse>
}

View file

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

View file

@ -39,6 +39,28 @@ object OKDialog {
.setCanceledOnTouchOutside(false)
}
@SuppressLint("InflateParams")
fun show(context: Context, title: String, message: Spanned, runnable: Runnable? = null) {
var okClicked = false
var notEmptyTitle = title
if (notEmptyTitle.isEmpty()) notEmptyTitle = context.getString(R.string.message)
MaterialAlertDialogBuilder(context, R.style.DialogTheme)
.setCustomTitle(AlertDialogHelper.buildCustomTitle(context, notEmptyTitle))
.setMessage(message)
.setPositiveButton(context.getString(R.string.ok)) { dialog: DialogInterface, _: Int ->
if (okClicked) return@setPositiveButton
else {
okClicked = true
dialog.dismiss()
SystemClock.sleep(100)
runOnUiThread(runnable)
}
}
.show()
.setCanceledOnTouchOutside(false)
}
@SuppressLint("InflateParams")
fun show(activity: FragmentActivity, title: String, message: Spanned, runnable: Runnable? = null) {
var okClicked = false

View file

@ -45,7 +45,7 @@
<string name="mute5min">Mute for 5 minutes</string>
<string name="mute">Mute</string>
<string name="success">Success</string>
<string name="advancedsettings_title">Advanced Settings</string>
<string name="advanced_settings_title">Advanced Settings</string>
<string name="extendedbolusdeliveryerror">Extended bolus delivery error</string>
<string name="aps_mode_title">APS Mode</string>
<string name="extended_bolus">Extended bolus</string>
@ -620,4 +620,9 @@
<item quantity="other">%1$d minutes</item>
</plurals>
<!-- Maintenance-->
<string name="cleanup_db_confirm">Do you want to cleanup the database?\nIt will remove tracked changes and historic data older than 3 months.</string>
<string name="cleanup_db_confirm_sync">Do you want to cleanup the database?\nIt will remove tracked changes and historic data older than 3 months.\nDoing it will speedup full synchronization dramatically.</string>
<string name="cleared_entries">Cleared entries</string>
</resources>

View file

@ -70,8 +70,7 @@
<string name="key_autotune_additional_log" translatable="false">autotune_additional_log</string>
<string name="key_autotune_plugin" translatable="false">key_autotune_plugin</string>
<string name="key_autotune_last_run" translatable="false">key_autotune_last_run</string>
<string name="key_dexcomg5_xdripupload" translatable="false">dexcomg5_xdripupload</string>
<string name="key_nsclient_localbroadcasts" translatable="false">nsclient_localbroadcasts</string>
<string name="key_xdrip_local_broadcasts" translatable="false">xdrip_local_broadcasts</string>
<string name="key_usebolusreminder" translatable="false">use_bolus_reminder</string>
<string name="key_carbs_button_increment_1" translatable="false">carbs_button_increment_1</string>
<string name="key_carbs_button_increment_2" translatable="false">carbs_button_increment_2</string>
@ -85,6 +84,7 @@
<string name="key_ns_receive_profile_store" translatable="false">ns_receive_profile_store</string>
<string name="key_nsclientinternal_url" translatable="false">nsclientinternal_url</string>
<string name="key_nsclientinternal_api_secret" translatable="false">nsclientinternal_api_secret</string>
<string name="key_ns_use_ws" translatable="false">ns_use_ws</string>
<string name="key_ns_receive_insulin" translatable="false">ns_receive_insulin</string>
<string name="key_ns_receive_carbs" translatable="false">ns_receive_carbs</string>
<string name="key_ns_receive_therapy_events" translatable="false">ns_receive_therapy_events</string>

View file

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

View file

@ -123,7 +123,7 @@ import kotlin.math.roundToInt
val ret = StringBuilder()
removed
.filter { it.second > 0 }
.map { ret.append(it.first + " " + it.second + "\n") }
.map { ret.append(it.first + " " + it.second + "<br>") }
return ret.toString()
}
@ -150,10 +150,8 @@ import kotlin.math.roundToInt
database.glucoseValueDao.getModifiedFrom(lastId)
.subscribeOn(Schedulers.io())
fun getLastGlucoseValueIdWrapped(): Single<ValueWrapper<Long>> =
fun getLastGlucoseValueId(): Long? =
database.glucoseValueDao.getLastId()
.subscribeOn(Schedulers.io())
.toWrappedSingle()
fun getLastGlucoseValueWrapped(): Single<ValueWrapper<GlucoseValue>> =
database.glucoseValueDao.getLast()
@ -233,10 +231,8 @@ import kotlin.math.roundToInt
fun deleteAllTempTargetEntries() =
database.temporaryTargetDao.deleteAllEntries()
fun getLastTempTargetIdWrapped(): Single<ValueWrapper<Long>> =
fun getLastTempTargetId(): Long? =
database.temporaryTargetDao.getLastId()
.subscribeOn(Schedulers.io())
.toWrappedSingle()
// USER ENTRY
fun getAllUserEntries(): Single<List<UserEntry>> =
@ -309,10 +305,8 @@ import kotlin.math.roundToInt
.map { if (!ascending) it.reversed() else it }
.subscribeOn(Schedulers.io())
fun getLastProfileSwitchIdWrapped(): Single<ValueWrapper<Long>> =
fun getLastProfileSwitchId(): Long? =
database.profileSwitchDao.getLastId()
.subscribeOn(Schedulers.io())
.toWrappedSingle()
// EFFECTIVE PROFILE SWITCH
/*
@ -368,10 +362,8 @@ import kotlin.math.roundToInt
fun deleteAllEffectiveProfileSwitches() =
database.effectiveProfileSwitchDao.deleteAllEntries()
fun getLastEffectiveProfileSwitchIdWrapped(): Single<ValueWrapper<Long>> =
fun getLastEffectiveProfileSwitchId(): Long? =
database.effectiveProfileSwitchDao.getLastId()
.subscribeOn(Schedulers.io())
.toWrappedSingle()
// THERAPY EVENT
/*
@ -435,10 +427,8 @@ import kotlin.math.roundToInt
database.therapyEventDao.compatGetTherapyEventDataFromToTime(from, to)
.subscribeOn(Schedulers.io())
fun getLastTherapyEventIdWrapped(): Single<ValueWrapper<Long>> =
fun getLastTherapyEventId(): Long? =
database.therapyEventDao.getLastId()
.subscribeOn(Schedulers.io())
.toWrappedSingle()
// FOOD
/*
@ -471,10 +461,8 @@ import kotlin.math.roundToInt
fun deleteAllFoods() =
database.foodDao.deleteAllEntries()
fun getLastFoodIdWrapped(): Single<ValueWrapper<Long>> =
fun getLastFoodId(): Long? =
database.foodDao.getLastId()
.subscribeOn(Schedulers.io())
.toWrappedSingle()
// BOLUS
/*
@ -539,10 +527,8 @@ import kotlin.math.roundToInt
fun deleteAllBoluses() =
database.bolusDao.deleteAllEntries()
fun getLastBolusIdWrapped(): Single<ValueWrapper<Long>> =
fun getLastBolusId(): Long? =
database.bolusDao.getLastId()
.subscribeOn(Schedulers.io())
.toWrappedSingle()
// CARBS
private fun expandCarbs(carbs: Carbs): List<Carbs> =
@ -656,10 +642,8 @@ import kotlin.math.roundToInt
fun deleteAllCarbs() =
database.carbsDao.deleteAllEntries()
fun getLastCarbsIdWrapped(): Single<ValueWrapper<Long>> =
fun getLastCarbsId(): Long? =
database.carbsDao.getLastId()
.subscribeOn(Schedulers.io())
.toWrappedSingle()
// BOLUS CALCULATOR RESULT
/*
@ -698,10 +682,8 @@ import kotlin.math.roundToInt
fun deleteAllBolusCalculatorResults() =
database.bolusCalculatorResultDao.deleteAllEntries()
fun getLastBolusCalculatorResultIdWrapped(): Single<ValueWrapper<Long>> =
fun getLastBolusCalculatorResultId(): Long? =
database.bolusCalculatorResultDao.getLastId()
.subscribeOn(Schedulers.io())
.toWrappedSingle()
// DEVICE STATUS
fun insert(deviceStatus: DeviceStatus): Long =
@ -723,10 +705,8 @@ import kotlin.math.roundToInt
database.deviceStatusDao.getModifiedFrom(lastId)
.subscribeOn(Schedulers.io())
fun getLastDeviceStatusIdWrapped(): Single<ValueWrapper<Long>> =
fun getLastDeviceStatusId(): Long? =
database.deviceStatusDao.getLastId()
.subscribeOn(Schedulers.io())
.toWrappedSingle()
// TEMPORARY BASAL
/*
@ -789,10 +769,8 @@ import kotlin.math.roundToInt
fun getOldestTemporaryBasalRecord(): TemporaryBasal? =
database.temporaryBasalDao.getOldestRecord()
fun getLastTemporaryBasalIdWrapped(): Single<ValueWrapper<Long>> =
fun getLastTemporaryBasalId(): Long? =
database.temporaryBasalDao.getLastId()
.subscribeOn(Schedulers.io())
.toWrappedSingle()
// EXTENDED BOLUS
/*
@ -847,10 +825,8 @@ import kotlin.math.roundToInt
fun getOldestExtendedBolusRecord(): ExtendedBolus? =
database.extendedBolusDao.getOldestRecord()
fun getLastExtendedBolusIdWrapped(): Single<ValueWrapper<Long>> =
fun getLastExtendedBolusId(): Long? =
database.extendedBolusDao.getLastId()
.subscribeOn(Schedulers.io())
.toWrappedSingle()
// TotalDailyDose
fun getLastTotalDailyDoses(count: Int, ascending: Boolean): Single<List<TotalDailyDose>> =
@ -918,10 +894,8 @@ import kotlin.math.roundToInt
fun deleteAllOfflineEventEntries() =
database.offlineEventDao.deleteAllEntries()
fun getLastOfflineEventIdWrapped(): Single<ValueWrapper<Long>> =
fun getLastOfflineEventId(): Long? =
database.offlineEventDao.getLastId()
.subscribeOn(Schedulers.io())
.toWrappedSingle()
suspend fun collectNewEntriesSince(since: Long, until: Long, limit: Int, offset: Int) = NewEntries(
apsResults = database.apsResultDao.getNewEntriesSince(since, until, limit, offset),

View file

@ -24,7 +24,7 @@ internal interface BolusCalculatorResultDao : TraceableDao<BolusCalculatorResult
override fun deleteTrackedChanges(): Int
@Query("SELECT id FROM $TABLE_BOLUS_CALCULATOR_RESULTS ORDER BY id DESC limit 1")
fun getLastId(): Maybe<Long>
fun getLastId(): Long?
@Query("SELECT * FROM $TABLE_BOLUS_CALCULATOR_RESULTS WHERE timestamp = :timestamp AND referenceId IS NULL")
fun findByTimestamp(timestamp: Long): BolusCalculatorResult?

View file

@ -24,7 +24,7 @@ internal interface BolusDao : TraceableDao<Bolus> {
override fun deleteTrackedChanges(): Int
@Query("SELECT id FROM $TABLE_BOLUSES ORDER BY id DESC limit 1")
fun getLastId(): Maybe<Long>
fun getLastId(): Long?
@Query("SELECT * FROM $TABLE_BOLUSES WHERE timestamp = :timestamp AND referenceId IS NULL")
fun findByTimestamp(timestamp: Long): Bolus?

View file

@ -23,7 +23,7 @@ internal interface CarbsDao : TraceableDao<Carbs> {
override fun deleteTrackedChanges(): Int
@Query("SELECT id FROM $TABLE_CARBS ORDER BY id DESC limit 1")
fun getLastId(): Maybe<Long>
fun getLastId(): Long?
@Query("SELECT * FROM $TABLE_CARBS WHERE nightscoutId = :nsId AND referenceId IS NULL")
fun findByNSId(nsId: String): Carbs?

View file

@ -29,7 +29,7 @@ internal interface DeviceStatusDao {
fun deleteOlderThan(than: Long): Int
@Query("SELECT id FROM $TABLE_DEVICE_STATUS ORDER BY id DESC limit 1")
fun getLastId(): Maybe<Long>
fun getLastId(): Long?
@Query("DELETE FROM $TABLE_DEVICE_STATUS WHERE id NOT IN (SELECT MAX(id) FROM $TABLE_DEVICE_STATUS)")
fun deleteAllEntriesExceptLast()

View file

@ -23,7 +23,7 @@ internal interface EffectiveProfileSwitchDao : TraceableDao<EffectiveProfileSwit
override fun deleteTrackedChanges(): Int
@Query("SELECT id FROM $TABLE_EFFECTIVE_PROFILE_SWITCHES ORDER BY id DESC limit 1")
fun getLastId(): Maybe<Long>
fun getLastId(): Long?
@Query("SELECT * FROM $TABLE_EFFECTIVE_PROFILE_SWITCHES WHERE timestamp = :timestamp AND referenceId IS NULL")
fun findByTimestamp(timestamp: Long): EffectiveProfileSwitch?

View file

@ -24,7 +24,7 @@ internal interface ExtendedBolusDao : TraceableDao<ExtendedBolus> {
override fun deleteTrackedChanges(): Int
@Query("SELECT id FROM $TABLE_EXTENDED_BOLUSES ORDER BY id DESC limit 1")
fun getLastId(): Maybe<Long>
fun getLastId(): Long?
@Query("SELECT * FROM $TABLE_EXTENDED_BOLUSES WHERE timestamp = :timestamp AND referenceId IS NULL")
fun findByTimestamp(timestamp: Long): ExtendedBolus?

View file

@ -23,7 +23,7 @@ internal interface FoodDao : TraceableDao<Food> {
override fun deleteTrackedChanges(): Int
@Query("SELECT id FROM $TABLE_FOODS ORDER BY id DESC limit 1")
fun getLastId(): Maybe<Long>
fun getLastId(): Long?
@Query("SELECT * FROM $TABLE_FOODS WHERE nightscoutId = :nsId AND referenceId IS NULL")
fun findByNSId(nsId: String): Food?

View file

@ -26,7 +26,7 @@ internal interface GlucoseValueDao : TraceableDao<GlucoseValue> {
fun getLast(): Maybe<GlucoseValue>
@Query("SELECT id FROM $TABLE_GLUCOSE_VALUES ORDER BY id DESC limit 1")
fun getLastId(): Maybe<Long>
fun getLastId(): Long?
@Query("SELECT * FROM $TABLE_GLUCOSE_VALUES WHERE nightscoutId = :nsId AND referenceId IS NULL")
fun findByNSIdMaybe(nsId: String): Maybe<GlucoseValue>

View file

@ -23,7 +23,7 @@ internal interface OfflineEventDao : TraceableDao<OfflineEvent> {
override fun deleteTrackedChanges(): Int
@Query("SELECT id FROM $TABLE_OFFLINE_EVENTS ORDER BY id DESC limit 1")
fun getLastId(): Maybe<Long>
fun getLastId(): Long?
@Query("SELECT * FROM $TABLE_OFFLINE_EVENTS WHERE nightscoutId = :nsId AND referenceId IS NULL")
fun findByNSId(nsId: String): OfflineEvent?

View file

@ -24,7 +24,7 @@ internal interface ProfileSwitchDao : info.nightscout.database.impl.daos.workaro
override fun deleteTrackedChanges(): Int
@Query("SELECT id FROM $TABLE_PROFILE_SWITCHES ORDER BY id DESC limit 1")
fun getLastId(): Maybe<Long>
fun getLastId(): Long?
@Query("SELECT * FROM $TABLE_PROFILE_SWITCHES WHERE timestamp = :timestamp AND referenceId IS NULL")
fun findByTimestamp(timestamp: Long): ProfileSwitch?

View file

@ -24,7 +24,7 @@ internal interface TemporaryBasalDao : TraceableDao<TemporaryBasal> {
override fun deleteTrackedChanges(): Int
@Query("SELECT id FROM $TABLE_TEMPORARY_BASALS ORDER BY id DESC limit 1")
fun getLastId(): Maybe<Long>
fun getLastId(): Long?
@Query("SELECT * FROM $TABLE_TEMPORARY_BASALS WHERE temporaryId = :temporaryId")
fun findByTempId(temporaryId: Long): TemporaryBasal?

View file

@ -23,7 +23,7 @@ internal interface TemporaryTargetDao : TraceableDao<TemporaryTarget> {
override fun deleteTrackedChanges(): Int
@Query("SELECT id FROM $TABLE_TEMPORARY_TARGETS ORDER BY id DESC limit 1")
fun getLastId(): Maybe<Long>
fun getLastId(): Long?
@Query("SELECT * FROM $TABLE_TEMPORARY_TARGETS WHERE nightscoutId = :nsId AND referenceId IS NULL")
fun findByNSId(nsId: String): TemporaryTarget?

View file

@ -23,7 +23,7 @@ internal interface TherapyEventDao : TraceableDao<TherapyEvent> {
override fun deleteTrackedChanges(): Int
@Query("SELECT id FROM $TABLE_THERAPY_EVENTS ORDER BY id DESC limit 1")
fun getLastId(): Maybe<Long>
fun getLastId(): Long?
@Query("SELECT * FROM $TABLE_THERAPY_EVENTS WHERE type = :type AND timestamp = :timestamp AND referenceId IS NULL")
fun findByTimestamp(type: TherapyEvent.Type, timestamp: Long): TherapyEvent?

View file

@ -31,7 +31,7 @@ class PersistenceLayerImpl @Inject constructor(
private val disposable = CompositeDisposable()
override fun clearDatabases() = repository.clearDatabases()
override fun cleanupDatabase(keepDays: Long, deleteTrackedChanges: Boolean): String = cleanupDatabase(keepDays, deleteTrackedChanges)
override fun cleanupDatabase(keepDays: Long, deleteTrackedChanges: Boolean): String = repository.cleanupDatabase(keepDays, deleteTrackedChanges)
override fun insertOrUpdate(bolusCalculatorResult: BolusCalculatorResult) {
disposable += repository.runTransactionForResult(InsertOrUpdateBolusCalculatorResultTransaction(bolusCalculatorResult))

View file

@ -142,14 +142,14 @@ class GlucoseStatusTest : TestBase() {
// [{"mgdl":214,"mills":1521895773113,"device":"xDrip-DexcomG5","direction":"Flat","filtered":191040,"unfiltered":205024,"noise":1,"rssi":100},{"mgdl":219,"mills":1521896073352,"device":"xDrip-DexcomG5","direction":"Flat","filtered":200160,"unfiltered":209760,"noise":1,"rssi":100},{"mgdl":222,"mills":1521896372890,"device":"xDrip-DexcomG5","direction":"Flat","filtered":207360,"unfiltered":212512,"noise":1,"rssi":100},{"mgdl":220,"mills":1521896673062,"device":"xDrip-DexcomG5","direction":"Flat","filtered":211488,"unfiltered":210688,"noise":1,"rssi":100},{"mgdl":193,"mills":1521896972933,"device":"xDrip-DexcomG5","direction":"Flat","filtered":212384,"unfiltered":208960,"noise":1,"rssi":100},{"mgdl":181,"mills":1521897273336,"device":"xDrip-DexcomG5","direction":"SingleDown","filtered":210592,"unfiltered":204320,"noise":1,"rssi":100},{"mgdl":176,"mills":1521897572875,"device":"xDrip-DexcomG5","direction":"FortyFiveDown","filtered":206720,"unfiltered":197440,"noise":1,"rssi":100},{"mgdl":168,"mills":1521897872929,"device":"xDrip-DexcomG5","direction":"FortyFiveDown","filtered":201024,"unfiltered":187904,"noise":1,"rssi":100},{"mgdl":161,"mills":1521898172814,"device":"xDrip-DexcomG5","direction":"FortyFiveDown","filtered":193376,"unfiltered":178144,"noise":1,"rssi":100},{"mgdl":148,"mills":1521898472879,"device":"xDrip-DexcomG5","direction":"SingleDown","filtered":183264,"unfiltered":161216,"noise":1,"rssi":100},{"mgdl":139,"mills":1521898772862,"device":"xDrip-DexcomG5","direction":"FortyFiveDown","filtered":170784,"unfiltered":148928,"noise":1,"rssi":100},{"mgdl":132,"mills":1521899072896,"device":"xDrip-DexcomG5","direction":"FortyFiveDown","filtered":157248,"unfiltered":139552,"noise":1,"rssi":100},{"mgdl":125,"mills":1521899372834,"device":"xDrip-DexcomG5","direction":"FortyFiveDown","filtered":144416,"unfiltered":129616.00000000001,"noise":1,"rssi":100},{"mgdl":128,"mills":1521899973456,"device":"xDrip-DexcomG5","direction":"Flat","filtered":130240.00000000001,"unfiltered":133536,"noise":1,"rssi":100},{"mgdl":132,"mills":1521900573287,"device":"xDrip-DexcomG5","direction":"Flat","filtered":133504,"unfiltered":138720,"noise":1,"rssi":100},{"mgdl":127,"mills":1521900873711,"device":"xDrip-DexcomG5","direction":"Flat","filtered":136480,"unfiltered":132992,"noise":1,"rssi":100},{"mgdl":127,"mills":1521901180151,"device":"xDrip-DexcomG5","direction":"Flat","filtered":136896,"unfiltered":132128,"noise":1,"rssi":100},{"mgdl":125,"mills":1521901473582,"device":"xDrip-DexcomG5","direction":"Flat","filtered":134624,"unfiltered":129696,"noise":1,"rssi":100},{"mgdl":120,"mills":1521901773597,"device":"xDrip-DexcomG5","direction":"Flat","filtered":130704.00000000001,"unfiltered":123376,"noise":1,"rssi":100},{"mgdl":116,"mills":1521902075855,"device":"xDrip-DexcomG5","direction":"Flat","filtered":126272,"unfiltered":118448,"noise":1,"rssi":100}]
private fun generateValidBgData(): MutableList<InMemoryGlucoseValue> {
val list: MutableList<InMemoryGlucoseValue> = ArrayList()
list.add(InMemoryGlucoseValue(value = 214.0, timestamp = 1514766900000, trendArrow = GlucoseValue.TrendArrow.FLAT))
list.add(InMemoryGlucoseValue(value = 216.0, timestamp = 1514766600000, trendArrow = GlucoseValue.TrendArrow.FLAT))
list.add(InMemoryGlucoseValue(value = 219.0, timestamp = 1514766300000, trendArrow = GlucoseValue.TrendArrow.FLAT))
list.add(InMemoryGlucoseValue(value = 223.0, timestamp = 1514766000000, trendArrow = GlucoseValue.TrendArrow.FLAT))
list.add(InMemoryGlucoseValue(value = 222.0, timestamp = 1514765700000, trendArrow = GlucoseValue.TrendArrow.FLAT))
list.add(InMemoryGlucoseValue(value = 224.0, timestamp = 1514765400000, trendArrow = GlucoseValue.TrendArrow.FLAT))
list.add(InMemoryGlucoseValue(value = 226.0, timestamp = 1514765100000, trendArrow = GlucoseValue.TrendArrow.FLAT))
list.add(InMemoryGlucoseValue(value = 228.0, timestamp = 1514764800000, trendArrow = GlucoseValue.TrendArrow.FLAT))
list.add(InMemoryGlucoseValue(value = 214.0, timestamp = 1514766900000, trendArrow = GlucoseValue.TrendArrow.FLAT, sourceSensor = GlucoseValue.SourceSensor.UNKNOWN))
list.add(InMemoryGlucoseValue(value = 216.0, timestamp = 1514766600000, trendArrow = GlucoseValue.TrendArrow.FLAT, sourceSensor = GlucoseValue.SourceSensor.UNKNOWN))
list.add(InMemoryGlucoseValue(value = 219.0, timestamp = 1514766300000, trendArrow = GlucoseValue.TrendArrow.FLAT, sourceSensor = GlucoseValue.SourceSensor.UNKNOWN))
list.add(InMemoryGlucoseValue(value = 223.0, timestamp = 1514766000000, trendArrow = GlucoseValue.TrendArrow.FLAT, sourceSensor = GlucoseValue.SourceSensor.UNKNOWN))
list.add(InMemoryGlucoseValue(value = 222.0, timestamp = 1514765700000, trendArrow = GlucoseValue.TrendArrow.FLAT, sourceSensor = GlucoseValue.SourceSensor.UNKNOWN))
list.add(InMemoryGlucoseValue(value = 224.0, timestamp = 1514765400000, trendArrow = GlucoseValue.TrendArrow.FLAT, sourceSensor = GlucoseValue.SourceSensor.UNKNOWN))
list.add(InMemoryGlucoseValue(value = 226.0, timestamp = 1514765100000, trendArrow = GlucoseValue.TrendArrow.FLAT, sourceSensor = GlucoseValue.SourceSensor.UNKNOWN))
list.add(InMemoryGlucoseValue(value = 228.0, timestamp = 1514764800000, trendArrow = GlucoseValue.TrendArrow.FLAT, sourceSensor = GlucoseValue.SourceSensor.UNKNOWN))
return list
}
@ -159,13 +159,13 @@ class GlucoseStatusTest : TestBase() {
private fun generateOldBgData(): MutableList<InMemoryGlucoseValue> {
val list: MutableList<InMemoryGlucoseValue> = ArrayList()
list.add(InMemoryGlucoseValue(value = 228.0, timestamp = 1514764800000, trendArrow = GlucoseValue.TrendArrow.FLAT))
list.add(InMemoryGlucoseValue(value = 228.0, timestamp = 1514764800000, trendArrow = GlucoseValue.TrendArrow.FLAT, sourceSensor = GlucoseValue.SourceSensor.UNKNOWN))
return list
}
private fun generateOneCurrentRecordBgData(): MutableList<InMemoryGlucoseValue> {
val list: MutableList<InMemoryGlucoseValue> = ArrayList()
list.add(InMemoryGlucoseValue(value = 214.0, timestamp = 1514766900000, trendArrow = GlucoseValue.TrendArrow.FLAT))
list.add(InMemoryGlucoseValue(value = 214.0, timestamp = 1514766900000, trendArrow = GlucoseValue.TrendArrow.FLAT, sourceSensor = GlucoseValue.SourceSensor.UNKNOWN))
return list
}
}

View file

@ -52,7 +52,7 @@
<androidx.preference.PreferenceScreen
android:key="absorption_ama_advanced"
android:title="@string/advancedsettings_title">
android:title="@string/advanced_settings_title">
<Preference android:summary="@string/openapsama_link_to_preference_json_doc_txt">
<intent

View file

@ -162,7 +162,7 @@
<androidx.preference.PreferenceScreen
android:key="absorption_smb_advanced"
android:title="@string/advancedsettings_title">
android:title="@string/advanced_settings_title">
<Preference android:summary="@string/openapsama_link_to_preference_json_doc_txt">
<intent

View file

@ -183,7 +183,7 @@
<androidx.preference.PreferenceScreen
android:key="absorption_smb_advanced"
android:title="@string/advancedsettings_title">
android:title="@string/advanced_settings_title">
<Preference android:summary="@string/openapsama_link_to_preference_json_doc_txt">
<intent

View file

@ -82,7 +82,7 @@ class TriggerBgTest : TriggerTestBase() {
private fun generateOneCurrentRecordBgData(): MutableList<InMemoryGlucoseValue> {
val list: MutableList<InMemoryGlucoseValue> = ArrayList()
list.add(InMemoryGlucoseValue(value = 214.0, timestamp = now - 1, trendArrow = GlucoseValue.TrendArrow.FLAT))
list.add(InMemoryGlucoseValue(value = 214.0, timestamp = now - 1, trendArrow = GlucoseValue.TrendArrow.FLAT, sourceSensor = GlucoseValue.SourceSensor.UNKNOWN))
return list
}
}

View file

@ -91,14 +91,14 @@ class TriggerDeltaTest : TriggerTestBase() {
private fun generateValidBgData(): MutableList<InMemoryGlucoseValue> {
val list: MutableList<InMemoryGlucoseValue> = ArrayList()
list.add(InMemoryGlucoseValue(value = 214.0, timestamp = 1514766900000, trendArrow = GlucoseValue.TrendArrow.FLAT))
list.add(InMemoryGlucoseValue(value = 216.0, timestamp = 1514766600000, trendArrow = GlucoseValue.TrendArrow.FLAT))
list.add(InMemoryGlucoseValue(value = 219.0, timestamp = 1514766300000, trendArrow = GlucoseValue.TrendArrow.FLAT))
list.add(InMemoryGlucoseValue(value = 223.0, timestamp = 1514766000000, trendArrow = GlucoseValue.TrendArrow.FLAT))
list.add(InMemoryGlucoseValue(value = 222.0, timestamp = 1514765700000, trendArrow = GlucoseValue.TrendArrow.FLAT))
list.add(InMemoryGlucoseValue(value = 224.0, timestamp = 1514765400000, trendArrow = GlucoseValue.TrendArrow.FLAT))
list.add(InMemoryGlucoseValue(value = 226.0, timestamp = 1514765100000, trendArrow = GlucoseValue.TrendArrow.FLAT))
list.add(InMemoryGlucoseValue(value = 228.0, timestamp = 1514764800000, trendArrow = GlucoseValue.TrendArrow.FLAT))
list.add(InMemoryGlucoseValue(value = 214.0, timestamp = 1514766900000, trendArrow = GlucoseValue.TrendArrow.FLAT, sourceSensor = GlucoseValue.SourceSensor.UNKNOWN))
list.add(InMemoryGlucoseValue(value = 216.0, timestamp = 1514766600000, trendArrow = GlucoseValue.TrendArrow.FLAT, sourceSensor = GlucoseValue.SourceSensor.UNKNOWN))
list.add(InMemoryGlucoseValue(value = 219.0, timestamp = 1514766300000, trendArrow = GlucoseValue.TrendArrow.FLAT, sourceSensor = GlucoseValue.SourceSensor.UNKNOWN))
list.add(InMemoryGlucoseValue(value = 223.0, timestamp = 1514766000000, trendArrow = GlucoseValue.TrendArrow.FLAT, sourceSensor = GlucoseValue.SourceSensor.UNKNOWN))
list.add(InMemoryGlucoseValue(value = 222.0, timestamp = 1514765700000, trendArrow = GlucoseValue.TrendArrow.FLAT, sourceSensor = GlucoseValue.SourceSensor.UNKNOWN))
list.add(InMemoryGlucoseValue(value = 224.0, timestamp = 1514765400000, trendArrow = GlucoseValue.TrendArrow.FLAT, sourceSensor = GlucoseValue.SourceSensor.UNKNOWN))
list.add(InMemoryGlucoseValue(value = 226.0, timestamp = 1514765100000, trendArrow = GlucoseValue.TrendArrow.FLAT, sourceSensor = GlucoseValue.SourceSensor.UNKNOWN))
list.add(InMemoryGlucoseValue(value = 228.0, timestamp = 1514764800000, trendArrow = GlucoseValue.TrendArrow.FLAT, sourceSensor = GlucoseValue.SourceSensor.UNKNOWN))
return list
}
}

View file

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

View file

@ -24,7 +24,7 @@ import info.nightscout.interfaces.plugin.OwnDatabasePlugin
import info.nightscout.interfaces.protection.ProtectionCheck
import info.nightscout.interfaces.protection.ProtectionCheck.Protection.PREFERENCES
import info.nightscout.interfaces.pump.PumpSync
import info.nightscout.interfaces.sync.DataSyncSelector
import info.nightscout.interfaces.sync.DataSyncSelectorXdrip
import info.nightscout.interfaces.ui.UiInteraction
import info.nightscout.interfaces.utils.HtmlHelper
import info.nightscout.rx.AapsSchedulers
@ -51,7 +51,7 @@ class MaintenanceFragment : DaggerFragment() {
@Inject lateinit var persistenceLayer: PersistenceLayer
@Inject lateinit var protectionCheck: ProtectionCheck
@Inject lateinit var uel: UserEntryLogger
@Inject lateinit var dataSyncSelector: DataSyncSelector
@Inject lateinit var dataSyncSelectorXdrip: DataSyncSelectorXdrip
@Inject lateinit var pumpSync: PumpSync
@Inject lateinit var iobCobCalculator: IobCobCalculator
@Inject lateinit var overviewData: OverviewData
@ -93,7 +93,8 @@ class MaintenanceFragment : DaggerFragment() {
for (plugin in activePlugin.getSpecificPluginsListByInterface(OwnDatabasePlugin::class.java)) {
(plugin as OwnDatabasePlugin).clearAllTables()
}
dataSyncSelector.resetToNextFullSync()
activePlugin.activeNsClient?.dataSyncSelector?.resetToNextFullSync()
dataSyncSelectorXdrip.resetToNextFullSync()
pumpSync.connectNewPump()
overviewData.reset()
iobCobCalculator.ads.reset()
@ -111,7 +112,7 @@ class MaintenanceFragment : DaggerFragment() {
binding.cleanupDb.setOnClickListener {
activity?.let { activity ->
var result = ""
OKDialog.showConfirmation(activity, rh.gs(R.string.maintenance), rh.gs(R.string.cleanup_db_confirm), Runnable {
OKDialog.showConfirmation(activity, rh.gs(R.string.maintenance), rh.gs(info.nightscout.core.ui.R.string.cleanup_db_confirm), Runnable {
disposable += Completable.fromAction { result = persistenceLayer.cleanupDatabase(93, deleteTrackedChanges = true) }
.subscribeOn(aapsSchedulers.io)
.observeOn(aapsSchedulers.main)
@ -119,7 +120,12 @@ class MaintenanceFragment : DaggerFragment() {
onError = { aapsLogger.error("Error cleaning up databases", it) },
onComplete = {
if (result.isNotEmpty())
OKDialog.show(activity, rh.gs(info.nightscout.core.ui.R.string.result), HtmlHelper.fromHtml("<b>" + rh.gs(R.string.cleared_entries) + "</b>\n" + result).toSpanned())
OKDialog.show(
activity,
rh.gs(info.nightscout.core.ui.R.string.result),
HtmlHelper.fromHtml("<b>" + rh.gs(info.nightscout.core.ui.R.string.cleared_entries) + "</b><br>" + result)
.toSpanned()
)
aapsLogger.info(LTag.CORE, "Cleaned up databases with result: $result")
}
)

View file

@ -122,8 +122,6 @@
<string name="maintenance_shortname">MAINT</string>
<string name="description_maintenance">Provides several functions for maintenance (eg. log sending, log deletion).</string>
<string name="database_cleanup">Database cleanup</string>
<string name="cleanup_db_confirm">Do you want to cleanup the database?\nIt will remove tracked changes and historic data older than 3 months.</string>
<string name="cleared_entries">Cleared entries</string>
<string name="reset_db_confirm">Do you really want to reset the databases?</string>
<string name="maintenance_settings">Maintenance Settings</string>
<string name="maintenance_email">Email recipient</string>

View file

@ -17,6 +17,7 @@ import info.nightscout.plugins.iob.iobCobCalculator.data.AutosensDataObject
FoodModule::class,
SMSCommunicatorModule::class,
ProfileModule::class,
ProfileModule.Bindings::class,
SkinsModule::class,
SkinsUiModule::class,
ActionsModule::class,

View file

@ -1,7 +1,9 @@
package info.nightscout.plugins.di
import dagger.Binds
import dagger.Module
import dagger.android.ContributesAndroidInjector
import info.nightscout.interfaces.profile.ProfileSource
import info.nightscout.plugins.profile.ProfileFragment
import info.nightscout.plugins.profile.ProfilePlugin
@ -9,6 +11,12 @@ import info.nightscout.plugins.profile.ProfilePlugin
@Suppress("unused")
abstract class ProfileModule {
@ContributesAndroidInjector abstract fun contributesNSProfileWorker(): ProfilePlugin.NSProfileWorker
@ContributesAndroidInjector abstract fun contributesLocalProfileFragment(): ProfileFragment
@Module
interface Bindings {
@Binds fun bindProfileSource(profilePlugin: ProfilePlugin): ProfileSource
}
}

View file

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

View file

@ -1,9 +1,6 @@
package info.nightscout.plugins.profile
import android.content.Context
import androidx.fragment.app.FragmentActivity
import androidx.work.WorkerParameters
import androidx.work.workDataOf
import dagger.android.HasAndroidInjector
import info.nightscout.androidaps.annotations.OpenForTesting
import info.nightscout.core.extensions.blockFromJsonArray
@ -11,12 +8,9 @@ import info.nightscout.core.extensions.pureProfileFromJson
import info.nightscout.core.profile.ProfileSealed
import info.nightscout.core.ui.dialogs.OKDialog
import info.nightscout.core.ui.toast.ToastUtils
import info.nightscout.core.utils.receivers.DataWorkerStorage
import info.nightscout.core.utils.worker.LoggingWorker
import info.nightscout.interfaces.Config
import info.nightscout.interfaces.Constants
import info.nightscout.interfaces.GlucoseUnit
import info.nightscout.interfaces.XDripBroadcast
import info.nightscout.interfaces.notifications.Notification
import info.nightscout.interfaces.plugin.ActivePlugin
import info.nightscout.interfaces.plugin.PluginBase
@ -40,7 +34,6 @@ import info.nightscout.rx.logging.LTag
import info.nightscout.shared.interfaces.ResourceHelper
import info.nightscout.shared.sharedPreferences.SP
import info.nightscout.shared.utils.DateUtil
import kotlinx.coroutines.Dispatchers
import org.json.JSONArray
import org.json.JSONException
import org.json.JSONObject
@ -235,7 +228,7 @@ class ProfilePlugin @Inject constructor(
}
@Synchronized
fun loadFromStore(store: ProfileStore) {
override fun loadFromStore(store: ProfileStore) {
try {
val newProfiles: ArrayList<ProfileSource.SingleProfile> = ArrayList()
for (p in store.getProfileList()) {
@ -429,41 +422,4 @@ class ProfilePlugin @Inject constructor(
get() = rawProfile?.getDefaultProfile()?.let {
DecimalFormatter.to2Decimal(ProfileSealed.Pure(it).percentageBasalSum()) + "U "
} ?: "INVALID"
// cannot be inner class because of needed injection
class NSProfileWorker(
context: Context,
params: WorkerParameters
) : LoggingWorker(context, params, Dispatchers.Default) {
@Inject lateinit var injector: HasAndroidInjector
@Inject lateinit var rxBus: RxBus
@Inject lateinit var dateUtil: DateUtil
@Inject lateinit var dataWorkerStorage: DataWorkerStorage
@Inject lateinit var sp: SP
@Inject lateinit var config: Config
@Inject lateinit var profilePlugin: ProfilePlugin
@Inject lateinit var xDripBroadcast: XDripBroadcast
@Inject lateinit var instantiator: Instantiator
override suspend fun doWorkAndLog(): Result {
val profileJson = dataWorkerStorage.pickupJSONObject(inputData.getLong(DataWorkerStorage.STORE_KEY, -1))
?: return Result.failure(workDataOf("Error" to "missing input data"))
xDripBroadcast.sendProfile(profileJson)
if (sp.getBoolean(info.nightscout.core.utils.R.string.key_ns_receive_profile_store, true) || config.NSCLIENT) {
val store = instantiator.provideProfileStore(profileJson)
val createdAt = store.getStartDate()
val lastLocalChange = sp.getLong(info.nightscout.core.utils.R.string.key_local_profile_last_change, 0)
aapsLogger.debug(LTag.PROFILE, "Received profileStore: createdAt: $createdAt Local last modification: $lastLocalChange")
@Suppress("LiftReturnOrAssignment")
if (createdAt > lastLocalChange || createdAt % 1000 == 0L) {// whole second means edited in NS
profilePlugin.loadFromStore(store)
aapsLogger.debug(LTag.PROFILE, "Received profileStore: $profileJson")
return Result.success(workDataOf("Data" to profileJson.toString().substring(0..Integer.min(5000, profileJson.length()))))
} else
return Result.success(workDataOf("Result" to "Unchanged. Ignoring"))
}
return Result.success(workDataOf("Result" to "Sync not enabled"))
}
}
}

View file

@ -496,7 +496,7 @@
<androidx.preference.PreferenceScreen
android:key="overview_advanced"
android:title="@string/advancedsettings_title">
android:title="@string/advanced_settings_title">
<SwitchPreference
android:defaultValue="false"

View file

@ -1,6 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
<application>
<activity
android:name=".ui.OHLoginActivity"

View file

@ -30,6 +30,7 @@ import info.nightscout.database.impl.AppRepository
import info.nightscout.interfaces.plugin.PluginBase
import info.nightscout.interfaces.plugin.PluginDescription
import info.nightscout.interfaces.plugin.PluginType
import info.nightscout.interfaces.sync.Sync
import info.nightscout.rx.bus.RxBus
import info.nightscout.rx.events.EventPreferenceChange
import info.nightscout.rx.logging.AAPSLogger
@ -67,7 +68,7 @@ class OpenHumansUploaderPlugin @Inject internal constructor(
counterDelegate: OHCounterDelegate,
appIdDelegate: OHAppIDDelegate,
private val rxBus: RxBus
) : PluginBase(
) : Sync, PluginBase(
PluginDescription()
.mainType(PluginType.SYNC)
.pluginIcon(R.drawable.open_humans_white)
@ -85,6 +86,11 @@ class OpenHumansUploaderPlugin @Inject internal constructor(
private val preferenceChangeDisposable = CompositeDisposable()
// Not used Sync interface members
override val hasWritePermission: Boolean = true
override val connected: Boolean = true
override val status: String = ""
override fun onStart() {
super.onStart()
setupNotificationChannels()

View file

@ -38,7 +38,7 @@
<androidx.preference.PreferenceScreen
android:key="absorption_aaps_advanced"
android:title="@string/advancedsettings_title">
android:title="@string/advanced_settings_title">
<info.nightscout.core.validators.ValidatingEditTextPreference
android:defaultValue="1.2"

View file

@ -37,7 +37,7 @@
<androidx.preference.PreferenceScreen
android:key="absorption_oref1_advanced"
android:title="@string/advancedsettings_title">
android:title="@string/advanced_settings_title">
<info.nightscout.core.validators.ValidatingEditTextPreference
android:defaultValue="1.2"

View file

@ -35,6 +35,7 @@ import info.nightscout.rx.events.EventNewBG
import info.nightscout.rx.logging.AAPSLogger
import info.nightscout.rx.logging.LTag
import info.nightscout.shared.extensions.toVisibility
import info.nightscout.shared.extensions.toVisibilityKeepSpace
import info.nightscout.shared.interfaces.ResourceHelper
import info.nightscout.shared.utils.DateUtil
import info.nightscout.shared.utils.T
@ -135,7 +136,7 @@ class BGSourceFragment : DaggerFragment(), MenuProvider {
override fun onBindViewHolder(holder: GlucoseValuesViewHolder, position: Int) {
val glucoseValue = glucoseValues[position]
holder.binding.ns.visibility = (glucoseValue.interfaceIDs.nightscoutId != null).toVisibility()
holder.binding.ns.visibility = (glucoseValue.interfaceIDs.nightscoutId != null).toVisibilityKeepSpace()
holder.binding.invalid.visibility = (!glucoseValue.isValid).toVisibility()
val newDay = position == 0 || !dateUtil.isSameDay(glucoseValue.timestamp, glucoseValues[position - 1].timestamp)
holder.binding.date.visibility = newDay.toVisibility()
@ -201,7 +202,7 @@ class BGSourceFragment : DaggerFragment(), MenuProvider {
R.string.tomato -> Sources.Tomato
R.string.glunovo -> Sources.Glunovo
R.string.intelligo -> Sources.Intelligo
R.string.xdrip -> Sources.Xdrip
R.string.source_xdrip -> Sources.Xdrip
R.string.aidex -> Sources.Aidex
else -> Sources.Unknown
}

View file

@ -20,7 +20,6 @@ import info.nightscout.database.impl.transactions.CgmSourceTransaction
import info.nightscout.database.impl.transactions.InvalidateGlucoseValueTransaction
import info.nightscout.database.transactions.TransactionGlucoseValue
import info.nightscout.interfaces.Config
import info.nightscout.interfaces.XDripBroadcast
import info.nightscout.interfaces.logging.UserEntryLogger
import info.nightscout.interfaces.plugin.PluginBase
import info.nightscout.interfaces.plugin.PluginDescription
@ -91,7 +90,6 @@ class DexcomPlugin @Inject constructor(
@Inject lateinit var sp: SP
@Inject lateinit var dateUtil: DateUtil
@Inject lateinit var dataWorkerStorage: DataWorkerStorage
@Inject lateinit var xDripBroadcast: XDripBroadcast
@Inject lateinit var repository: AppRepository
@Inject lateinit var uel: UserEntryLogger
@ -185,11 +183,9 @@ class DexcomPlugin @Inject constructor(
}
}
}
xDripBroadcast.sendIn640gMode(result.inserted[i])
aapsLogger.debug(LTag.DATABASE, "Inserted bg ${result.inserted[i]}")
}
result.updated.forEach {
xDripBroadcast.sendIn640gMode(it)
aapsLogger.debug(LTag.DATABASE, "Updated bg $it")
}
result.sensorInsertionsInserted.forEach {

View file

@ -12,7 +12,6 @@ import info.nightscout.database.impl.AppRepository
import info.nightscout.database.impl.transactions.CgmSourceTransaction
import info.nightscout.database.impl.transactions.InsertIfNewByTimestampTherapyEventTransaction
import info.nightscout.database.transactions.TransactionGlucoseValue
import info.nightscout.interfaces.XDripBroadcast
import info.nightscout.interfaces.plugin.PluginBase
import info.nightscout.interfaces.plugin.PluginDescription
import info.nightscout.interfaces.plugin.PluginType
@ -61,7 +60,6 @@ class EversensePlugin @Inject constructor(
@Inject lateinit var dateUtil: DateUtil
@Inject lateinit var dataWorkerStorage: DataWorkerStorage
@Inject lateinit var repository: AppRepository
@Inject lateinit var xDripBroadcast: XDripBroadcast
override suspend fun doWorkAndLog(): Result {
var ret = Result.success()
@ -114,7 +112,6 @@ class EversensePlugin @Inject constructor(
.blockingGet()
.also { savedValues ->
savedValues.inserted.forEach {
xDripBroadcast.sendIn640gMode(it)
aapsLogger.debug(LTag.DATABASE, "Inserted bg $it")
}
}

View file

@ -10,7 +10,6 @@ import info.nightscout.database.entities.GlucoseValue
import info.nightscout.database.impl.AppRepository
import info.nightscout.database.impl.transactions.CgmSourceTransaction
import info.nightscout.database.transactions.TransactionGlucoseValue
import info.nightscout.interfaces.XDripBroadcast
import info.nightscout.interfaces.plugin.PluginBase
import info.nightscout.interfaces.plugin.PluginDescription
import info.nightscout.interfaces.plugin.PluginType
@ -50,7 +49,6 @@ class GlimpPlugin @Inject constructor(
@Inject lateinit var injector: HasAndroidInjector
@Inject lateinit var glimpPlugin: GlimpPlugin
@Inject lateinit var repository: AppRepository
@Inject lateinit var xDripBroadcast: XDripBroadcast
override suspend fun doWorkAndLog(): Result {
var ret = Result.success()
@ -74,7 +72,6 @@ class GlimpPlugin @Inject constructor(
.blockingGet()
.also { savedValues ->
savedValues.inserted.forEach {
xDripBroadcast.sendIn640gMode(it)
aapsLogger.debug(LTag.DATABASE, "Inserted bg $it")
}
}

View file

@ -14,7 +14,6 @@ import info.nightscout.database.impl.AppRepository
import info.nightscout.database.impl.transactions.CgmSourceTransaction
import info.nightscout.database.transactions.TransactionGlucoseValue
import info.nightscout.interfaces.Constants
import info.nightscout.interfaces.XDripBroadcast
import info.nightscout.interfaces.logging.UserEntryLogger
import info.nightscout.interfaces.plugin.PluginBase
import info.nightscout.interfaces.plugin.PluginDescription
@ -38,7 +37,6 @@ class GlunovoPlugin @Inject constructor(
private val sp: SP,
private val context: Context,
private val repository: AppRepository,
private val xDripBroadcast: XDripBroadcast,
private val dateUtil: DateUtil,
private val uel: UserEntryLogger,
private val fabricPrivacy: FabricPrivacy
@ -148,7 +146,6 @@ class GlunovoPlugin @Inject constructor(
.blockingGet()
.also { savedValues ->
savedValues.inserted.forEach {
xDripBroadcast.sendIn640gMode(it)
aapsLogger.debug(LTag.DATABASE, "Inserted bg $it")
}
savedValues.calibrationsInserted.forEach { calibration ->

View file

@ -16,7 +16,6 @@ import info.nightscout.database.impl.AppRepository
import info.nightscout.database.impl.transactions.CgmSourceTransaction
import info.nightscout.database.transactions.TransactionGlucoseValue
import info.nightscout.interfaces.Constants
import info.nightscout.interfaces.XDripBroadcast
import info.nightscout.interfaces.logging.UserEntryLogger
import info.nightscout.interfaces.plugin.PluginBase
import info.nightscout.interfaces.plugin.PluginDescription
@ -41,7 +40,6 @@ class IntelligoPlugin @Inject constructor(
private val sp: SP,
private val context: Context,
private val repository: AppRepository,
private val xDripBroadcast: XDripBroadcast,
private val dateUtil: DateUtil,
private val uel: UserEntryLogger,
private val fabricPrivacy: FabricPrivacy
@ -159,7 +157,6 @@ class IntelligoPlugin @Inject constructor(
.blockingGet()
.also { savedValues ->
savedValues.inserted.forEach {
xDripBroadcast.sendIn640gMode(it)
aapsLogger.debug(LTag.DATABASE, "Inserted bg $it")
}
savedValues.calibrationsInserted.forEach { calibration ->

View file

@ -4,13 +4,11 @@ import android.content.Context
import androidx.work.WorkerParameters
import androidx.work.workDataOf
import dagger.android.HasAndroidInjector
import info.nightscout.core.utils.receivers.DataWorkerStorage
import info.nightscout.core.utils.worker.LoggingWorker
import info.nightscout.database.entities.GlucoseValue
import info.nightscout.database.impl.AppRepository
import info.nightscout.database.impl.transactions.CgmSourceTransaction
import info.nightscout.database.transactions.TransactionGlucoseValue
import info.nightscout.interfaces.XDripBroadcast
import info.nightscout.interfaces.plugin.PluginBase
import info.nightscout.interfaces.plugin.PluginDescription
import info.nightscout.interfaces.plugin.PluginType
@ -51,9 +49,7 @@ class MM640gPlugin @Inject constructor(
@Inject lateinit var mM640gPlugin: MM640gPlugin
@Inject lateinit var injector: HasAndroidInjector
@Inject lateinit var dateUtil: DateUtil
@Inject lateinit var dataWorkerStorage: DataWorkerStorage
@Inject lateinit var repository: AppRepository
@Inject lateinit var xDripBroadcast: XDripBroadcast
override suspend fun doWorkAndLog(): Result {
var ret = Result.success()
@ -90,7 +86,6 @@ class MM640gPlugin @Inject constructor(
.blockingGet()
.also { savedValues ->
savedValues.all().forEach {
xDripBroadcast.sendIn640gMode(it)
aapsLogger.debug(LTag.DATABASE, "Inserted bg $it")
}
}

View file

@ -1,39 +1,16 @@
package info.nightscout.source
import android.content.Context
import androidx.work.WorkerParameters
import androidx.work.workDataOf
import dagger.android.HasAndroidInjector
import info.nightscout.core.utils.receivers.DataWorkerStorage
import info.nightscout.core.utils.worker.LoggingWorker
import info.nightscout.database.entities.GlucoseValue
import info.nightscout.database.impl.AppRepository
import info.nightscout.database.transactions.TransactionGlucoseValue
import info.nightscout.interfaces.Config
import info.nightscout.interfaces.XDripBroadcast
import info.nightscout.interfaces.notifications.Notification
import info.nightscout.interfaces.nsclient.NSSgv
import info.nightscout.interfaces.nsclient.StoreDataForDb
import info.nightscout.interfaces.plugin.ActivePlugin
import info.nightscout.interfaces.plugin.PluginBase
import info.nightscout.interfaces.plugin.PluginDescription
import info.nightscout.interfaces.plugin.PluginType
import info.nightscout.interfaces.source.BgSource
import info.nightscout.interfaces.source.DoingOwnUploadSource
import info.nightscout.interfaces.source.NSClientSource
import info.nightscout.rx.bus.RxBus
import info.nightscout.rx.events.EventDismissNotification
import info.nightscout.rx.logging.AAPSLogger
import info.nightscout.rx.logging.LTag
import info.nightscout.sdk.localmodel.entry.NSSgvV3
import info.nightscout.shared.interfaces.ResourceHelper
import info.nightscout.shared.sharedPreferences.SP
import info.nightscout.shared.utils.DateUtil
import info.nightscout.shared.utils.T
import kotlinx.coroutines.Dispatchers
import org.json.JSONArray
import org.json.JSONObject
import java.security.InvalidParameterException
import javax.inject.Inject
import javax.inject.Singleton
@ -50,21 +27,15 @@ class NSClientSourcePlugin @Inject constructor(
.pluginIcon(info.nightscout.core.main.R.drawable.ic_nsclient_bg)
.pluginName(R.string.ns_client_bg)
.shortName(R.string.ns_client_bg_short)
.description(R.string.description_source_ns_client),
.description(R.string.description_source_ns_client)
.alwaysEnabled(config.NSCLIENT)
.setDefault(config.NSCLIENT),
aapsLogger, rh, injector
), BgSource, NSClientSource, DoingOwnUploadSource {
private var lastBGTimeStamp: Long = 0
private var isAdvancedFilteringEnabled = false
init {
if (config.NSCLIENT) {
pluginDescription
.alwaysEnabled(true)
.setDefault()
}
}
override fun advancedFilteringSupported(): Boolean = isAdvancedFilteringEnabled
override fun shouldUploadToNs(glucoseValue: GlucoseValue): Boolean = false
@ -81,96 +52,4 @@ class NSClientSourcePlugin @Inject constructor(
lastBGTimeStamp = glucoseValue.timestamp
}
}
// cannot be inner class because of needed injection
class NSClientSourceWorker(
context: Context,
params: WorkerParameters
) : LoggingWorker(context, params, Dispatchers.IO) {
@Inject lateinit var nsClientSourcePlugin: NSClientSourcePlugin
@Inject lateinit var injector: HasAndroidInjector
@Inject lateinit var sp: SP
@Inject lateinit var rxBus: RxBus
@Inject lateinit var dateUtil: DateUtil
@Inject lateinit var dataWorkerStorage: DataWorkerStorage
@Inject lateinit var repository: AppRepository
@Inject lateinit var xDripBroadcast: XDripBroadcast
@Inject lateinit var activePlugin: ActivePlugin
@Inject lateinit var storeDataForDb: StoreDataForDb
private fun toGv(jsonObject: JSONObject): TransactionGlucoseValue? {
val sgv = NSSgv(jsonObject)
return TransactionGlucoseValue(
timestamp = sgv.mills ?: return null,
value = sgv.mgdl?.toDouble() ?: return null,
noise = null,
raw = sgv.filtered?.toDouble(),
trendArrow = GlucoseValue.TrendArrow.fromString(sgv.direction),
nightscoutId = sgv.id,
sourceSensor = GlucoseValue.SourceSensor.fromString(sgv.device)
)
}
private fun toGv(sgv: NSSgvV3): TransactionGlucoseValue {
return TransactionGlucoseValue(
timestamp = sgv.date ?: throw InvalidParameterException(),
value = sgv.sgv,
noise = sgv.noise?.toDouble(),
raw = sgv.filtered,
trendArrow = GlucoseValue.TrendArrow.fromString(sgv.direction?.nsName),
nightscoutId = sgv.identifier,
sourceSensor = GlucoseValue.SourceSensor.fromString(sgv.device),
isValid = sgv.isValid,
utcOffset = T.mins(sgv.utcOffset ?: 0L).msecs()
)
}
@Suppress("SpellCheckingInspection")
override suspend fun doWorkAndLog(): Result {
var ret = Result.success()
val sgvs = dataWorkerStorage.pickupObject(inputData.getLong(DataWorkerStorage.STORE_KEY, -1))
?: return Result.failure(workDataOf("Error" to "missing input data"))
if (!nsClientSourcePlugin.isEnabled() && !sp.getBoolean(info.nightscout.core.utils.R.string.key_ns_receive_cgm, false))
return Result.success(workDataOf("Result" to "Sync not enabled"))
var latestDateInReceivedData: Long = 0
aapsLogger.debug(LTag.BGSOURCE, "Received NS Data: $sgvs")
val glucoseValues = mutableListOf<TransactionGlucoseValue>()
try {
if (sgvs is JSONArray) { // V1 client
xDripBroadcast.sendSgvs(sgvs)
for (i in 0 until sgvs.length()) {
val sgv = toGv(sgvs.getJSONObject(i)) ?: continue
if (sgv.timestamp < dateUtil.now() && sgv.timestamp > latestDateInReceivedData) latestDateInReceivedData = sgv.timestamp
glucoseValues += sgv
}
} else if (sgvs is List<*>) { // V3 client
for (i in 0 until sgvs.size) {
val sgv = toGv(sgvs[i] as NSSgvV3)
if (sgv.timestamp < dateUtil.now() && sgv.timestamp > latestDateInReceivedData) latestDateInReceivedData = sgv.timestamp
glucoseValues += sgv
}
}
activePlugin.activeNsClient?.updateLatestBgReceivedIfNewer(latestDateInReceivedData)
// Was that sgv more less 5 mins ago ?
if (T.msecs(dateUtil.now() - latestDateInReceivedData).mins() < 5L) {
rxBus.send(EventDismissNotification(Notification.NS_ALARM))
rxBus.send(EventDismissNotification(Notification.NS_URGENT_ALARM))
}
storeDataForDb.glucoseValues.addAll(glucoseValues)
} catch (e: Exception) {
aapsLogger.error("Unhandled exception", e)
ret = Result.failure(workDataOf("Error" to e.toString()))
}
return ret
}
}
}

View file

@ -10,7 +10,6 @@ import info.nightscout.database.impl.AppRepository
import info.nightscout.database.impl.transactions.CgmSourceTransaction
import info.nightscout.database.transactions.TransactionGlucoseValue
import info.nightscout.interfaces.Constants
import info.nightscout.interfaces.XDripBroadcast
import info.nightscout.interfaces.plugin.PluginBase
import info.nightscout.interfaces.plugin.PluginDescription
import info.nightscout.interfaces.plugin.PluginType
@ -52,7 +51,6 @@ class PoctechPlugin @Inject constructor(
@Inject lateinit var injector: HasAndroidInjector
@Inject lateinit var poctechPlugin: PoctechPlugin
@Inject lateinit var repository: AppRepository
@Inject lateinit var xDripBroadcast: XDripBroadcast
override suspend fun doWorkAndLog(): Result {
var ret = Result.success()
@ -83,7 +81,6 @@ class PoctechPlugin @Inject constructor(
.blockingGet()
.also { savedValues ->
savedValues.inserted.forEach {
xDripBroadcast.sendIn640gMode(it)
aapsLogger.debug(LTag.DATABASE, "Inserted bg $it")
}
}

View file

@ -10,7 +10,6 @@ import info.nightscout.database.impl.AppRepository
import info.nightscout.database.impl.transactions.CgmSourceTransaction
import info.nightscout.database.transactions.TransactionGlucoseValue
import info.nightscout.interfaces.Config
import info.nightscout.interfaces.XDripBroadcast
import info.nightscout.interfaces.plugin.PluginBase
import info.nightscout.interfaces.plugin.PluginDescription
import info.nightscout.interfaces.plugin.PluginType
@ -38,7 +37,6 @@ class RandomBgPlugin @Inject constructor(
aapsLogger: AAPSLogger,
private val sp: SP,
private val repository: AppRepository,
private val xDripBroadcast: XDripBroadcast,
private val virtualPump: VirtualPump,
private val config: Config
) : PluginBase(
@ -119,7 +117,6 @@ class RandomBgPlugin @Inject constructor(
disposable += repository.runTransactionForResult(CgmSourceTransaction(glucoseValues, emptyList(), null))
.subscribe({ savedValues ->
savedValues.inserted.forEach {
xDripBroadcast.sendIn640gMode(it)
aapsLogger.debug(LTag.DATABASE, "Inserted bg $it")
}
}, { aapsLogger.error(LTag.DATABASE, "Error while saving values from Random plugin", it) }

View file

@ -9,7 +9,6 @@ import info.nightscout.database.entities.GlucoseValue
import info.nightscout.database.impl.AppRepository
import info.nightscout.database.impl.transactions.CgmSourceTransaction
import info.nightscout.database.transactions.TransactionGlucoseValue
import info.nightscout.interfaces.XDripBroadcast
import info.nightscout.interfaces.plugin.PluginBase
import info.nightscout.interfaces.plugin.PluginDescription
import info.nightscout.interfaces.plugin.PluginType
@ -50,7 +49,6 @@ class TomatoPlugin @Inject constructor(
@Inject lateinit var tomatoPlugin: TomatoPlugin
@Inject lateinit var sp: SP
@Inject lateinit var repository: AppRepository
@Inject lateinit var xDripBroadcast: XDripBroadcast
@Suppress("SpellCheckingInspection")
override suspend fun doWorkAndLog(): Result {
@ -74,7 +72,6 @@ class TomatoPlugin @Inject constructor(
.blockingGet()
.also { savedValues ->
savedValues.inserted.forEach {
xDripBroadcast.sendIn640gMode(it)
aapsLogger.debug(LTag.DATABASE, "Inserted bg $it")
}
}

View file

@ -34,7 +34,7 @@ class XdripSourcePlugin @Inject constructor(
.mainType(PluginType.BGSOURCE)
.fragmentClass(BGSourceFragment::class.java.name)
.pluginIcon((info.nightscout.core.main.R.drawable.ic_blooddrop_48))
.pluginName(R.string.xdrip)
.pluginName(R.string.source_xdrip)
.description(R.string.description_source_xdrip),
aapsLogger, rh, injector
), BgSource, DoingOwnUploadSource, XDrip {

View file

@ -29,7 +29,6 @@ abstract class SourceModule {
@ContributesAndroidInjector abstract fun contributesBGSourceFragment(): BGSourceFragment
@ContributesAndroidInjector abstract fun contributesNSClientSourceWorker(): NSClientSourcePlugin.NSClientSourceWorker
@ContributesAndroidInjector abstract fun contributesXdripWorker(): XdripSourcePlugin.XdripSourceWorker
@ContributesAndroidInjector abstract fun contributesDexcomWorker(): DexcomPlugin.DexcomWorker
@ContributesAndroidInjector abstract fun contributesMM640gWorker(): MM640gPlugin.MM640gWorker

View file

@ -8,7 +8,7 @@
<string name="ns_client_bg">NSClient BG</string>
<string name="ns_client_bg_short">NS BG</string>
<string name="description_source_ns_client">Downloads BG data from Nightscout</string>
<string name="xdrip">xDrip+</string>
<string name="source_xdrip">xDrip+ BG</string>
<string name="description_source_xdrip">Receive BG values from xDrip+.</string>
<string name="dexcom_app_patched">BYODA</string>
<string name="dexcom_short">BYODA</string>

View file

@ -12,12 +12,6 @@
android:key="@string/key_do_ns_upload"
android:title="@string/do_ns_upload_title" />
<SwitchPreference
android:defaultValue="false"
android:key="@string/key_dexcomg5_xdripupload"
android:summary="@string/do_xdrip_upload_summary"
android:title="@string/do_xdrip_upload_title" />
</PreferenceCategory>
</androidx.preference.PreferenceScreen>

View file

@ -12,12 +12,6 @@
android:key="@string/key_do_ns_upload"
android:title="@string/do_ns_upload_title" />
<SwitchPreference
android:defaultValue="false"
android:key="@string/key_dexcomg5_xdripupload"
android:summary="@string/do_xdrip_upload_summary"
android:title="@string/do_xdrip_upload_title" />
<SwitchPreference
android:defaultValue="false"
android:key="@string/key_dexcom_log_ns_sensor_change"

View file

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

View file

@ -11,10 +11,12 @@ import info.nightscout.interfaces.XDripBroadcast
import info.nightscout.interfaces.nsclient.NSSettingsStatus
import info.nightscout.interfaces.nsclient.ProcessedDeviceStatusData
import info.nightscout.interfaces.nsclient.StoreDataForDb
import info.nightscout.interfaces.sync.DataSyncSelector
import info.nightscout.plugins.sync.nsShared.DataSyncSelectorImplementation
import info.nightscout.interfaces.sync.DataSyncSelectorV1
import info.nightscout.interfaces.sync.DataSyncSelectorV3
import info.nightscout.interfaces.sync.DataSyncSelectorXdrip
import info.nightscout.plugins.sync.nsShared.NSClientFragment
import info.nightscout.plugins.sync.nsShared.StoreDataForDbImpl
import info.nightscout.plugins.sync.nsclient.DataSyncSelectorV1Impl
import info.nightscout.plugins.sync.nsclient.data.NSSettingsStatusImpl
import info.nightscout.plugins.sync.nsclient.data.ProcessedDeviceStatusDataImpl
import info.nightscout.plugins.sync.nsclient.services.NSClientService
@ -22,18 +24,13 @@ import info.nightscout.plugins.sync.nsclient.workers.NSClientAddAckWorker
import info.nightscout.plugins.sync.nsclient.workers.NSClientAddUpdateWorker
import info.nightscout.plugins.sync.nsclient.workers.NSClientMbgWorker
import info.nightscout.plugins.sync.nsclient.workers.NSClientUpdateRemoveAckWorker
import info.nightscout.plugins.sync.nsclientV3.workers.DataSyncWorker
import info.nightscout.plugins.sync.nsclientV3.workers.LoadBgWorker
import info.nightscout.plugins.sync.nsclientV3.workers.LoadDeviceStatusWorker
import info.nightscout.plugins.sync.nsclientV3.workers.LoadFoodsWorker
import info.nightscout.plugins.sync.nsclientV3.workers.LoadLastModificationWorker
import info.nightscout.plugins.sync.nsclientV3.workers.LoadProfileStoreWorker
import info.nightscout.plugins.sync.nsclientV3.workers.LoadStatusWorker
import info.nightscout.plugins.sync.nsclientV3.workers.LoadTreatmentsWorker
import info.nightscout.plugins.sync.nsclientV3.workers.ProcessFoodWorker
import info.nightscout.plugins.sync.nsclientV3.workers.ProcessTreatmentsWorker
import info.nightscout.plugins.sync.nsclientV3.DataSyncSelectorV3Impl
import info.nightscout.plugins.sync.nsclientV3.workers.*
import info.nightscout.plugins.sync.tidepool.TidepoolFragment
import info.nightscout.plugins.sync.xdrip.DataSyncSelectorXdripImpl
import info.nightscout.plugins.sync.xdrip.XdripFragment
import info.nightscout.plugins.sync.xdrip.XdripPlugin
import info.nightscout.plugins.sync.xdrip.workers.XdripDataSyncWorker
@Module(
includes = [
@ -58,15 +55,13 @@ abstract class SyncModule {
@ContributesAndroidInjector abstract fun contributesLoadBgWorker(): LoadBgWorker
@ContributesAndroidInjector abstract fun contributesLoadFoodsWorker(): LoadFoodsWorker
@ContributesAndroidInjector abstract fun contributesLoadProfileStoreWorker(): LoadProfileStoreWorker
@ContributesAndroidInjector abstract fun contributesStoreBgWorker(): StoreDataForDbImpl.StoreBgWorker
@ContributesAndroidInjector abstract fun contributesStoreFoodWorker(): StoreDataForDbImpl.StoreFoodWorker
@ContributesAndroidInjector abstract fun contributesTreatmentWorker(): LoadTreatmentsWorker
@ContributesAndroidInjector abstract fun contributesProcessTreatmentsWorker(): ProcessTreatmentsWorker
@ContributesAndroidInjector abstract fun contributesLoadDeviceStatusWorker(): LoadDeviceStatusWorker
@ContributesAndroidInjector abstract fun contributesDataSyncWorker(): DataSyncWorker
@ContributesAndroidInjector abstract fun contributesFoodWorker(): ProcessFoodWorker
@ContributesAndroidInjector abstract fun contributesTidepoolFragment(): TidepoolFragment
@ContributesAndroidInjector abstract fun contributesXdripFragment(): XdripFragment
@ContributesAndroidInjector abstract fun contributesXdripDataSyncWorker(): XdripDataSyncWorker
@Module
open class Provide {
@ -80,7 +75,9 @@ abstract class SyncModule {
@Binds fun bindProcessedDeviceStatusData(processedDeviceStatusDataImpl: ProcessedDeviceStatusDataImpl): ProcessedDeviceStatusData
@Binds fun bindNSSettingsStatus(nsSettingsStatusImpl: NSSettingsStatusImpl): NSSettingsStatus
@Binds fun bindDataSyncSelectorInterface(dataSyncSelectorImplementation: DataSyncSelectorImplementation): DataSyncSelector
@Binds fun bindDataSyncSelectorV1Interface(dataSyncSelectorV1Impl: DataSyncSelectorV1Impl): DataSyncSelectorV1
@Binds fun bindDataSyncSelectorV3Interface(dataSyncSelectorV3Impl: DataSyncSelectorV3Impl): DataSyncSelectorV3
@Binds fun bindDataSyncSelectorXdripInterface(dataSyncSelectorXdripImpl: DataSyncSelectorXdripImpl): DataSyncSelectorXdrip
@Binds fun bindStoreDataForDb(storeDataForDbImpl: StoreDataForDbImpl): StoreDataForDb
@Binds fun bindXDripBroadcastInterface(xDripBroadcastImpl: XdripPlugin): XDripBroadcast
}

View file

@ -1,36 +1,50 @@
package info.nightscout.plugins.sync.nsShared
import android.content.Context
import android.os.Bundle
import android.os.Handler
import android.os.HandlerThread
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.text.toSpanned
import androidx.core.view.MenuProvider
import androidx.lifecycle.Lifecycle
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import dagger.android.support.DaggerFragment
import info.nightscout.core.ui.dialogs.OKDialog
import info.nightscout.core.utils.fabric.FabricPrivacy
import info.nightscout.database.entities.UserEntry
import info.nightscout.interfaces.Config
import info.nightscout.interfaces.db.PersistenceLayer
import info.nightscout.interfaces.logging.UserEntryLogger
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.utils.HtmlHelper
import info.nightscout.plugins.sync.R
import info.nightscout.plugins.sync.databinding.NsClientFragmentBinding
import info.nightscout.plugins.sync.nsShared.events.EventNSClientUpdateGUI
import info.nightscout.plugins.sync.databinding.NsClientLogItemBinding
import info.nightscout.plugins.sync.nsShared.events.EventNSClientUpdateGuiData
import info.nightscout.plugins.sync.nsShared.events.EventNSClientUpdateGuiQueue
import info.nightscout.plugins.sync.nsShared.events.EventNSClientUpdateGuiStatus
import info.nightscout.rx.AapsSchedulers
import info.nightscout.rx.bus.RxBus
import info.nightscout.rx.events.EventNSClientNewLog
import info.nightscout.rx.events.EventNSClientRestart
import info.nightscout.rx.logging.AAPSLogger
import info.nightscout.rx.logging.LTag
import info.nightscout.shared.interfaces.ResourceHelper
import info.nightscout.shared.sharedPreferences.SP
import io.reactivex.rxjava3.core.Completable
import io.reactivex.rxjava3.disposables.CompositeDisposable
import io.reactivex.rxjava3.kotlin.plusAssign
import io.reactivex.rxjava3.kotlin.subscribeBy
import java.util.concurrent.TimeUnit
import javax.inject.Inject
class NSClientFragment : DaggerFragment(), MenuProvider, PluginFragment {
@ -40,11 +54,11 @@ class NSClientFragment : DaggerFragment(), MenuProvider, PluginFragment {
@Inject lateinit var rxBus: RxBus
@Inject lateinit var fabricPrivacy: FabricPrivacy
@Inject lateinit var aapsSchedulers: AapsSchedulers
@Inject lateinit var dataSyncSelector: DataSyncSelector
@Inject lateinit var uel: UserEntryLogger
@Inject lateinit var aapsLogger: AAPSLogger
@Inject lateinit var activePlugin: ActivePlugin
@Inject lateinit var config: Config
@Inject lateinit var persistenceLayer: PersistenceLayer
companion object {
@ -61,11 +75,19 @@ class NSClientFragment : DaggerFragment(), MenuProvider, PluginFragment {
private val disposable = CompositeDisposable()
private var _binding: NsClientFragmentBinding? = null
private lateinit var logAdapter: RecyclerViewAdapter
private var handler = Handler(HandlerThread(this::class.simpleName + "Handler").also { it.start() }.looper)
// This property is only valid between onCreateView and
// onDestroyView.
// This property is only valid between onCreateView and onDestroyView.
private val binding get() = _binding!!
// https://stackoverflow.com/questions/31759171/recyclerview-and-java-lang-indexoutofboundsexception-inconsistency-detected-in
class FixedLinearLayoutManager(context: Context?, @RecyclerView.Orientation orientation: Int = RecyclerView.VERTICAL, reverseLayout: Boolean = false) :
LinearLayoutManager(context, orientation, reverseLayout) {
override fun supportsPredictiveItemAnimations(): Boolean = false
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View =
NsClientFragmentBinding.inflate(inflater, container, false).also {
_binding = it
@ -75,18 +97,15 @@ class NSClientFragment : DaggerFragment(), MenuProvider, PluginFragment {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
binding.autoscroll.isChecked = sp.getBoolean(R.string.key_ns_client_autoscroll, true)
binding.autoscroll.setOnCheckedChangeListener { _, isChecked ->
sp.putBoolean(R.string.key_ns_client_autoscroll, isChecked)
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)
updateGui()
}
logAdapter = RecyclerViewAdapter(nsClientPlugin?.listLog ?: emptyList())
binding.recyclerview.layoutManager = FixedLinearLayoutManager(context)
binding.recyclerview.adapter = logAdapter
}
override fun onCreateMenu(menu: Menu, inflater: MenuInflater) {
@ -100,7 +119,12 @@ class NSClientFragment : DaggerFragment(), MenuProvider, PluginFragment {
override fun onMenuItemSelected(item: MenuItem): Boolean =
when (item.itemId) {
ID_MENU_CLEAR_LOG -> {
nsClientPlugin?.clearLog()
nsClientPlugin?.listLog?.let {
synchronized(it) {
it.clear()
_binding?.recyclerview?.swapAdapter(RecyclerViewAdapter(it), true)
}
}
true
}
@ -115,10 +139,40 @@ class NSClientFragment : DaggerFragment(), MenuProvider, PluginFragment {
}
ID_MENU_FULL_SYNC -> {
var result = ""
context?.let { context ->
OKDialog.showConfirmation(
context, rh.gs(R.string.ns_client), rh.gs(R.string.full_sync_comment),
Runnable { nsClientPlugin?.resetToFullSync() }
Runnable {
OKDialog.showConfirmation(requireContext(), rh.gs(R.string.ns_client), rh.gs(info.nightscout.core.ui.R.string.cleanup_db_confirm_sync), Runnable {
disposable += Completable.fromAction { result = persistenceLayer.cleanupDatabase(93, deleteTrackedChanges = true) }
.subscribeOn(aapsSchedulers.io)
.observeOn(aapsSchedulers.main)
.subscribeBy(
onError = { aapsLogger.error("Error cleaning up databases", it) },
onComplete = {
if (result.isNotEmpty())
OKDialog.show(
requireContext(),
rh.gs(info.nightscout.core.ui.R.string.result),
HtmlHelper.fromHtml("<b>" + rh.gs(info.nightscout.core.ui.R.string.cleared_entries) + "</b><br>" + result)
.toSpanned()
)
aapsLogger.info(LTag.CORE, "Cleaned up databases with result: $result")
handler.post {
nsClientPlugin?.resetToFullSync()
nsClientPlugin?.resend("FULL_SYNC")
}
}
)
uel.log(UserEntry.Action.CLEANUP_DATABASES, UserEntry.Sources.NSClient)
}, Runnable {
handler.post {
nsClientPlugin?.resetToFullSync()
nsClientPlugin?.resend("FULL_SYNC")
}
})
}
)
}
true
@ -127,28 +181,69 @@ class NSClientFragment : DaggerFragment(), MenuProvider, PluginFragment {
else -> false
}
@Synchronized override fun onResume() {
super.onResume()
disposable += rxBus
.toObservable(EventNSClientUpdateGUI::class.java)
.observeOn(aapsSchedulers.main)
.subscribe({ updateGui() }, fabricPrivacy::logException)
updateGui()
@Synchronized
override fun onDestroyView() {
super.onDestroyView()
binding.recyclerview.adapter = null // avoid leaks
_binding = null
}
@Synchronized override fun onPause() {
@Synchronized
override fun onResume() {
super.onResume()
disposable += rxBus
.toObservable(EventNSClientUpdateGuiData::class.java)
.observeOn(aapsSchedulers.main)
.subscribe(
{
_binding?.recyclerview?.swapAdapter(RecyclerViewAdapter(nsClientPlugin?.listLog ?: arrayListOf()), true)
}, fabricPrivacy::logException
)
disposable += rxBus
.toObservable(EventNSClientUpdateGuiQueue::class.java)
.observeOn(aapsSchedulers.main)
.subscribe({ updateQueue() }, fabricPrivacy::logException)
disposable += rxBus
.toObservable(EventNSClientUpdateGuiStatus::class.java)
.debounce(3L, TimeUnit.SECONDS)
.observeOn(aapsSchedulers.main)
.subscribe({ updateStatus() }, fabricPrivacy::logException)
updateStatus()
updateQueue()
}
@Synchronized
override fun onPause() {
super.onPause()
disposable.clear()
}
private fun updateGui() {
private fun updateQueue() {
val size = nsClientPlugin?.dataSyncSelector?.queueSize() ?: 0L
_binding?.queue?.text = if (size >= 0) size.toString() else rh.gs(info.nightscout.core.ui.R.string.value_unavailable_short)
}
private fun updateStatus() {
if (_binding == null) return
binding.paused.isChecked = sp.getBoolean(R.string.key_ns_client_paused, false)
binding.log.text = nsClientPlugin?.textLog()
if (sp.getBoolean(R.string.key_ns_client_autoscroll, true)) binding.logScrollview.fullScroll(ScrollView.FOCUS_DOWN)
binding.paused.isChecked = sp.getBoolean(R.string.key_ns_paused, false)
binding.url.text = nsClientPlugin?.address
binding.status.text = nsClientPlugin?.status
val size = dataSyncSelector.queueSize()
binding.queue.text = if (size >= 0) size.toString() else rh.gs(info.nightscout.core.ui.R.string.value_unavailable_short)
}
private inner class RecyclerViewAdapter(private var logList: List<EventNSClientNewLog>) : RecyclerView.Adapter<RecyclerViewAdapter.NsClientLogViewHolder>() {
override fun onCreateViewHolder(viewGroup: ViewGroup, viewType: Int): NsClientLogViewHolder =
NsClientLogViewHolder(LayoutInflater.from(viewGroup.context).inflate(R.layout.ns_client_log_item, viewGroup, false))
override fun onBindViewHolder(holder: NsClientLogViewHolder, position: Int) {
holder.binding.logText.text = HtmlHelper.fromHtml(logList[position].toPreparedHtml().toString())
}
override fun getItemCount() = logList.size
inner class NsClientLogViewHolder(view: View) : RecyclerView.ViewHolder(view) {
val binding = NsClientLogItemBinding.bind(view)
}
}
}

View file

@ -0,0 +1,232 @@
package info.nightscout.plugins.sync.nsShared
import info.nightscout.androidaps.annotations.OpenForTesting
import info.nightscout.core.extensions.foodFromJson
import info.nightscout.database.entities.Food
import info.nightscout.database.entities.GlucoseValue
import info.nightscout.database.transactions.TransactionGlucoseValue
import info.nightscout.interfaces.Config
import info.nightscout.interfaces.Constants
import info.nightscout.interfaces.notifications.Notification
import info.nightscout.interfaces.nsclient.NSSgv
import info.nightscout.interfaces.nsclient.StoreDataForDb
import info.nightscout.interfaces.plugin.ActivePlugin
import info.nightscout.interfaces.profile.Instantiator
import info.nightscout.interfaces.profile.ProfileSource
import info.nightscout.interfaces.source.NSClientSource
import info.nightscout.interfaces.utils.JsonHelper
import info.nightscout.plugins.sync.R
import info.nightscout.plugins.sync.nsclientV3.extensions.*
import info.nightscout.rx.bus.RxBus
import info.nightscout.rx.events.EventDismissNotification
import info.nightscout.rx.events.EventNSClientNewLog
import info.nightscout.rx.logging.AAPSLogger
import info.nightscout.rx.logging.LTag
import info.nightscout.sdk.localmodel.entry.NSSgvV3
import info.nightscout.sdk.localmodel.food.NSFood
import info.nightscout.sdk.localmodel.treatment.*
import info.nightscout.shared.sharedPreferences.SP
import info.nightscout.shared.utils.DateUtil
import info.nightscout.shared.utils.T
import org.json.JSONArray
import org.json.JSONObject
import javax.inject.Inject
import javax.inject.Singleton
@OpenForTesting
@Singleton
class NsIncomingDataProcessor @Inject constructor(
private val aapsLogger: AAPSLogger,
private val nsClientSource: NSClientSource,
private val sp: SP,
private val rxBus: RxBus,
private val dateUtil: DateUtil,
private val activePlugin: ActivePlugin,
private val storeDataForDb: StoreDataForDb,
private val config: Config,
private val instantiator: Instantiator,
private val profileSource: ProfileSource
) {
private fun toGv(jsonObject: JSONObject): TransactionGlucoseValue? {
val sgv = NSSgv(jsonObject)
return TransactionGlucoseValue(
timestamp = sgv.mills ?: return null,
value = sgv.mgdl?.toDouble() ?: return null,
noise = null,
raw = sgv.filtered?.toDouble(),
trendArrow = GlucoseValue.TrendArrow.fromString(sgv.direction),
nightscoutId = sgv.id,
sourceSensor = GlucoseValue.SourceSensor.fromString(sgv.device)
)
}
@Suppress("SpellCheckingInspection")
fun processSgvs(sgvs: Any) {
if (!nsClientSource.isEnabled() && !sp.getBoolean(info.nightscout.core.utils.R.string.key_ns_receive_cgm, false)) return
var latestDateInReceivedData: Long = 0
aapsLogger.debug(LTag.NSCLIENT, "Received NS Data: $sgvs")
val glucoseValues = mutableListOf<TransactionGlucoseValue>()
if (sgvs is JSONArray) { // V1 client
for (i in 0 until sgvs.length()) {
val sgv = toGv(sgvs.getJSONObject(i)) ?: continue
if (sgv.timestamp < dateUtil.now() && sgv.timestamp > latestDateInReceivedData) latestDateInReceivedData = sgv.timestamp
glucoseValues += sgv
}
} else if (sgvs is List<*>) { // V3 client
for (i in 0 until sgvs.size) {
val sgv = (sgvs[i] as NSSgvV3).toTransactionGlucoseValue()
if (sgv.timestamp < dateUtil.now() && sgv.timestamp > latestDateInReceivedData) latestDateInReceivedData = sgv.timestamp
glucoseValues += sgv
}
}
activePlugin.activeNsClient?.updateLatestBgReceivedIfNewer(latestDateInReceivedData)
// Was that sgv more less 5 mins ago ?
if (T.msecs(dateUtil.now() - latestDateInReceivedData).mins() < 5L) {
rxBus.send(EventDismissNotification(Notification.NS_ALARM))
rxBus.send(EventDismissNotification(Notification.NS_URGENT_ALARM))
}
storeDataForDb.glucoseValues.addAll(glucoseValues)
}
fun processTreatments(treatments: List<NSTreatment>) {
try {
var latestDateInReceivedData: Long = 0
for (treatment in treatments) {
aapsLogger.debug(LTag.DATABASE, "Received NS treatment: $treatment")
val date = treatment.date ?: continue
if (date > latestDateInReceivedData) latestDateInReceivedData = date
when (treatment) {
is NSBolus ->
if (sp.getBoolean(info.nightscout.core.utils.R.string.key_ns_receive_insulin, false) || config.NSCLIENT)
storeDataForDb.boluses.add(treatment.toBolus())
is NSCarbs ->
if (sp.getBoolean(info.nightscout.core.utils.R.string.key_ns_receive_carbs, false) || config.NSCLIENT)
storeDataForDb.carbs.add(treatment.toCarbs())
is NSTemporaryTarget ->
if (sp.getBoolean(info.nightscout.core.utils.R.string.key_ns_receive_temp_target, false) || config.NSCLIENT) {
if (treatment.duration > 0L) {
// not ending event
if (treatment.targetBottomAsMgdl() < Constants.MIN_TT_MGDL
|| treatment.targetBottomAsMgdl() > Constants.MAX_TT_MGDL
|| treatment.targetTopAsMgdl() < Constants.MIN_TT_MGDL
|| treatment.targetTopAsMgdl() > Constants.MAX_TT_MGDL
|| treatment.targetBottomAsMgdl() > treatment.targetTopAsMgdl()
) {
aapsLogger.debug(LTag.DATABASE, "Ignored TemporaryTarget $treatment")
continue
}
}
storeDataForDb.temporaryTargets.add(treatment.toTemporaryTarget())
}
is NSTemporaryBasal ->
if (config.isEngineeringMode() && sp.getBoolean(R.string.key_ns_receive_tbr_eb, false) || config.NSCLIENT)
storeDataForDb.temporaryBasals.add(treatment.toTemporaryBasal())
is NSEffectiveProfileSwitch ->
if (sp.getBoolean(info.nightscout.core.utils.R.string.key_ns_receive_profile_switch, false) || config.NSCLIENT) {
treatment.toEffectiveProfileSwitch(dateUtil)?.let { effectiveProfileSwitch ->
storeDataForDb.effectiveProfileSwitches.add(effectiveProfileSwitch)
}
}
is NSProfileSwitch ->
if (sp.getBoolean(info.nightscout.core.utils.R.string.key_ns_receive_profile_switch, false) || config.NSCLIENT) {
treatment.toProfileSwitch(activePlugin, dateUtil)?.let { profileSwitch ->
storeDataForDb.profileSwitches.add(profileSwitch)
}
}
is NSBolusWizard ->
treatment.toBolusCalculatorResult()?.let { bolusCalculatorResult ->
storeDataForDb.bolusCalculatorResults.add(bolusCalculatorResult)
}
is NSTherapyEvent ->
if (sp.getBoolean(info.nightscout.core.utils.R.string.key_ns_receive_therapy_events, false) || config.NSCLIENT)
treatment.toTherapyEvent().let { therapyEvent ->
storeDataForDb.therapyEvents.add(therapyEvent)
}
is NSOfflineEvent ->
if (sp.getBoolean(info.nightscout.core.utils.R.string.key_ns_receive_offline_event, false) && config.isEngineeringMode() || config.NSCLIENT)
treatment.toOfflineEvent().let { offlineEvent ->
storeDataForDb.offlineEvents.add(offlineEvent)
}
is NSExtendedBolus ->
if (config.isEngineeringMode() && sp.getBoolean(R.string.key_ns_receive_tbr_eb, false) || config.NSCLIENT)
treatment.toExtendedBolus().let { extendedBolus ->
storeDataForDb.extendedBoluses.add(extendedBolus)
}
}
}
activePlugin.activeNsClient?.updateLatestTreatmentReceivedIfNewer(latestDateInReceivedData)
} catch (error: Exception) {
aapsLogger.error("Error: ", error)
rxBus.send(EventNSClientNewLog("◄ ERROR", error.localizedMessage))
}
}
fun processFood(data: Any) {
aapsLogger.debug(LTag.DATABASE, "Received Food Data: $data")
try {
val foods = mutableListOf<Food>()
if (data is JSONArray) {
for (index in 0 until data.length()) {
val jsonFood: JSONObject = data.getJSONObject(index)
if (JsonHelper.safeGetString(jsonFood, "type") != "food") continue
when (JsonHelper.safeGetString(jsonFood, "action")) {
"remove" -> {
val delFood = Food(
name = "",
portion = 0.0,
carbs = 0,
isValid = false
).also { it.interfaceIDs.nightscoutId = JsonHelper.safeGetString(jsonFood, "_id") }
foods += delFood
}
else -> {
val food = foodFromJson(jsonFood)
if (food != null) foods += food
else aapsLogger.error(LTag.DATABASE, "Error parsing food", jsonFood.toString())
}
}
}
} else if (data is List<*>) {
for (i in 0 until data.size)
foods += (data[i] as NSFood).toFood()
}
storeDataForDb.foods.addAll(foods)
} catch (error: Exception) {
aapsLogger.error("Error: ", error)
rxBus.send(EventNSClientNewLog("◄ ERROR", error.localizedMessage))
}
}
fun processProfile(profileJson: JSONObject) {
if (sp.getBoolean(info.nightscout.core.utils.R.string.key_ns_receive_profile_store, true) || config.NSCLIENT) {
val store = instantiator.provideProfileStore(profileJson)
val createdAt = store.getStartDate()
val lastLocalChange = sp.getLong(info.nightscout.core.utils.R.string.key_local_profile_last_change, 0)
aapsLogger.debug(LTag.PROFILE, "Received profileStore: createdAt: $createdAt Local last modification: $lastLocalChange")
@Suppress("LiftReturnOrAssignment")
if (createdAt > lastLocalChange || createdAt % 1000 == 0L) {// whole second means edited in NS
profileSource.loadFromStore(store)
aapsLogger.debug(LTag.PROFILE, "Received profileStore: $profileJson")
}
}
}
}

View file

@ -1,9 +1,6 @@
package info.nightscout.plugins.sync.nsShared
import android.content.Context
import android.os.SystemClock
import androidx.work.WorkerParameters
import info.nightscout.core.utils.worker.LoggingWorker
import info.nightscout.database.entities.Bolus
import info.nightscout.database.entities.BolusCalculatorResult
import info.nightscout.database.entities.Carbs
@ -48,7 +45,6 @@ import info.nightscout.database.impl.transactions.UpdateNsIdTherapyEventTransact
import info.nightscout.database.transactions.TransactionGlucoseValue
import info.nightscout.interfaces.Config
import info.nightscout.interfaces.Constants
import info.nightscout.interfaces.XDripBroadcast
import info.nightscout.interfaces.logging.UserEntryLogger
import info.nightscout.interfaces.notifications.Notification
import info.nightscout.interfaces.nsclient.StoreDataForDb
@ -61,7 +57,6 @@ import info.nightscout.rx.logging.AAPSLogger
import info.nightscout.rx.logging.LTag
import info.nightscout.shared.sharedPreferences.SP
import info.nightscout.shared.utils.DateUtil
import kotlinx.coroutines.Dispatchers
import java.util.concurrent.Executors
import java.util.concurrent.ScheduledFuture
import java.util.concurrent.TimeUnit
@ -78,7 +73,6 @@ class StoreDataForDbImpl @Inject constructor(
private val dateUtil: DateUtil,
private val config: Config,
private val nsClientSource: NSClientSource,
private val xDripBroadcast: XDripBroadcast,
private val virtualPump: VirtualPump,
private val uiInteraction: UiInteraction
) : StoreDataForDb {
@ -121,39 +115,11 @@ class StoreDataForDbImpl @Inject constructor(
private val pause = 1000L // to slow down db operations
class StoreBgWorker(
context: Context,
params: WorkerParameters
) : LoggingWorker(context, params, Dispatchers.Default) {
@Inject lateinit var storeDataForDb: StoreDataForDb
override suspend fun doWorkAndLog(): Result {
storeDataForDb.storeGlucoseValuesToDb()
return Result.success()
}
}
class StoreFoodWorker(
context: Context,
params: WorkerParameters
) : LoggingWorker(context, params, Dispatchers.Default) {
@Inject lateinit var storeDataForDb: StoreDataForDb
override suspend fun doWorkAndLog(): Result {
storeDataForDb.storeFoodsToDb()
return Result.success()
}
}
fun <T> HashMap<T, Long>.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 {
@ -163,19 +129,16 @@ class StoreDataForDbImpl @Inject constructor(
.also { result ->
glucoseValues.clear()
result.updated.forEach {
xDripBroadcast.sendIn640gMode(it)
nsClientSource.detectSource(it)
aapsLogger.debug(LTag.DATABASE, "Updated bg $it")
updated.inc(GlucoseValue::class.java.simpleName)
}
result.inserted.forEach {
xDripBroadcast.sendIn640gMode(it)
nsClientSource.detectSource(it)
aapsLogger.debug(LTag.DATABASE, "Inserted bg $it")
inserted.inc(GlucoseValue::class.java.simpleName)
}
result.updatedNsId.forEach {
xDripBroadcast.sendIn640gMode(it)
nsClientSource.detectSource(it)
aapsLogger.debug(LTag.DATABASE, "Updated nsId bg $it")
nsIdUpdated.inc(GlucoseValue::class.java.simpleName)
@ -184,12 +147,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 +175,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,11 +755,13 @@ 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()
private var scheduledEventPost: ScheduledFuture<*>? = null
@Synchronized
override fun scheduleNsIdUpdate() {
class PostRunnable : Runnable {
@ -816,7 +777,8 @@ class StoreDataForDbImpl @Inject constructor(
scheduledEventPost = eventWorker.schedule(task, 10, TimeUnit.SECONDS)
}
private fun updateNsIds() {
@Synchronized
override fun updateNsIds() {
repository.runTransactionForResult(UpdateNsIdTemporaryTargetTransaction(nsIdTemporaryTargets))
.doOnError { error ->
aapsLogger.error(LTag.DATABASE, "Updated nsId of TemporaryTarget failed", error)
@ -996,32 +958,32 @@ 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) {
inserted[clazz]?.let {
rxBus.send(EventNSClientNewLog("INSERT", "$item $it"))
rxBus.send(EventNSClientNewLog("INSERT", "$item $it"))
}
inserted.remove(clazz)
updated[clazz]?.let {
rxBus.send(EventNSClientNewLog("UPDATE", "$item $it"))
rxBus.send(EventNSClientNewLog("UPDATE", "$item $it"))
}
updated.remove(clazz)
invalidated[clazz]?.let {
rxBus.send(EventNSClientNewLog("INVALIDATE", "$item $it"))
rxBus.send(EventNSClientNewLog("INVALIDATE", "$item $it"))
}
invalidated.remove(clazz)
nsIdUpdated[clazz]?.let {
rxBus.send(EventNSClientNewLog("NS_ID", "$item $it"))
rxBus.send(EventNSClientNewLog("NS_ID", "$item $it"))
}
nsIdUpdated.remove(clazz)
durationUpdated[clazz]?.let {
rxBus.send(EventNSClientNewLog("DURATION", "$item $it"))
rxBus.send(EventNSClientNewLog("DURATION", "$item $it"))
}
durationUpdated.remove(clazz)
ended[clazz]?.let {
rxBus.send(EventNSClientNewLog("CUT", "$item $it"))
rxBus.send(EventNSClientNewLog("CUT", "$item $it"))
}
ended.remove(clazz)
}

View file

@ -0,0 +1,5 @@
package info.nightscout.plugins.sync.nsShared.events
import info.nightscout.rx.events.Event
class EventConnectivityOptionChanged(val blockingReason: String) : Event()

View file

@ -2,4 +2,4 @@ package info.nightscout.plugins.sync.nsShared.events
import info.nightscout.rx.events.EventUpdateGui
class EventNSClientUpdateGUI : EventUpdateGui()
class EventNSClientUpdateGuiData : EventUpdateGui()

View file

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

View file

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

View file

@ -1,12 +1,15 @@
package info.nightscout.plugins.sync.nsShared
package info.nightscout.plugins.sync.nsclient
import info.nightscout.database.ValueWrapper
import info.nightscout.database.impl.AppRepository
import info.nightscout.interfaces.plugin.ActivePlugin
import info.nightscout.interfaces.profile.ProfileFunction
import info.nightscout.interfaces.sync.DataSyncSelector
import info.nightscout.interfaces.sync.DataSyncSelectorV1
import info.nightscout.interfaces.utils.JsonHelper
import info.nightscout.plugins.sync.R
import info.nightscout.plugins.sync.nsShared.events.EventNSClientUpdateGuiQueue
import info.nightscout.plugins.sync.nsShared.events.EventNSClientUpdateGuiStatus
import info.nightscout.rx.bus.RxBus
import info.nightscout.rx.logging.AAPSLogger
import info.nightscout.rx.logging.LTag
import info.nightscout.shared.sharedPreferences.SP
@ -15,14 +18,15 @@ import javax.inject.Inject
import javax.inject.Singleton
@Singleton
class DataSyncSelectorImplementation @Inject constructor(
class DataSyncSelectorV1Impl @Inject constructor(
private val sp: SP,
private val aapsLogger: AAPSLogger,
private val dateUtil: DateUtil,
private val profileFunction: ProfileFunction,
private val activePlugin: ActivePlugin,
private val appRepository: AppRepository
) : DataSyncSelector {
private val appRepository: AppRepository,
private val rxBus: RxBus
) : DataSyncSelectorV1 {
class QueueCounter(
var bolusesRemaining: Long = -1L,
@ -57,12 +61,27 @@ 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()
override fun doUpload() {
override suspend fun doUpload() {
rxBus.send(EventNSClientUpdateGuiStatus())
if (sp.getBoolean(R.string.key_ns_upload, true) && !isPaused) {
queueCounter.bolusesRemaining = (appRepository.getLastBolusId() ?: 0L) - sp.getLong(R.string.key_ns_bolus_last_synced_id, 0)
queueCounter.carbsRemaining = (appRepository.getLastCarbsId() ?: 0L) - sp.getLong(R.string.key_ns_carbs_last_synced_id, 0)
queueCounter.bcrRemaining = (appRepository.getLastBolusCalculatorResultId() ?: 0L) - sp.getLong(R.string.key_ns_bolus_calculator_result_last_synced_id, 0)
queueCounter.ttsRemaining = (appRepository.getLastTempTargetId() ?: 0L) - sp.getLong(R.string.key_ns_temporary_target_last_synced_id, 0)
queueCounter.foodsRemaining = (appRepository.getLastFoodId() ?: 0L) - sp.getLong(R.string.key_ns_food_last_synced_id, 0)
queueCounter.gvsRemaining = (appRepository.getLastGlucoseValueId() ?: 0L) - sp.getLong(R.string.key_ns_glucose_value_last_synced_id, 0)
queueCounter.tesRemaining = (appRepository.getLastTherapyEventId() ?: 0L) - sp.getLong(R.string.key_ns_therapy_event_last_synced_id, 0)
queueCounter.dssRemaining = (appRepository.getLastDeviceStatusId() ?: 0L) - sp.getLong(R.string.key_ns_device_status_last_synced_id, 0)
queueCounter.tbrsRemaining = (appRepository.getLastTemporaryBasalId() ?: 0L) - sp.getLong(R.string.key_ns_temporary_basal_last_synced_id, 0)
queueCounter.ebsRemaining = (appRepository.getLastExtendedBolusId() ?: 0L) - sp.getLong(R.string.key_ns_extended_bolus_last_synced_id, 0)
queueCounter.pssRemaining = (appRepository.getLastProfileSwitchId() ?: 0L) - sp.getLong(R.string.key_ns_profile_switch_last_synced_id, 0)
queueCounter.epssRemaining = (appRepository.getLastEffectiveProfileSwitchId() ?: 0L) - sp.getLong(R.string.key_ns_effective_profile_switch_last_synced_id, 0)
queueCounter.oesRemaining = (appRepository.getLastOfflineEventId() ?: 0L) - sp.getLong(R.string.key_ns_offline_event_last_synced_id, 0)
rxBus.send(EventNSClientUpdateGuiQueue())
processChangedBoluses()
processChangedCarbs()
processChangedBolusCalculatorResults()
@ -78,6 +97,7 @@ class DataSyncSelectorImplementation @Inject constructor(
processChangedOfflineEvents()
processChangedProfileStore()
}
rxBus.send(EventNSClientUpdateGuiStatus())
}
override fun resetToNextFullSync() {
@ -95,8 +115,8 @@ class DataSyncSelectorImplementation @Inject constructor(
sp.remove(R.string.key_ns_offline_event_last_synced_id)
sp.remove(R.string.key_ns_profile_store_last_synced_timestamp)
val lastDeviceStatusDbIdWrapped = appRepository.getLastDeviceStatusIdWrapped().blockingGet()
if (lastDeviceStatusDbIdWrapped is ValueWrapper.Existing) sp.putLong(R.string.key_ns_device_status_last_synced_id, lastDeviceStatusDbIdWrapped.value)
val lastDeviceStatusDbId = appRepository.getLastDeviceStatusId()
if (lastDeviceStatusDbId != null) sp.putLong(R.string.key_ns_device_status_last_synced_id, lastDeviceStatusDbId)
else sp.remove(R.string.key_ns_device_status_last_synced_id)
}
@ -107,16 +127,16 @@ class DataSyncSelectorImplementation @Inject constructor(
}
}
override tailrec fun processChangedBoluses() {
override tailrec suspend fun processChangedBoluses() {
if (isPaused) return
val lastDbIdWrapped = appRepository.getLastBolusIdWrapped().blockingGet()
val lastDbId = if (lastDbIdWrapped is ValueWrapper.Existing) lastDbIdWrapped.value else 0L
val lastDbId = appRepository.getLastBolusId() ?: 0L
var startId = sp.getLong(R.string.key_ns_bolus_last_synced_id, 0)
if (startId > lastDbId) {
sp.putLong(R.string.key_ns_bolus_last_synced_id, 0)
startId = 0
}
queueCounter.bolusesRemaining = lastDbId - startId
rxBus.send(EventNSClientUpdateGuiQueue())
appRepository.getNextSyncElementBolus(startId).blockingGet()?.let { bolus ->
aapsLogger.info(LTag.NSCLIENT, "Loading Bolus data Start: $startId ${bolus.first} forID: ${bolus.second.id} ")
when {
@ -136,18 +156,10 @@ class DataSyncSelectorImplementation @Inject constructor(
}
// without nsId = create new
bolus.first.interfaceIDs.nightscoutId == null ->
activePlugin.activeNsClient?.nsAdd(
"treatments",
DataSyncSelector.PairBolus(bolus.first, bolus.second.id),
" $startId/$lastDbId"
)
activePlugin.activeNsClient?.nsAdd("treatments", DataSyncSelector.PairBolus(bolus.first, bolus.second.id), " $startId/$lastDbId")
// with nsId = update if it's modified record
bolus.first.interfaceIDs.nightscoutId != null && bolus.first.id != bolus.second.id ->
activePlugin.activeNsClient?.nsUpdate(
"treatments",
DataSyncSelector.PairBolus(bolus.first, bolus.second.id),
"$startId/$lastDbId"
)
activePlugin.activeNsClient?.nsUpdate("treatments", DataSyncSelector.PairBolus(bolus.first, bolus.second.id), "$startId/$lastDbId")
}
return
}
@ -160,16 +172,16 @@ class DataSyncSelectorImplementation @Inject constructor(
}
}
override tailrec fun processChangedCarbs() {
override tailrec suspend fun processChangedCarbs() {
if (isPaused) return
val lastDbIdWrapped = appRepository.getLastCarbsIdWrapped().blockingGet()
val lastDbId = if (lastDbIdWrapped is ValueWrapper.Existing) lastDbIdWrapped.value else 0L
val lastDbId = appRepository.getLastCarbsId() ?: 0L
var startId = sp.getLong(R.string.key_ns_carbs_last_synced_id, 0)
if (startId > lastDbId) {
sp.putLong(R.string.key_ns_carbs_last_synced_id, 0)
startId = 0
}
queueCounter.carbsRemaining = lastDbId - startId
rxBus.send(EventNSClientUpdateGuiQueue())
appRepository.getNextSyncElementCarbs(startId).blockingGet()?.let { carb ->
aapsLogger.info(LTag.NSCLIENT, "Loading Carbs data Start: $startId ${carb.first} forID: ${carb.second.id} ")
when {
@ -209,16 +221,16 @@ class DataSyncSelectorImplementation @Inject constructor(
}
}
override tailrec fun processChangedBolusCalculatorResults() {
override tailrec suspend fun processChangedBolusCalculatorResults() {
if (isPaused) return
val lastDbIdWrapped = appRepository.getLastBolusCalculatorResultIdWrapped().blockingGet()
val lastDbId = if (lastDbIdWrapped is ValueWrapper.Existing) lastDbIdWrapped.value else 0L
val lastDbId = appRepository.getLastBolusCalculatorResultId() ?: 0L
var startId = sp.getLong(R.string.key_ns_bolus_calculator_result_last_synced_id, 0)
if (startId > lastDbId) {
sp.putLong(R.string.key_ns_bolus_calculator_result_last_synced_id, 0)
startId = 0
}
queueCounter.bcrRemaining = lastDbId - startId
rxBus.send(EventNSClientUpdateGuiQueue())
appRepository.getNextSyncElementBolusCalculatorResult(startId).blockingGet()?.let { bolusCalculatorResult ->
aapsLogger.info(LTag.NSCLIENT, "Loading BolusCalculatorResult data Start: $startId ${bolusCalculatorResult.first} forID: ${bolusCalculatorResult.second.id} ")
when {
@ -238,17 +250,10 @@ class DataSyncSelectorImplementation @Inject constructor(
}
// without nsId = create new
bolusCalculatorResult.first.interfaceIDs.nightscoutId == null ->
activePlugin.activeNsClient?.nsAdd(
"treatments",
DataSyncSelector.PairBolusCalculatorResult(bolusCalculatorResult.first, bolusCalculatorResult.second.id),
"$startId/$lastDbId"
)
activePlugin.activeNsClient?.nsAdd("treatments", DataSyncSelector.PairBolusCalculatorResult(bolusCalculatorResult.first, bolusCalculatorResult.second.id), "$startId/$lastDbId")
// with nsId = update if it's modified record
bolusCalculatorResult.first.interfaceIDs.nightscoutId != null && bolusCalculatorResult.first.id != bolusCalculatorResult.second.id ->
activePlugin.activeNsClient?.nsUpdate(
"treatments",
DataSyncSelector.PairBolusCalculatorResult(bolusCalculatorResult.first, bolusCalculatorResult.second.id), "$startId/$lastDbId"
)
activePlugin.activeNsClient?.nsUpdate("treatments", DataSyncSelector.PairBolusCalculatorResult(bolusCalculatorResult.first, bolusCalculatorResult.second.id), "$startId/$lastDbId")
}
return
}
@ -261,16 +266,16 @@ class DataSyncSelectorImplementation @Inject constructor(
}
}
override tailrec fun processChangedTempTargets() {
override tailrec suspend fun processChangedTempTargets() {
if (isPaused) return
val lastDbIdWrapped = appRepository.getLastTempTargetIdWrapped().blockingGet()
val lastDbId = if (lastDbIdWrapped is ValueWrapper.Existing) lastDbIdWrapped.value else 0L
val lastDbId = appRepository.getLastTempTargetId() ?: 0L
var startId = sp.getLong(R.string.key_ns_temporary_target_last_synced_id, 0)
if (startId > lastDbId) {
sp.putLong(R.string.key_ns_temporary_target_last_synced_id, 0)
startId = 0
}
queueCounter.ttsRemaining = lastDbId - startId
rxBus.send(EventNSClientUpdateGuiQueue())
appRepository.getNextSyncElementTemporaryTarget(startId).blockingGet()?.let { tt ->
aapsLogger.info(LTag.NSCLIENT, "Loading TemporaryTarget data Start: $startId ${tt.first} forID: ${tt.second.id} ")
when {
@ -290,18 +295,10 @@ class DataSyncSelectorImplementation @Inject constructor(
}
// without nsId = create new
tt.first.interfaceIDs.nightscoutId == null ->
activePlugin.activeNsClient?.nsAdd(
"treatments",
DataSyncSelector.PairTemporaryTarget(tt.first, tt.second.id),
"$startId/$lastDbId"
)
activePlugin.activeNsClient?.nsAdd("treatments", DataSyncSelector.PairTemporaryTarget(tt.first, tt.second.id), "$startId/$lastDbId")
// existing with nsId = update
tt.first.interfaceIDs.nightscoutId != null ->
activePlugin.activeNsClient?.nsUpdate(
"treatments",
DataSyncSelector.PairTemporaryTarget(tt.first, tt.second.id),
"$startId/$lastDbId"
)
activePlugin.activeNsClient?.nsUpdate("treatments", DataSyncSelector.PairTemporaryTarget(tt.first, tt.second.id), "$startId/$lastDbId")
}
return
}
@ -314,16 +311,16 @@ class DataSyncSelectorImplementation @Inject constructor(
}
}
override tailrec fun processChangedFoods() {
override tailrec suspend fun processChangedFoods() {
if (isPaused) return
val lastDbIdWrapped = appRepository.getLastFoodIdWrapped().blockingGet()
val lastDbId = if (lastDbIdWrapped is ValueWrapper.Existing) lastDbIdWrapped.value else 0L
val lastDbId = appRepository.getLastFoodId() ?: 0L
var startId = sp.getLong(R.string.key_ns_food_last_synced_id, 0)
if (startId > lastDbId) {
sp.putLong(R.string.key_ns_food_last_synced_id, 0)
startId = 0
}
queueCounter.foodsRemaining = lastDbId - startId
rxBus.send(EventNSClientUpdateGuiQueue())
appRepository.getNextSyncElementFood(startId).blockingGet()?.let { food ->
aapsLogger.info(LTag.NSCLIENT, "Loading Food data Start: $startId ${food.first} forID: ${food.second.id} ")
when {
@ -346,11 +343,7 @@ class DataSyncSelectorImplementation @Inject constructor(
activePlugin.activeNsClient?.nsAdd("food", DataSyncSelector.PairFood(food.first, food.second.id), "$startId/$lastDbId")
// with nsId = update
food.first.interfaceIDs.nightscoutId != null ->
activePlugin.activeNsClient?.nsUpdate(
"food",
DataSyncSelector.PairFood(food.first, food.second.id),
"$startId/$lastDbId"
)
activePlugin.activeNsClient?.nsUpdate("food", DataSyncSelector.PairFood(food.first, food.second.id), "$startId/$lastDbId")
}
return
}
@ -363,16 +356,16 @@ class DataSyncSelectorImplementation @Inject constructor(
}
}
override tailrec fun processChangedGlucoseValues() {
override tailrec suspend fun processChangedGlucoseValues() {
if (isPaused) return
val lastDbIdWrapped = appRepository.getLastGlucoseValueIdWrapped().blockingGet()
val lastDbId = if (lastDbIdWrapped is ValueWrapper.Existing) lastDbIdWrapped.value else 0L
val lastDbId = appRepository.getLastGlucoseValueId() ?: 0L
var startId = sp.getLong(R.string.key_ns_glucose_value_last_synced_id, 0)
if (startId > lastDbId) {
sp.putLong(R.string.key_ns_glucose_value_last_synced_id, 0)
startId = 0
}
queueCounter.gvsRemaining = lastDbId - startId
rxBus.send(EventNSClientUpdateGuiQueue())
appRepository.getNextSyncElementGlucoseValue(startId).blockingGet()?.let { gv ->
aapsLogger.info(LTag.NSCLIENT, "Loading GlucoseValue data Start: $startId ${gv.first} forID: ${gv.second.id} ")
if (activePlugin.activeBgSource.shouldUploadToNs(gv.first)) {
@ -396,11 +389,7 @@ class DataSyncSelectorImplementation @Inject constructor(
activePlugin.activeNsClient?.nsAdd("entries", DataSyncSelector.PairGlucoseValue(gv.first, gv.second.id), "$startId/$lastDbId")
// with nsId = update
else -> // gv.first.interfaceIDs.nightscoutId != null
activePlugin.activeNsClient?.nsUpdate(
"entries",
DataSyncSelector.PairGlucoseValue(gv.first, gv.second.id),
"$startId/$lastDbId"
)
activePlugin.activeNsClient?.nsUpdate("entries", DataSyncSelector.PairGlucoseValue(gv.first, gv.second.id), "$startId/$lastDbId")
}
} else {
confirmLastGlucoseValueIdIfGreater(gv.second.id)
@ -417,16 +406,16 @@ class DataSyncSelectorImplementation @Inject constructor(
}
}
override tailrec fun processChangedTherapyEvents() {
override tailrec suspend fun processChangedTherapyEvents() {
if (isPaused) return
val lastDbIdWrapped = appRepository.getLastTherapyEventIdWrapped().blockingGet()
val lastDbId = if (lastDbIdWrapped is ValueWrapper.Existing) lastDbIdWrapped.value else 0L
val lastDbId = appRepository.getLastTherapyEventId() ?: 0L
var startId = sp.getLong(R.string.key_ns_therapy_event_last_synced_id, 0)
if (startId > lastDbId) {
sp.putLong(R.string.key_ns_therapy_event_last_synced_id, 0)
startId = 0
}
queueCounter.tesRemaining = lastDbId - startId
rxBus.send(EventNSClientUpdateGuiQueue())
appRepository.getNextSyncElementTherapyEvent(startId).blockingGet()?.let { te ->
aapsLogger.info(LTag.NSCLIENT, "Loading TherapyEvents data Start: $startId ${te.first} forID: ${te.second.id} ")
when {
@ -449,11 +438,7 @@ class DataSyncSelectorImplementation @Inject constructor(
activePlugin.activeNsClient?.nsAdd("treatments", DataSyncSelector.PairTherapyEvent(te.first, te.second.id), "$startId/$lastDbId")
// nsId = update
te.first.interfaceIDs.nightscoutId != null ->
activePlugin.activeNsClient?.nsUpdate(
"treatments",
DataSyncSelector.PairTherapyEvent(te.first, te.second.id),
"$startId/$lastDbId"
)
activePlugin.activeNsClient?.nsUpdate("treatments", DataSyncSelector.PairTherapyEvent(te.first, te.second.id), "$startId/$lastDbId")
}
return
}
@ -466,16 +451,16 @@ class DataSyncSelectorImplementation @Inject constructor(
}
}
override fun processChangedDeviceStatuses() {
override suspend fun processChangedDeviceStatuses() {
if (isPaused) return
val lastDbIdWrapped = appRepository.getLastDeviceStatusIdWrapped().blockingGet()
val lastDbId = if (lastDbIdWrapped is ValueWrapper.Existing) lastDbIdWrapped.value else 0L
val lastDbId = appRepository.getLastDeviceStatusId() ?: 0L
var startId = sp.getLong(R.string.key_ns_device_status_last_synced_id, 0)
if (startId > lastDbId) {
sp.putLong(R.string.key_ns_device_status_last_synced_id, 0)
startId = 0
}
queueCounter.dssRemaining = lastDbId - startId
rxBus.send(EventNSClientUpdateGuiQueue())
appRepository.getNextSyncElementDeviceStatus(startId).blockingGet()?.let { deviceStatus ->
aapsLogger.info(LTag.NSCLIENT, "Loading DeviceStatus data Start: $startId $deviceStatus")
when {
@ -496,16 +481,16 @@ class DataSyncSelectorImplementation @Inject constructor(
}
}
override tailrec fun processChangedTemporaryBasals() {
override tailrec suspend fun processChangedTemporaryBasals() {
if (isPaused) return
val lastDbIdWrapped = appRepository.getLastTemporaryBasalIdWrapped().blockingGet()
val lastDbId = if (lastDbIdWrapped is ValueWrapper.Existing) lastDbIdWrapped.value else 0L
val lastDbId = appRepository.getLastTemporaryBasalId() ?: 0L
var startId = sp.getLong(R.string.key_ns_temporary_basal_last_synced_id, 0)
if (startId > lastDbId) {
sp.putLong(R.string.key_ns_temporary_basal_last_synced_id, 0)
startId = 0
}
queueCounter.tbrsRemaining = lastDbId - startId
rxBus.send(EventNSClientUpdateGuiQueue())
appRepository.getNextSyncElementTemporaryBasal(startId).blockingGet()?.let { tb ->
aapsLogger.info(LTag.NSCLIENT, "Loading TemporaryBasal data Start: $startId ${tb.first} forID: ${tb.second.id} ")
when {
@ -525,18 +510,10 @@ class DataSyncSelectorImplementation @Inject constructor(
}
// without nsId = create new
tb.first.interfaceIDs.nightscoutId == null ->
activePlugin.activeNsClient?.nsAdd(
"treatments",
DataSyncSelector.PairTemporaryBasal(tb.first, tb.second.id),
"$startId/$lastDbId"
)
activePlugin.activeNsClient?.nsAdd("treatments", DataSyncSelector.PairTemporaryBasal(tb.first, tb.second.id), "$startId/$lastDbId")
// with nsId = update
tb.first.interfaceIDs.nightscoutId != null ->
activePlugin.activeNsClient?.nsUpdate(
"treatments",
DataSyncSelector.PairTemporaryBasal(tb.first, tb.second.id),
"$startId/$lastDbId"
)
activePlugin.activeNsClient?.nsUpdate("treatments", DataSyncSelector.PairTemporaryBasal(tb.first, tb.second.id), "$startId/$lastDbId")
}
return
}
@ -549,16 +526,16 @@ class DataSyncSelectorImplementation @Inject constructor(
}
}
override tailrec fun processChangedExtendedBoluses() {
override tailrec suspend fun processChangedExtendedBoluses() {
if (isPaused) return
val lastDbIdWrapped = appRepository.getLastExtendedBolusIdWrapped().blockingGet()
val lastDbId = if (lastDbIdWrapped is ValueWrapper.Existing) lastDbIdWrapped.value else 0L
val lastDbId = appRepository.getLastExtendedBolusId() ?: 0L
var startId = sp.getLong(R.string.key_ns_extended_bolus_last_synced_id, 0)
if (startId > lastDbId) {
sp.putLong(R.string.key_ns_extended_bolus_last_synced_id, 0)
startId = 0
}
queueCounter.ebsRemaining = lastDbId - startId
rxBus.send(EventNSClientUpdateGuiQueue())
appRepository.getNextSyncElementExtendedBolus(startId).blockingGet()?.let { eb ->
aapsLogger.info(LTag.NSCLIENT, "Loading ExtendedBolus data Start: $startId ${eb.first} forID: ${eb.second.id} ")
val profile = profileFunction.getProfile(eb.first.timestamp)
@ -580,18 +557,10 @@ class DataSyncSelectorImplementation @Inject constructor(
}
// without nsId = create new
eb.first.interfaceIDs.nightscoutId == null ->
activePlugin.activeNsClient?.nsAdd(
"treatments",
DataSyncSelector.PairExtendedBolus(eb.first, eb.second.id),
"$startId/$lastDbId"
)
activePlugin.activeNsClient?.nsAdd("treatments", DataSyncSelector.PairExtendedBolus(eb.first, eb.second.id), "$startId/$lastDbId")
// with nsId = update
eb.first.interfaceIDs.nightscoutId != null ->
activePlugin.activeNsClient?.nsUpdate(
"treatments",
DataSyncSelector.PairExtendedBolus(eb.first, eb.second.id),
"$startId/$lastDbId"
)
activePlugin.activeNsClient?.nsUpdate("treatments", DataSyncSelector.PairExtendedBolus(eb.first, eb.second.id), "$startId/$lastDbId")
}
return
} else {
@ -610,16 +579,16 @@ class DataSyncSelectorImplementation @Inject constructor(
}
}
override tailrec fun processChangedProfileSwitches() {
override tailrec suspend fun processChangedProfileSwitches() {
if (isPaused) return
val lastDbIdWrapped = appRepository.getLastProfileSwitchIdWrapped().blockingGet()
val lastDbId = if (lastDbIdWrapped is ValueWrapper.Existing) lastDbIdWrapped.value else 0L
val lastDbId = appRepository.getLastProfileSwitchId() ?: 0L
var startId = sp.getLong(R.string.key_ns_profile_switch_last_synced_id, 0)
if (startId > lastDbId) {
sp.putLong(R.string.key_ns_profile_switch_last_synced_id, 0)
startId = 0
}
queueCounter.pssRemaining = lastDbId - startId
rxBus.send(EventNSClientUpdateGuiQueue())
appRepository.getNextSyncElementProfileSwitch(startId).blockingGet()?.let { ps ->
aapsLogger.info(LTag.NSCLIENT, "Loading ProfileSwitch data Start: $startId ${ps.first} forID: ${ps.second.id} ")
when {
@ -642,11 +611,7 @@ class DataSyncSelectorImplementation @Inject constructor(
activePlugin.activeNsClient?.nsAdd("treatments", DataSyncSelector.PairProfileSwitch(ps.first, ps.second.id), "$startId/$lastDbId")
// with nsId = update
ps.first.interfaceIDs.nightscoutId != null ->
activePlugin.activeNsClient?.nsUpdate(
"treatments",
DataSyncSelector.PairProfileSwitch(ps.first, ps.second.id),
"$startId/$lastDbId"
)
activePlugin.activeNsClient?.nsUpdate("treatments", DataSyncSelector.PairProfileSwitch(ps.first, ps.second.id), "$startId/$lastDbId")
}
return
}
@ -659,16 +624,16 @@ class DataSyncSelectorImplementation @Inject constructor(
}
}
override tailrec fun processChangedEffectiveProfileSwitches() {
override tailrec suspend fun processChangedEffectiveProfileSwitches() {
if (isPaused) return
val lastDbIdWrapped = appRepository.getLastEffectiveProfileSwitchIdWrapped().blockingGet()
val lastDbId = if (lastDbIdWrapped is ValueWrapper.Existing) lastDbIdWrapped.value else 0L
val lastDbId = appRepository.getLastEffectiveProfileSwitchId() ?: 0L
var startId = sp.getLong(R.string.key_ns_effective_profile_switch_last_synced_id, 0)
if (startId > lastDbId) {
sp.putLong(R.string.key_ns_effective_profile_switch_last_synced_id, 0)
startId = 0
}
queueCounter.epssRemaining = lastDbId - startId
rxBus.send(EventNSClientUpdateGuiQueue())
appRepository.getNextSyncElementEffectiveProfileSwitch(startId).blockingGet()?.let { ps ->
aapsLogger.info(LTag.NSCLIENT, "Loading EffectiveProfileSwitch data Start: $startId ${ps.first} forID: ${ps.second.id} ")
when {
@ -688,18 +653,10 @@ class DataSyncSelectorImplementation @Inject constructor(
}
// without nsId = create new
ps.first.interfaceIDs.nightscoutId == null ->
activePlugin.activeNsClient?.nsAdd(
"treatments",
DataSyncSelector.PairEffectiveProfileSwitch(ps.first, ps.second.id),
"$startId/$lastDbId"
)
activePlugin.activeNsClient?.nsAdd("treatments", DataSyncSelector.PairEffectiveProfileSwitch(ps.first, ps.second.id), "$startId/$lastDbId")
// with nsId = update
ps.first.interfaceIDs.nightscoutId != null ->
activePlugin.activeNsClient?.nsUpdate(
"treatments",
DataSyncSelector.PairEffectiveProfileSwitch(ps.first, ps.second.id),
"$startId/$lastDbId"
)
activePlugin.activeNsClient?.nsUpdate("treatments", DataSyncSelector.PairEffectiveProfileSwitch(ps.first, ps.second.id), "$startId/$lastDbId")
}
return
}
@ -712,16 +669,16 @@ class DataSyncSelectorImplementation @Inject constructor(
}
}
override tailrec fun processChangedOfflineEvents() {
override tailrec suspend fun processChangedOfflineEvents() {
if (isPaused) return
val lastDbIdWrapped = appRepository.getLastOfflineEventIdWrapped().blockingGet()
val lastDbId = if (lastDbIdWrapped is ValueWrapper.Existing) lastDbIdWrapped.value else 0L
val lastDbId = appRepository.getLastOfflineEventId() ?: 0L
var startId = sp.getLong(R.string.key_ns_offline_event_last_synced_id, 0)
if (startId > lastDbId) {
sp.putLong(R.string.key_ns_offline_event_last_synced_id, 0)
startId = 0
}
queueCounter.oesRemaining = lastDbId - startId
rxBus.send(EventNSClientUpdateGuiQueue())
appRepository.getNextSyncElementOfflineEvent(startId).blockingGet()?.let { oe ->
aapsLogger.info(LTag.NSCLIENT, "Loading OfflineEvent data Start: $startId ${oe.first} forID: ${oe.second.id} ")
when {
@ -744,11 +701,7 @@ class DataSyncSelectorImplementation @Inject constructor(
activePlugin.activeNsClient?.nsAdd("treatments", DataSyncSelector.PairOfflineEvent(oe.first, oe.second.id), "$startId/$lastDbId")
// existing with nsId = update
oe.first.interfaceIDs.nightscoutId != null ->
activePlugin.activeNsClient?.nsUpdate(
"treatments",
DataSyncSelector.PairOfflineEvent(oe.first, oe.second.id),
"$startId/$lastDbId"
)
activePlugin.activeNsClient?.nsUpdate("treatments", DataSyncSelector.PairOfflineEvent(oe.first, oe.second.id), "$startId/$lastDbId")
}
return
}
@ -758,7 +711,7 @@ class DataSyncSelectorImplementation @Inject constructor(
sp.putLong(R.string.key_ns_profile_store_last_synced_timestamp, lastSynced)
}
override fun processChangedProfileStore() {
override suspend fun processChangedProfileStore() {
if (isPaused) return
val lastSync = sp.getLong(R.string.key_ns_profile_store_last_synced_timestamp, 0)
val lastChange = sp.getLong(info.nightscout.core.utils.R.string.key_local_profile_last_change, 0)

View file

@ -4,17 +4,13 @@ import android.content.ComponentName
import android.content.Context
import android.content.Intent
import android.content.ServiceConnection
import android.os.Handler
import android.os.HandlerThread
import android.os.IBinder
import android.text.Spanned
import androidx.preference.PreferenceFragmentCompat
import androidx.preference.PreferenceScreen
import androidx.preference.SwitchPreference
import dagger.android.HasAndroidInjector
import info.nightscout.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
@ -26,24 +22,22 @@ import info.nightscout.interfaces.plugin.PluginType
import info.nightscout.interfaces.profile.ProfileFunction
import info.nightscout.interfaces.source.DoingOwnUploadSource
import info.nightscout.interfaces.sync.DataSyncSelector
import info.nightscout.interfaces.sync.DataSyncSelectorV1
import info.nightscout.interfaces.sync.NsClient
import info.nightscout.interfaces.sync.Sync
import info.nightscout.interfaces.ui.UiInteraction
import info.nightscout.interfaces.utils.HtmlHelper.fromHtml
import info.nightscout.plugins.sync.R
import info.nightscout.plugins.sync.nsShared.NSClientFragment
import info.nightscout.plugins.sync.nsShared.events.EventNSClientResend
import info.nightscout.plugins.sync.nsShared.events.EventNSClientStatus
import info.nightscout.plugins.sync.nsShared.events.EventNSClientUpdateGUI
import info.nightscout.plugins.sync.nsShared.events.EventNSClientUpdateGuiData
import info.nightscout.plugins.sync.nsShared.events.EventNSClientUpdateGuiStatus
import info.nightscout.plugins.sync.nsclient.data.AlarmAck
import info.nightscout.plugins.sync.nsclient.extensions.toJson
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
@ -66,10 +60,9 @@ class NSClientPlugin @Inject constructor(
private val context: Context,
private val fabricPrivacy: FabricPrivacy,
private val sp: SP,
private val nsClientReceiverDelegate: NsClientReceiverDelegate,
private val receiverDelegate: ReceiverDelegate,
private val config: Config,
private val dataSyncSelector: DataSyncSelector,
private val uiInteraction: UiInteraction,
private val dataSyncSelectorV1: DataSyncSelectorV1,
private val activePlugin: ActivePlugin,
private val dateUtil: DateUtil,
private val profileFunction: ProfileFunction,
@ -87,36 +80,28 @@ class NSClientPlugin @Inject constructor(
) {
private val disposable = CompositeDisposable()
private val handler = Handler(HandlerThread(this::class.simpleName + "Handler").also { it.start() }.looper)
private val listLog: MutableList<EventNSClientNewLog> = ArrayList()
override val listLog: MutableList<EventNSClientNewLog> = ArrayList()
override val dataSyncSelector: DataSyncSelector get() = dataSyncSelectorV1
override var status = ""
var nsClientService: NSClientService? = null
val isAllowed: Boolean
get() = nsClientReceiverDelegate.allowed
get() = receiverDelegate.allowed
val blockingReason: String
get() = nsClientReceiverDelegate.blockingReason
get() = receiverDelegate.blockingReason
override fun onStart() {
context.bindService(Intent(context, NSClientService::class.java), mConnection, Context.BIND_AUTO_CREATE)
super.onStart()
nsClientReceiverDelegate.grabReceiversState()
receiverDelegate.grabReceiversState()
disposable += rxBus
.toObservable(EventNSClientStatus::class.java)
.observeOn(aapsSchedulers.io)
.subscribe({ event ->
status = event.getStatus(context)
rxBus.send(EventNSClientUpdateGUI())
// Pass to setup wizard
rxBus.send(EventSWSyncStatus(event.getStatus(context)))
status = event.getStatus(context)
rxBus.send(EventNSClientUpdateGuiStatus())
// 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 +113,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)
@ -174,37 +155,17 @@ class NSClientPlugin @Inject constructor(
}
}
override fun clearLog() {
handler.post {
synchronized(listLog) { listLog.clear() }
rxBus.send(EventNSClientUpdateGUI())
}
}
override fun detectedNsVersion(): String? = nsSettingsStatus.getVersion()
override fun detectedNsVersion(): String = nsSettingsStatus.getVersion()
private fun addToLog(ev: EventNSClientNewLog) {
synchronized(listLog) {
listLog.add(ev)
listLog.add(0, ev)
// remove the first line if log is too large
if (listLog.size >= Constants.MAX_LOG_LINES) {
listLog.removeAt(0)
listLog.removeAt(listLog.size - 1)
}
rxBus.send(EventNSClientUpdateGuiData())
}
rxBus.send(EventNSClientUpdateGUI())
}
override fun textLog(): Spanned {
try {
val newTextLog = StringBuilder()
synchronized(listLog) {
for (log in listLog) newTextLog.append(log.toPreparedHtml())
}
return fromHtml(newTextLog.toString())
} catch (e: OutOfMemoryError) {
uiInteraction.showToastAndNotification(context, "Out of memory!\nStop using this phone !!!", info.nightscout.core.ui.R.raw.error)
}
return fromHtml("")
}
override fun resend(reason: String) {
@ -212,8 +173,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 ?: ""
@ -244,7 +205,7 @@ class NSClientPlugin @Inject constructor(
dataSyncSelector.resetToNextFullSync()
}
override fun nsAdd(collection: String, dataPair: DataSyncSelector.DataPair, progress: String) {
override suspend fun nsAdd(collection: String, dataPair: DataSyncSelector.DataPair, progress: String): Boolean {
when (dataPair) {
is DataSyncSelector.PairBolus -> dataPair.value.toJson(true, dateUtil)
is DataSyncSelector.PairCarbs -> dataPair.value.toJson(true, dateUtil)
@ -264,9 +225,10 @@ class NSClientPlugin @Inject constructor(
}?.let { data ->
nsClientService?.dbAdd(collection, data, dataPair, progress)
}
return true
}
override fun nsUpdate(collection: String, dataPair: DataSyncSelector.DataPair, progress: String) {
override suspend fun nsUpdate(collection: String, dataPair: DataSyncSelector.DataPair, progress: String): Boolean {
val id = when (dataPair) {
is DataSyncSelector.PairBolus -> dataPair.value.interfaceIDs.nightscoutId
is DataSyncSelector.PairCarbs -> dataPair.value.interfaceIDs.nightscoutId
@ -299,5 +261,6 @@ class NSClientPlugin @Inject constructor(
}?.let { data ->
nsClientService?.dbUpdate(collection, id, data, dataPair, progress)
}
return true
}
}

View file

@ -1,43 +1,67 @@
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.EventConnectivityOptionChanged
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
@OpenForTesting
@Singleton
class NsClientReceiverDelegate @Inject constructor(
class ReceiverDelegate @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(EventConnectivityOptionChanged(blockingReason))
}
}

View file

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

View file

@ -24,15 +24,16 @@ import info.nightscout.interfaces.Config
import info.nightscout.interfaces.notifications.Notification
import info.nightscout.interfaces.nsclient.NSAlarm
import info.nightscout.interfaces.nsclient.NSSettingsStatus
import info.nightscout.interfaces.sync.DataSyncSelector
import info.nightscout.interfaces.nsclient.StoreDataForDb
import info.nightscout.interfaces.sync.DataSyncSelectorV1
import info.nightscout.interfaces.ui.UiInteraction
import info.nightscout.interfaces.utils.JsonHelper.safeGetString
import info.nightscout.interfaces.utils.JsonHelper.safeGetStringAllowNull
import info.nightscout.interfaces.workflow.WorkerClasses
import info.nightscout.plugins.sync.R
import info.nightscout.plugins.sync.nsShared.StoreDataForDbImpl
import info.nightscout.plugins.sync.nsShared.NsIncomingDataProcessor
import info.nightscout.plugins.sync.nsShared.events.EventConnectivityOptionChanged
import info.nightscout.plugins.sync.nsShared.events.EventNSClientStatus
import info.nightscout.plugins.sync.nsShared.events.EventNSClientUpdateGUI
import info.nightscout.plugins.sync.nsShared.events.EventNSClientUpdateGuiStatus
import info.nightscout.plugins.sync.nsclient.NSClientPlugin
import info.nightscout.plugins.sync.nsclient.acks.NSAddAck
import info.nightscout.plugins.sync.nsclient.acks.NSAuthAck
@ -41,15 +42,9 @@ import info.nightscout.plugins.sync.nsclient.data.AlarmAck
import info.nightscout.plugins.sync.nsclient.data.NSDeviceStatusHandler
import info.nightscout.plugins.sync.nsclient.workers.NSClientAddUpdateWorker
import info.nightscout.plugins.sync.nsclient.workers.NSClientMbgWorker
import info.nightscout.plugins.sync.nsclientV3.workers.ProcessFoodWorker
import info.nightscout.rx.AapsSchedulers
import info.nightscout.rx.bus.RxBus
import info.nightscout.rx.events.EventAppExit
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.EventPreferenceChange
import info.nightscout.rx.events.*
import info.nightscout.rx.logging.AAPSLogger
import info.nightscout.rx.logging.LTag
import info.nightscout.sdk.localmodel.devicestatus.NSDeviceStatus
@ -62,14 +57,19 @@ import io.reactivex.rxjava3.kotlin.plusAssign
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.async
import kotlinx.coroutines.runBlocking
import org.json.JSONArray
import org.json.JSONException
import org.json.JSONObject
import java.net.URISyntaxException
import java.util.Locale
import java.util.*
import javax.inject.Inject
class NSClientService : DaggerService() {
@Suppress("SpellCheckingInspection") class NSClientService : DaggerService() {
@Inject lateinit var injector: HasAndroidInjector
@Inject lateinit var aapsLogger: AAPSLogger
@ -84,10 +84,11 @@ class NSClientService : DaggerService() {
@Inject lateinit var config: Config
@Inject lateinit var dateUtil: DateUtil
@Inject lateinit var dataWorkerStorage: DataWorkerStorage
@Inject lateinit var dataSyncSelector: DataSyncSelector
@Inject lateinit var dataSyncSelectorV1: DataSyncSelectorV1
@Inject lateinit var repository: AppRepository
@Inject lateinit var uiInteraction: UiInteraction
@Inject lateinit var workerClasses: WorkerClasses
@Inject lateinit var nsIncomingDataProcessor: NsIncomingDataProcessor
@Inject lateinit var storeDataForDb: StoreDataForDb
companion object {
@ -97,6 +98,7 @@ class NSClientService : DaggerService() {
}
private val disposable = CompositeDisposable()
private var scope = CoroutineScope(Dispatchers.IO + SupervisorJob())
private var wakeLock: PowerManager.WakeLock? = null
private val binder: IBinder = LocalBinder()
@ -139,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(EventConnectivityOptionChanged::class.java)
.observeOn(aapsSchedulers.io)
.subscribe({
latestDateInReceivedData = 0
destroy()
initialize()
}, fabricPrivacy::logException)
disposable += rxBus
.toObservable(EventAppExit::class.java)
.observeOn(aapsSchedulers.io)
@ -165,6 +175,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() {
@ -182,12 +196,12 @@ class NSClientService : DaggerService() {
isConnected = true
hasWriteAuth = ack.write && ack.writeTreatment
rxBus.send(EventNSClientStatus(connectionStatus))
rxBus.send(EventNSClientNewLog("AUTH", connectionStatus))
rxBus.send(EventNSClientNewLog("AUTH", connectionStatus))
if (!ack.write) {
rxBus.send(EventNSClientNewLog("ERROR", "Write permission not granted "))
rxBus.send(EventNSClientNewLog("ERROR", "Write permission not granted "))
}
if (!ack.writeTreatment) {
rxBus.send(EventNSClientNewLog("ERROR", "Write treatment permission not granted "))
rxBus.send(EventNSClientNewLog("ERROR", "Write treatment permission not granted "))
}
if (!hasWriteAuth) {
val noWritePerm = Notification(Notification.NSCLIENT_NO_WRITE_PERMISSION, rh.gs(R.string.no_write_permission), Notification.URGENT)
@ -214,28 +228,22 @@ class NSClientService : DaggerService() {
if (nsAPISecret != "") nsApiHashCode = Hashing.sha1().hashString(nsAPISecret, Charsets.UTF_8).toString()
rxBus.send(EventNSClientStatus("Initializing"))
if (!nsClientPlugin.isAllowed) {
rxBus.send(EventNSClientNewLog("NSCLIENT", nsClientPlugin.blockingReason))
rxBus.send(EventNSClientNewLog("NSCLIENT", nsClientPlugin.blockingReason))
rxBus.send(EventNSClientStatus(nsClientPlugin.blockingReason))
} else if (sp.getBoolean(R.string.key_ns_client_paused, false)) {
rxBus.send(EventNSClientNewLog("NSCLIENT", "paused"))
} else if (sp.getBoolean(R.string.key_ns_paused, false)) {
rxBus.send(EventNSClientNewLog("NSCLIENT", "paused"))
rxBus.send(EventNSClientStatus("Paused"))
} else if (!nsEnabled) {
rxBus.send(EventNSClientNewLog("NSCLIENT", "disabled"))
rxBus.send(EventNSClientNewLog("NSCLIENT", "disabled"))
rxBus.send(EventNSClientStatus("Disabled"))
} 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)
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"))
rxBus.send(EventNSClientNewLog("● NSCLIENT", "do connect"))
socket.connect()
socket.on("dataUpdate", onDataUpdate)
socket.on("announcement", onAnnouncement)
@ -244,17 +252,17 @@ class NSClientService : DaggerService() {
socket.on("clear_alarm", onClearAlarm)
}
} catch (e: URISyntaxException) {
rxBus.send(EventNSClientNewLog("NSCLIENT", "Wrong URL syntax"))
rxBus.send(EventNSClientNewLog("NSCLIENT", "Wrong URL syntax"))
rxBus.send(EventNSClientStatus("Wrong URL syntax"))
} catch (e: RuntimeException) {
rxBus.send(EventNSClientNewLog("NSCLIENT", "Wrong URL syntax"))
rxBus.send(EventNSClientNewLog("NSCLIENT", "Wrong URL syntax"))
rxBus.send(EventNSClientStatus("Wrong URL syntax"))
}
} else if (nsURL.lowercase(Locale.getDefault()).startsWith("http://")) {
rxBus.send(EventNSClientNewLog("NSCLIENT", "NS URL not encrypted"))
rxBus.send(EventNSClientNewLog("NSCLIENT", "NS URL not encrypted"))
rxBus.send(EventNSClientStatus("Not encrypted"))
} else {
rxBus.send(EventNSClientNewLog("NSCLIENT", "No NS URL specified"))
rxBus.send(EventNSClientNewLog("NSCLIENT", "No NS URL specified"))
rxBus.send(EventNSClientStatus("Not configured"))
}
}
@ -262,7 +270,7 @@ class NSClientService : DaggerService() {
private val onConnect = Emitter.Listener {
connectCounter++
val socketId = socket?.id() ?: "NULL"
rxBus.send(EventNSClientNewLog("NSCLIENT", "connect #$connectCounter event. ID: $socketId"))
rxBus.send(EventNSClientNewLog("NSCLIENT", "connect #$connectCounter event. ID: $socketId"))
if (socket != null) sendAuthMessage(NSAuthAck(rxBus))
watchdog()
}
@ -276,16 +284,16 @@ class NSClientService : DaggerService() {
reconnections.remove(r)
}
}
rxBus.send(EventNSClientNewLog("WATCHDOG", "connections in last " + WATCHDOG_INTERVAL_MINUTES + " minutes: " + reconnections.size + "/" + WATCHDOG_MAX_CONNECTIONS))
rxBus.send(EventNSClientNewLog("WATCHDOG", "connections in last " + WATCHDOG_INTERVAL_MINUTES + " minutes: " + reconnections.size + "/" + WATCHDOG_MAX_CONNECTIONS))
if (reconnections.size >= WATCHDOG_MAX_CONNECTIONS) {
val n = Notification(Notification.NS_MALFUNCTION, rh.gs(R.string.ns_malfunction), Notification.URGENT)
rxBus.send(EventNewNotification(n))
rxBus.send(EventNSClientNewLog("WATCHDOG", "pausing for $WATCHDOG_RECONNECT_IN minutes"))
rxBus.send(EventNSClientNewLog("WATCHDOG", "pausing for $WATCHDOG_RECONNECT_IN minutes"))
nsClientPlugin.pause(true)
rxBus.send(EventNSClientUpdateGUI())
rxBus.send(EventNSClientUpdateGuiStatus())
Thread {
SystemClock.sleep(mins(WATCHDOG_RECONNECT_IN.toLong()).msecs())
rxBus.send(EventNSClientNewLog("WATCHDOG", "re-enabling NSClient"))
rxBus.send(EventNSClientNewLog("WATCHDOG", "re-enabling NSClient"))
nsClientPlugin.pause(false)
}.start()
}
@ -294,19 +302,18 @@ class NSClientService : DaggerService() {
private val onDisconnect = Emitter.Listener { args ->
aapsLogger.debug(LTag.NSCLIENT, "disconnect reason: {}", *args)
rxBus.send(EventNSClientNewLog("NSCLIENT", "disconnect event"))
rxBus.send(EventNSClientNewLog("NSCLIENT", "disconnect event"))
}
@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")
socket?.off("urgent_alarm")
socket?.off("clear_alarm")
rxBus.send(EventNSClientNewLog("NSCLIENT", "destroy"))
rxBus.send(EventNSClientNewLog("NSCLIENT", "destroy"))
isConnected = false
hasWriteAuth = false
socket?.disconnect()
@ -325,7 +332,7 @@ class NSClientService : DaggerService() {
aapsLogger.error("Unhandled exception", e)
return
}
rxBus.send(EventNSClientNewLog("AUTH", "requesting auth"))
rxBus.send(EventNSClientNewLog("AUTH", "requesting auth"))
socket?.emit("authorize", authMessage, ack)
}
@ -336,18 +343,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 ->
/*
@ -414,7 +409,7 @@ class NSClientService : DaggerService() {
val data: JSONObject
try {
data = args[0] as JSONObject
rxBus.send(EventNSClientNewLog("CLEARALARM", "received"))
rxBus.send(EventNSClientNewLog("CLEARALARM", "received"))
rxBus.send(EventDismissNotification(Notification.NS_ALARM))
rxBus.send(EventDismissNotification(Notification.NS_URGENT_ALARM))
aapsLogger.debug(LTag.NSCLIENT, data.toString())
@ -433,30 +428,26 @@ class NSClientService : DaggerService() {
try {
// delta means only increment/changes are coming
val isDelta = data.has("delta")
rxBus.send(EventNSClientNewLog("DATA", "Data packet #" + dataCounter++ + if (isDelta) " delta" else " full"))
rxBus.send(EventNSClientNewLog("DATA", "Data packet #" + dataCounter++ + if (isDelta) " delta" else " full"))
if (data.has("status")) {
val status = data.getJSONObject("status")
nsSettingsStatus.handleNewData(status)
} else if (!isDelta) {
rxBus.send(EventNSClientNewLog("ERROR", "Unsupported Nightscout version "))
rxBus.send(EventNSClientNewLog("ERROR", "Unsupported Nightscout version "))
}
if (data.has("profiles")) {
val profiles = data.getJSONArray("profiles")
if (profiles.length() > 0) {
// take the newest
val profileStoreJson = profiles[profiles.length() - 1] as JSONObject
rxBus.send(EventNSClientNewLog("PROFILE", "profile received"))
dataWorkerStorage.enqueue(
OneTimeWorkRequest.Builder(workerClasses.nsProfileWorker)
.setInputData(dataWorkerStorage.storeInputData(profileStoreJson))
.build()
)
rxBus.send(EventNSClientNewLog("◄ PROFILE", "profile received"))
nsIncomingDataProcessor.processProfile(profileStoreJson)
}
}
if (data.has("treatments")) {
val treatments = data.getJSONArray("treatments")
val addedOrUpdatedTreatments = JSONArray()
if (treatments.length() > 0) rxBus.send(EventNSClientNewLog("DATA", "received " + treatments.length() + " treatments"))
if (treatments.length() > 0) rxBus.send(EventNSClientNewLog("DATA", "received " + treatments.length() + " treatments"))
for (index in 0 until treatments.length()) {
val jsonTreatment = treatments.getJSONObject(index)
val action = safeGetStringAllowNull(jsonTreatment, "action", null)
@ -502,7 +493,7 @@ class NSClientService : DaggerService() {
aapsLogger.warn(
LTag.NSCLIENT,
"JSON devicestatus object #$arrayIndex (out of ${devicestatusJsonArray.length()}) " +
"has invalid value \"$batteryValue\" (expected integer); replacing with hardcoded integer 100"
"has invalid value \"$batteryValue\" (expected integer); replacing with hardcoded integer 100"
)
uploaderObject.put("battery", 100)
}
@ -512,7 +503,7 @@ class NSClientService : DaggerService() {
val devicestatuses = gson.fromJson(data.getString("devicestatus"), Array<NSDeviceStatus>::class.java)
if (devicestatuses.isNotEmpty()) {
rxBus.send(EventNSClientNewLog("DATA", "received " + devicestatuses.size + " device statuses"))
rxBus.send(EventNSClientNewLog("DATA", "received " + devicestatuses.size + " device statuses"))
nsDeviceStatusHandler.handleNewData(devicestatuses)
}
} catch (e: JSONException) {
@ -521,19 +512,13 @@ class NSClientService : DaggerService() {
}
if (data.has("food")) {
val foods = data.getJSONArray("food")
if (foods.length() > 0) rxBus.send(EventNSClientNewLog("DATA", "received " + foods.length() + " foods"))
dataWorkerStorage
.beginUniqueWork(
"ProcessFoods",
OneTimeWorkRequest.Builder(ProcessFoodWorker::class.java)
.setInputData(dataWorkerStorage.storeInputData(foods))
.build()
).then(OneTimeWorkRequest.Builder(StoreDataForDbImpl.StoreFoodWorker::class.java).build())
.enqueue()
if (foods.length() > 0) rxBus.send(EventNSClientNewLog("◄ DATA", "received " + foods.length() + " foods"))
nsIncomingDataProcessor.processFood(foods)
storeDataForDb.storeFoodsToDb()
}
if (data.has("mbgs")) {
val mbgArray = data.getJSONArray("mbgs")
if (mbgArray.length() > 0) rxBus.send(EventNSClientNewLog("DATA", "received " + mbgArray.length() + " mbgs"))
if (mbgArray.length() > 0) rxBus.send(EventNSClientNewLog("◄ DATA", "received " + mbgArray.length() + " mbgs"))
dataWorkerStorage.enqueue(
OneTimeWorkRequest.Builder(NSClientMbgWorker::class.java)
.setInputData(dataWorkerStorage.storeInputData(mbgArray))
@ -542,26 +527,20 @@ class NSClientService : DaggerService() {
}
if (data.has("cals")) {
val cals = data.getJSONArray("cals")
if (cals.length() > 0) rxBus.send(EventNSClientNewLog("DATA", "received " + cals.length() + " cals"))
if (cals.length() > 0) rxBus.send(EventNSClientNewLog("DATA", "received " + cals.length() + " cals"))
// Calibrations ignored
}
if (data.has("sgvs")) {
val sgvs = data.getJSONArray("sgvs")
if (sgvs.length() > 0) {
rxBus.send(EventNSClientNewLog("DATA", "received " + sgvs.length() + " sgvs"))
rxBus.send(EventNSClientNewLog("DATA", "received " + sgvs.length() + " sgvs"))
// Objective0
sp.putBoolean(info.nightscout.core.utils.R.string.key_objectives_bg_is_available_in_ns, true)
dataWorkerStorage
.beginUniqueWork(
"ProcessBg",
OneTimeWorkRequest.Builder(workerClasses.nsClientSourceWorker)
.setInputData(dataWorkerStorage.storeInputData(sgvs))
.build()
).then(OneTimeWorkRequest.Builder(StoreDataForDbImpl.StoreBgWorker::class.java).build())
.enqueue()
nsIncomingDataProcessor.processSgvs(sgvs)
storeDataForDb.storeGlucoseValuesToDb()
}
}
rxBus.send(EventNSClientNewLog("LAST", dateUtil.dateAndTimeString(latestDateInReceivedData)))
rxBus.send(EventNSClientNewLog("◄ LAST", dateUtil.dateAndTimeString(latestDateInReceivedData)))
} catch (e: JSONException) {
aapsLogger.error("Unhandled exception", e)
}
@ -583,7 +562,7 @@ class NSClientService : DaggerService() {
socket?.emit("dbUpdate", message, NSUpdateAck("dbUpdate", _id, aapsLogger, rxBus, this, dateUtil, dataWorkerStorage, originalObject))
rxBus.send(
EventNSClientNewLog(
"UPDATE $collection", "Sent " + originalObject.javaClass.simpleName + " " +
"UPDATE $collection", "Sent " + originalObject.javaClass.simpleName + " " +
"" + _id + " " + data + progress
)
)
@ -599,7 +578,7 @@ class NSClientService : DaggerService() {
message.put("collection", collection)
message.put("data", data)
socket?.emit("dbAdd", message, NSAddAck(aapsLogger, rxBus, this, dateUtil, dataWorkerStorage, originalObject))
rxBus.send(EventNSClientNewLog("ADD $collection", "Sent " + originalObject.javaClass.simpleName + " " + data + " " + progress))
rxBus.send(EventNSClientNewLog("ADD $collection", "Sent " + originalObject.javaClass.simpleName + " " + data + " " + progress))
} catch (e: JSONException) {
aapsLogger.error("Unhandled exception", e)
}
@ -608,29 +587,22 @@ class NSClientService : DaggerService() {
fun sendAlarmAck(alarmAck: AlarmAck) {
if (!isConnected || !hasWriteAuth) return
socket?.emit("ack", alarmAck.level, alarmAck.group, alarmAck.silenceTime)
rxBus.send(EventNSClientNewLog("ALARMACK ", alarmAck.level.toString() + " " + alarmAck.group + " " + alarmAck.silenceTime))
rxBus.send(EventNSClientNewLog("ALARMACK ", alarmAck.level.toString() + " " + alarmAck.group + " " + alarmAck.silenceTime))
}
fun resend(reason: String) {
if (!isConnected || !hasWriteAuth) return
handler.post {
if (socket?.connected() != true) return@post
@Synchronized
fun resend(reason: String) = runBlocking {
if (!isConnected || !hasWriteAuth) return@runBlocking
scope.async {
if (socket?.connected() != true) return@async
if (lastAckTime > System.currentTimeMillis() - 10 * 1000L) {
aapsLogger.debug(LTag.NSCLIENT, "Skipping resend by lastAckTime: " + (System.currentTimeMillis() - lastAckTime) / 1000L + " sec")
return@post
return@async
}
// val powerManager = getSystemService(POWER_SERVICE) as PowerManager
// val wakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
// "AndroidAPS:NSClientService_onDataUpdate")
// wakeLock.acquire(mins(10).msecs())
try {
rxBus.send(EventNSClientNewLog("QUEUE", "Resend started: $reason"))
dataSyncSelector.doUpload()
rxBus.send(EventNSClientNewLog("QUEUE", "Resend ended: $reason"))
} finally {
// if (wakeLock.isHeld) wakeLock.release()
}
}
rxBus.send(EventNSClientNewLog("● QUEUE", "Resend started: $reason"))
dataSyncSelectorV1.doUpload()
rxBus.send(EventNSClientNewLog("● QUEUE", "Resend ended: $reason"))
}.join()
}
fun restart() {
@ -643,7 +615,7 @@ class NSClientService : DaggerService() {
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", safeGetString(announcement, "message", "received")))
rxBus.send(EventNSClientNewLog("ANNOUNCEMENT", safeGetString(announcement, "message", "received")))
aapsLogger.debug(LTag.NSCLIENT, announcement.toString())
}
}
@ -651,12 +623,12 @@ 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)
}
rxBus.send(EventNSClientNewLog("ALARM", safeGetString(alarm, "message", "received")))
rxBus.send(EventNSClientNewLog("ALARM", safeGetString(alarm, "message", "received")))
aapsLogger.debug(LTag.NSCLIENT, alarm.toString())
}
}
@ -664,12 +636,12 @@ 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)
}
rxBus.send(EventNSClientNewLog("URGENTALARM", safeGetString(alarm, "message", "received")))
rxBus.send(EventNSClientNewLog("URGENTALARM", safeGetString(alarm, "message", "received")))
aapsLogger.debug(LTag.NSCLIENT, alarm.toString())
}
}

View file

@ -22,6 +22,7 @@ import info.nightscout.interfaces.sync.DataSyncSelector.PairProfileSwitch
import info.nightscout.interfaces.sync.DataSyncSelector.PairTemporaryBasal
import info.nightscout.interfaces.sync.DataSyncSelector.PairTemporaryTarget
import info.nightscout.interfaces.sync.DataSyncSelector.PairTherapyEvent
import info.nightscout.interfaces.sync.DataSyncSelectorV1
import info.nightscout.plugins.sync.R
import info.nightscout.plugins.sync.nsclient.acks.NSAddAck
import info.nightscout.rx.AapsSchedulers
@ -39,7 +40,7 @@ class NSClientAddAckWorker(
@Inject lateinit var dataWorkerStorage: DataWorkerStorage
@Inject lateinit var repository: AppRepository
@Inject lateinit var rxBus: RxBus
@Inject lateinit var dataSyncSelector: DataSyncSelector
@Inject lateinit var dataSyncSelectorV1: DataSyncSelectorV1
@Inject lateinit var aapsSchedulers: AapsSchedulers
@Inject lateinit var sp: SP
@Inject lateinit var storeDataForDb: StoreDataForDb
@ -60,148 +61,148 @@ class NSClientAddAckWorker(
val pair = ack.originalObject
pair.value.interfaceIDs.nightscoutId = ack.id
storeDataForDb.nsIdTemporaryTargets.add(pair.value)
dataSyncSelector.confirmLastTempTargetsIdIfGreater(pair.id)
dataSyncSelectorV1.confirmLastTempTargetsIdIfGreater(pair.id)
storeDataForDb.scheduleNsIdUpdate()
rxBus.send(EventNSClientNewLog("DBADD", "Acked TemporaryTarget " + pair.value.interfaceIDs.nightscoutId))
rxBus.send(EventNSClientNewLog("DBADD", "Acked TemporaryTarget " + pair.value.interfaceIDs.nightscoutId))
// Send new if waiting
dataSyncSelector.processChangedTempTargets()
dataSyncSelectorV1.processChangedTempTargets()
}
is PairGlucoseValue -> {
val pair = ack.originalObject
pair.value.interfaceIDs.nightscoutId = ack.id
storeDataForDb.nsIdGlucoseValues.add(pair.value)
dataSyncSelector.confirmLastGlucoseValueIdIfGreater(pair.id)
dataSyncSelectorV1.confirmLastGlucoseValueIdIfGreater(pair.id)
storeDataForDb.scheduleNsIdUpdate()
rxBus.send(EventNSClientNewLog("DBADD", "Acked GlucoseValue " + pair.value.interfaceIDs.nightscoutId))
rxBus.send(EventNSClientNewLog("DBADD", "Acked GlucoseValue " + pair.value.interfaceIDs.nightscoutId))
// Send new if waiting
dataSyncSelector.processChangedGlucoseValues()
dataSyncSelectorV1.processChangedGlucoseValues()
}
is PairFood -> {
val pair = ack.originalObject
pair.value.interfaceIDs.nightscoutId = ack.id
storeDataForDb.nsIdFoods.add(pair.value)
dataSyncSelector.confirmLastFoodIdIfGreater(pair.id)
dataSyncSelectorV1.confirmLastFoodIdIfGreater(pair.id)
storeDataForDb.scheduleNsIdUpdate()
rxBus.send(EventNSClientNewLog("DBADD", "Acked Food " + pair.value.interfaceIDs.nightscoutId))
rxBus.send(EventNSClientNewLog("DBADD", "Acked Food " + pair.value.interfaceIDs.nightscoutId))
// Send new if waiting
dataSyncSelector.processChangedFoods()
dataSyncSelectorV1.processChangedFoods()
}
is PairTherapyEvent -> {
val pair = ack.originalObject
pair.value.interfaceIDs.nightscoutId = ack.id
storeDataForDb.nsIdTherapyEvents.add(pair.value)
dataSyncSelector.confirmLastTherapyEventIdIfGreater(pair.id)
dataSyncSelectorV1.confirmLastTherapyEventIdIfGreater(pair.id)
storeDataForDb.scheduleNsIdUpdate()
rxBus.send(EventNSClientNewLog("DBADD", "Acked TherapyEvent " + pair.value.interfaceIDs.nightscoutId))
rxBus.send(EventNSClientNewLog("DBADD", "Acked TherapyEvent " + pair.value.interfaceIDs.nightscoutId))
// Send new if waiting
dataSyncSelector.processChangedTherapyEvents()
dataSyncSelectorV1.processChangedTherapyEvents()
}
is PairBolus -> {
val pair = ack.originalObject
pair.value.interfaceIDs.nightscoutId = ack.id
storeDataForDb.nsIdBoluses.add(pair.value)
dataSyncSelector.confirmLastBolusIdIfGreater(pair.id)
dataSyncSelectorV1.confirmLastBolusIdIfGreater(pair.id)
storeDataForDb.scheduleNsIdUpdate()
rxBus.send(EventNSClientNewLog("DBADD", "Acked Bolus " + pair.value.interfaceIDs.nightscoutId))
rxBus.send(EventNSClientNewLog("DBADD", "Acked Bolus " + pair.value.interfaceIDs.nightscoutId))
// Send new if waiting
dataSyncSelector.processChangedBoluses()
dataSyncSelectorV1.processChangedBoluses()
}
is PairCarbs -> {
val pair = ack.originalObject
pair.value.interfaceIDs.nightscoutId = ack.id
storeDataForDb.nsIdCarbs.add(pair.value)
dataSyncSelector.confirmLastCarbsIdIfGreater(pair.id)
dataSyncSelectorV1.confirmLastCarbsIdIfGreater(pair.id)
storeDataForDb.scheduleNsIdUpdate()
rxBus.send(EventNSClientNewLog("DBADD", "Acked Carbs " + pair.value.interfaceIDs.nightscoutId))
rxBus.send(EventNSClientNewLog("DBADD", "Acked Carbs " + pair.value.interfaceIDs.nightscoutId))
// Send new if waiting
dataSyncSelector.processChangedCarbs()
dataSyncSelectorV1.processChangedCarbs()
}
is PairBolusCalculatorResult -> {
val pair = ack.originalObject
pair.value.interfaceIDs.nightscoutId = ack.id
storeDataForDb.nsIdBolusCalculatorResults.add(pair.value)
dataSyncSelector.confirmLastBolusCalculatorResultsIdIfGreater(pair.id)
dataSyncSelectorV1.confirmLastBolusCalculatorResultsIdIfGreater(pair.id)
storeDataForDb.scheduleNsIdUpdate()
rxBus.send(EventNSClientNewLog("DBADD", "Acked BolusCalculatorResult " + pair.value.interfaceIDs.nightscoutId))
rxBus.send(EventNSClientNewLog("DBADD", "Acked BolusCalculatorResult " + pair.value.interfaceIDs.nightscoutId))
// Send new if waiting
dataSyncSelector.processChangedBolusCalculatorResults()
dataSyncSelectorV1.processChangedBolusCalculatorResults()
}
is PairTemporaryBasal -> {
val pair = ack.originalObject
pair.value.interfaceIDs.nightscoutId = ack.id
storeDataForDb.nsIdTemporaryBasals.add(pair.value)
dataSyncSelector.confirmLastTemporaryBasalIdIfGreater(pair.id)
dataSyncSelectorV1.confirmLastTemporaryBasalIdIfGreater(pair.id)
storeDataForDb.scheduleNsIdUpdate()
rxBus.send(EventNSClientNewLog("DBADD", "Acked TemporaryBasal " + pair.value.interfaceIDs.nightscoutId))
rxBus.send(EventNSClientNewLog("DBADD", "Acked TemporaryBasal " + pair.value.interfaceIDs.nightscoutId))
// Send new if waiting
dataSyncSelector.processChangedTemporaryBasals()
dataSyncSelectorV1.processChangedTemporaryBasals()
}
is PairExtendedBolus -> {
val pair = ack.originalObject
pair.value.interfaceIDs.nightscoutId = ack.id
storeDataForDb.nsIdExtendedBoluses.add(pair.value)
dataSyncSelector.confirmLastExtendedBolusIdIfGreater(pair.id)
dataSyncSelectorV1.confirmLastExtendedBolusIdIfGreater(pair.id)
storeDataForDb.scheduleNsIdUpdate()
rxBus.send(EventNSClientNewLog("DBADD", "Acked ExtendedBolus " + pair.value.interfaceIDs.nightscoutId))
rxBus.send(EventNSClientNewLog("DBADD", "Acked ExtendedBolus " + pair.value.interfaceIDs.nightscoutId))
// Send new if waiting
dataSyncSelector.processChangedExtendedBoluses()
dataSyncSelectorV1.processChangedExtendedBoluses()
}
is PairProfileSwitch -> {
val pair = ack.originalObject
pair.value.interfaceIDs.nightscoutId = ack.id
storeDataForDb.nsIdProfileSwitches.add(pair.value)
dataSyncSelector.confirmLastProfileSwitchIdIfGreater(pair.id)
dataSyncSelectorV1.confirmLastProfileSwitchIdIfGreater(pair.id)
storeDataForDb.scheduleNsIdUpdate()
rxBus.send(EventNSClientNewLog("DBADD", "Acked ProfileSwitch " + pair.value.interfaceIDs.nightscoutId))
rxBus.send(EventNSClientNewLog("DBADD", "Acked ProfileSwitch " + pair.value.interfaceIDs.nightscoutId))
// Send new if waiting
dataSyncSelector.processChangedProfileSwitches()
dataSyncSelectorV1.processChangedProfileSwitches()
}
is PairEffectiveProfileSwitch -> {
val pair = ack.originalObject
pair.value.interfaceIDs.nightscoutId = ack.id
storeDataForDb.nsIdEffectiveProfileSwitches.add(pair.value)
dataSyncSelector.confirmLastEffectiveProfileSwitchIdIfGreater(pair.id)
dataSyncSelectorV1.confirmLastEffectiveProfileSwitchIdIfGreater(pair.id)
storeDataForDb.scheduleNsIdUpdate()
rxBus.send(EventNSClientNewLog("DBADD", "Acked EffectiveProfileSwitch " + pair.value.interfaceIDs.nightscoutId))
rxBus.send(EventNSClientNewLog("DBADD", "Acked EffectiveProfileSwitch " + pair.value.interfaceIDs.nightscoutId))
// Send new if waiting
dataSyncSelector.processChangedEffectiveProfileSwitches()
dataSyncSelectorV1.processChangedEffectiveProfileSwitches()
}
is DataSyncSelector.PairDeviceStatus -> {
val pair = ack.originalObject
pair.value.interfaceIDs.nightscoutId = ack.id
storeDataForDb.nsIdDeviceStatuses.add(pair.value)
dataSyncSelector.confirmLastDeviceStatusIdIfGreater(pair.value.id)
dataSyncSelectorV1.confirmLastDeviceStatusIdIfGreater(pair.value.id)
storeDataForDb.scheduleNsIdUpdate()
rxBus.send(EventNSClientNewLog("DBADD", "Acked DeviceStatus " + pair.value.interfaceIDs.nightscoutId))
rxBus.send(EventNSClientNewLog("DBADD", "Acked DeviceStatus " + pair.value.interfaceIDs.nightscoutId))
// Send new if waiting
dataSyncSelector.processChangedDeviceStatuses()
dataSyncSelectorV1.processChangedDeviceStatuses()
}
is PairProfileStore -> {
dataSyncSelector.confirmLastProfileStore(ack.originalObject.id)
rxBus.send(EventNSClientNewLog("DBADD", "Acked ProfileStore " + ack.id))
dataSyncSelectorV1.confirmLastProfileStore(ack.originalObject.id)
rxBus.send(EventNSClientNewLog("DBADD", "Acked ProfileStore " + ack.id))
}
is PairOfflineEvent -> {
val pair = ack.originalObject
pair.value.interfaceIDs.nightscoutId = ack.id
storeDataForDb.nsIdOfflineEvents.add(pair.value)
dataSyncSelector.confirmLastOfflineEventIdIfGreater(pair.id)
dataSyncSelectorV1.confirmLastOfflineEventIdIfGreater(pair.id)
storeDataForDb.scheduleNsIdUpdate()
rxBus.send(EventNSClientNewLog("DBADD", "Acked OfflineEvent " + pair.value.interfaceIDs.nightscoutId))
rxBus.send(EventNSClientNewLog("DBADD", "Acked OfflineEvent " + pair.value.interfaceIDs.nightscoutId))
// Send new if waiting
dataSyncSelector.processChangedOfflineEvents()
dataSyncSelectorV1.processChangedOfflineEvents()
}
}

View file

@ -44,7 +44,6 @@ class NSClientAddUpdateWorker(
@Inject lateinit var repository: AppRepository
@Inject lateinit var activePlugin: ActivePlugin
@Inject lateinit var rxBus: RxBus
@Inject lateinit var xDripBroadcast: XDripBroadcast
@Inject lateinit var storeDataForDb: StoreDataForDb
override suspend fun doWorkAndLog(): Result {
@ -164,7 +163,6 @@ class NSClientAddUpdateWorker(
}
storeDataForDb.storeTreatmentsToDb()
activePlugin.activeNsClient?.updateLatestTreatmentReceivedIfNewer(latestDateInReceivedData)
xDripBroadcast.sendTreatments(treatments)
return ret
}
}

View file

@ -6,7 +6,6 @@ import androidx.work.workDataOf
import info.nightscout.core.utils.receivers.DataWorkerStorage
import info.nightscout.core.utils.worker.LoggingWorker
import info.nightscout.database.impl.AppRepository
import info.nightscout.interfaces.sync.DataSyncSelector
import info.nightscout.interfaces.sync.DataSyncSelector.PairBolus
import info.nightscout.interfaces.sync.DataSyncSelector.PairBolusCalculatorResult
import info.nightscout.interfaces.sync.DataSyncSelector.PairCarbs
@ -19,6 +18,7 @@ import info.nightscout.interfaces.sync.DataSyncSelector.PairProfileSwitch
import info.nightscout.interfaces.sync.DataSyncSelector.PairTemporaryBasal
import info.nightscout.interfaces.sync.DataSyncSelector.PairTemporaryTarget
import info.nightscout.interfaces.sync.DataSyncSelector.PairTherapyEvent
import info.nightscout.interfaces.sync.DataSyncSelectorV1
import info.nightscout.plugins.sync.nsclient.acks.NSUpdateAck
import info.nightscout.rx.AapsSchedulers
import info.nightscout.rx.bus.RxBus
@ -34,7 +34,7 @@ class NSClientUpdateRemoveAckWorker(
@Inject lateinit var dataWorkerStorage: DataWorkerStorage
@Inject lateinit var repository: AppRepository
@Inject lateinit var rxBus: RxBus
@Inject lateinit var dataSyncSelector: DataSyncSelector
@Inject lateinit var dataSyncSelectorV1: DataSyncSelectorV1
@Inject lateinit var aapsSchedulers: AapsSchedulers
override suspend fun doWorkAndLog(): Result {
@ -47,109 +47,109 @@ class NSClientUpdateRemoveAckWorker(
when (ack.originalObject) {
is PairTemporaryTarget -> {
val pair = ack.originalObject
dataSyncSelector.confirmLastTempTargetsIdIfGreater(pair.id)
rxBus.send(EventNSClientNewLog("DBUPDATE", "Acked TemporaryTarget" + ack._id))
dataSyncSelectorV1.confirmLastTempTargetsIdIfGreater(pair.id)
rxBus.send(EventNSClientNewLog("DBUPDATE", "Acked TemporaryTarget" + ack._id))
// Send new if waiting
dataSyncSelector.processChangedTempTargets()
dataSyncSelectorV1.processChangedTempTargets()
ret = Result.success(workDataOf("ProcessedData" to pair.toString()))
}
is PairGlucoseValue -> {
val pair = ack.originalObject
dataSyncSelector.confirmLastGlucoseValueIdIfGreater(pair.id)
rxBus.send(EventNSClientNewLog("DBUPDATE", "Acked GlucoseValue " + ack._id))
dataSyncSelectorV1.confirmLastGlucoseValueIdIfGreater(pair.id)
rxBus.send(EventNSClientNewLog("DBUPDATE", "Acked GlucoseValue " + ack._id))
// Send new if waiting
dataSyncSelector.processChangedGlucoseValues()
dataSyncSelectorV1.processChangedGlucoseValues()
ret = Result.success(workDataOf("ProcessedData" to pair.toString()))
}
is PairFood -> {
val pair = ack.originalObject
dataSyncSelector.confirmLastFoodIdIfGreater(pair.id)
rxBus.send(EventNSClientNewLog("DBUPDATE", "Acked Food " + ack._id))
dataSyncSelectorV1.confirmLastFoodIdIfGreater(pair.id)
rxBus.send(EventNSClientNewLog("DBUPDATE", "Acked Food " + ack._id))
// Send new if waiting
dataSyncSelector.processChangedFoods()
dataSyncSelectorV1.processChangedFoods()
ret = Result.success(workDataOf("ProcessedData" to pair.toString()))
}
is PairTherapyEvent -> {
val pair = ack.originalObject
dataSyncSelector.confirmLastTherapyEventIdIfGreater(pair.id)
rxBus.send(EventNSClientNewLog("DBUPDATE", "Acked TherapyEvent " + ack._id))
dataSyncSelectorV1.confirmLastTherapyEventIdIfGreater(pair.id)
rxBus.send(EventNSClientNewLog("DBUPDATE", "Acked TherapyEvent " + ack._id))
// Send new if waiting
dataSyncSelector.processChangedTherapyEvents()
dataSyncSelectorV1.processChangedTherapyEvents()
ret = Result.success(workDataOf("ProcessedData" to pair.toString()))
}
is PairBolus -> {
val pair = ack.originalObject
dataSyncSelector.confirmLastBolusIdIfGreater(pair.id)
rxBus.send(EventNSClientNewLog("DBUPDATE", "Acked Bolus " + ack._id))
dataSyncSelectorV1.confirmLastBolusIdIfGreater(pair.id)
rxBus.send(EventNSClientNewLog("DBUPDATE", "Acked Bolus " + ack._id))
// Send new if waiting
dataSyncSelector.processChangedBoluses()
dataSyncSelectorV1.processChangedBoluses()
ret = Result.success(workDataOf("ProcessedData" to pair.toString()))
}
is PairCarbs -> {
val pair = ack.originalObject
dataSyncSelector.confirmLastCarbsIdIfGreater(pair.id)
rxBus.send(EventNSClientNewLog("DBUPDATE", "Acked Carbs " + ack._id))
dataSyncSelectorV1.confirmLastCarbsIdIfGreater(pair.id)
rxBus.send(EventNSClientNewLog("DBUPDATE", "Acked Carbs " + ack._id))
// Send new if waiting
dataSyncSelector.processChangedCarbs()
dataSyncSelectorV1.processChangedCarbs()
ret = Result.success(workDataOf("ProcessedData" to pair.toString()))
}
is PairBolusCalculatorResult -> {
val pair = ack.originalObject
dataSyncSelector.confirmLastBolusCalculatorResultsIdIfGreater(pair.id)
rxBus.send(EventNSClientNewLog("DBUPDATE", "Acked BolusCalculatorResult " + ack._id))
dataSyncSelectorV1.confirmLastBolusCalculatorResultsIdIfGreater(pair.id)
rxBus.send(EventNSClientNewLog("DBUPDATE", "Acked BolusCalculatorResult " + ack._id))
// Send new if waiting
dataSyncSelector.processChangedBolusCalculatorResults()
dataSyncSelectorV1.processChangedBolusCalculatorResults()
ret = Result.success(workDataOf("ProcessedData" to pair.toString()))
}
is PairTemporaryBasal -> {
val pair = ack.originalObject
dataSyncSelector.confirmLastTemporaryBasalIdIfGreater(pair.id)
rxBus.send(EventNSClientNewLog("DBUPDATE", "Acked TemporaryBasal " + ack._id))
dataSyncSelectorV1.confirmLastTemporaryBasalIdIfGreater(pair.id)
rxBus.send(EventNSClientNewLog("DBUPDATE", "Acked TemporaryBasal " + ack._id))
// Send new if waiting
dataSyncSelector.processChangedTemporaryBasals()
dataSyncSelectorV1.processChangedTemporaryBasals()
ret = Result.success(workDataOf("ProcessedData" to pair.toString()))
}
is PairExtendedBolus -> {
val pair = ack.originalObject
dataSyncSelector.confirmLastExtendedBolusIdIfGreater(pair.id)
rxBus.send(EventNSClientNewLog("DBUPDATE", "Acked ExtendedBolus " + ack._id))
dataSyncSelectorV1.confirmLastExtendedBolusIdIfGreater(pair.id)
rxBus.send(EventNSClientNewLog("DBUPDATE", "Acked ExtendedBolus " + ack._id))
// Send new if waiting
dataSyncSelector.processChangedExtendedBoluses()
dataSyncSelectorV1.processChangedExtendedBoluses()
ret = Result.success(workDataOf("ProcessedData" to pair.toString()))
}
is PairProfileSwitch -> {
val pair = ack.originalObject
dataSyncSelector.confirmLastProfileSwitchIdIfGreater(pair.id)
rxBus.send(EventNSClientNewLog("DBUPDATE", "Acked ProfileSwitch " + ack._id))
dataSyncSelectorV1.confirmLastProfileSwitchIdIfGreater(pair.id)
rxBus.send(EventNSClientNewLog("DBUPDATE", "Acked ProfileSwitch " + ack._id))
// Send new if waiting
dataSyncSelector.processChangedProfileSwitches()
dataSyncSelectorV1.processChangedProfileSwitches()
ret = Result.success(workDataOf("ProcessedData" to pair.toString()))
}
is PairEffectiveProfileSwitch -> {
val pair = ack.originalObject
dataSyncSelector.confirmLastEffectiveProfileSwitchIdIfGreater(pair.id)
rxBus.send(EventNSClientNewLog("DBUPDATE", "Acked EffectiveProfileSwitch " + ack._id))
dataSyncSelectorV1.confirmLastEffectiveProfileSwitchIdIfGreater(pair.id)
rxBus.send(EventNSClientNewLog("DBUPDATE", "Acked EffectiveProfileSwitch " + ack._id))
// Send new if waiting
dataSyncSelector.processChangedEffectiveProfileSwitches()
dataSyncSelectorV1.processChangedEffectiveProfileSwitches()
ret = Result.success(workDataOf("ProcessedData" to pair.toString()))
}
is PairOfflineEvent -> {
val pair = ack.originalObject
dataSyncSelector.confirmLastOfflineEventIdIfGreater(pair.id)
rxBus.send(EventNSClientNewLog("DBUPDATE", "Acked OfflineEvent" + ack._id))
dataSyncSelectorV1.confirmLastOfflineEventIdIfGreater(pair.id)
rxBus.send(EventNSClientNewLog("DBUPDATE", "Acked OfflineEvent" + ack._id))
// Send new if waiting
dataSyncSelector.processChangedOfflineEvents()
dataSyncSelectorV1.processChangedOfflineEvents()
ret = Result.success(workDataOf("ProcessedData" to pair.toString()))
}
}

View file

@ -0,0 +1,708 @@
package info.nightscout.plugins.sync.nsclientV3
import info.nightscout.androidaps.annotations.OpenForTesting
import info.nightscout.database.impl.AppRepository
import info.nightscout.interfaces.nsclient.StoreDataForDb
import info.nightscout.interfaces.plugin.ActivePlugin
import info.nightscout.interfaces.profile.ProfileFunction
import info.nightscout.interfaces.sync.DataSyncSelector
import info.nightscout.interfaces.sync.DataSyncSelectorV3
import info.nightscout.interfaces.utils.JsonHelper
import info.nightscout.plugins.sync.R
import info.nightscout.plugins.sync.nsShared.events.EventNSClientUpdateGuiQueue
import info.nightscout.plugins.sync.nsShared.events.EventNSClientUpdateGuiStatus
import info.nightscout.rx.bus.RxBus
import info.nightscout.rx.logging.AAPSLogger
import info.nightscout.rx.logging.LTag
import info.nightscout.shared.sharedPreferences.SP
import info.nightscout.shared.utils.DateUtil
import javax.inject.Inject
import javax.inject.Singleton
@OpenForTesting
@Singleton
class DataSyncSelectorV3Impl @Inject constructor(
private val sp: SP,
private val aapsLogger: AAPSLogger,
private val dateUtil: DateUtil,
private val profileFunction: ProfileFunction,
private val activePlugin: ActivePlugin,
private val appRepository: AppRepository,
private val rxBus: RxBus,
private val storeDataForDb: StoreDataForDb
) : DataSyncSelectorV3 {
class QueueCounter(
var bolusesRemaining: Long = -1L,
var carbsRemaining: Long = -1L,
var bcrRemaining: Long = -1L,
var ttsRemaining: Long = -1L,
var foodsRemaining: Long = -1L,
var gvsRemaining: Long = -1L,
var tesRemaining: Long = -1L,
var dssRemaining: Long = -1L,
var tbrsRemaining: Long = -1L,
var ebsRemaining: Long = -1L,
var pssRemaining: Long = -1L,
var epssRemaining: Long = -1L,
var oesRemaining: Long = -1L
) {
fun size(): Long =
bolusesRemaining +
carbsRemaining +
bcrRemaining +
ttsRemaining +
foodsRemaining +
gvsRemaining +
tesRemaining +
dssRemaining +
tbrsRemaining +
ebsRemaining +
pssRemaining +
epssRemaining +
oesRemaining
}
private val queueCounter = QueueCounter()
private val isPaused get() = sp.getBoolean(R.string.key_ns_paused, false)
override fun queueSize(): Long = queueCounter.size()
override suspend fun doUpload() {
rxBus.send(EventNSClientUpdateGuiStatus())
if (sp.getBoolean(R.string.key_ns_upload, true) && !isPaused) {
queueCounter.bolusesRemaining = (appRepository.getLastBolusId() ?: 0L) - sp.getLong(R.string.key_ns_bolus_last_synced_id, 0)
queueCounter.carbsRemaining = (appRepository.getLastCarbsId() ?: 0L) - sp.getLong(R.string.key_ns_carbs_last_synced_id, 0)
queueCounter.bcrRemaining = (appRepository.getLastBolusCalculatorResultId() ?: 0L) - sp.getLong(R.string.key_ns_bolus_calculator_result_last_synced_id, 0)
queueCounter.ttsRemaining = (appRepository.getLastTempTargetId() ?: 0L) - sp.getLong(R.string.key_ns_temporary_target_last_synced_id, 0)
queueCounter.foodsRemaining = (appRepository.getLastFoodId() ?: 0L) - sp.getLong(R.string.key_ns_food_last_synced_id, 0)
queueCounter.gvsRemaining = (appRepository.getLastGlucoseValueId() ?: 0L) - sp.getLong(R.string.key_ns_glucose_value_last_synced_id, 0)
queueCounter.tesRemaining = (appRepository.getLastTherapyEventId() ?: 0L) - sp.getLong(R.string.key_ns_therapy_event_last_synced_id, 0)
queueCounter.dssRemaining = (appRepository.getLastDeviceStatusId() ?: 0L) - sp.getLong(R.string.key_ns_device_status_last_synced_id, 0)
queueCounter.tbrsRemaining = (appRepository.getLastTemporaryBasalId() ?: 0L) - sp.getLong(R.string.key_ns_temporary_basal_last_synced_id, 0)
queueCounter.ebsRemaining = (appRepository.getLastExtendedBolusId() ?: 0L) - sp.getLong(R.string.key_ns_extended_bolus_last_synced_id, 0)
queueCounter.pssRemaining = (appRepository.getLastProfileSwitchId() ?: 0L) - sp.getLong(R.string.key_ns_profile_switch_last_synced_id, 0)
queueCounter.epssRemaining = (appRepository.getLastEffectiveProfileSwitchId() ?: 0L) - sp.getLong(R.string.key_ns_effective_profile_switch_last_synced_id, 0)
queueCounter.oesRemaining = (appRepository.getLastOfflineEventId() ?: 0L) - sp.getLong(R.string.key_ns_offline_event_last_synced_id, 0)
rxBus.send(EventNSClientUpdateGuiQueue())
processChangedGlucoseValues()
processChangedBoluses()
processChangedCarbs()
processChangedBolusCalculatorResults()
processChangedTemporaryBasals()
processChangedExtendedBoluses()
processChangedProfileSwitches()
processChangedEffectiveProfileSwitches()
processChangedTempTargets()
processChangedFoods()
processChangedTherapyEvents()
processChangedDeviceStatuses()
processChangedOfflineEvents()
processChangedProfileStore()
storeDataForDb.updateNsIds()
}
rxBus.send(EventNSClientUpdateGuiStatus())
}
override fun resetToNextFullSync() {
sp.remove(R.string.key_ns_glucose_value_last_synced_id)
sp.remove(R.string.key_ns_temporary_basal_last_synced_id)
sp.remove(R.string.key_ns_temporary_target_last_synced_id)
sp.remove(R.string.key_ns_extended_bolus_last_synced_id)
sp.remove(R.string.key_ns_food_last_synced_id)
sp.remove(R.string.key_ns_bolus_last_synced_id)
sp.remove(R.string.key_ns_carbs_last_synced_id)
sp.remove(R.string.key_ns_bolus_calculator_result_last_synced_id)
sp.remove(R.string.key_ns_therapy_event_last_synced_id)
sp.remove(R.string.key_ns_profile_switch_last_synced_id)
sp.remove(R.string.key_ns_effective_profile_switch_last_synced_id)
sp.remove(R.string.key_ns_offline_event_last_synced_id)
sp.remove(R.string.key_ns_profile_store_last_synced_timestamp)
val lastDeviceStatusDbId = appRepository.getLastDeviceStatusId()
if (lastDeviceStatusDbId != null) sp.putLong(R.string.key_ns_device_status_last_synced_id, lastDeviceStatusDbId)
else sp.remove(R.string.key_ns_device_status_last_synced_id)
}
fun confirmLastBolusIdIfGreater(lastSynced: Long) {
if (lastSynced > sp.getLong(R.string.key_ns_bolus_last_synced_id, 0)) {
//aapsLogger.debug(LTag.NSCLIENT, "Setting Bolus data sync from $lastSynced")
sp.putLong(R.string.key_ns_bolus_last_synced_id, lastSynced)
}
}
suspend fun processChangedBoluses() {
var cont = true
while (cont) {
if (isPaused) return
val lastDbId = appRepository.getLastBolusId() ?: 0L
var startId = sp.getLong(R.string.key_ns_bolus_last_synced_id, 0)
if (startId > lastDbId) {
aapsLogger.info(LTag.NSCLIENT, "Resetting startId: $startId lastDbId: $lastDbId")
sp.putLong(R.string.key_ns_bolus_last_synced_id, 0)
startId = 0
}
queueCounter.bolusesRemaining = lastDbId - startId
rxBus.send(EventNSClientUpdateGuiQueue())
appRepository.getNextSyncElementBolus(startId).blockingGet()?.let { bolus ->
//aapsLogger.info(LTag.NSCLIENT, "Loading Bolus data Start: $startId ${bolus.first} forID: ${bolus.second.id} ")
when {
// new record with existing NS id => must be coming from NS => ignore
bolus.first.id == bolus.second.id && bolus.first.interfaceIDs.nightscoutId != null ->
aapsLogger.info(LTag.NSCLIENT, "Ignoring Bolus. Loaded from NS: ${bolus.second.id} ")
// only NsId changed, no need to upload
bolus.first.onlyNsIdAdded(bolus.second) ->
aapsLogger.info(LTag.NSCLIENT, "Ignoring Bolus. Only NS id changed: ${bolus.second.id} ")
// without nsId = create new
bolus.first.interfaceIDs.nightscoutId == null ->
cont = activePlugin.activeNsClient?.nsAdd("treatments", DataSyncSelector.PairBolus(bolus.first, bolus.second.id), " $startId/$lastDbId") ?: false
// with nsId = update if it's modified record
bolus.first.interfaceIDs.nightscoutId != null && bolus.first.id != bolus.second.id ->
cont = activePlugin.activeNsClient?.nsUpdate("treatments", DataSyncSelector.PairBolus(bolus.first, bolus.second.id), "$startId/$lastDbId") ?: false
}
confirmLastBolusIdIfGreater(bolus.second.id)
} ?: run {
cont = false
}
}
}
fun confirmLastCarbsIdIfGreater(lastSynced: Long) {
if (lastSynced > sp.getLong(R.string.key_ns_carbs_last_synced_id, 0)) {
//aapsLogger.debug(LTag.NSCLIENT, "Setting Carbs data sync from $lastSynced")
sp.putLong(R.string.key_ns_carbs_last_synced_id, lastSynced)
}
}
suspend fun processChangedCarbs() {
var cont = true
while (cont) {
if (isPaused) return
val lastDbId = appRepository.getLastCarbsId() ?: 0L
var startId = sp.getLong(R.string.key_ns_carbs_last_synced_id, 0)
if (startId > lastDbId) {
aapsLogger.info(LTag.NSCLIENT, "Resetting startId: $startId lastDbId: $lastDbId")
sp.putLong(R.string.key_ns_carbs_last_synced_id, 0)
startId = 0
}
queueCounter.carbsRemaining = lastDbId - startId
rxBus.send(EventNSClientUpdateGuiQueue())
appRepository.getNextSyncElementCarbs(startId).blockingGet()?.let { carb ->
//aapsLogger.info(LTag.NSCLIENT, "Loading Carbs data Start: $startId ${carb.first} forID: ${carb.second.id} ")
when {
// new record with existing NS id => must be coming from NS => ignore
carb.first.id == carb.second.id && carb.first.interfaceIDs.nightscoutId != null ->
aapsLogger.info(LTag.NSCLIENT, "Ignoring Carbs. Loaded from NS: ${carb.second.id} ")
// only NsId changed, no need to upload
carb.first.onlyNsIdAdded(carb.second) ->
aapsLogger.info(LTag.NSCLIENT, "Ignoring Carbs. Only NS id changed ID: ${carb.second.id} ")
// without nsId = create new
carb.first.interfaceIDs.nightscoutId == null ->
cont = activePlugin.activeNsClient?.nsAdd("treatments", DataSyncSelector.PairCarbs(carb.first, carb.second.id), "$startId/$lastDbId") ?: false
// with nsId = update if it's modified record
carb.first.interfaceIDs.nightscoutId != null && carb.first.id != carb.second.id ->
cont = activePlugin.activeNsClient?.nsUpdate("treatments", DataSyncSelector.PairCarbs(carb.first, carb.second.id), "$startId/$lastDbId") ?: false
}
confirmLastCarbsIdIfGreater(carb.second.id)
} ?: run {
cont = false
}
}
}
fun confirmLastBolusCalculatorResultsIdIfGreater(lastSynced: Long) {
if (lastSynced > sp.getLong(R.string.key_ns_bolus_calculator_result_last_synced_id, 0)) {
//aapsLogger.debug(LTag.NSCLIENT, "Setting BolusCalculatorResult data sync from $lastSynced")
sp.putLong(R.string.key_ns_bolus_calculator_result_last_synced_id, lastSynced)
}
}
suspend fun processChangedBolusCalculatorResults() {
var cont = true
while (cont) {
if (isPaused) return
val lastDbId = appRepository.getLastBolusCalculatorResultId() ?: 0L
var startId = sp.getLong(R.string.key_ns_bolus_calculator_result_last_synced_id, 0)
if (startId > lastDbId) {
aapsLogger.info(LTag.NSCLIENT, "Resetting startId: $startId lastDbId: $lastDbId")
sp.putLong(R.string.key_ns_bolus_calculator_result_last_synced_id, 0)
startId = 0
}
queueCounter.bcrRemaining = lastDbId - startId
rxBus.send(EventNSClientUpdateGuiQueue())
appRepository.getNextSyncElementBolusCalculatorResult(startId).blockingGet()?.let { bolusCalculatorResult ->
//aapsLogger.info(LTag.NSCLIENT, "Loading BolusCalculatorResult data Start: $startId ${bolusCalculatorResult.first} forID: ${bolusCalculatorResult.second.id} ")
when {
// new record with existing NS id => must be coming from NS => ignore
bolusCalculatorResult.first.id == bolusCalculatorResult.second.id && bolusCalculatorResult.first.interfaceIDs.nightscoutId != null ->
aapsLogger.info(LTag.NSCLIENT, "Ignoring BolusCalculatorResult. Loaded from NS: ${bolusCalculatorResult.second.id} ")
// only NsId changed, no need to upload
bolusCalculatorResult.first.onlyNsIdAdded(bolusCalculatorResult.second) ->
aapsLogger.info(LTag.NSCLIENT, "Ignoring BolusCalculatorResult. Only NS id changed ID: ${bolusCalculatorResult.second.id} ")
// without nsId = create new
bolusCalculatorResult.first.interfaceIDs.nightscoutId == null ->
cont = activePlugin.activeNsClient?.nsAdd(
"treatments",
DataSyncSelector.PairBolusCalculatorResult(bolusCalculatorResult.first, bolusCalculatorResult.second.id),
"$startId/$lastDbId"
) ?: false
// with nsId = update if it's modified record
bolusCalculatorResult.first.interfaceIDs.nightscoutId != null && bolusCalculatorResult.first.id != bolusCalculatorResult.second.id ->
cont = activePlugin.activeNsClient?.nsUpdate(
"treatments",
DataSyncSelector.PairBolusCalculatorResult(bolusCalculatorResult.first, bolusCalculatorResult.second.id),
"$startId/$lastDbId"
) ?: false
}
confirmLastBolusCalculatorResultsIdIfGreater(bolusCalculatorResult.second.id)
} ?: run {
cont = false
}
}
}
fun confirmLastTempTargetsIdIfGreater(lastSynced: Long) {
if (lastSynced > sp.getLong(R.string.key_ns_temporary_target_last_synced_id, 0)) {
//aapsLogger.debug(LTag.NSCLIENT, "Setting TemporaryTarget data sync from $lastSynced")
sp.putLong(R.string.key_ns_temporary_target_last_synced_id, lastSynced)
}
}
suspend fun processChangedTempTargets() {
var cont = true
while (cont) {
if (isPaused) return
val lastDbId = appRepository.getLastTempTargetId() ?: 0L
var startId = sp.getLong(R.string.key_ns_temporary_target_last_synced_id, 0)
if (startId > lastDbId) {
aapsLogger.info(LTag.NSCLIENT, "Resetting startId: $startId lastDbId: $lastDbId")
sp.putLong(R.string.key_ns_temporary_target_last_synced_id, 0)
startId = 0
}
queueCounter.ttsRemaining = lastDbId - startId
rxBus.send(EventNSClientUpdateGuiQueue())
appRepository.getNextSyncElementTemporaryTarget(startId).blockingGet()?.let { tt ->
//aapsLogger.info(LTag.NSCLIENT, "Loading TemporaryTarget data Start: $startId ${tt.first} forID: ${tt.second.id} ")
when {
// new record with existing NS id => must be coming from NS => ignore
tt.first.id == tt.second.id && tt.first.interfaceIDs.nightscoutId != null ->
aapsLogger.info(LTag.NSCLIENT, "Ignoring TemporaryTarget. Loaded from NS: ${tt.second.id} ")
// only NsId changed, no need to upload
tt.first.onlyNsIdAdded(tt.second) ->
aapsLogger.info(LTag.NSCLIENT, "Ignoring TemporaryTarget. Only NS id changed ID: ${tt.second.id} ")
// without nsId = create new
tt.first.interfaceIDs.nightscoutId == null ->
cont = activePlugin.activeNsClient?.nsAdd("treatments", DataSyncSelector.PairTemporaryTarget(tt.first, tt.second.id), "$startId/$lastDbId") ?: false
// existing with nsId = update
tt.first.interfaceIDs.nightscoutId != null ->
cont = activePlugin.activeNsClient?.nsUpdate("treatments", DataSyncSelector.PairTemporaryTarget(tt.first, tt.second.id), "$startId/$lastDbId") ?: false
}
confirmLastTempTargetsIdIfGreater(tt.second.id)
} ?: run {
cont = false
}
}
}
fun confirmLastFoodIdIfGreater(lastSynced: Long) {
if (lastSynced > sp.getLong(R.string.key_ns_food_last_synced_id, 0)) {
//aapsLogger.debug(LTag.NSCLIENT, "Setting Food data sync from $lastSynced")
sp.putLong(R.string.key_ns_food_last_synced_id, lastSynced)
}
}
suspend fun processChangedFoods() {
var cont = true
while (cont) {
if (isPaused) return
val lastDbId = appRepository.getLastFoodId() ?: 0L
var startId = sp.getLong(R.string.key_ns_food_last_synced_id, 0)
if (startId > lastDbId) {
aapsLogger.info(LTag.NSCLIENT, "Resetting startId: $startId lastDbId: $lastDbId")
sp.putLong(R.string.key_ns_food_last_synced_id, 0)
startId = 0
}
queueCounter.foodsRemaining = lastDbId - startId
rxBus.send(EventNSClientUpdateGuiQueue())
appRepository.getNextSyncElementFood(startId).blockingGet()?.let { food ->
//aapsLogger.info(LTag.NSCLIENT, "Loading Food data Start: $startId ${food.first} forID: ${food.second.id} ")
when {
// new record with existing NS id => must be coming from NS => ignore
food.first.id == food.second.id && food.first.interfaceIDs.nightscoutId != null ->
aapsLogger.info(LTag.NSCLIENT, "Ignoring Food. Loaded from NS: ${food.second.id} ")
// only NsId changed, no need to upload
food.first.onlyNsIdAdded(food.second) ->
aapsLogger.info(LTag.NSCLIENT, "Ignoring Food. Only NS id changed ID: ${food.second.id} ")
// without nsId = create new
food.first.interfaceIDs.nightscoutId == null ->
cont = activePlugin.activeNsClient?.nsAdd("food", DataSyncSelector.PairFood(food.first, food.second.id), "$startId/$lastDbId") ?: false
// with nsId = update
food.first.interfaceIDs.nightscoutId != null ->
cont = activePlugin.activeNsClient?.nsUpdate("food", DataSyncSelector.PairFood(food.first, food.second.id), "$startId/$lastDbId") ?: false
}
confirmLastFoodIdIfGreater(food.second.id)
} ?: run {
cont = false
}
}
}
fun confirmLastGlucoseValueIdIfGreater(lastSynced: Long) {
if (lastSynced > sp.getLong(R.string.key_ns_glucose_value_last_synced_id, 0)) {
//aapsLogger.debug(LTag.NSCLIENT, "Setting GlucoseValue data sync from $lastSynced")
sp.putLong(R.string.key_ns_glucose_value_last_synced_id, lastSynced)
}
}
suspend fun processChangedGlucoseValues() {
var cont = true
while (cont) {
if (isPaused) return
val lastDbId = appRepository.getLastGlucoseValueId() ?: 0L
var startId = sp.getLong(R.string.key_ns_glucose_value_last_synced_id, 0)
if (startId > lastDbId) {
aapsLogger.info(LTag.NSCLIENT, "Resetting startId: $startId lastDbId: $lastDbId")
sp.putLong(R.string.key_ns_glucose_value_last_synced_id, 0)
startId = 0
}
queueCounter.gvsRemaining = lastDbId - startId
rxBus.send(EventNSClientUpdateGuiQueue())
appRepository.getNextSyncElementGlucoseValue(startId).blockingGet()?.let { gv ->
//aapsLogger.info(LTag.NSCLIENT, "Loading GlucoseValue data Start: $startId ${gv.first} forID: ${gv.second.id} ")
if (activePlugin.activeBgSource.shouldUploadToNs(gv.first)) {
when {
// new record with existing NS id => must be coming from NS => ignore
gv.first.id == gv.second.id && gv.first.interfaceIDs.nightscoutId != null ->
aapsLogger.info(LTag.NSCLIENT, "Ignoring GlucoseValue. Loaded from NS: ${gv.second.id} ")
// only NsId changed, no need to upload
gv.first.onlyNsIdAdded(gv.second) ->
aapsLogger.info(LTag.NSCLIENT, "Ignoring GlucoseValue. Only NS id changed ID: ${gv.second.id} ")
// without nsId = create new
gv.first.interfaceIDs.nightscoutId == null ->
cont = activePlugin.activeNsClient?.nsAdd("entries", DataSyncSelector.PairGlucoseValue(gv.first, gv.second.id), "$startId/$lastDbId") ?: false
// with nsId = update
else -> // gv.first.interfaceIDs.nightscoutId != null
cont = activePlugin.activeNsClient?.nsUpdate("entries", DataSyncSelector.PairGlucoseValue(gv.first, gv.second.id), "$startId/$lastDbId") ?: false
}
}
confirmLastGlucoseValueIdIfGreater(gv.second.id)
} ?: run {
cont = false
}
}
}
fun confirmLastTherapyEventIdIfGreater(lastSynced: Long) {
if (lastSynced > sp.getLong(R.string.key_ns_therapy_event_last_synced_id, 0)) {
//aapsLogger.debug(LTag.NSCLIENT, "Setting TherapyEvents data sync from $lastSynced")
sp.putLong(R.string.key_ns_therapy_event_last_synced_id, lastSynced)
}
}
suspend fun processChangedTherapyEvents() {
var cont = true
while (cont) {
if (isPaused) return
val lastDbId = appRepository.getLastTherapyEventId() ?: 0L
var startId = sp.getLong(R.string.key_ns_therapy_event_last_synced_id, 0)
if (startId > lastDbId) {
aapsLogger.info(LTag.NSCLIENT, "Resetting startId: $startId lastDbId: $lastDbId")
sp.putLong(R.string.key_ns_therapy_event_last_synced_id, 0)
startId = 0
}
queueCounter.tesRemaining = lastDbId - startId
rxBus.send(EventNSClientUpdateGuiQueue())
appRepository.getNextSyncElementTherapyEvent(startId).blockingGet()?.let { te ->
//aapsLogger.info(LTag.NSCLIENT, "Loading TherapyEvents data Start: $startId ${te.first} forID: ${te.second.id} ")
when {
// new record with existing NS id => must be coming from NS => ignore
te.first.id == te.second.id && te.first.interfaceIDs.nightscoutId != null ->
aapsLogger.info(LTag.NSCLIENT, "Ignoring TherapyEvent. Loaded from NS: ${te.second.id} ")
// only NsId changed, no need to upload
te.first.onlyNsIdAdded(te.second) ->
aapsLogger.info(LTag.NSCLIENT, "Ignoring TherapyEvent. Only NS id changed ID: ${te.second.id} ")
// without nsId = create new
te.first.interfaceIDs.nightscoutId == null ->
cont = activePlugin.activeNsClient?.nsAdd("treatments", DataSyncSelector.PairTherapyEvent(te.first, te.second.id), "$startId/$lastDbId") ?: false
// nsId = update
te.first.interfaceIDs.nightscoutId != null ->
cont = activePlugin.activeNsClient?.nsUpdate("treatments", DataSyncSelector.PairTherapyEvent(te.first, te.second.id), "$startId/$lastDbId") ?: false
}
confirmLastTherapyEventIdIfGreater(te.second.id)
} ?: run {
cont = false
}
}
}
fun confirmLastDeviceStatusIdIfGreater(lastSynced: Long) {
if (lastSynced > sp.getLong(R.string.key_ns_device_status_last_synced_id, 0)) {
//aapsLogger.debug(LTag.NSCLIENT, "Setting DeviceStatus data sync from $lastSynced")
sp.putLong(R.string.key_ns_device_status_last_synced_id, lastSynced)
}
}
suspend fun processChangedDeviceStatuses() {
if (isPaused) return
val lastDbId = appRepository.getLastDeviceStatusId() ?: 0L
var startId = sp.getLong(R.string.key_ns_device_status_last_synced_id, 0)
if (startId > lastDbId) {
aapsLogger.info(LTag.NSCLIENT, "Resetting startId: $startId lastDbId: $lastDbId")
sp.putLong(R.string.key_ns_device_status_last_synced_id, 0)
startId = 0
}
queueCounter.dssRemaining = lastDbId - startId
rxBus.send(EventNSClientUpdateGuiQueue())
appRepository.getNextSyncElementDeviceStatus(startId).blockingGet()?.let { deviceStatus ->
//aapsLogger.info(LTag.NSCLIENT, "Loading DeviceStatus data Start: $startId $deviceStatus")
// without nsId = create new
if (deviceStatus.interfaceIDs.nightscoutId == null) {
if (activePlugin.activeNsClient?.nsAdd("devicestatus", DataSyncSelector.PairDeviceStatus(deviceStatus, lastDbId), "$startId/$lastDbId") == true)
confirmLastDeviceStatusIdIfGreater(lastDbId)
}
// with nsId = ignore
}
queueCounter.dssRemaining = 0
}
fun confirmLastTemporaryBasalIdIfGreater(lastSynced: Long) {
if (lastSynced > sp.getLong(R.string.key_ns_temporary_basal_last_synced_id, 0)) {
//aapsLogger.debug(LTag.NSCLIENT, "Setting TemporaryBasal data sync from $lastSynced")
sp.putLong(R.string.key_ns_temporary_basal_last_synced_id, lastSynced)
}
}
suspend fun processChangedTemporaryBasals() {
var cont = true
while (cont) {
if (isPaused) return
val lastDbId = appRepository.getLastTemporaryBasalId() ?: 0L
var startId = sp.getLong(R.string.key_ns_temporary_basal_last_synced_id, 0)
if (startId > lastDbId) {
aapsLogger.info(LTag.NSCLIENT, "Resetting startId: $startId lastDbId: $lastDbId")
sp.putLong(R.string.key_ns_temporary_basal_last_synced_id, 0)
startId = 0
}
queueCounter.tbrsRemaining = lastDbId - startId
rxBus.send(EventNSClientUpdateGuiQueue())
appRepository.getNextSyncElementTemporaryBasal(startId).blockingGet()?.let { tb ->
//aapsLogger.info(LTag.NSCLIENT, "Loading TemporaryBasal data Start: $startId ${tb.first} forID: ${tb.second.id} ")
when {
// new record with existing NS id => must be coming from NS => ignore
tb.first.id == tb.second.id && tb.first.interfaceIDs.nightscoutId != null ->
aapsLogger.info(LTag.NSCLIENT, "Ignoring TemporaryBasal. Loaded from NS: ${tb.second.id} ")
// only NsId changed, no need to upload
tb.first.onlyNsIdAdded(tb.second) ->
aapsLogger.info(LTag.NSCLIENT, "Ignoring TemporaryBasal. Only NS id changed ID: ${tb.second.id} ")
// without nsId = create new
tb.first.interfaceIDs.nightscoutId == null ->
cont = activePlugin.activeNsClient?.nsAdd("treatments", DataSyncSelector.PairTemporaryBasal(tb.first, tb.second.id), "$startId/$lastDbId") ?: false
// with nsId = update
tb.first.interfaceIDs.nightscoutId != null ->
cont = activePlugin.activeNsClient?.nsUpdate("treatments", DataSyncSelector.PairTemporaryBasal(tb.first, tb.second.id), "$startId/$lastDbId") ?: false
}
confirmLastTemporaryBasalIdIfGreater(tb.second.id)
} ?: run {
cont = false
}
}
}
fun confirmLastExtendedBolusIdIfGreater(lastSynced: Long) {
if (lastSynced > sp.getLong(R.string.key_ns_extended_bolus_last_synced_id, 0)) {
//aapsLogger.debug(LTag.NSCLIENT, "Setting ExtendedBolus data sync from $lastSynced")
sp.putLong(R.string.key_ns_extended_bolus_last_synced_id, lastSynced)
}
}
suspend fun processChangedExtendedBoluses() {
var cont = true
while (cont) {
if (isPaused) return
val lastDbId = appRepository.getLastExtendedBolusId() ?: 0L
var startId = sp.getLong(R.string.key_ns_extended_bolus_last_synced_id, 0)
if (startId > lastDbId) {
aapsLogger.info(LTag.NSCLIENT, "Resetting startId: $startId lastDbId: $lastDbId")
sp.putLong(R.string.key_ns_extended_bolus_last_synced_id, 0)
startId = 0
}
queueCounter.ebsRemaining = lastDbId - startId
rxBus.send(EventNSClientUpdateGuiQueue())
appRepository.getNextSyncElementExtendedBolus(startId).blockingGet()?.let { eb ->
//aapsLogger.info(LTag.NSCLIENT, "Loading ExtendedBolus data Start: $startId ${eb.first} forID: ${eb.second.id} ")
val profile = profileFunction.getProfile(eb.first.timestamp)
if (profile != null) {
when {
// new record with existing NS id => must be coming from NS => ignore
eb.first.id == eb.second.id && eb.first.interfaceIDs.nightscoutId != null ->
aapsLogger.info(LTag.NSCLIENT, "Ignoring ExtendedBolus. Loaded from NS: ${eb.second.id} ")
// only NsId changed, no need to upload
eb.first.onlyNsIdAdded(eb.second) ->
aapsLogger.info(LTag.NSCLIENT, "Ignoring ExtendedBolus. Only NS id changed ID: ${eb.second.id} ")
// without nsId = create new
eb.first.interfaceIDs.nightscoutId == null ->
cont = activePlugin.activeNsClient?.nsAdd("treatments", DataSyncSelector.PairExtendedBolus(eb.first, eb.second.id), "$startId/$lastDbId") ?: false
// with nsId = update
eb.first.interfaceIDs.nightscoutId != null ->
cont = activePlugin.activeNsClient?.nsUpdate("treatments", DataSyncSelector.PairExtendedBolus(eb.first, eb.second.id), "$startId/$lastDbId") ?: false
}
} else aapsLogger.info(LTag.NSCLIENT, "Ignoring ExtendedBolus. No profile: ${eb.second.id} ")
confirmLastExtendedBolusIdIfGreater(eb.second.id)
} ?: run {
cont = false
}
}
}
fun confirmLastProfileSwitchIdIfGreater(lastSynced: Long) {
if (lastSynced > sp.getLong(R.string.key_ns_profile_switch_last_synced_id, 0)) {
//aapsLogger.debug(LTag.NSCLIENT, "Setting ProfileSwitch data sync from $lastSynced")
sp.putLong(R.string.key_ns_profile_switch_last_synced_id, lastSynced)
}
}
suspend fun processChangedProfileSwitches() {
var cont = true
while (cont) {
if (isPaused) return
val lastDbId = appRepository.getLastProfileSwitchId() ?: 0L
var startId = sp.getLong(R.string.key_ns_profile_switch_last_synced_id, 0)
if (startId > lastDbId) {
aapsLogger.info(LTag.NSCLIENT, "Resetting startId: $startId lastDbId: $lastDbId")
sp.putLong(R.string.key_ns_profile_switch_last_synced_id, 0)
startId = 0
}
queueCounter.pssRemaining = lastDbId - startId
rxBus.send(EventNSClientUpdateGuiQueue())
appRepository.getNextSyncElementProfileSwitch(startId).blockingGet()?.let { ps ->
//aapsLogger.info(LTag.NSCLIENT, "Loading ProfileSwitch data Start: $startId ${ps.first} forID: ${ps.second.id} ")
when {
// new record with existing NS id => must be coming from NS => ignore
ps.first.id == ps.second.id && ps.first.interfaceIDs.nightscoutId != null ->
aapsLogger.info(LTag.NSCLIENT, "Ignoring ProfileSwitch. Loaded from NS: ${ps.second.id} ")
// only NsId changed, no need to upload
ps.first.onlyNsIdAdded(ps.second) ->
aapsLogger.info(LTag.NSCLIENT, "Ignoring ProfileSwitch. Only NS id changed ID: ${ps.second.id} ")
// without nsId = create new
ps.first.interfaceIDs.nightscoutId == null ->
cont = activePlugin.activeNsClient?.nsAdd("treatments", DataSyncSelector.PairProfileSwitch(ps.first, ps.second.id), "$startId/$lastDbId") ?: false
// with nsId = update
ps.first.interfaceIDs.nightscoutId != null ->
cont = activePlugin.activeNsClient?.nsUpdate("treatments", DataSyncSelector.PairProfileSwitch(ps.first, ps.second.id), "$startId/$lastDbId") ?: false
}
confirmLastProfileSwitchIdIfGreater(ps.second.id)
} ?: run {
cont = false
}
}
}
fun confirmLastEffectiveProfileSwitchIdIfGreater(lastSynced: Long) {
if (lastSynced > sp.getLong(R.string.key_ns_effective_profile_switch_last_synced_id, 0)) {
//aapsLogger.debug(LTag.NSCLIENT, "Setting EffectiveProfileSwitch data sync from $lastSynced")
sp.putLong(R.string.key_ns_effective_profile_switch_last_synced_id, lastSynced)
}
}
suspend fun processChangedEffectiveProfileSwitches() {
var cont = true
while (cont) {
if (isPaused) return
val lastDbId = appRepository.getLastEffectiveProfileSwitchId() ?: 0L
var startId = sp.getLong(R.string.key_ns_effective_profile_switch_last_synced_id, 0)
if (startId > lastDbId) {
aapsLogger.info(LTag.NSCLIENT, "Resetting startId: $startId lastDbId: $lastDbId")
sp.putLong(R.string.key_ns_effective_profile_switch_last_synced_id, 0)
startId = 0
}
queueCounter.epssRemaining = lastDbId - startId
rxBus.send(EventNSClientUpdateGuiQueue())
appRepository.getNextSyncElementEffectiveProfileSwitch(startId).blockingGet()?.let { ps ->
//aapsLogger.info(LTag.NSCLIENT, "Loading EffectiveProfileSwitch data Start: $startId ${ps.first} forID: ${ps.second.id} ")
when {
// new record with existing NS id => must be coming from NS => ignore
ps.first.id == ps.second.id && ps.first.interfaceIDs.nightscoutId != null ->
aapsLogger.info(LTag.NSCLIENT, "Ignoring EffectiveProfileSwitch. Loaded from NS: ${ps.second.id} ")
// only NsId changed, no need to upload
ps.first.onlyNsIdAdded(ps.second) ->
aapsLogger.info(LTag.NSCLIENT, "Ignoring EffectiveProfileSwitch. Only NS id changed ID: ${ps.second.id} ")
// without nsId = create new
ps.first.interfaceIDs.nightscoutId == null ->
cont = activePlugin.activeNsClient?.nsAdd("treatments", DataSyncSelector.PairEffectiveProfileSwitch(ps.first, ps.second.id), "$startId/$lastDbId") ?: false
// with nsId = update
ps.first.interfaceIDs.nightscoutId != null ->
cont = activePlugin.activeNsClient?.nsUpdate("treatments", DataSyncSelector.PairEffectiveProfileSwitch(ps.first, ps.second.id), "$startId/$lastDbId") ?: false
}
confirmLastEffectiveProfileSwitchIdIfGreater(ps.second.id)
} ?: run {
cont = false
}
}
}
fun confirmLastOfflineEventIdIfGreater(lastSynced: Long) {
if (lastSynced > sp.getLong(R.string.key_ns_offline_event_last_synced_id, 0)) {
//aapsLogger.debug(LTag.NSCLIENT, "Setting OfflineEvent data sync from $lastSynced")
sp.putLong(R.string.key_ns_offline_event_last_synced_id, lastSynced)
}
}
suspend fun processChangedOfflineEvents() {
var cont = true
while (cont) {
if (isPaused) return
val lastDbId = appRepository.getLastOfflineEventId() ?: 0L
var startId = sp.getLong(R.string.key_ns_offline_event_last_synced_id, 0)
if (startId > lastDbId) {
aapsLogger.info(LTag.NSCLIENT, "Resetting startId: $startId lastDbId: $lastDbId")
sp.putLong(R.string.key_ns_offline_event_last_synced_id, 0)
startId = 0
}
queueCounter.oesRemaining = lastDbId - startId
rxBus.send(EventNSClientUpdateGuiQueue())
appRepository.getNextSyncElementOfflineEvent(startId).blockingGet()?.let { oe ->
//aapsLogger.info(LTag.NSCLIENT, "Loading OfflineEvent data Start: $startId ${oe.first} forID: ${oe.second.id} ")
when {
// new record with existing NS id => must be coming from NS => ignore
oe.first.id == oe.second.id && oe.first.interfaceIDs.nightscoutId != null ->
aapsLogger.info(LTag.NSCLIENT, "Ignoring OfflineEvent. Loaded from NS: ${oe.second.id} ")
// only NsId changed, no need to upload
oe.first.onlyNsIdAdded(oe.second) ->
aapsLogger.info(LTag.NSCLIENT, "Ignoring OfflineEvent. Only NS id changed ID: ${oe.second.id} ")
// without nsId = create new
oe.first.interfaceIDs.nightscoutId == null ->
cont = activePlugin.activeNsClient?.nsAdd("treatments", DataSyncSelector.PairOfflineEvent(oe.first, oe.second.id), "$startId/$lastDbId") ?: false
// existing with nsId = update
oe.first.interfaceIDs.nightscoutId != null ->
cont = activePlugin.activeNsClient?.nsUpdate("treatments", DataSyncSelector.PairOfflineEvent(oe.first, oe.second.id), "$startId/$lastDbId") ?: false
}
confirmLastOfflineEventIdIfGreater(oe.second.id)
} ?: run {
cont = false
}
}
}
fun confirmLastProfileStore(lastSynced: Long) {
sp.putLong(R.string.key_ns_profile_store_last_synced_timestamp, lastSynced)
}
suspend fun processChangedProfileStore() {
if (isPaused) return
val lastSync = sp.getLong(R.string.key_ns_profile_store_last_synced_timestamp, 0)
val lastChange = sp.getLong(info.nightscout.core.utils.R.string.key_local_profile_last_change, 0)
if (lastChange == 0L) return
if (lastChange > lastSync) {
if (activePlugin.activeProfileSource.profile?.allProfilesValid != true) return
val profileStore = activePlugin.activeProfileSource.profile
val profileJson = profileStore?.data ?: return
// add for v3
if (JsonHelper.safeGetLongAllowNull(profileJson, "date") == null)
profileJson.put("date", profileStore.getStartDate())
val now = dateUtil.now()
if (activePlugin.activeNsClient?.nsAdd("profile", DataSyncSelector.PairProfileStore(profileJson, now), "") == true)
confirmLastProfileStore(now)
}
}
}

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