NSCv3: process GlucoseValue

This commit is contained in:
Milos Kozak 2023-01-01 17:18:09 +01:00
parent cc605efc93
commit 823c26aa64
36 changed files with 417 additions and 160 deletions

View file

@ -14,6 +14,7 @@ import info.nightscout.sdk.localmodel.treatment.CreateUpdateResponse
import info.nightscout.sdk.localmodel.treatment.NSTreatment
import info.nightscout.sdk.mapper.toLocal
import info.nightscout.sdk.mapper.toNSFood
import info.nightscout.sdk.mapper.toRemoteEntry
import info.nightscout.sdk.mapper.toRemoteFood
import info.nightscout.sdk.mapper.toRemoteTreatment
import info.nightscout.sdk.mapper.toSgv
@ -94,13 +95,6 @@ class NSAndroidClientImpl(
api.statusSimple().result!!.toLocal().also { lastStatus = it }
}
// TODO: return something better than a String
// TODO: parameters like count?
// TODO: updated after timestamp
override suspend fun getEntries(): String = callWrapper(dispatcher) {
api.getEntries().toString()
}
override suspend fun getLastModified(): LastModified = callWrapper(dispatcher) {
val response = api.lastModified()
@ -125,9 +119,9 @@ class NSAndroidClientImpl(
override suspend fun getSgvsModifiedSince(from: Long, limit: Long): NSAndroidClient.ReadResponse<List<NSSgvV3>> = callWrapper(dispatcher) {
val response = api.getSgvsModifiedSince(from, limit)
val eTagString = response.headers()["ETag"]
val eTag = eTagString?.substring(3, eTagString.length - 1)?.toLong() ?: throw UnsuccessfullNightscoutException()
if (response.isSuccessful) {
val eTagString = response.headers()["ETag"]
val eTag = eTagString?.substring(3, eTagString.length - 1)?.toLong() ?: throw UnsuccessfullNightscoutException()
return@callWrapper NSAndroidClient.ReadResponse(eTag, response.body()?.result?.map(RemoteEntry::toSgv).toNotNull())
} else {
throw UnsuccessfullNightscoutException()
@ -144,6 +138,55 @@ class NSAndroidClientImpl(
}
}
override suspend fun createSvg(nsSgvV3: NSSgvV3): CreateUpdateResponse = callWrapper(dispatcher) {
val remoteEntry = nsSgvV3.toRemoteEntry()
remoteEntry.app = "AAPS"
val response = api.createEntry(remoteEntry)
if (response.isSuccessful) {
if (response.code() == 200) {
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
)
} else throw UnsuccessfullNightscoutException()
} else {
throw UnsuccessfullNightscoutException()
}
}
override suspend fun updateSvg(nsSgvV3: NSSgvV3): CreateUpdateResponse = callWrapper(dispatcher) {
// following cannot be updated
nsSgvV3.utcOffset = null
nsSgvV3.date = null
val remoteEntry = nsSgvV3.toRemoteEntry()
val identifier = remoteEntry.identifier ?: throw InvalidFormatNightscoutException()
val response = api.updateEntry(remoteEntry, identifier)
if (response.isSuccessful) {
return@callWrapper CreateUpdateResponse(
response = response.code(),
identifier = null,
isDeduplication = false,
deduplicatedIdentifier = null,
lastModified = null
)
} else {
throw UnsuccessfullNightscoutException()
}
}
override suspend fun getTreatmentsNewerThan(createdAt: String, limit: Long): List<NSTreatment> = callWrapper(dispatcher) {
val response = api.getTreatmentsNewerThan(createdAt, limit)
@ -157,10 +200,10 @@ class NSAndroidClientImpl(
override suspend fun getTreatmentsModifiedSince(from: Long, limit: Long): NSAndroidClient.ReadResponse<List<NSTreatment>> = callWrapper(dispatcher) {
val response = api.getTreatmentsModifiedSince(from, limit)
val eTagString = response.headers()["ETag"]
val eTag = eTagString?.substring(3, eTagString.length - 1)?.toLong()
?: throw UnsuccessfullNightscoutException()
if (response.isSuccessful) {
val eTagString = response.headers()["ETag"]
val eTag = eTagString?.substring(3, eTagString.length - 1)?.toLong()
?: throw UnsuccessfullNightscoutException()
return@callWrapper NSAndroidClient.ReadResponse(eTag, response.body()?.result?.map(RemoteTreatment::toTreatment).toNotNull())
} else {
throw UnsuccessfullNightscoutException()
@ -183,13 +226,24 @@ class NSAndroidClientImpl(
remoteTreatment.app = "AAPS"
val response = api.createTreatment(remoteTreatment)
if (response.isSuccessful) {
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
)
if (response.code() == 200) {
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
)
} else throw UnknownResponseNightscoutException()
} else {
throw UnsuccessfullNightscoutException()
}
@ -197,15 +251,19 @@ class NSAndroidClientImpl(
override suspend fun updateTreatment(nsTreatment: NSTreatment): CreateUpdateResponse = callWrapper(dispatcher) {
// following cannot be updated
nsTreatment.utcOffset = null
nsTreatment.date = null
val remoteTreatment = nsTreatment.toRemoteTreatment() ?: throw InvalidFormatNightscoutException()
val response = api.updateTreatment(remoteTreatment)
val identifier = remoteTreatment.identifier ?: throw InvalidFormatNightscoutException()
val response = api.updateTreatment(remoteTreatment, identifier)
if (response.isSuccessful) {
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 = null,
isDeduplication = false,
deduplicatedIdentifier = null,
lastModified = null
)
} else {
throw UnsuccessfullNightscoutException()
@ -227,11 +285,11 @@ class NSAndroidClientImpl(
val response = api.getFoodsModifiedSince(from, limit)
val eTagString = response.headers()["ETag"]
val eTag = eTagString?.substring(3, eTagString.length - 1)?.toLong() ?: throw UnsuccessfullNightscoutException()
val eTag = eTagString?.substring(3, eTagString.length - 1)?.toLong() ?: throw UnsuccessfulNightscoutException()
if (response.isSuccessful) {
return@callWrapper NSAndroidClient.ReadResponse(eTag, response.body()?.result?.map(RemoteFood::toNSFood).toNotNull())
} else {
throw UnsuccessfullNightscoutException()
throw UnsuccessfulNightscoutException()
}
}
*/
@ -241,13 +299,23 @@ class NSAndroidClientImpl(
remoteFood.app = "AAPS"
val response = api.createFood(remoteFood)
if (response.isSuccessful) {
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
)
if (response.code() == 200) {
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
)
} else throw UnsuccessfullNightscoutException()
} else {
throw UnsuccessfullNightscoutException()
}
@ -260,10 +328,10 @@ class NSAndroidClientImpl(
if (response.isSuccessful) {
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 = null,
isDeduplication = false,
deduplicatedIdentifier = null,
lastModified = null
)
} else {
throw UnsuccessfullNightscoutException()

View file

@ -18,12 +18,12 @@ interface NSAndroidClient {
val lastStatus: Status?
suspend fun getVersion(): String
suspend fun getStatus(): Status
suspend fun getEntries(): String
suspend fun getLastModified(): LastModified
suspend fun getSgvs(): List<NSSgvV3>
suspend fun getSgvsModifiedSince(from: Long, limit: Long): ReadResponse<List<NSSgvV3>>
suspend fun getSgvsNewerThan(from: Long, limit: Long): List<NSSgvV3>
suspend fun createSvg(nsSgvV3: NSSgvV3): CreateUpdateResponse
suspend fun updateSvg(nsSgvV3: NSSgvV3): CreateUpdateResponse
suspend fun getTreatmentsNewerThan(createdAt: String, limit: Long): List<NSTreatment>
suspend fun getTreatmentsModifiedSince(from: Long, limit: Long): ReadResponse<List<NSTreatment>>
suspend fun getDeviceStatusModifiedSince(from: Long): List<RemoteDeviceStatus>

View file

@ -10,8 +10,13 @@ enum class Direction(val nsName: String, val txtIcon: String) {
SINGLE_UP("SingleUp", "\u2191"), // ↑
DOUBLE_UP("DoubleUp", "\u21c8"), // ⇈
TRIPLE_UP("TripleUp", "\u290A"), // ⤊
NONE("NONE", ""), //
INVALID("", "-"), //
NONE("NONE", ""),
INVALID("", "-");
companion object {
fun fromString(text: String?) = Direction.values().firstOrNull { it.nsName == text } ?: NONE
}
}
/*

View file

@ -1,13 +0,0 @@
package info.nightscout.sdk.localmodel.entry
interface Entry {
val date: Long
val device: String?
val identifier: String
val srvModified: Long
val srvCreated: Long
val utcOffset: Long?
val subject: String?
var isReadOnly: Boolean // TODO: nullability?
val isValid: Boolean
}

View file

@ -1,20 +1,19 @@
package info.nightscout.sdk.localmodel.entry
data class NSSgvV3(
override val date: Long,
override val device: String?,
override val identifier: String,
override val srvModified: Long,
override val srvCreated: Long,
override val utcOffset: Long?,
override val subject: String?,
override var isReadOnly: Boolean,
override val isValid: Boolean,
val sgv: Double, // TODO: might be Double?
var date: Long?,
val device: String? = null, // sourceSensor
val identifier: String?,
val srvModified: Long? = null,
val srvCreated: Long? = null,
var utcOffset: Long?,
val subject: String? = null,
var isReadOnly: Boolean = false,
val isValid: Boolean,
val sgv: Double,
val units: NsUnits,
val direction: Direction,
val noise: Int?, // TODO: enum?
val direction: Direction?,
val noise: Double?,
val filtered: Double?, // number in doc (I found decimal values in API v1
val unfiltered: Double?, // number in doc (I found decimal values in API v1
// TODO: add SVG fields
) : Entry
val unfiltered: Double? // number in doc (I found decimal values in API v1
)

View file

@ -3,13 +3,13 @@ package info.nightscout.sdk.localmodel.treatment
import info.nightscout.sdk.localmodel.entry.NsUnits
data class NSBolus(
override val date: Long,
override var date: Long?,
override val device: String?= null,
override val identifier: String?,
override val units: NsUnits?= null,
override val srvModified: Long? = null,
override val srvCreated: Long? = null,
override val utcOffset: Long,
override var utcOffset: Long?,
override val subject: String? = null,
override var isReadOnly: Boolean = false,
override val isValid: Boolean,

View file

@ -3,13 +3,13 @@ package info.nightscout.sdk.localmodel.treatment
import info.nightscout.sdk.localmodel.entry.NsUnits
data class NSBolusWizard(
override val date: Long,
override var date: Long?,
override val device: String? = null,
override val identifier: String? = null,
override val units: NsUnits?,
override val srvModified: Long? = null,
override val srvCreated: Long? = null,
override val utcOffset: Long,
override var utcOffset: Long?,
override val subject: String? = null,
override var isReadOnly: Boolean = false,
override val isValid: Boolean,

View file

@ -3,13 +3,13 @@ package info.nightscout.sdk.localmodel.treatment
import info.nightscout.sdk.localmodel.entry.NsUnits
data class NSCarbs(
override val date: Long,
override var date: Long?,
override val device: String? = null,
override val identifier: String?,
override val units: NsUnits? = null,
override val srvModified: Long? = null,
override val srvCreated: Long? = null,
override val utcOffset: Long,
override var utcOffset: Long?,
override val subject: String? = null,
override var isReadOnly: Boolean = false,
override val isValid: Boolean,

View file

@ -4,14 +4,14 @@ import info.nightscout.sdk.localmodel.entry.NsUnits
import org.json.JSONObject
data class NSEffectiveProfileSwitch(
override val date: Long,
override var date: Long?,
override val device: String? = null,
override val identifier: String? = null,
override val units: NsUnits? = null,
override val srvModified: Long? = null,
override val srvCreated: Long? = null,
override val utcOffset: Long,
override val subject: String? = null ,
override var utcOffset: Long?,
override val subject: String? = null,
override var isReadOnly: Boolean = false,
override val isValid: Boolean,
override val eventType: EventType,

View file

@ -3,13 +3,13 @@ package info.nightscout.sdk.localmodel.treatment
import info.nightscout.sdk.localmodel.entry.NsUnits
data class NSExtendedBolus(
override val date: Long,
override var date: Long?,
override val device: String? = null,
override val identifier: String?,
override val units: NsUnits? = null,
override val srvModified: Long? = null,
override val srvCreated: Long? = null,
override val utcOffset: Long,
override var utcOffset: Long?,
override val subject: String? = null,
override var isReadOnly: Boolean = false,
override val isValid: Boolean,

View file

@ -3,13 +3,13 @@ package info.nightscout.sdk.localmodel.treatment
import info.nightscout.sdk.localmodel.entry.NsUnits
data class NSOfflineEvent(
override val date: Long,
override var date: Long?,
override val device: String? = null,
override val identifier: String?,
override val units: NsUnits? = null,
override val srvModified: Long? = null,
override val srvCreated: Long? = null,
override val utcOffset: Long,
override var utcOffset: Long?,
override val subject: String? = null,
override var isReadOnly: Boolean = false,
override val isValid: Boolean,

View file

@ -4,13 +4,13 @@ import info.nightscout.sdk.localmodel.entry.NsUnits
import org.json.JSONObject
data class NSProfileSwitch(
override val date: Long,
override var date: Long?,
override val device: String? = null,
override val identifier: String?,
override val units: NsUnits? = null,
override val srvModified: Long? = null,
override val srvCreated: Long? = null,
override val utcOffset: Long,
override var utcOffset: Long?,
override val subject: String? = null,
override var isReadOnly: Boolean = false,
override val isValid: Boolean,

View file

@ -3,13 +3,13 @@ package info.nightscout.sdk.localmodel.treatment
import info.nightscout.sdk.localmodel.entry.NsUnits
data class NSTemporaryBasal(
override val date: Long,
override var date: Long?,
override val device: String? = null,
override val identifier: String?,
override val units: NsUnits? = null,
override val srvModified: Long? = null,
override val srvCreated: Long? = null,
override val utcOffset: Long,
override var utcOffset: Long?,
override val subject: String? = null,
override var isReadOnly: Boolean = false,
override val isValid: Boolean,

View file

@ -3,13 +3,13 @@ package info.nightscout.sdk.localmodel.treatment
import info.nightscout.sdk.localmodel.entry.NsUnits
data class NSTemporaryTarget(
override val date: Long,
override var date: Long?,
override val device: String? = null,
override val identifier: String?,
override val units: NsUnits?,
override val srvModified: Long? = null,
override val srvCreated: Long? = null,
override val utcOffset: Long,
override var utcOffset: Long?,
override val subject: String? = null,
override var isReadOnly: Boolean = false,
override val isValid: Boolean = true,

View file

@ -4,13 +4,13 @@ import com.google.gson.annotations.SerializedName
import info.nightscout.sdk.localmodel.entry.NsUnits
data class NSTherapyEvent(
override val date: Long,
override var date: Long?,
override val device: String? = null,
override val identifier: String?,
override val units: NsUnits?,
override val srvModified: Long? = null,
override val srvCreated: Long? = null,
override val utcOffset: Long,
override var utcOffset: Long?,
override val subject: String? = null,
override var isReadOnly: Boolean = false,
override val isValid: Boolean,

View file

@ -3,14 +3,14 @@ package info.nightscout.sdk.localmodel.treatment
import info.nightscout.sdk.localmodel.entry.NsUnits
interface NSTreatment {
val date: Long
var date: Long?
val device: String?
val identifier: String?
val units: NsUnits?
val eventType: EventType
val srvModified: Long?
val srvCreated: Long?
val utcOffset: Long
var utcOffset: Long?
val subject: String?
var isReadOnly: Boolean
val isValid: Boolean

View file

@ -5,19 +5,21 @@ import info.nightscout.sdk.localmodel.entry.NSSgvV3
import info.nightscout.sdk.localmodel.entry.NsUnits
import info.nightscout.sdk.remotemodel.RemoteEntry
@JvmSynthetic
fun NSSgvV3.convertToRemoteAndBack(): NSSgvV3? =
toRemoteEntry().toSgv()
internal fun RemoteEntry.toSgv(): NSSgvV3? {
this.sgv ?: return null
if (this.type != "sgv") return null
return NSSgvV3(
date = this.date,
date = this.date ?: 0L,
device = this.device,
identifier = this.identifier,
srvModified = this.srvModified,
srvCreated = this.srvCreated,
utcOffset = this.utcOffset ?: 0,
utcOffset = this.utcOffset,
subject = this.subject,
direction = this.direction.toDirection(),
sgv = this.sgv,
@ -26,9 +28,30 @@ internal fun RemoteEntry.toSgv(): NSSgvV3? {
noise = this.noise, // TODO: to Enum?
filtered = this.filtered,
unfiltered = this.unfiltered,
units = NsUnits.fromString(this.units)
units = NsUnits.fromString(this.units),
)
}
private fun String?.toDirection(): Direction =
Direction.values().firstOrNull { it.nsName == this } ?: Direction.INVALID
Direction.values().firstOrNull { it.nsName == this } ?: Direction.INVALID
internal fun NSSgvV3.toRemoteEntry(): RemoteEntry =
RemoteEntry(
type = "sgv",
date = this.date,
device = this.device,
identifier = this.identifier,
srvModified = this.srvModified,
srvCreated = this.srvCreated,
utcOffset = this.utcOffset,
subject = this.subject,
direction = this.direction?.nsName,
sgv = this.sgv,
isReadOnly = this.isReadOnly,
isValid = this.isValid,
noise = this.noise,
filtered = this.filtered,
unfiltered = this.unfiltered,
units = this.units.value
)

View file

@ -1,6 +1,5 @@
package info.nightscout.sdk.networking
import com.google.gson.JsonElement
import info.nightscout.sdk.remotemodel.LastModified
import info.nightscout.sdk.remotemodel.NSResponse
import info.nightscout.sdk.remotemodel.RemoteCreateUpdateResponse
@ -12,8 +11,8 @@ import info.nightscout.sdk.remotemodel.RemoteTreatment
import retrofit2.Response
import retrofit2.http.Body
import retrofit2.http.GET
import retrofit2.http.PATCH
import retrofit2.http.POST
import retrofit2.http.PUT
import retrofit2.http.Path
import retrofit2.http.Query
@ -33,9 +32,6 @@ internal interface NightscoutRemoteService {
@GET("v3/status")
suspend fun statusSimple(): NSResponse<RemoteStatusResponse>
@GET("v3/entries")
suspend fun getEntries(): List<JsonElement>
@GET("v3/lastModified")
suspend fun lastModified(): Response<NSResponse<LastModified>>
@ -48,6 +44,12 @@ internal interface NightscoutRemoteService {
@GET("v3/entries/history/{from}")
suspend fun getSgvsModifiedSince(@Path("from") from: Long, @Query("limit") limit: Long): Response<NSResponse<List<RemoteEntry>>>
@POST("v3/entries")
suspend fun createEntry(@Body remoteEntry: RemoteEntry): Response<NSResponse<RemoteCreateUpdateResponse>>
@PATCH("v3/entries/{identifier}")
suspend fun updateEntry(@Body remoteEntry: RemoteEntry, @Path("identifier") identifier: String): Response<NSResponse<RemoteCreateUpdateResponse>>
@GET("v3/treatments")
suspend fun getTreatmentsNewerThan(@Query(value = "created_at\$gt", encoded = true) createdAt: String, @Query("limit") limit: Long): Response<NSResponse<List<RemoteTreatment>>>
@ -60,8 +62,8 @@ internal interface NightscoutRemoteService {
@POST("v3/treatments")
suspend fun createTreatment(@Body remoteTreatment: RemoteTreatment): Response<NSResponse<RemoteCreateUpdateResponse>>
@PUT("v3/treatments")
suspend fun updateTreatment(@Body remoteTreatment: RemoteTreatment): Response<NSResponse<RemoteCreateUpdateResponse>>
@PATCH("v3/treatments/{identifier}")
suspend fun updateTreatment(@Body remoteTreatment: RemoteTreatment, @Path("identifier") identifier: String): Response<NSResponse<RemoteCreateUpdateResponse>>
@GET("v3/food")
suspend fun getFoods(@Query("limit") limit: Long): Response<NSResponse<List<RemoteFood>>>
@ -72,7 +74,7 @@ internal interface NightscoutRemoteService {
@POST("v3/food")
suspend fun createFood(@Body remoteFood: RemoteFood): Response<NSResponse<RemoteCreateUpdateResponse>>
@PUT("v3/food")
@PATCH("v3/food")
suspend fun updateFood(@Body remoteFood: RemoteFood): Response<NSResponse<RemoteCreateUpdateResponse>>
}

View file

@ -1,7 +1,6 @@
package info.nightscout.sdk.remotemodel
import com.google.gson.annotations.SerializedName
import info.nightscout.sdk.localmodel.treatment.EventType
/*
* Depending on the type, different other fields are present.
@ -15,23 +14,23 @@ import info.nightscout.sdk.localmodel.treatment.EventType
internal data class RemoteEntry(
@SerializedName("type") val type: String, // sgv, mbg, cal, etc; Bolus type NORMAL, SMB, PRIMING
@SerializedName("sgv") val sgv: Double?, // number The glucose reading. (only available for sgv types)
@SerializedName("dateString") val dateString: String,
@SerializedName("date") val date: Long, // required ? TODO: date and dateString are redundant - are both needed? how to handle inconsistency then? Only expose one to clients?
@SerializedName("dateString") val dateString: String? = null,
@SerializedName("date") var date: Long?, // required ? TODO: date and dateString are redundant - are both needed? how to handle inconsistency then? Only expose one to clients?
@SerializedName("device") val device: String?, // The device from which the data originated (including serial number of the device, if it is relevant and safe).
@SerializedName("direction") val direction: String?, // TODO: what implicit convention for the directions exists?
@SerializedName("identifier") val identifier: String,
@SerializedName("srvModified") val srvModified: Long,
@SerializedName("srvCreated") val srvCreated: Long,
@SerializedName("identifier") val identifier: String?,
@SerializedName("srvModified") val srvModified: Long?,
@SerializedName("srvCreated") val srvCreated: Long?,
// Philoul Others fields below found in API v3 doc
// @SerializedName("app") val app : String, // TODO required ? Application or system in which the record was entered by human or device for the first time.
@SerializedName("utcOffset") val utcOffset: Long?, // Local UTC offset (timezone) of the event in minutes. This field can be set either directly by the client (in the incoming document) or it is
@SerializedName("app") var app : String? = null,
@SerializedName("utcOffset") var utcOffset: Long?, // Local UTC offset (timezone) of the event in minutes. This field can be set either directly by the client (in the incoming document) or it is
// automatically parsed from the date field.
@SerializedName("subject") val subject: String?, // Name of the security subject (within Nightscout scope) which has created the document. This field is automatically set by the server from the passed token or JWT.
@SerializedName("modifiedBy") val modifiedBy: String?, // Name of the security subject (within Nightscout scope) which has patched or deleted the document for the last time. This field is automatically set by the server.
@SerializedName("modifiedBy") val modifiedBy: String? = null, // Name of the security subject (within Nightscout scope) which has patched or deleted the document for the last time. This field is automatically set by the server.
@SerializedName("isValid") val isValid: Boolean?, // A flag set by the server only for deleted documents. This field appears only within history operation and for documents which were deleted by API v3 (and they always have a false value)
@SerializedName("isReadOnly") val isReadOnly: Boolean?, // A flag set by client that locks the document from any changes. Every document marked with isReadOnly=true is forever immutable and cannot even be deleted.
@SerializedName("noise") val noise: Int?, // 0 or 1 found in the export, I don't know if other values possible ?
@SerializedName("noise") val noise: Double?, // 0 or 1 found in the export, I don't know if other values possible ?
@SerializedName("filtered") val filtered: Double?, // The raw filtered value directly from CGM transmitter. (only available for sgv types)
@SerializedName("unfiltered") val unfiltered: Double?, // The raw unfiltered value directly from CGM transmitter. (only available for sgv types)
@SerializedName("units") val units: String?, // The units for the glucose value, mg/dl or mmol/l. It is strongly recommended to fill in this field.
@SerializedName("units") val units: String? // The units for the glucose value, mg/dl or mmol/l. It is strongly recommended to fill in this field.
)

View file

@ -16,11 +16,11 @@ import org.joda.time.format.ISODateTimeFormat
* */
internal data class RemoteTreatment(
@SerializedName("identifier") val identifier: String?, // string Main addressing, required field that identifies document in the collection. The client should not create the identifier, the server automatically assigns it when the document is inserted.
@SerializedName("date") val date: Long? = null, // integer($int64) or string required timestamp when the record or event occurred, you can choose from three input formats Unix epoch in milliseconds (1525383610088), Unix epoch in seconds (1525383610), ISO 8601 with optional timezone ('2018-05-03T21:40:10.088Z' or '2018-05-03T23:40:10.088+02:00')
@SerializedName("date") var date: Long? = null, // integer($int64) or string required timestamp when the record or event occurred, you can choose from three input formats Unix epoch in milliseconds (1525383610088), Unix epoch in seconds (1525383610), ISO 8601 with optional timezone ('2018-05-03T21:40:10.088Z' or '2018-05-03T23:40:10.088+02:00')
@SerializedName("mills") val mills: Long? = null, // integer($int64) or string required timestamp when the record or event occurred, you can choose from three input formats Unix
@SerializedName("timestamp") val timestamp: Long? = null, // integer($int64) or string required timestamp when the record or event occurred, you can choose from three input formats Unix epoch in milliseconds (1525383610088), Unix epoch in seconds (1525383610), ISO 8601 with optional timezone ('2018-05-03T21:40:10.088Z' or '2018-05-03T23:40:10.088+02:00')
@SerializedName("created_at") val created_at: String? = null, // integer($int64) or string timestamp on previous version of api, in my examples, a lot of treatments don't have date, only created_at, some of them with string others with long...
@SerializedName("utcOffset") val utcOffset: Long? = null, // integer Local UTC offset (timezone) of the event in minutes. This field can be set either directly by the client (in the incoming document) or it is automatically parsed from the date field.
@SerializedName("utcOffset") var utcOffset: Long? = null, // integer Local UTC offset (timezone) of the event in minutes. This field can be set either directly by the client (in the incoming document) or it is automatically parsed from the date field.
@SerializedName("app") var app : String? = null, // Application or system in which the record was entered by human or device for the first time.
@SerializedName("device") val device: String? = null, // string The device from which the data originated (including serial number of the device, if it is relevant and safe).
@SerializedName("srvCreated") val srvCreated: Long? = null, // integer($int64) example: 1525383610088 The server's timestamp of document insertion into the database (Unix epoch in ms). This field appears only for documents which were inserted by API v3.

View file

@ -32,6 +32,7 @@ import info.nightscout.shared.utils.DateUtil
import info.nightscout.shared.utils.T
import org.json.JSONArray
import org.json.JSONObject
import java.security.InvalidParameterException
import javax.inject.Inject
import javax.inject.Singleton
@ -113,11 +114,11 @@ class NSClientSourcePlugin @Inject constructor(
private fun toGv(sgv: NSSgvV3): TransactionGlucoseValue {
return TransactionGlucoseValue(
timestamp = sgv.date,
timestamp = sgv.date ?: throw InvalidParameterException(),
value = sgv.sgv,
noise = sgv.noise?.toDouble(),
raw = sgv.filtered,
trendArrow = GlucoseValue.TrendArrow.fromString(sgv.direction.nsName),
trendArrow = GlucoseValue.TrendArrow.fromString(sgv.direction?.nsName),
nightscoutId = sgv.identifier,
sourceSensor = GlucoseValue.SourceSensor.fromString(sgv.device),
isValid = sgv.isValid

View file

@ -42,6 +42,7 @@ import info.nightscout.plugins.sync.nsclientV3.extensions.toNSExtendedBolus
import info.nightscout.plugins.sync.nsclientV3.extensions.toNSFood
import info.nightscout.plugins.sync.nsclientV3.extensions.toNSOfflineEvent
import info.nightscout.plugins.sync.nsclientV3.extensions.toNSProfileSwitch
import info.nightscout.plugins.sync.nsclientV3.extensions.toNSSvgV3
import info.nightscout.plugins.sync.nsclientV3.extensions.toNSTemporaryBasal
import info.nightscout.plugins.sync.nsclientV3.extensions.toNSTemporaryTarget
import info.nightscout.plugins.sync.nsclientV3.extensions.toNSTherapyEvent
@ -310,7 +311,7 @@ class NSClientV3Plugin @Inject constructor(
override fun resetToFullSync() {
firstLoadContinueTimestamp = LastModified(LastModified.Collections())
lastLoadedSrvModified = LastModified(LastModified.Collections())
storeLastFetched()
storeLastLoadedSrvModified()
}
override fun dbAdd(collection: String, dataPair: DataSyncSelector.DataPair, progress: String) {
@ -325,6 +326,58 @@ class NSClientV3Plugin @Inject constructor(
private val gson: Gson = GsonBuilder().create()
private fun dbOperation(collection: String, dataPair: DataSyncSelector.DataPair, progress: String, operation: Operation) {
if (collection == "entries") {
val call = when (operation) {
Operation.CREATE -> nsAndroidClient?.let { return@let it::createSvg }
Operation.UPDATE -> nsAndroidClient?.let { return@let it::updateSvg }
}
when (dataPair) {
is DataSyncSelector.PairGlucoseValue -> dataPair.value.toNSSvgV3()
else -> null
}?.let { data ->
runBlocking {
try {
val id = if (dataPair.value is TraceableDBEntry) (dataPair.value as TraceableDBEntry).interfaceIDs.nightscoutId else ""
rxBus.send(
EventNSClientNewLog(
when (operation) {
Operation.CREATE -> "ADD $collection"
Operation.UPDATE -> "UPDATE $collection"
},
when (operation) {
Operation.CREATE -> "Sent ${dataPair.javaClass.simpleName} ${gson.toJson(data)} $progress"
Operation.UPDATE -> "Sent ${dataPair.javaClass.simpleName} $id ${gson.toJson(data)} $progress"
}
)
)
call?.let { it(data) }?.let { result ->
when (result.response) {
200 -> rxBus.send(EventNSClientNewLog("UPDATED", "OK ${dataPair.value.javaClass.simpleName}"))
201 -> rxBus.send(EventNSClientNewLog("ADDED", "OK ${dataPair.value.javaClass.simpleName} ${result.identifier}"))
else -> {
rxBus.send(EventNSClientNewLog("ERROR", "${dataPair.value.javaClass.simpleName} "))
return@runBlocking
}
}
when (dataPair) {
is DataSyncSelector.PairGlucoseValue -> {
if (result.response == 201) { // created
dataPair.value.interfaceIDs.nightscoutId = result.identifier
storeDataForDb.nsIdGlucoseValues.add(dataPair.value)
storeDataForDb.scheduleNsIdUpdate()
}
dataSyncSelector.confirmLastGlucoseValueIdIfGreater(dataPair.id)
dataSyncSelector.processChangedGlucoseValuesCompat()
}
}
}
} catch (e: Exception) {
aapsLogger.error(LTag.NSCLIENT, "Upload exception", e)
}
}
}
}
if (collection == "food") {
val call = when (operation) {
Operation.CREATE -> nsAndroidClient?.let { return@let it::createFood }
@ -350,6 +403,15 @@ class NSClientV3Plugin @Inject constructor(
)
)
call?.let { it(data) }?.let { result ->
when (result.response) {
200 -> rxBus.send(EventNSClientNewLog("UPDATED", "OK ${dataPair.value.javaClass.simpleName}"))
201 -> rxBus.send(EventNSClientNewLog("ADDED", "OK ${dataPair.value.javaClass.simpleName} ${result.identifier}"))
else -> {
rxBus.send(EventNSClientNewLog("ERROR", "${dataPair.value.javaClass.simpleName} "))
return@runBlocking
}
}
when (dataPair) {
is DataSyncSelector.PairFood -> {
if (result.response == 201) { // created
@ -358,6 +420,7 @@ class NSClientV3Plugin @Inject constructor(
storeDataForDb.scheduleNsIdUpdate()
}
dataSyncSelector.confirmLastFoodIdIfGreater(dataPair.id)
dataSyncSelector.processChangedFoodsCompat()
}
}
}
@ -377,13 +440,13 @@ class NSClientV3Plugin @Inject constructor(
is DataSyncSelector.PairCarbs -> dataPair.value.toNSCarbs()
is DataSyncSelector.PairBolusCalculatorResult -> dataPair.value.toNSBolusWizard()
is DataSyncSelector.PairTemporaryTarget -> dataPair.value.toNSTemporaryTarget()
// is DataSyncSelector.PairGlucoseValue -> dataPair.value.toJson(false, dateUtil)
is DataSyncSelector.PairTherapyEvent -> dataPair.value.toNSTherapyEvent()
is DataSyncSelector.PairTemporaryBasal -> {
val profile = profileFunction.getProfile(dataPair.value.timestamp)
if (profile == null) {
dataSyncSelector.confirmLastTemporaryBasalIdIfGreater(dataPair.id)
dataSyncSelector.processChangedTemporaryBasalsCompat()
return
}
dataPair.value.toNSTemporaryBasal(profile)
@ -392,6 +455,7 @@ class NSClientV3Plugin @Inject constructor(
val profile = profileFunction.getProfile(dataPair.value.timestamp)
if (profile == null) {
dataSyncSelector.confirmLastExtendedBolusIdIfGreater(dataPair.id)
dataSyncSelector.processChangedExtendedBolusesCompat()
return
}
dataPair.value.toNSExtendedBolus(profile)
@ -417,60 +481,76 @@ class NSClientV3Plugin @Inject constructor(
)
)
call?.let { it(data) }?.let { result ->
when (result.response) {
200 -> rxBus.send(EventNSClientNewLog("UPDATED", "OK ${dataPair.value.javaClass.simpleName}"))
201 -> rxBus.send(EventNSClientNewLog("ADDED", "OK ${dataPair.value.javaClass.simpleName} ${result.identifier}"))
else -> {
rxBus.send(EventNSClientNewLog("ERROR", "${dataPair.value.javaClass.simpleName} "))
return@runBlocking
}
}
when (dataPair) {
is DataSyncSelector.PairBolus -> {
is DataSyncSelector.PairBolus -> {
if (result.response == 201) { // created
dataPair.value.interfaceIDs.nightscoutId = result.identifier
storeDataForDb.nsIdBoluses.add(dataPair.value)
storeDataForDb.scheduleNsIdUpdate()
}
dataSyncSelector.confirmLastBolusIdIfGreater(dataPair.id)
dataSyncSelector.processChangedBolusesCompat()
}
is DataSyncSelector.PairCarbs -> {
is DataSyncSelector.PairCarbs -> {
if (result.response == 201) { // created
dataPair.value.interfaceIDs.nightscoutId = result.identifier
storeDataForDb.nsIdCarbs.add(dataPair.value)
storeDataForDb.scheduleNsIdUpdate()
}
dataSyncSelector.confirmLastCarbsIdIfGreater(dataPair.id)
dataSyncSelector.processChangedCarbsCompat()
}
is DataSyncSelector.PairBolusCalculatorResult -> {
is DataSyncSelector.PairBolusCalculatorResult -> {
if (result.response == 201) { // created
dataPair.value.interfaceIDs.nightscoutId = result.identifier
storeDataForDb.nsIdBolusCalculatorResults.add(dataPair.value)
storeDataForDb.scheduleNsIdUpdate()
}
dataSyncSelector.confirmLastBolusCalculatorResultsIdIfGreater(dataPair.id)
dataSyncSelector.processChangedBolusCalculatorResultsCompat()
}
is DataSyncSelector.PairTemporaryTarget -> {
is DataSyncSelector.PairTemporaryTarget -> {
if (result.response == 201) { // created
dataPair.value.interfaceIDs.nightscoutId = result.identifier
storeDataForDb.nsIdTemporaryTargets.add(dataPair.value)
storeDataForDb.scheduleNsIdUpdate()
}
dataSyncSelector.confirmLastTempTargetsIdIfGreater(dataPair.id)
dataSyncSelector.processChangedTempTargetsCompat()
}
// is DataSyncSelector.PairGlucoseValue -> dataPair.value.toJson(false, dateUtil)
is DataSyncSelector.PairTherapyEvent -> {
is DataSyncSelector.PairTherapyEvent -> {
if (result.response == 201) { // created
dataPair.value.interfaceIDs.nightscoutId = result.identifier
storeDataForDb.nsIdTherapyEvents.add(dataPair.value)
storeDataForDb.scheduleNsIdUpdate()
}
dataSyncSelector.confirmLastTherapyEventIdIfGreater(dataPair.id)
dataSyncSelector.processChangedTherapyEventsCompat()
}
is DataSyncSelector.PairTemporaryBasal -> {
is DataSyncSelector.PairTemporaryBasal -> {
if (result.response == 201) { // created
dataPair.value.interfaceIDs.nightscoutId = result.identifier
storeDataForDb.nsIdTemporaryBasals.add(dataPair.value)
storeDataForDb.scheduleNsIdUpdate()
}
dataSyncSelector.confirmLastTemporaryBasalIdIfGreater(dataPair.id)
dataSyncSelector.processChangedTemporaryBasalsCompat()
}
is DataSyncSelector.PairExtendedBolus -> {
if (result.response == 201) { // created
dataPair.value.interfaceIDs.nightscoutId = result.identifier
@ -478,6 +558,7 @@ class NSClientV3Plugin @Inject constructor(
storeDataForDb.scheduleNsIdUpdate()
}
dataSyncSelector.confirmLastExtendedBolusIdIfGreater(dataPair.id)
dataSyncSelector.processChangedExtendedBolusesCompat()
}
is DataSyncSelector.PairProfileSwitch -> {
@ -487,6 +568,7 @@ class NSClientV3Plugin @Inject constructor(
storeDataForDb.scheduleNsIdUpdate()
}
dataSyncSelector.confirmLastProfileSwitchIdIfGreater(dataPair.id)
dataSyncSelector.processChangedProfileSwitchesCompat()
}
is DataSyncSelector.PairEffectiveProfileSwitch -> {
@ -496,15 +578,17 @@ class NSClientV3Plugin @Inject constructor(
storeDataForDb.scheduleNsIdUpdate()
}
dataSyncSelector.confirmLastEffectiveProfileSwitchIdIfGreater(dataPair.id)
dataSyncSelector.processChangedEffectiveProfileSwitchesCompat()
}
is DataSyncSelector.PairOfflineEvent -> {
is DataSyncSelector.PairOfflineEvent -> {
if (result.response == 201) { // created
dataPair.value.interfaceIDs.nightscoutId = result.identifier
storeDataForDb.nsIdOfflineEvents.add(dataPair.value)
storeDataForDb.scheduleNsIdUpdate()
}
dataSyncSelector.confirmLastOfflineEventIdIfGreater(dataPair.id)
dataSyncSelector.processChangedOfflineEventsCompat()
}
}
}
@ -516,14 +600,10 @@ class NSClientV3Plugin @Inject constructor(
}
}
fun storeLastFetched() {
fun storeLastLoadedSrvModified() {
sp.putString(R.string.key_ns_client_v3_last_modified, Json.encodeToString(LastModified.serializer(), lastLoadedSrvModified))
}
fun test() {
executeLoop()
}
fun scheduleNewExecution() {
var toTime = lastLoadedSrvModified.collections.entries + T.mins(6).plus(T.secs(0)).msecs()
if (toTime < dateUtil.now()) toTime = dateUtil.now() + T.mins(1).plus(T.secs(0)).msecs()

View file

@ -4,12 +4,13 @@ import info.nightscout.database.entities.Bolus
import info.nightscout.database.entities.embedments.InterfaceIDs
import info.nightscout.sdk.localmodel.treatment.EventType
import info.nightscout.sdk.localmodel.treatment.NSBolus
import java.security.InvalidParameterException
fun NSBolus.toBolus(): Bolus =
Bolus(
isValid = isValid,
timestamp = date,
utcOffset = utcOffset,
timestamp = date ?: throw InvalidParameterException(),
utcOffset = utcOffset ?: 0L,
amount = insulin,
type = type.toBolusType(),
notes = notes,

View file

@ -4,12 +4,13 @@ import info.nightscout.database.entities.Carbs
import info.nightscout.database.entities.embedments.InterfaceIDs
import info.nightscout.sdk.localmodel.treatment.EventType
import info.nightscout.sdk.localmodel.treatment.NSCarbs
import java.security.InvalidParameterException
fun NSCarbs.toCarbs(): Carbs =
Carbs(
isValid = isValid,
timestamp = date,
utcOffset = utcOffset,
timestamp = date ?: throw InvalidParameterException(),
utcOffset = utcOffset ?: 0L,
amount = carbs,
notes = notes,
duration = duration ?: 0L,

View file

@ -8,6 +8,7 @@ import info.nightscout.plugins.sync.nsclient.extensions.fromConstant
import info.nightscout.sdk.localmodel.treatment.EventType
import info.nightscout.sdk.localmodel.treatment.NSEffectiveProfileSwitch
import info.nightscout.shared.utils.DateUtil
import java.security.InvalidParameterException
fun NSEffectiveProfileSwitch.toEffectiveProfileSwitch(dateUtil: DateUtil): EffectiveProfileSwitch? {
val pureProfile = pureProfileFromJson(profileJson, dateUtil) ?: return null
@ -15,8 +16,8 @@ fun NSEffectiveProfileSwitch.toEffectiveProfileSwitch(dateUtil: DateUtil): Effec
return EffectiveProfileSwitch(
isValid = isValid,
timestamp = date,
utcOffset = utcOffset,
timestamp = date ?: throw InvalidParameterException(),
utcOffset = utcOffset ?: 0L,
basalBlocks = profileSealed.basalBlocks,
isfBlocks = profileSealed.isfBlocks,
icBlocks = profileSealed.icBlocks,

View file

@ -7,12 +7,13 @@ import info.nightscout.interfaces.profile.Profile
import info.nightscout.sdk.localmodel.treatment.EventType
import info.nightscout.sdk.localmodel.treatment.NSExtendedBolus
import info.nightscout.sdk.localmodel.treatment.NSTreatment
import java.security.InvalidParameterException
fun NSExtendedBolus.toExtendedBolus(): ExtendedBolus =
ExtendedBolus(
isValid = isValid,
timestamp = date,
utcOffset = utcOffset,
timestamp = date ?: throw InvalidParameterException(),
utcOffset = utcOffset ?: 0L,
amount = enteredinsulin,
duration = duration,
isEmulatingTempBasal = isEmulatingTempBasal ?: false,

View file

@ -0,0 +1,51 @@
package info.nightscout.plugins.sync.nsclientV3.extensions
import info.nightscout.database.entities.GlucoseValue
import info.nightscout.database.transactions.TransactionGlucoseValue
import info.nightscout.sdk.localmodel.entry.Direction
import info.nightscout.sdk.localmodel.entry.NSSgvV3
import info.nightscout.sdk.localmodel.entry.NsUnits
import java.security.InvalidParameterException
// copy of NSClientSourcePlugin for testing
fun NSSgvV3.toTransactionGlucoseValue(): TransactionGlucoseValue {
return TransactionGlucoseValue(
timestamp = date ?: throw InvalidParameterException(),
value = sgv,
noise = noise?.toDouble(),
raw = filtered,
trendArrow = GlucoseValue.TrendArrow.fromString(direction?.nsName),
nightscoutId = identifier,
sourceSensor = GlucoseValue.SourceSensor.fromString(device),
isValid = isValid
)
}
// for testing
fun TransactionGlucoseValue.toGlucoseValue() =
GlucoseValue(
timestamp = timestamp,
raw = raw,
value = value,
noise = noise,
trendArrow = trendArrow,
sourceSensor = sourceSensor,
isValid = isValid
).also { gv ->
gv.interfaceIDs.nightscoutId = nightscoutId
}
fun GlucoseValue.toNSSvgV3(): NSSgvV3 =
NSSgvV3(
isValid = isValid,
date = timestamp,
utcOffset = utcOffset,
filtered = raw,
unfiltered = 0.0,
sgv = value,
units = NsUnits.MG_DL,
direction = Direction.fromString(trendArrow.text),
noise = noise,
device = sourceSensor.text,
identifier = interfaceIDs.nightscoutId
)

View file

@ -4,12 +4,13 @@ import info.nightscout.database.entities.OfflineEvent
import info.nightscout.database.entities.embedments.InterfaceIDs
import info.nightscout.sdk.localmodel.treatment.EventType
import info.nightscout.sdk.localmodel.treatment.NSOfflineEvent
import java.security.InvalidParameterException
fun NSOfflineEvent.toOfflineEvent(): OfflineEvent =
OfflineEvent(
isValid = isValid,
timestamp = date,
utcOffset = utcOffset,
timestamp = date ?: throw InvalidParameterException(),
utcOffset = utcOffset ?: 0L,
duration = duration,
reason = reason.toReason(),
interfaceIDs_backing = InterfaceIDs(nightscoutId = identifier, pumpId = pumpId, pumpType = InterfaceIDs.PumpType.fromString(pumpType), pumpSerial = pumpSerial, endId = endId)

View file

@ -11,6 +11,7 @@ import info.nightscout.sdk.localmodel.treatment.EventType
import info.nightscout.sdk.localmodel.treatment.NSProfileSwitch
import info.nightscout.shared.utils.DateUtil
import info.nightscout.shared.utils.T
import java.security.InvalidParameterException
fun NSProfileSwitch.toProfileSwitch(activePlugin: ActivePlugin, dateUtil: DateUtil): ProfileSwitch? {
val pureProfile =
@ -21,8 +22,8 @@ fun NSProfileSwitch.toProfileSwitch(activePlugin: ActivePlugin, dateUtil: DateUt
return ProfileSwitch(
isValid = isValid,
timestamp = date,
utcOffset = utcOffset,
timestamp = date ?: throw InvalidParameterException(),
utcOffset = utcOffset ?: 0L,
basalBlocks = profileSealed.basalBlocks,
isfBlocks = profileSealed.isfBlocks,
icBlocks = profileSealed.icBlocks,

View file

@ -6,12 +6,13 @@ import info.nightscout.database.entities.embedments.InterfaceIDs
import info.nightscout.interfaces.profile.Profile
import info.nightscout.sdk.localmodel.treatment.EventType
import info.nightscout.sdk.localmodel.treatment.NSTemporaryBasal
import java.security.InvalidParameterException
fun NSTemporaryBasal.toTemporaryBasal(): TemporaryBasal =
TemporaryBasal(
isValid = isValid,
timestamp = date,
utcOffset = utcOffset,
timestamp = date ?: throw InvalidParameterException(),
utcOffset = utcOffset ?: 0L,
type = type.toType(),
rate = rate,
isAbsolute = isAbsolute,

View file

@ -5,12 +5,13 @@ import info.nightscout.database.entities.embedments.InterfaceIDs
import info.nightscout.sdk.localmodel.entry.NsUnits
import info.nightscout.sdk.localmodel.treatment.EventType
import info.nightscout.sdk.localmodel.treatment.NSTemporaryTarget
import java.security.InvalidParameterException
fun NSTemporaryTarget.toTemporaryTarget(): TemporaryTarget =
TemporaryTarget(
isValid = isValid,
timestamp = date,
utcOffset = utcOffset,
timestamp = date ?: throw InvalidParameterException(),
utcOffset = utcOffset ?: 0L,
reason = reason.toReason(),
highTarget = targetTop.asMgdl(),
lowTarget = targetBottom.asMgdl(),

View file

@ -5,12 +5,13 @@ import info.nightscout.database.entities.embedments.InterfaceIDs
import info.nightscout.sdk.localmodel.entry.NsUnits
import info.nightscout.sdk.localmodel.treatment.EventType
import info.nightscout.sdk.localmodel.treatment.NSTherapyEvent
import java.security.InvalidParameterException
fun NSTherapyEvent.toTherapyEvent(): TherapyEvent =
TherapyEvent(
isValid = isValid,
timestamp = date,
utcOffset = utcOffset,
timestamp = date ?: throw InvalidParameterException(),
utcOffset = utcOffset ?: 0L,
glucoseUnit = units.toUnits(),
type = eventType.toType(),
note = notes,

View file

@ -56,7 +56,7 @@ class LoadBgWorker(
response = nsAndroidClient.getSgvsModifiedSince(lastLoaded, 500)
sgvs = response.values
nsClientV3Plugin.lastLoadedSrvModified.collections.entries = response.lastServerModified
nsClientV3Plugin.storeLastFetched()
nsClientV3Plugin.storeLastLoadedSrvModified()
}
aapsLogger.debug("SGVS: $sgvs")
if (sgvs.isNotEmpty()) {
@ -74,7 +74,7 @@ class LoadBgWorker(
// End first load
if (isFirstLoad) {
nsClientV3Plugin.lastLoadedSrvModified.collections.entries = lastLoaded
nsClientV3Plugin.storeLastFetched()
nsClientV3Plugin.storeLastLoadedSrvModified()
}
rxBus.send(EventNSClientNewLog("RCV END", "No SGVs from ${dateUtil
.dateAndTimeAndSecondsString(lastLoaded)}"))
@ -95,7 +95,7 @@ class LoadBgWorker(
// End first load
if (isFirstLoad) {
nsClientV3Plugin.lastLoadedSrvModified.collections.entries = lastLoaded
nsClientV3Plugin.storeLastFetched()
nsClientV3Plugin.storeLastLoadedSrvModified()
}
rxBus.send(EventNSClientNewLog("RCV END", "No new SGVs from ${dateUtil
.dateAndTimeAndSecondsString(lastLoaded)}"))

View file

@ -54,7 +54,7 @@ class LoadTreatmentsWorker(
response = nsAndroidClient.getTreatmentsModifiedSince(lastLoaded, 500)
treatments = response.values
nsClientV3Plugin.lastLoadedSrvModified.collections.treatments = response.lastServerModified
nsClientV3Plugin.storeLastFetched()
nsClientV3Plugin.storeLastLoadedSrvModified()
}
aapsLogger.debug("TREATMENTS: $treatments")
if (treatments.isNotEmpty()) {
@ -74,7 +74,7 @@ class LoadTreatmentsWorker(
// End first load
if (isFirstLoad) {
nsClientV3Plugin.lastLoadedSrvModified.collections.treatments = lastLoaded
nsClientV3Plugin.storeLastFetched()
nsClientV3Plugin.storeLastLoadedSrvModified()
}
rxBus.send(EventNSClientNewLog("RCV END", "No TRs from ${dateUtil.dateAndTimeAndSecondsString(lastLoaded)}"))
storeDataForDb.storeTreatmentsToDb()
@ -93,7 +93,7 @@ class LoadTreatmentsWorker(
// End first load
if (isFirstLoad) {
nsClientV3Plugin.lastLoadedSrvModified.collections.treatments = lastLoaded
nsClientV3Plugin.storeLastFetched()
nsClientV3Plugin.storeLastLoadedSrvModified()
}
rxBus.send(EventNSClientNewLog("RCV END", "No new TRs from ${dateUtil.dateAndTimeAndSecondsString(lastLoaded)}"))
storeDataForDb.storeTreatmentsToDb()

View file

@ -66,7 +66,8 @@ class ProcessTreatmentsWorker(
val ret = Result.success()
for (treatment in treatments.values) {
aapsLogger.debug(LTag.DATABASE, "Received NS treatment: $treatment")
if (treatment.date > latestDateInReceivedData) latestDateInReceivedData = treatment.date
val date = treatment.date ?: continue
if (date > latestDateInReceivedData) latestDateInReceivedData = date
when (treatment) {
is NSBolus ->

View file

@ -0,0 +1,32 @@
package info.nightscout.plugins.sync.nsclientV3.extensions
import info.nightscout.androidaps.TestBaseWithProfile
import info.nightscout.database.entities.GlucoseValue
import info.nightscout.database.entities.embedments.InterfaceIDs
import info.nightscout.sdk.mapper.convertToRemoteAndBack
import org.junit.jupiter.api.Assertions
import org.junit.jupiter.api.Test
@Suppress("SpellCheckingInspection")
internal class GlucoseValueExtensionKtTest : TestBaseWithProfile() {
@Test
fun toGlucoseValue() {
val glucoseValue = GlucoseValue(
timestamp = 10000,
isValid = true,
raw = 101.0,
value = 99.0,
trendArrow = GlucoseValue.TrendArrow.DOUBLE_UP,
noise = 1.0,
sourceSensor = GlucoseValue.SourceSensor.DEXCOM_G4_WIXEL,
interfaceIDs_backing = InterfaceIDs(
nightscoutId = "nightscoutId"
)
)
var glucoseValue2 = glucoseValue.toNSSvgV3().convertToRemoteAndBack()?.toTransactionGlucoseValue()?.toGlucoseValue()
Assertions.assertTrue(glucoseValue.contentEqualsTo(glucoseValue2!!))
Assertions.assertTrue(glucoseValue.interfaceIdsEqualsTo(glucoseValue2))
}
}