Added pump logs upload setting to diacon platform

This commit is contained in:
miyeongkim 2022-04-29 14:33:54 +09:00
parent 507632d9a7
commit f61cac2087
11 changed files with 849 additions and 618 deletions

View file

@ -187,6 +187,13 @@ class DiaconnG8Pump @Inject constructor(
var lgsTime:Int = 0 // LGS Setting time (0~255 min) var lgsTime:Int = 0 // LGS Setting time (0~255 min)
var lgsElapsedTime:Int = 0 // LGS Passed Time (0~255 min) var lgsElapsedTime:Int = 0 // LGS Passed Time (0~255 min)
val pumpUid: String
get() = "$country-$productType-$makeYear-${makeMonth.toString().padStart(2,'0')}-${makeDay.toString().padStart(2, '0')}-${lotNo.toString().padStart(3,'0')}-${serialNo.toString().padStart(5,'0')}"
val pumpVersion: String
get() = "$majorVersion.$minorVersion"
fun buildDiaconnG8ProfileRecord(nsProfile: Profile): Array<Double> { fun buildDiaconnG8ProfileRecord(nsProfile: Profile): Array<Double> {
val record = Array(24) { 0.0 } val record = Array(24) { 0.0 }
for (hour in 0..23) { for (hour in 0..23) {
@ -247,6 +254,7 @@ class DiaconnG8Pump @Inject constructor(
var apslastLogNum = 0 // 앱에서 처리한 마지막 로그 번호. var apslastLogNum = 0 // 앱에서 처리한 마지막 로그 번호.
var apsWrappingCount = 0 // 앱에서 처리한 마지막 로그 번호. var apsWrappingCount = 0 // 앱에서 처리한 마지막 로그 번호.
var isProgressPumpLogSync = false // 로그 동기화 진행 여부 var isProgressPumpLogSync = false // 로그 동기화 진행 여부
var isPlatformUploadStarted = false // 플랫폼 로그 동기화 진행 여부
// 6. bolus speed status. // 6. bolus speed status.
var speed = 0 // 주입 속도(1 ~ 8) var speed = 0 // 주입 속도(1 ~ 8)

View file

@ -0,0 +1,25 @@
package info.nightscout.androidaps.diaconn.api
import com.google.gson.annotations.SerializedName
data class LastNoResponse(val ok: Boolean, val info:Info )
data class Info(val pumplog_no: Long)
data class ApiResponse(val ok: Boolean)
data class PumpLogDto(
@SerializedName("app_uid") val app_uid: String,
@SerializedName("app_version") val app_version: String,
@SerializedName("pump_uid") val pump_uid: String,
@SerializedName("pump_version") val pump_version: String,
@SerializedName("incarnation_num") val incarnation_num: Int,
@SerializedName("pumplog_info") val pumplog_info: List<PumpLog>
)
data class PumpLog(
@SerializedName("pumplog_no") val pumplog_no: Long,
@SerializedName("pumplog_wrapping_count") val pumplog_wrapping_count: Int,
@SerializedName("pumplog_data") val pumplog_data: String,
@SerializedName("act_type") val act_type: String
)

View file

@ -0,0 +1,24 @@
package info.nightscout.androidaps.diaconn.api
import retrofit2.Call
import retrofit2.http.Body
import retrofit2.http.GET
import retrofit2.http.Headers
import retrofit2.http.POST
import retrofit2.http.Query
interface DiaconnApiService {
@Headers("api-key: ${DiaconnLogUploader.UPLOAD_API_KEY}")
@GET("v1/pumplog/last_no")
fun getPumpLastNo(
@Query("pump_uid") pump_uid: String,
@Query("pump_version") pump_version: String,
@Query("incarnation_num") incarnation_num: Int): Call<LastNoResponse>
@Headers("api-key: ${DiaconnLogUploader.UPLOAD_API_KEY}")
@POST("v1/pumplog/save")
fun uploadPumpLogs(@Body pumpLogDto: PumpLogDto): Call<ApiResponse>
}

View file

@ -0,0 +1,33 @@
package info.nightscout.androidaps.diaconn.api
import android.content.Context
import info.nightscout.androidaps.plugins.bus.RxBus
import info.nightscout.shared.logging.AAPSLogger
import info.nightscout.shared.logging.LTag
import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory
import javax.inject.Inject
import javax.inject.Singleton
@Singleton
class DiaconnLogUploader @Inject constructor (
private val aapsLogger: AAPSLogger,
) {
companion object {
private const val BASE_URL = "https://api.diaconn.com/aaps/"
const val UPLOAD_API_KEY = "D7B3DA9FA8229D5253F3D75E1E2B1BA4"
}
private var retrofit: Retrofit? = null
fun getRetrofitInstance(): Retrofit? {
//aapsLogger.debug(LTag.PUMPCOMM, "Diaconn pump logs upload BASE_URL : $BASE_URL")
if (retrofit == null) {
retrofit = Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.build()
}
return retrofit
}
}

View file

@ -6,7 +6,8 @@ import dagger.Module
DiaconnG8ActivitiesModule::class, DiaconnG8ActivitiesModule::class,
DiaconnG8ServiceModule::class, DiaconnG8ServiceModule::class,
DiaconnG8PacketModule::class, DiaconnG8PacketModule::class,
DiaconnHistoryModule::class DiaconnHistoryModule::class,
DiaconnLogUploaderModule::class
]) ])
open class DiaconnG8Module open class DiaconnG8Module

View file

@ -0,0 +1,12 @@
package info.nightscout.androidaps.diaconn.di
import dagger.Module
import dagger.android.ContributesAndroidInjector
import info.nightscout.androidaps.diaconn.api.DiaconnLogUploader
import info.nightscout.androidaps.diaconn.service.DiaconnG8Service
@Module
@Suppress("unused")
abstract class DiaconnLogUploaderModule {
@ContributesAndroidInjector abstract fun contributesDiaconnLogUploader(): DiaconnLogUploader
}

View file

@ -14,6 +14,8 @@ import info.nightscout.androidaps.data.PumpEnactResult
import info.nightscout.androidaps.diaconn.DiaconnG8Plugin import info.nightscout.androidaps.diaconn.DiaconnG8Plugin
import info.nightscout.androidaps.diaconn.DiaconnG8Pump import info.nightscout.androidaps.diaconn.DiaconnG8Pump
import info.nightscout.androidaps.diaconn.R import info.nightscout.androidaps.diaconn.R
import info.nightscout.androidaps.diaconn.api.DiaconnApiService
import info.nightscout.androidaps.diaconn.api.DiaconnLogUploader
import info.nightscout.androidaps.diaconn.events.EventDiaconnG8NewStatus import info.nightscout.androidaps.diaconn.events.EventDiaconnG8NewStatus
import info.nightscout.androidaps.diaconn.events.EventDiaconnG8PumpLogReset import info.nightscout.androidaps.diaconn.events.EventDiaconnG8PumpLogReset
import info.nightscout.androidaps.diaconn.packet.* import info.nightscout.androidaps.diaconn.packet.*
@ -51,6 +53,7 @@ import java.util.concurrent.TimeUnit
import javax.inject.Inject import javax.inject.Inject
import kotlin.math.abs import kotlin.math.abs
import kotlin.math.ceil import kotlin.math.ceil
import kotlin.math.floor
import kotlin.math.min import kotlin.math.min
class DiaconnG8Service : DaggerService() { class DiaconnG8Service : DaggerService() {
@ -74,6 +77,7 @@ class DiaconnG8Service : DaggerService() {
@Inject lateinit var pumpSync: PumpSync @Inject lateinit var pumpSync: PumpSync
@Inject lateinit var dateUtil: DateUtil @Inject lateinit var dateUtil: DateUtil
@Inject lateinit var aapsSchedulers: AapsSchedulers @Inject lateinit var aapsSchedulers: AapsSchedulers
@Inject lateinit var diaconnLogUploader: DiaconnLogUploader
private val disposable = CompositeDisposable() private val disposable = CompositeDisposable()
private val mBinder: IBinder = LocalBinder() private val mBinder: IBinder = LocalBinder()
@ -137,11 +141,14 @@ class DiaconnG8Service : DaggerService() {
} }
private fun sendMessage(message: DiaconnG8Packet) { private fun sendMessage(message: DiaconnG8Packet) {
bleCommonService.sendMessage(message, 500) bleCommonService.sendMessage(message, 2000)
} }
fun readPumpStatus() { fun readPumpStatus() {
try { try {
aapsLogger.error(LTag.PUMPCOMM, "패키지 명!!! : "+context.packageManager.getPackageInfo(context.packageName, 0).versionName)
val pump = activePlugin.activePump val pump = activePlugin.activePump
rxBus.send(EventPumpStatusChanged(rh.gs(R.string.gettingpumpsettings))) rxBus.send(EventPumpStatusChanged(rh.gs(R.string.gettingpumpsettings)))
@ -283,51 +290,89 @@ class DiaconnG8Service : DaggerService() {
apsWrappingCount = sp.getInt(rh.gs(R.string.apsWrappingCount), 0) apsWrappingCount = sp.getInt(rh.gs(R.string.apsWrappingCount), 0)
apsLastLogNum = sp.getInt(rh.gs(R.string.apslastLogNum), 0) apsLastLogNum = sp.getInt(rh.gs(R.string.apslastLogNum), 0)
val apsLastNum = apsWrappingCount * 10000 + apsLastLogNum aapsLogger.debug(LTag.PUMPCOMM, "apsWrappingCount : $apsWrappingCount, apsLastLogNum : $apsLastLogNum")
if ((pumpWrappingCount * 10000 + pumpLastNum) < apsLastLogNum) { if ((pumpWrappingCount * 10000 + pumpLastNum) < apsLastLogNum) {
pumpLogDefaultSetting() pumpLogDefaultSetting()
} }
val start: Int? // log sync startNo
val end: Int? // log sync endNo
if (((pumpWrappingCount * 10000 + pumpLastNum) - apsLastNum) > 10000) {
start = pumpLastNum
end = 10000
} else if (pumpWrappingCount > apsWrappingCount && apsLastLogNum < 9999) {
start = apsLastLogNum + 1
end = 10000
} else if (pumpWrappingCount > apsWrappingCount && apsLastLogNum >= 9999) {
start = 0
end = pumpLastNum
} else {
start = apsLastLogNum + 1
end = pumpLastNum
}
// pump log loop size // pump log loop size
val pumpLogPageSize = 11 val pumpLogPageSize = 11
val loopCount: Int = ceil(((end - start) / 11.0)).toInt() val (start, end, loopSize) = getLogLoopCount(apsLastLogNum, apsWrappingCount, pumpLastNum, pumpWrappingCount)
// log sync start! // log sync start!
if (loopCount > 0) { if (loopSize > 0) {
diaconnG8Pump.isProgressPumpLogSync = true for (i in 0 until loopSize) {
for (i in 0 until loopCount) {
val startLogNo: Int = start + i * pumpLogPageSize val startLogNo: Int = start + i * pumpLogPageSize
val endLogNo: Int = startLogNo + min(end - startLogNo, pumpLogPageSize) val endLogNo: Int = startLogNo + min(end - startLogNo, pumpLogPageSize)
val msg = BigLogInquirePacket(injector, startLogNo, endLogNo, 100) val msg = BigLogInquirePacket(injector, startLogNo, endLogNo, 100)
sendMessage(msg) sendMessage(msg, 500)
}
diaconnG8Pump.historyDoneReceived = true
while (!diaconnG8Pump.historyDoneReceived && bleCommonService.isConnected) {
SystemClock.sleep(100)
} }
result.success(true) result.success(true)
diaconnG8Pump.lastConnection = System.currentTimeMillis() diaconnG8Pump.lastConnection = System.currentTimeMillis()
} }
// upload pump log to Diaconn Cloud
if (sp.getBoolean(R.string.key_diaconn_g8_cloudsend, true)) {
SystemClock.sleep(1000)
try {
// getting last uploaded log number
val retrofit = diaconnLogUploader.getRetrofitInstance()
val api = retrofit?.create(DiaconnApiService::class.java)
val response = api?.getPumpLastNo(diaconnG8Pump.pumpUid, diaconnG8Pump.pumpVersion, diaconnG8Pump.pumpIncarnationNum)?.execute()
if(response?.body()?.ok == true) {
aapsLogger.debug(LTag.PUMPCOMM, "pumplog_no = ${response.body()?.info?.pumplog_no}")
val platformLastNo = response.body()?.info?.pumplog_no!!
val platformWrappingCount: Int = floor(platformLastNo / 10000.0).toInt()
val platformLogNo: Int = if (platformLastNo.toInt() == -1) {
9999
} else {
(platformLastNo % 10000).toInt()
}
aapsLogger.debug(LTag.PUMPCOMM, "platformLogNo: $platformLogNo, platformWrappingCount: $platformWrappingCount")
// 페이지 사이즈로 처리할 때 루핑 횟수 계산
val (platformStart, platformEnd, platformLoopSize) = getLogLoopCount(platformLogNo, platformWrappingCount, pumpLastNum, pumpWrappingCount)
if(platformLoopSize > 0) {
diaconnG8Pump.isPlatformUploadStarted = true
for (i in 0 until platformLoopSize) {
rxBus.send(EventPumpStatusChanged("클라우드동기화 진행 중 : $i / $platformLoopSize"))
val startLogNo: Int = platformStart + i * pumpLogPageSize
val endLogNo: Int = startLogNo + min(platformEnd - startLogNo, pumpLogPageSize)
val msg = BigLogInquirePacket(injector, startLogNo, endLogNo, 100)
sendMessage(msg, 500)
}
SystemClock.sleep(1000)
diaconnG8Pump.isPlatformUploadStarted = false
}
}
} catch (e:Exception) {
aapsLogger.error("Unhandled exception", e)
}
}
return result return result
} }
private fun getLogLoopCount(lastLogNum: Int, wrappingCount: Int, pumpLastNum: Int, pumpWrappingCount: Int): Triple<Int, Int, Int> {
val start: Int// log sync start number
val end: Int // log sync end number1311
if (pumpWrappingCount * 10000 + pumpLastNum - lastLogNum > 10000) {
start = pumpLastNum
end = 10000
} else if (pumpWrappingCount > wrappingCount && lastLogNum < 9999) {
start = (lastLogNum + 1)
end = 10000
} else if (pumpWrappingCount > wrappingCount && lastLogNum >= 9999) {
start = 0 // 처음부터 시작
end = pumpLastNum
} else {
start = (lastLogNum + 1)
end = pumpLastNum
}
val size = ceil((end - start) / 11.0).toInt()
//
return Triple(start, end, size)
}
fun setUserSettings(): PumpEnactResult { fun setUserSettings(): PumpEnactResult {
val result = PumpEnactResult(injector) val result = PumpEnactResult(injector)
@ -344,7 +389,7 @@ class DiaconnG8Service : DaggerService() {
if (diaconnG8Pump.otpNumber == 0) { if (diaconnG8Pump.otpNumber == 0) {
aapsLogger.error(LTag.PUMPCOMM, "otp is not received yet") aapsLogger.error(LTag.PUMPCOMM, "otp is not received yet")
result.success(false) result.success(false)
result.comment("펌프와 연결 상태를 확인해주세요.") result.comment("")
return result return result
} }
sendMessage(AppConfirmSettingPacket(injector, msg.msgType, diaconnG8Pump.otpNumber)) sendMessage(AppConfirmSettingPacket(injector, msg.msgType, diaconnG8Pump.otpNumber))
@ -356,6 +401,13 @@ class DiaconnG8Service : DaggerService() {
fun bolus(insulin: Double, carbs: Int, carbTime: Long, t: EventOverviewBolusProgress.Treatment): Boolean { fun bolus(insulin: Double, carbs: Int, carbTime: Long, t: EventOverviewBolusProgress.Treatment): Boolean {
if (!isConnected) return false if (!isConnected) return false
if (BolusProgressDialog.stopPressed) return false if (BolusProgressDialog.stopPressed) return false
// Only Carbs
if (carbs > 0 && insulin == 0.0) {
pumpSync.syncCarbsWithTimestamp(carbTime, carbs.toDouble(), null, PumpType.DIACONN_G8, diaconnG8Pump.serialNo.toString())
return true
}
rxBus.send(EventPumpStatusChanged(rh.gs(R.string.startingbolus))) rxBus.send(EventPumpStatusChanged(rh.gs(R.string.startingbolus)))
// bolus speed setting // bolus speed setting
@ -622,9 +674,9 @@ class DiaconnG8Service : DaggerService() {
(basalList[23] * 100).toInt() (basalList[23] * 100).toInt()
) )
// setting basal pattern 1,2,3,4 // setting basal pattern 1,2,3,4
sendMessage(requestReqPacket1) sendMessage(requestReqPacket1, 500)
sendMessage(requestReqPacket2) sendMessage(requestReqPacket2, 500)
sendMessage(requestReqPacket3) sendMessage(requestReqPacket3, 500)
sendMessage(requestReqPacket4) sendMessage(requestReqPacket4)
// otp process // otp process
@ -671,7 +723,7 @@ class DiaconnG8Service : DaggerService() {
return false return false
} }
sendMessage(AppConfirmSettingPacket(injector, msgType, diaconnG8Pump.otpNumber), 2000) sendMessage(AppConfirmSettingPacket(injector, msgType, diaconnG8Pump.otpNumber))
diaconnG8Pump.otpNumber = 0 diaconnG8Pump.otpNumber = 0
return true return true
} }

View file

@ -89,6 +89,8 @@
<string name="diaconn_g8_logcanulachange_title">바늘 교체</string> <string name="diaconn_g8_logcanulachange_title">바늘 교체</string>
<string name="diaconn_g8_logcanulachange_summary">로그 동기화 시 케어포털 \"위치 교체\" 정보 자동 업로드</string> <string name="diaconn_g8_logcanulachange_summary">로그 동기화 시 케어포털 \"위치 교체\" 정보 자동 업로드</string>
<string name="diaconn_g8_logbatterychange_summary">로그 동기화 시 케어포털 \"베터리 교체\" 정보 자동 업로드</string> <string name="diaconn_g8_logbatterychange_summary">로그 동기화 시 케어포털 \"베터리 교체\" 정보 자동 업로드</string>
<string name="diaconn_g8_cloudsend_summary">펌프 로그정보를 \"디아콘 클라우드\"로 자동 업로드</string>
<string name="diaconn_g8_cloudsend_title">디아콘 클라우드 전송</string>
<string name="diaconn_g8_logbatterychange_title">베터리 교체</string> <string name="diaconn_g8_logbatterychange_title">베터리 교체</string>
<string name="diaconn_g8_logsyncinprogress">로그 동기화 진행 중</string> <string name="diaconn_g8_logsyncinprogress">로그 동기화 진행 중</string>
<string name="diaconn_g8_loginsulinshorage">인슐린 부족 경고</string> <string name="diaconn_g8_loginsulinshorage">인슐린 부족 경고</string>

View file

@ -10,6 +10,7 @@
<string name="key_diaconn_g8_logbatterychange" translatable="false">diaconn_g8_logbatterychanges</string> <string name="key_diaconn_g8_logbatterychange" translatable="false">diaconn_g8_logbatterychanges</string>
<string name="key_diaconn_g8_loginsulinchange" translatable="false">diaconn_g8_loginsulinchange</string> <string name="key_diaconn_g8_loginsulinchange" translatable="false">diaconn_g8_loginsulinchange</string>
<string name="key_diaconn_g8_logneedlechange" translatable="false">diaconn_g8_logneedlechange</string> <string name="key_diaconn_g8_logneedlechange" translatable="false">diaconn_g8_logneedlechange</string>
<string name="key_diaconn_g8_cloudsend" translatable="false">diaconn_g8_cloudsend</string>
<string name="resetpairing" >Reset Pairing</string> <string name="resetpairing" >Reset Pairing</string>
<string name="diaconn_nodeviceavailable" >No Device available</string> <string name="diaconn_nodeviceavailable" >No Device available</string>
@ -166,5 +167,7 @@
<string name="diaconn_g8_errorcode_34">LGS status is OFF, OFF Command is declined.</string> <string name="diaconn_g8_errorcode_34">LGS status is OFF, OFF Command is declined.</string>
<string name="diaconn_g8_errorcode_35">Tempbasal start is rejected when tempbasal is running</string> <string name="diaconn_g8_errorcode_35">Tempbasal start is rejected when tempbasal is running</string>
<string name="diaconn_g8_errorcode_36">Tempbasal stop is rejected when tempbasal is not running</string> <string name="diaconn_g8_errorcode_36">Tempbasal stop is rejected when tempbasal is not running</string>
<string name="diaconn_g8_cloudsend_summary">Send pump logs to the Diaconn Cloud.</string>
<string name="diaconn_g8_cloudsend_title">Diaconn Cloud Sync</string>
<string name="key_diaconn_g8_appuid">diaconn_g8_appuid</string>
</resources> </resources>

View file

@ -45,6 +45,12 @@
android:summary="@string/diaconn_g8_logbatterychange_summary" android:summary="@string/diaconn_g8_logbatterychange_summary"
android:title="@string/diaconn_g8_logbatterychange_title" /> android:title="@string/diaconn_g8_logbatterychange_title" />
<SwitchPreference
android:defaultValue="true"
android:key="@string/key_diaconn_g8_cloudsend"
android:summary="@string/diaconn_g8_cloudsend_summary"
android:title="@string/diaconn_g8_cloudsend_title" />
</PreferenceCategory> </PreferenceCategory>
</androidx.preference.PreferenceScreen> </androidx.preference.PreferenceScreen>