Merge remote-tracking branch 'Nightscout/dev' into wear/new_custom_watchface
This commit is contained in:
commit
9cd166f802
|
@ -2,6 +2,7 @@
|
|||
<dictionary name="project-dictionary">
|
||||
<words>
|
||||
<w>aaps</w>
|
||||
<w>aapsclient</w>
|
||||
<w>abcdef</w>
|
||||
<w>accu</w>
|
||||
<w>acked</w>
|
||||
|
@ -18,11 +19,13 @@
|
|||
<w>bage</w>
|
||||
<w>basaliob</w>
|
||||
<w>basals</w>
|
||||
<w>batt</w>
|
||||
<w>bgcheck</w>
|
||||
<w>bgsource</w>
|
||||
<w>boluscalc</w>
|
||||
<w>bolusing</w>
|
||||
<w>boluswizard</w>
|
||||
<w>boyda</w>
|
||||
<w>carb</w>
|
||||
<w>carbratio</w>
|
||||
<w>carbs</w>
|
||||
|
@ -67,6 +70,7 @@
|
|||
<w>humalog</w>
|
||||
<w>iage</w>
|
||||
<w>infinivocgm</w>
|
||||
<w>instantiator</w>
|
||||
<w>insulet</w>
|
||||
<w>intelligo</w>
|
||||
<w>iobtotal</w>
|
||||
|
@ -78,6 +82,7 @@
|
|||
<w>lyumjev</w>
|
||||
<w>mdtp</w>
|
||||
<w>medtronic</w>
|
||||
<w>medtrum</w>
|
||||
<w>mgdl</w>
|
||||
<w>miao</w>
|
||||
<w>misformatted</w>
|
||||
|
@ -99,6 +104,7 @@
|
|||
<w>oref</w>
|
||||
<w>otpauth</w>
|
||||
<w>passcode</w>
|
||||
<w>pbage</w>
|
||||
<w>pdus</w>
|
||||
<w>philoul</w>
|
||||
<w>poctech</w>
|
||||
|
@ -108,6 +114,7 @@
|
|||
<w>pumpcontrol</w>
|
||||
<w>pumpdrivers</w>
|
||||
<w>quickwizard</w>
|
||||
<w>rawbg</w>
|
||||
<w>readstatus</w>
|
||||
<w>realduration</w>
|
||||
<w>refresheventsfromnightscout</w>
|
||||
|
|
76
_docs/icons/ic_medtrum_128.svg
Normal file
76
_docs/icons/ic_medtrum_128.svg
Normal file
|
@ -0,0 +1,76 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
width="128px" height="128px" viewBox="0 0 128 128" enable-background="new 0 0 128 128" xml:space="preserve">
|
||||
<g id="Layer_7">
|
||||
<g id="Medtrum_2">
|
||||
<path fill="#FFFFFF" d="M94.383,15.26H34.367c-16.327,0-29.563,13.3-29.563,29.706v38.687c0,16.406,13.236,29.706,29.563,29.706
|
||||
h60.017c16.327,0,29.563-13.3,29.563-29.706V44.965C123.946,28.559,110.71,15.26,94.383,15.26z M56.935,106.393
|
||||
c-1.272,0-2.303-1.031-2.303-2.303c0-1.272,1.031-2.303,2.303-2.303c1.272,0,2.303,1.031,2.303,2.303
|
||||
C59.238,105.362,58.207,106.393,56.935,106.393z M56.935,26.83c-1.272,0-2.303-1.031-2.303-2.303c0-1.272,1.031-2.303,2.303-2.303
|
||||
c1.272,0,2.303,1.031,2.303,2.303C59.238,25.801,58.207,26.83,56.935,26.83z M112.167,73.321V55.296
|
||||
c2.428,2.241,3.95,5.448,3.95,9.013S114.595,71.081,112.167,73.321z"/>
|
||||
<g>
|
||||
<path fill="#E0E0E0" d="M88.268,99.547c5.196-0.229,9.454-0.602,11.926-1.147c8.841-1.951,12.243-6.224,12.243-13.385v-1.263
|
||||
V44.865v-1.263c0-7.162-3.402-11.436-12.243-13.385c-2.472-0.546-6.73-0.918-11.926-1.147"/>
|
||||
</g>
|
||||
<g>
|
||||
<path fill="#AAAAAA" d="M88.531,29.079c-19.865-0.79-52.154,0.131-58.579,1.565c-8.285,1.848-12.095,5.194-13.418,12.916
|
||||
c-0.606,3.544-0.627,12.306-0.473,20.748c-0.154,8.442-0.134,17.204,0.473,20.75c1.323,7.721,5.133,11.066,13.418,12.916
|
||||
c6.425,1.434,38.715,2.355,58.579,1.565"/>
|
||||
</g>
|
||||
<g>
|
||||
<path fill="#EAEAEA" d="M88.268,98.819c5.011-0.224,9.117-0.59,11.502-1.123c8.527-1.911,11.808-6.095,11.808-13.109v-1.237
|
||||
V45.267V44.03c0-7.014-3.281-11.199-11.808-13.109c-2.384-0.535-6.491-0.899-11.502-1.123"/>
|
||||
</g>
|
||||
<path fill="#B2B2B2" d="M88.531,29.807c-19.567-0.774-51.374,0.128-57.702,1.533c-8.161,1.81-11.914,5.087-13.217,12.649
|
||||
c-0.597,3.471-0.618,12.052-0.466,20.32c-0.152,8.268-0.132,16.849,0.466,20.321c1.303,7.562,5.056,10.837,13.217,12.649
|
||||
c6.329,1.405,38.135,2.306,57.702,1.533"/>
|
||||
<g>
|
||||
<path fill="#F0F0F0" d="M88.268,97.88c4.751-0.218,8.643-0.573,10.904-1.092c8.084-1.859,11.194-5.929,11.194-12.752v-1.203
|
||||
V45.785v-1.203c0-6.823-3.11-10.895-11.194-12.752c-2.261-0.52-6.153-0.874-10.904-1.092"/>
|
||||
</g>
|
||||
<path fill="#B9B9B9" d="M88.531,30.745c-19.148-0.753-50.274,0.124-56.467,1.491c-7.986,1.761-11.659,4.949-12.934,12.305
|
||||
c-0.585,3.377-0.604,11.724-0.456,19.767c-0.149,8.043-0.129,16.39,0.456,19.768c1.275,7.356,4.948,10.542,12.934,12.305
|
||||
c6.193,1.367,37.319,2.244,56.467,1.491"/>
|
||||
<g>
|
||||
<path fill="#F4F4F4" d="M88.268,96.224c4.241-0.207,7.717-0.545,9.735-1.039c7.217-1.767,9.994-5.637,9.994-12.123v-1.144V46.698
|
||||
v-1.144c0-6.486-2.777-10.357-9.994-12.123c-2.018-0.495-5.494-0.831-9.735-1.039"/>
|
||||
</g>
|
||||
<path fill="#BEBEBE" d="M88.531,32.401c-18.728-0.715-49.17,0.118-55.227,1.417c-7.811,1.674-11.403,4.705-12.65,11.698
|
||||
c-0.572,3.21-0.591,11.146-0.446,18.792c-0.145,7.646-0.126,15.582,0.446,18.793c1.247,6.993,4.839,10.022,12.65,11.698
|
||||
c6.057,1.299,36.499,2.133,55.227,1.417"/>
|
||||
<g>
|
||||
|
||||
<linearGradient id="SVGID_1_" gradientUnits="userSpaceOnUse" x1="157.3581" y1="-156.2687" x2="184.8192" y2="-156.2687" gradientTransform="matrix(1 0 0 -1 -97.66 -91.96)">
|
||||
<stop offset="0" style="stop-color:#BBBDBF"/>
|
||||
<stop offset="0.1232" style="stop-color:#B5B7B9"/>
|
||||
<stop offset="0.5123" style="stop-color:#B5B7B9"/>
|
||||
<stop offset="0.5764" style="stop-color:#B5B7B9"/>
|
||||
<stop offset="1" style="stop-color:#929497"/>
|
||||
</linearGradient>
|
||||
<polyline fill="url(#SVGID_1_)" stroke="#9D9DA0" stroke-width="0.4252" stroke-miterlimit="10" points="59.698,75.534
|
||||
76.854,75.534 76.854,74.24 87.159,74.24 87.159,54.379 76.854,54.379 76.854,53.083 59.698,53.083 "/>
|
||||
</g>
|
||||
<g>
|
||||
<path fill="#D0D2D3" stroke="#A3A3A3" stroke-width="0.4252" stroke-miterlimit="10" d="M90.39,68.37
|
||||
c0,1.835-1.432,3.322-3.198,3.322H72.747c-1.766,0-3.198-1.487-3.198-3.322v-8.12c0-1.835,1.432-3.322,3.198-3.322h14.446
|
||||
c1.766,0,3.198,1.487,3.198,3.322V68.37z"/>
|
||||
</g>
|
||||
<g>
|
||||
<path fill="#F4F4F4" stroke="#C1C1C1" stroke-width="0.2835" stroke-miterlimit="10" d="M84.165,74.54
|
||||
c0,4.387-0.05,4.448,3.627,4.448l0,0c4.387,0,7.945-3.557,7.945-7.945v-13.47c0-4.387-3.557-7.945-7.945-7.945l0,0
|
||||
c-3.678,0-3.627,0.102-3.627,4.489V74.54z"/>
|
||||
</g>
|
||||
<g>
|
||||
<g>
|
||||
<path fill="#F1F1F2" stroke="#B2B2B2" stroke-width="0.2835" stroke-miterlimit="10" d="M94.571,67.677
|
||||
c0,0.834-0.677,1.511-1.511,1.511l0,0c-0.834,0-1.511-0.677-1.511-1.511v-6.735c0-0.834,0.677-1.511,1.511-1.511l0,0
|
||||
c0.834,0,1.511,0.677,1.511,1.511V67.677z"/>
|
||||
</g>
|
||||
<path fill="#231F20" d="M94.291,61.74c0,0.679-0.551,1.231-1.231,1.231l0,0c-0.679,0-1.231-0.551-1.231-1.231l0,0
|
||||
c0-0.679,0.551-1.231,1.231-1.231l0,0C93.74,60.51,94.291,61.06,94.291,61.74L94.291,61.74z"/>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 4.8 KiB |
|
@ -13,7 +13,7 @@ android {
|
|||
|
||||
namespace 'info.nightscout.shared.impl'
|
||||
defaultConfig {
|
||||
minSdkVersion 23 // for wear
|
||||
minSdkVersion 25 // for wear
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -16,7 +16,7 @@ android {
|
|||
|
||||
namespace 'info.nightscout.shared'
|
||||
defaultConfig {
|
||||
minSdkVersion 23 // for wear
|
||||
minSdkVersion 25 // for wear
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
package info.nightscout.rx.events
|
||||
|
||||
class EventDeviceStatusChange : Event()
|
|
@ -1,5 +1,3 @@
|
|||
package info.nightscout.rx.events
|
||||
|
||||
import info.nightscout.rx.events.Event
|
||||
|
||||
class EventRefreshButtonState (val newState : Boolean): Event()
|
|
@ -96,9 +96,9 @@ class DateUtil @Inject constructor(private val context: Context) {
|
|||
return calendar.timeInMillis
|
||||
}
|
||||
|
||||
fun toSeconds(hh_colon_mm: String): Int {
|
||||
fun toSeconds(hhColonMm: String): Int {
|
||||
val p = Pattern.compile("(\\d+):(\\d+)( a.m.| p.m.| AM| PM|AM|PM|)")
|
||||
val m = p.matcher(hh_colon_mm)
|
||||
val m = p.matcher(hhColonMm)
|
||||
var retVal = 0
|
||||
if (m.find()) {
|
||||
retVal = SafeParse.stringToInt(m.group(1)) * 60 * 60 + SafeParse.stringToInt(m.group(2)) * 60
|
||||
|
@ -342,8 +342,8 @@ class DateUtil @Inject constructor(private val context: Context) {
|
|||
minutes = rh.gs(R.string.shortminute)
|
||||
}
|
||||
var result = ""
|
||||
if (diff[TimeUnit.DAYS]!! > 0) result += diff[TimeUnit.DAYS].toString() + days
|
||||
if (diff[TimeUnit.HOURS]!! > 0) result += diff[TimeUnit.HOURS].toString() + hours
|
||||
if (diff.getOrDefault(TimeUnit.DAYS, -1) > 0) result += diff[TimeUnit.DAYS].toString() + days
|
||||
if (diff.getOrDefault(TimeUnit.HOURS, -1) > 0) result += diff[TimeUnit.HOURS].toString() + hours
|
||||
if (diff[TimeUnit.DAYS] == 0L) result += diff[TimeUnit.MINUTES].toString() + minutes
|
||||
return result
|
||||
}
|
||||
|
@ -368,6 +368,7 @@ class DateUtil @Inject constructor(private val context: Context) {
|
|||
if (t > 28) {
|
||||
unit = rh.gs(R.string.unit_week)
|
||||
t /= 7
|
||||
@Suppress("KotlinConstantConditions")
|
||||
if (t != 1L) unit = rh.gs(R.string.unit_weeks)
|
||||
}
|
||||
}
|
||||
|
@ -406,8 +407,8 @@ class DateUtil @Inject constructor(private val context: Context) {
|
|||
} else {
|
||||
thisDf = DecimalFormat("#", dfs)
|
||||
}
|
||||
thisDf!!.maximumFractionDigits = digits
|
||||
return thisDf.format(x)
|
||||
thisDf?.maximumFractionDigits = digits
|
||||
return thisDf?.format(x) ?: ""
|
||||
}
|
||||
|
||||
fun formatHHMM(timeAsSeconds: Int): String {
|
||||
|
@ -432,9 +433,9 @@ class DateUtil @Inject constructor(private val context: Context) {
|
|||
fun timeStampToUtcDateMillis(timestamp: Long): Long {
|
||||
val current = Calendar.getInstance().apply { timeInMillis = timestamp }
|
||||
return Calendar.getInstance().apply {
|
||||
set(Calendar.YEAR, current.get(Calendar.YEAR))
|
||||
set(Calendar.MONTH, current.get(Calendar.MONTH))
|
||||
set(Calendar.DAY_OF_MONTH, current.get(Calendar.DAY_OF_MONTH))
|
||||
set(Calendar.YEAR, current[Calendar.YEAR])
|
||||
set(Calendar.MONTH, current[Calendar.MONTH])
|
||||
set(Calendar.DAY_OF_MONTH, current[Calendar.DAY_OF_MONTH])
|
||||
}.timeInMillis
|
||||
}
|
||||
|
||||
|
@ -442,9 +443,9 @@ class DateUtil @Inject constructor(private val context: Context) {
|
|||
val selected = Calendar.getInstance().apply { timeInMillis = dateUtcMillis }
|
||||
return Calendar.getInstance().apply {
|
||||
timeInMillis = timestamp
|
||||
set(Calendar.YEAR, selected.get(Calendar.YEAR))
|
||||
set(Calendar.MONTH, selected.get(Calendar.MONTH))
|
||||
set(Calendar.DAY_OF_MONTH, selected.get(Calendar.DAY_OF_MONTH))
|
||||
set(Calendar.YEAR, selected[Calendar.YEAR])
|
||||
set(Calendar.MONTH, selected[Calendar.MONTH])
|
||||
set(Calendar.DAY_OF_MONTH, selected[Calendar.DAY_OF_MONTH])
|
||||
}.timeInMillis
|
||||
}
|
||||
|
||||
|
|
|
@ -110,7 +110,7 @@ android {
|
|||
defaultConfig {
|
||||
multiDexEnabled true
|
||||
versionCode 1500
|
||||
version "3.2.0-dev-j"
|
||||
version "3.2.0-dev-k"
|
||||
buildConfigField "String", "VERSION", '"' + version + '"'
|
||||
buildConfigField "String", "BUILDVERSION", '"' + generateGitBuild() + '-' + generateDate() + '"'
|
||||
buildConfigField "String", "REMOTE", '"' + generateGitRemote() + '"'
|
||||
|
@ -213,6 +213,7 @@ dependencies {
|
|||
implementation project(':pump:danar')
|
||||
implementation project(':pump:diaconn')
|
||||
implementation project(':pump:eopatch')
|
||||
implementation project(':pump:medtrum')
|
||||
implementation project(':insight')
|
||||
implementation project(':pump:medtronic')
|
||||
implementation project(':pump:pump-common')
|
||||
|
|
|
@ -469,7 +469,7 @@ class MainActivity : DaggerAppCompatActivityWithResult() {
|
|||
* Check for existing PasswordReset file and
|
||||
* reset password to SN of active pump if file exists
|
||||
*/
|
||||
fun passwordResetCheck(context: Context) {
|
||||
private fun passwordResetCheck(context: Context) {
|
||||
val passwordReset = File(fileListProvider.ensureExtraDirExists(), "PasswordReset")
|
||||
if (passwordReset.exists()) {
|
||||
val sn = activePlugin.activePump.serialNumber()
|
||||
|
|
|
@ -54,6 +54,7 @@ import info.nightscout.plugins.sync.xdrip.XdripPlugin
|
|||
import info.nightscout.pump.combo.ComboPlugin
|
||||
import info.nightscout.pump.combov2.ComboV2Plugin
|
||||
import info.nightscout.pump.diaconn.DiaconnG8Plugin
|
||||
import info.nightscout.pump.medtrum.MedtrumPlugin
|
||||
import info.nightscout.pump.virtual.VirtualPumpPlugin
|
||||
import info.nightscout.rx.bus.RxBus
|
||||
import info.nightscout.rx.events.EventPreferenceChange
|
||||
|
@ -122,6 +123,7 @@ class MyPreferenceFragment : PreferenceFragmentCompat(), OnSharedPreferenceChang
|
|||
@Inject lateinit var wearPlugin: WearPlugin
|
||||
@Inject lateinit var maintenancePlugin: MaintenancePlugin
|
||||
@Inject lateinit var eopatchPumpPlugin: EopatchPumpPlugin
|
||||
@Inject lateinit var medtrumPlugin: MedtrumPlugin
|
||||
|
||||
@Inject lateinit var passwordCheck: PasswordCheck
|
||||
@Inject lateinit var nsSettingStatus: NSSettingsStatus
|
||||
|
@ -212,6 +214,7 @@ class MyPreferenceFragment : PreferenceFragmentCompat(), OnSharedPreferenceChang
|
|||
addPreferencesFromResourceIfEnabled(medtronicPumpPlugin, rootKey, config.PUMPDRIVERS)
|
||||
addPreferencesFromResourceIfEnabled(diaconnG8Plugin, rootKey, config.PUMPDRIVERS)
|
||||
addPreferencesFromResourceIfEnabled(eopatchPumpPlugin, rootKey, config.PUMPDRIVERS)
|
||||
addPreferencesFromResourceIfEnabled(medtrumPlugin, rootKey, config.PUMPDRIVERS)
|
||||
addPreferencesFromResource(R.xml.pref_pump, rootKey, config.PUMPDRIVERS)
|
||||
addPreferencesFromResourceIfEnabled(virtualPumpPlugin, rootKey)
|
||||
addPreferencesFromResourceIfEnabled(insulinOrefFreePeakPlugin, rootKey)
|
||||
|
|
|
@ -31,6 +31,7 @@ import info.nightscout.pump.common.di.PumpCommonModule
|
|||
import info.nightscout.pump.dana.di.DanaHistoryModule
|
||||
import info.nightscout.pump.dana.di.DanaModule
|
||||
import info.nightscout.pump.danars.di.DanaRSModule
|
||||
import info.nightscout.pump.medtrum.di.MedtrumModule
|
||||
import info.nightscout.pump.diaconn.di.DiaconnG8Module
|
||||
import info.nightscout.pump.virtual.di.VirtualPumpModule
|
||||
import info.nightscout.rx.di.RxModule
|
||||
|
@ -87,6 +88,7 @@ import javax.inject.Singleton
|
|||
OmnipodErosModule::class,
|
||||
PumpCommonModule::class,
|
||||
RileyLinkModule::class,
|
||||
MedtrumModule::class,
|
||||
VirtualPumpModule::class
|
||||
]
|
||||
)
|
||||
|
|
|
@ -46,6 +46,7 @@ import info.nightscout.plugins.sync.tidepool.TidepoolPlugin
|
|||
import info.nightscout.plugins.sync.xdrip.XdripPlugin
|
||||
import info.nightscout.pump.combo.ComboPlugin
|
||||
import info.nightscout.pump.combov2.ComboV2Plugin
|
||||
import info.nightscout.pump.medtrum.MedtrumPlugin
|
||||
import info.nightscout.pump.diaconn.DiaconnG8Plugin
|
||||
import info.nightscout.pump.virtual.VirtualPumpPlugin
|
||||
import info.nightscout.sensitivity.SensitivityAAPSPlugin
|
||||
|
@ -209,6 +210,12 @@ abstract class PluginsListModule {
|
|||
@IntKey(156)
|
||||
abstract fun bindEopatchPumpPlugin(plugin: EopatchPumpPlugin): PluginBase
|
||||
|
||||
@Binds
|
||||
@PumpDriver
|
||||
@IntoMap
|
||||
@IntKey(160)
|
||||
abstract fun bindMedtrumPlugin(plugin: MedtrumPlugin): PluginBase
|
||||
|
||||
@Binds
|
||||
@AllConfigs
|
||||
@IntoMap
|
||||
|
|
|
@ -59,7 +59,7 @@ buildscript {
|
|||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:8.1.0'
|
||||
classpath 'com.google.gms:google-services:4.3.15'
|
||||
classpath 'com.google.firebase:firebase-crashlytics-gradle:2.9.7'
|
||||
classpath 'com.google.firebase:firebase-crashlytics-gradle:2.9.8'
|
||||
|
||||
// NOTE: Do not place your application dependencies here; they belong
|
||||
// in the individual module build.gradle files
|
||||
|
@ -75,7 +75,7 @@ buildscript {
|
|||
plugins {
|
||||
// Test Gradle build, keep disabled under normal circumstances
|
||||
// id "com.osacky.doctor" version "0.8.1"
|
||||
id "org.jlleitschuh.gradle.ktlint" version "11.5.0"
|
||||
id "org.jlleitschuh.gradle.ktlint" version "11.5.1"
|
||||
// Aggregates and/or logs Jacoco test coverage to the Gradle build log
|
||||
id 'org.barfuin.gradle.jacocolog' version '3.1.0'
|
||||
id 'org.jetbrains.kotlin.android' version "$kotlin_version" apply false
|
||||
|
|
|
@ -131,9 +131,12 @@ open class Notification {
|
|||
const val IDENTIFICATION_NOT_SET = 77
|
||||
const val PERMISSION_BT = 78
|
||||
const val EOELOW_PATCH_ALERTS = 79
|
||||
const val COMBO_PUMP_SUSPENDED = 80
|
||||
const val PUMP_SUSPENDED = 80
|
||||
const val COMBO_UNKNOWN_TBR = 81
|
||||
const val BLUETOOTH_NOT_ENABLED = 82
|
||||
const val PATCH_NOT_ACTIVE = 83
|
||||
const val PUMP_SETTINGS_FAILED = 84
|
||||
const val PUMP_TIMEZONE_UPDATE_FAILED = 85
|
||||
|
||||
const val USER_MESSAGE = 1000
|
||||
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
package info.nightscout.interfaces.pump
|
||||
|
||||
/**
|
||||
* Functionality supported by Medtrum* pumps only
|
||||
*/
|
||||
interface Medtrum {
|
||||
|
||||
fun loadEvents(): PumpEnactResult // events history to build treatments from
|
||||
fun setUserOptions(): PumpEnactResult // set user settings
|
||||
fun clearAlarms(): PumpEnactResult // clear alarms
|
||||
fun deactivate(): PumpEnactResult // deactivate patch
|
||||
fun updateTime(): PumpEnactResult // update time
|
||||
}
|
|
@ -2,6 +2,7 @@ package info.nightscout.interfaces.pump.defs
|
|||
|
||||
enum class ManufacturerType(val description: String) {
|
||||
AAPS("AAPS"),
|
||||
Medtrum("Medtrum"),
|
||||
Medtronic("Medtronic"),
|
||||
Sooil("SOOIL"),
|
||||
Tandem("Tandem"),
|
||||
|
|
|
@ -26,6 +26,7 @@ enum class PumpCapability {
|
|||
YpsomedCapabilities(arrayOf(Bolus, ExtendedBolus, TempBasal, BasalProfileSet, Refill, ReplaceBattery, TDD, ManualTDDLoad)), // BasalRates (separately grouped)
|
||||
DiaconnCapabilities(arrayOf(Bolus, ExtendedBolus, TempBasal, BasalProfileSet, Refill, ReplaceBattery, TDD, ManualTDDLoad)), //
|
||||
EopatchCapabilities(arrayOf(Bolus, ExtendedBolus, TempBasal, BasalProfileSet, BasalRate30min)),
|
||||
MedtrumCapabilities(arrayOf(Bolus, TempBasal, BasalProfileSet, BasalRate30min, TDD)), // Technically the pump supports ExtendedBolus, but not implemented (yet)
|
||||
BasalRate_Duration15minAllowed,
|
||||
BasalRate_Duration30minAllowed,
|
||||
BasalRate_Duration15and30minAllowed(arrayOf(BasalRate_Duration15minAllowed, BasalRate_Duration30minAllowed)),
|
||||
|
|
|
@ -391,7 +391,29 @@ enum class PumpType {
|
|||
isPatchPump = true,
|
||||
maxReservoirReading = 50,
|
||||
source = Source.EOPatch2
|
||||
);
|
||||
),
|
||||
|
||||
//Medtrum Nano Pump
|
||||
MEDTRUM_NANO(
|
||||
description = "Medtrum Nano",
|
||||
manufacturer = ManufacturerType.Medtrum,
|
||||
model = "Nano",
|
||||
bolusSize = 0.05,
|
||||
specialBolusSize = null,
|
||||
extendedBolusSettings = DoseSettings(0.05, 30, 8 * 60, 0.05, 30.0),
|
||||
pumpTempBasalType = PumpTempBasalType.Absolute,
|
||||
tbrSettings = DoseSettings(0.05, 30, 12 * 60, 0.0, 25.0),
|
||||
specialBasalDurations = PumpCapability.BasalRate_Duration30minAllowed,
|
||||
baseBasalMinValue = 0.05,
|
||||
baseBasalMaxValue = 25.0,
|
||||
baseBasalStep = 0.05,
|
||||
baseBasalSpecialSteps = null,
|
||||
pumpCapability = PumpCapability.MedtrumCapabilities,
|
||||
isPatchPump = true,
|
||||
maxReservoirReading = 400,
|
||||
source = Source.Medtrum
|
||||
),
|
||||
MEDTRUM_UNTESTED(description = "Medtrum untested", model = "untested", parent = MEDTRUM_NANO);
|
||||
|
||||
val description: String
|
||||
var manufacturer: ManufacturerType? = null
|
||||
|
@ -458,6 +480,7 @@ enum class PumpType {
|
|||
OmnipodEros,
|
||||
OmnipodDash,
|
||||
EOPatch2,
|
||||
Medtrum,
|
||||
MDI,
|
||||
VirtualPump,
|
||||
Unknown
|
||||
|
|
|
@ -23,11 +23,14 @@ abstract class Command(
|
|||
BASAL_PROFILE,
|
||||
READSTATUS,
|
||||
LOAD_HISTORY, // TDDs and so far only Dana specific
|
||||
LOAD_EVENTS, // so far only Dana specific
|
||||
LOAD_EVENTS,
|
||||
LOAD_TDD,
|
||||
SET_USER_SETTINGS, // so far only Dana specific,
|
||||
START_PUMP,
|
||||
STOP_PUMP,
|
||||
CLEAR_ALARMS, // so far only Medtrum specific
|
||||
DEACTIVATE, // so far only Medtrum specific
|
||||
UPDATE_TIME, // so far only Medtrum specific
|
||||
INSIGHT_SET_TBR_OVER_ALARM, // insight only
|
||||
CUSTOM_COMMAND
|
||||
}
|
||||
|
|
|
@ -31,6 +31,9 @@ interface CommandQueue {
|
|||
fun setUserOptions(callback: Callback?): Boolean
|
||||
fun loadTDDs(callback: Callback?): Boolean
|
||||
fun loadEvents(callback: Callback?): Boolean
|
||||
fun clearAlarms(callback: Callback?): Boolean
|
||||
fun deactivate(callback: Callback?): Boolean
|
||||
fun updateTime(callback: Callback?): Boolean
|
||||
fun customCommand(customCommand: CustomCommand, callback: Callback?): Boolean
|
||||
fun isCustomCommandRunning(customCommandType: Class<out CustomCommand>): Boolean
|
||||
fun isCustomCommandInQueue(customCommandType: Class<out CustomCommand>): Boolean
|
||||
|
|
|
@ -21,22 +21,23 @@ interface DataSyncSelector {
|
|||
|
||||
val value: Any
|
||||
val id: Long
|
||||
var confirmed: Boolean
|
||||
}
|
||||
|
||||
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, override var confirmed: Boolean = false) : DataPair
|
||||
data class PairGlucoseValue(override val value: GlucoseValue, override val id: Long, override var confirmed: Boolean = false) : DataPair
|
||||
data class PairTherapyEvent(override val value: TherapyEvent, override val id: Long, override var confirmed: Boolean = false) : DataPair
|
||||
data class PairFood(override val value: Food, override val id: Long, override var confirmed: Boolean = false) : DataPair
|
||||
data class PairBolus(override val value: Bolus, override val id: Long, override var confirmed: Boolean = false) : DataPair
|
||||
data class PairCarbs(override val value: Carbs, override val id: Long, override var confirmed: Boolean = false) : DataPair
|
||||
data class PairBolusCalculatorResult(override val value: BolusCalculatorResult, override val id: Long, override var confirmed: Boolean = false) : DataPair
|
||||
data class PairTemporaryBasal(override val value: TemporaryBasal, override val id: Long, override var confirmed: Boolean = false) : DataPair
|
||||
data class PairExtendedBolus(override val value: ExtendedBolus, override val id: Long, override var confirmed: Boolean = false) : DataPair
|
||||
data class PairProfileSwitch(override val value: ProfileSwitch, override val id: Long, override var confirmed: Boolean = false) : DataPair
|
||||
data class PairEffectiveProfileSwitch(override val value: EffectiveProfileSwitch, override val id: Long, override var confirmed: Boolean = false) : DataPair
|
||||
data class PairOfflineEvent(override val value: OfflineEvent, override val id: Long, override var confirmed: Boolean = false) : DataPair
|
||||
data class PairProfileStore(override val value: JSONObject, override val id: Long, override var confirmed: Boolean = false) : DataPair
|
||||
data class PairDeviceStatus(override val value: DeviceStatus, override val id: Long, override var confirmed: Boolean = false) : DataPair
|
||||
|
||||
fun queueSize(): Long
|
||||
|
||||
|
|
|
@ -1,46 +0,0 @@
|
|||
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()
|
||||
}
|
|
@ -1,3 +0,0 @@
|
|||
package info.nightscout.interfaces.sync
|
||||
|
||||
interface DataSyncSelectorV3 : DataSyncSelector
|
|
@ -59,6 +59,8 @@ fun PumpType.Companion.fromDbPumpType(pt: InterfaceIDs.PumpType): PumpType =
|
|||
InterfaceIDs.PumpType.USER -> PumpType.USER
|
||||
InterfaceIDs.PumpType.DIACONN_G8 -> PumpType.DIACONN_G8
|
||||
InterfaceIDs.PumpType.EOPATCH2 -> PumpType.EOFLOW_EOPATCH2
|
||||
InterfaceIDs.PumpType.MEDTRUM -> PumpType.MEDTRUM_NANO
|
||||
InterfaceIDs.PumpType.MEDTRUM_UNTESTED -> PumpType.MEDTRUM_UNTESTED
|
||||
InterfaceIDs.PumpType.CACHE -> PumpType.CACHE
|
||||
}
|
||||
|
||||
|
@ -117,5 +119,7 @@ fun PumpType.toDbPumpType(): InterfaceIDs.PumpType =
|
|||
PumpType.USER -> InterfaceIDs.PumpType.USER
|
||||
PumpType.DIACONN_G8 -> InterfaceIDs.PumpType.DIACONN_G8
|
||||
PumpType.EOFLOW_EOPATCH2 -> InterfaceIDs.PumpType.EOPATCH2
|
||||
PumpType.MEDTRUM_NANO -> InterfaceIDs.PumpType.MEDTRUM
|
||||
PumpType.MEDTRUM_UNTESTED -> InterfaceIDs.PumpType.MEDTRUM_UNTESTED
|
||||
PumpType.CACHE -> InterfaceIDs.PumpType.CACHE
|
||||
}
|
||||
|
|
71
core/ui/src/main/res/drawable/ic_medtrum_128.xml
Normal file
71
core/ui/src/main/res/drawable/ic_medtrum_128.xml
Normal file
|
@ -0,0 +1,71 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:aapt="http://schemas.android.com/aapt"
|
||||
android:width="128dp"
|
||||
android:height="128dp"
|
||||
android:viewportWidth="128"
|
||||
android:viewportHeight="128">
|
||||
<path
|
||||
android:pathData="M94.38,15.26H34.37c-16.33,0 -29.56,13.3 -29.56,29.71v38.69c0,16.41 13.24,29.71 29.56,29.71h60.02c16.33,0 29.56,-13.3 29.56,-29.71V44.97C123.95,28.56 110.71,15.26 94.38,15.26zM56.94,106.39c-1.27,0 -2.3,-1.03 -2.3,-2.3c0,-1.27 1.03,-2.3 2.3,-2.3c1.27,0 2.3,1.03 2.3,2.3C59.24,105.36 58.21,106.39 56.94,106.39zM56.94,26.83c-1.27,0 -2.3,-1.03 -2.3,-2.3c0,-1.27 1.03,-2.3 2.3,-2.3c1.27,0 2.3,1.03 2.3,2.3C59.24,25.8 58.21,26.83 56.94,26.83zM112.17,73.32V55.3c2.43,2.24 3.95,5.45 3.95,9.01S114.6,71.08 112.17,73.32z"
|
||||
android:fillColor="#FFFFFF"/>
|
||||
<path
|
||||
android:pathData="M88.27,99.55c5.2,-0.23 9.45,-0.6 11.93,-1.15c8.84,-1.95 12.24,-6.22 12.24,-13.39v-1.26V44.87v-1.26c0,-7.16 -3.4,-11.44 -12.24,-13.39c-2.47,-0.55 -6.73,-0.92 -11.93,-1.15"
|
||||
android:fillColor="#E0E0E0"/>
|
||||
<path
|
||||
android:pathData="M88.53,29.08c-19.86,-0.79 -52.15,0.13 -58.58,1.57c-8.28,1.85 -12.1,5.19 -13.42,12.92c-0.61,3.54 -0.63,12.31 -0.47,20.75c-0.15,8.44 -0.13,17.2 0.47,20.75c1.32,7.72 5.13,11.07 13.42,12.92c6.43,1.43 38.72,2.36 58.58,1.57"
|
||||
android:fillColor="#AAAAAA"/>
|
||||
<path
|
||||
android:pathData="M88.27,98.82c5.01,-0.22 9.12,-0.59 11.5,-1.12c8.53,-1.91 11.81,-6.09 11.81,-13.11v-1.24V45.27V44.03c0,-7.01 -3.28,-11.2 -11.81,-13.11c-2.38,-0.54 -6.49,-0.9 -11.5,-1.12"
|
||||
android:fillColor="#EAEAEA"/>
|
||||
<path
|
||||
android:pathData="M88.53,29.81c-19.57,-0.77 -51.37,0.13 -57.7,1.53c-8.16,1.81 -11.91,5.09 -13.22,12.65c-0.6,3.47 -0.62,12.05 -0.47,20.32c-0.15,8.27 -0.13,16.85 0.47,20.32c1.3,7.56 5.06,10.84 13.22,12.65c6.33,1.4 38.13,2.31 57.7,1.53"
|
||||
android:fillColor="#B2B2B2"/>
|
||||
<path
|
||||
android:pathData="M88.27,97.88c4.75,-0.22 8.64,-0.57 10.9,-1.09c8.08,-1.86 11.19,-5.93 11.19,-12.75v-1.2V45.78v-1.2c0,-6.82 -3.11,-10.9 -11.19,-12.75c-2.26,-0.52 -6.15,-0.87 -10.9,-1.09"
|
||||
android:fillColor="#F0F0F0"/>
|
||||
<path
|
||||
android:pathData="M88.53,30.75c-19.15,-0.75 -50.27,0.12 -56.47,1.49c-7.99,1.76 -11.66,4.95 -12.93,12.31c-0.58,3.38 -0.6,11.72 -0.46,19.77c-0.15,8.04 -0.13,16.39 0.46,19.77c1.27,7.36 4.95,10.54 12.93,12.31c6.19,1.37 37.32,2.24 56.47,1.49"
|
||||
android:fillColor="#B9B9B9"/>
|
||||
<path
|
||||
android:pathData="M88.27,96.22c4.24,-0.21 7.72,-0.55 9.73,-1.04c7.22,-1.77 9.99,-5.64 9.99,-12.12v-1.14V46.7v-1.14c0,-6.49 -2.78,-10.36 -9.99,-12.12c-2.02,-0.5 -5.49,-0.83 -9.73,-1.04"
|
||||
android:fillColor="#F4F4F4"/>
|
||||
<path
|
||||
android:pathData="M88.53,32.4c-18.73,-0.71 -49.17,0.12 -55.23,1.42c-7.81,1.67 -11.4,4.7 -12.65,11.7c-0.57,3.21 -0.59,11.15 -0.45,18.79c-0.14,7.65 -0.13,15.58 0.45,18.79c1.25,6.99 4.84,10.02 12.65,11.7c6.06,1.3 36.5,2.13 55.23,1.42"
|
||||
android:fillColor="#BEBEBE"/>
|
||||
<path
|
||||
android:pathData="M59.7,75.53l17.16,0l0,-1.29l10.31,0l0,-19.86l-10.31,0l0,-1.3l-17.16,0"
|
||||
android:strokeWidth="0.4252"
|
||||
android:strokeColor="#9D9DA0">
|
||||
<aapt:attr name="android:fillColor">
|
||||
<gradient
|
||||
android:startX="59.7"
|
||||
android:startY="64.31"
|
||||
android:endX="87.16"
|
||||
android:endY="64.31"
|
||||
android:type="linear">
|
||||
<item android:offset="0" android:color="#FFBBBDBF"/>
|
||||
<item android:offset="0.12" android:color="#FFB5B7B9"/>
|
||||
<item android:offset="0.51" android:color="#FFB5B7B9"/>
|
||||
<item android:offset="0.58" android:color="#FFB5B7B9"/>
|
||||
<item android:offset="1" android:color="#FF929497"/>
|
||||
</gradient>
|
||||
</aapt:attr>
|
||||
</path>
|
||||
<path
|
||||
android:pathData="M90.39,68.37c0,1.84 -1.43,3.32 -3.2,3.32H72.75c-1.77,0 -3.2,-1.49 -3.2,-3.32v-8.12c0,-1.84 1.43,-3.32 3.2,-3.32h14.45c1.77,0 3.2,1.49 3.2,3.32V68.37z"
|
||||
android:strokeWidth="0.4252"
|
||||
android:fillColor="#D0D2D3"
|
||||
android:strokeColor="#A3A3A3"/>
|
||||
<path
|
||||
android:pathData="M84.17,74.54c0,4.39 -0.05,4.45 3.63,4.45l0,0c4.39,0 7.95,-3.56 7.95,-7.95v-13.47c0,-4.39 -3.56,-7.95 -7.95,-7.95l0,0c-3.68,0 -3.63,0.1 -3.63,4.49V74.54z"
|
||||
android:strokeWidth="0.2835"
|
||||
android:fillColor="#F4F4F4"
|
||||
android:strokeColor="#C1C1C1"/>
|
||||
<path
|
||||
android:pathData="M94.57,67.68c0,0.83 -0.68,1.51 -1.51,1.51l0,0c-0.83,0 -1.51,-0.68 -1.51,-1.51v-6.74c0,-0.83 0.68,-1.51 1.51,-1.51l0,0c0.83,0 1.51,0.68 1.51,1.51V67.68z"
|
||||
android:strokeWidth="0.2835"
|
||||
android:fillColor="#F1F1F2"
|
||||
android:strokeColor="#B2B2B2"/>
|
||||
<path
|
||||
android:pathData="M94.29,61.74c0,0.68 -0.55,1.23 -1.23,1.23l0,0c-0.68,0 -1.23,-0.55 -1.23,-1.23l0,0c0,-0.68 0.55,-1.23 1.23,-1.23l0,0C93.74,60.51 94.29,61.06 94.29,61.74L94.29,61.74z"
|
||||
android:fillColor="#231F20"/>
|
||||
</vector>
|
|
@ -393,6 +393,9 @@
|
|||
<string name="carbs_g">CARBS %1$d g</string>
|
||||
<string name="extended_bolus_u_min">EXTENDED BOLUS %1$.2f U %2$d min</string>
|
||||
<string name="load_events">LOAD EVENTS</string>
|
||||
<string name="clear_alarms">CLEAR ALARMS</string>
|
||||
<string name="deactivate">DEACTIVATE</string>
|
||||
<string name="update_time">UPDATE TIME</string>
|
||||
<string name="load_history">LOAD HISTORY %1$d</string>
|
||||
<string name="load_tdds">LOAD TDDs</string>
|
||||
<string name="set_profile">SET PROFILE</string>
|
||||
|
|
|
@ -21,7 +21,7 @@ dependencies {
|
|||
implementation project(':app-wear-shared:shared')
|
||||
|
||||
//Firebase
|
||||
api platform('com.google.firebase:firebase-bom:32.2.0')
|
||||
api platform('com.google.firebase:firebase-bom:32.2.2')
|
||||
api "com.google.firebase:firebase-analytics-ktx"
|
||||
api "com.google.firebase:firebase-crashlytics-ktx"
|
||||
// StatsActivity not in use now
|
||||
|
|
|
@ -71,6 +71,10 @@ files:
|
|||
translation: /pump/danars/src/main/res/values-%android_code%/strings.xml
|
||||
- source: /pump/medtronic/src/main/res/values/strings.xml
|
||||
translation: /pump/medtronic/src/main/res/values-%android_code%/strings.xml
|
||||
- source: /pump/medtrum/src/main/res/values/strings.xml
|
||||
translation: /pump/medtrum/src/main/res/values-%android_code%/strings.xml
|
||||
- source: /pump/medtrum/src/main/res/values/arrays.xml
|
||||
translation: /pump/medtrum/src/main/res/values-%android_code%/arrays.xml
|
||||
- source: /pump/omnipod-common/src/main/res/values/strings.xml
|
||||
translation: /pump/omnipod-common/src/main/res/values-%android_code%/strings.xml
|
||||
- source: /pump/omnipod-dash/src/main/res/values/strings.xml
|
||||
|
|
|
@ -5,6 +5,7 @@ import androidx.room.Entity
|
|||
import androidx.room.Index
|
||||
import androidx.room.PrimaryKey
|
||||
import info.nightscout.database.entities.embedments.InterfaceIDs
|
||||
import info.nightscout.database.entities.interfaces.DBEntry
|
||||
import info.nightscout.database.entities.interfaces.DBEntryWithTime
|
||||
import java.util.TimeZone
|
||||
|
||||
|
@ -17,7 +18,7 @@ import java.util.TimeZone
|
|||
])
|
||||
data class DeviceStatus(
|
||||
@PrimaryKey(autoGenerate = true)
|
||||
var id: Long = 0,
|
||||
override var id: Long = 0,
|
||||
@Embedded
|
||||
var interfaceIDs_backing: InterfaceIDs? = null,
|
||||
override var timestamp: Long,
|
||||
|
@ -31,7 +32,7 @@ data class DeviceStatus(
|
|||
var isCharging: Boolean?,
|
||||
var configuration: String? = null
|
||||
|
||||
) : DBEntryWithTime {
|
||||
) : DBEntry, DBEntryWithTime {
|
||||
|
||||
var interfaceIDs: InterfaceIDs
|
||||
get() {
|
||||
|
|
|
@ -43,6 +43,8 @@ data class InterfaceIDs(
|
|||
MDI,
|
||||
DIACONN_G8,
|
||||
EOPATCH2,
|
||||
MEDTRUM,
|
||||
MEDTRUM_UNTESTED,
|
||||
USER,
|
||||
CACHE;
|
||||
|
||||
|
|
|
@ -254,6 +254,7 @@ import kotlin.math.roundToInt
|
|||
|
||||
fun insert(word: UserEntry) {
|
||||
database.userEntryDao.insert(word)
|
||||
changeSubject.onNext(mutableListOf(word)) // Not TraceableDao
|
||||
}
|
||||
|
||||
// PROFILE SWITCH
|
||||
|
@ -712,8 +713,10 @@ import kotlin.math.roundToInt
|
|||
database.bolusCalculatorResultDao.getLastId()
|
||||
|
||||
// DEVICE STATUS
|
||||
fun insert(deviceStatus: DeviceStatus): Long =
|
||||
fun insert(deviceStatus: DeviceStatus) {
|
||||
database.deviceStatusDao.insert(deviceStatus)
|
||||
changeSubject.onNext(mutableListOf(deviceStatus)) // Not TraceableDao
|
||||
}
|
||||
|
||||
/*
|
||||
* returns a Pair of the next entity to sync and the ID of the "update".
|
||||
|
@ -727,10 +730,6 @@ import kotlin.math.roundToInt
|
|||
database.deviceStatusDao.getNextModifiedOrNewAfter(id)
|
||||
.subscribeOn(Schedulers.io())
|
||||
|
||||
fun getModifiedDeviceStatusDataFromId(lastId: Long): Single<List<DeviceStatus>> =
|
||||
database.deviceStatusDao.getModifiedFrom(lastId)
|
||||
.subscribeOn(Schedulers.io())
|
||||
|
||||
fun getLastDeviceStatusId(): Long? =
|
||||
database.deviceStatusDao.getLastId()
|
||||
|
||||
|
|
|
@ -3,6 +3,7 @@ package info.nightscout.implementation.db
|
|||
import android.content.Context
|
||||
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.Food
|
||||
|
@ -15,6 +16,7 @@ import info.nightscout.database.entities.TherapyEvent
|
|||
import info.nightscout.database.impl.AppRepository
|
||||
import info.nightscout.interfaces.ui.UiInteraction
|
||||
import info.nightscout.rx.bus.RxBus
|
||||
import info.nightscout.rx.events.EventDeviceStatusChange
|
||||
import info.nightscout.rx.events.EventEffectiveProfileSwitchChanged
|
||||
import info.nightscout.rx.events.EventExtendedBolusChange
|
||||
import info.nightscout.rx.events.EventFoodDatabaseChanged
|
||||
|
@ -109,5 +111,9 @@ class CompatDBHelper @Inject constructor(
|
|||
aapsLogger.debug(LTag.DATABASE, "Firing EventOfflineChange $oe")
|
||||
rxBus.send(EventOfflineChange())
|
||||
}
|
||||
it.filterIsInstance<DeviceStatus>().firstOrNull()?.let { ds ->
|
||||
aapsLogger.debug(LTag.DATABASE, "Firing EventDeviceStatusChange $ds")
|
||||
rxBus.send(EventDeviceStatusChange())
|
||||
}
|
||||
}
|
||||
}
|
|
@ -14,12 +14,15 @@ import info.nightscout.implementation.queue.commands.CommandTempBasalPercent
|
|||
import info.nightscout.implementation.queue.commands.CommandBolus
|
||||
import info.nightscout.implementation.queue.commands.CommandCancelExtendedBolus
|
||||
import info.nightscout.implementation.queue.commands.CommandCancelTempBasal
|
||||
import info.nightscout.implementation.queue.commands.CommandClearAlarms
|
||||
import info.nightscout.implementation.queue.commands.CommandCustomCommand
|
||||
import info.nightscout.implementation.queue.commands.CommandDeactivate
|
||||
import info.nightscout.implementation.queue.commands.CommandExtendedBolus
|
||||
import info.nightscout.implementation.queue.commands.CommandInsightSetTBROverNotification
|
||||
import info.nightscout.implementation.queue.commands.CommandLoadEvents
|
||||
import info.nightscout.implementation.queue.commands.CommandLoadHistory
|
||||
import info.nightscout.implementation.queue.commands.CommandLoadTDDs
|
||||
import info.nightscout.implementation.queue.commands.CommandUpdateTime
|
||||
|
||||
@Module
|
||||
@Suppress("unused")
|
||||
|
@ -32,6 +35,9 @@ abstract class CommandQueueModule {
|
|||
@ContributesAndroidInjector abstract fun commandExtendedBolusInjector(): CommandExtendedBolus
|
||||
@ContributesAndroidInjector abstract fun commandInsightSetTBROverNotificationInjector(): CommandInsightSetTBROverNotification
|
||||
@ContributesAndroidInjector abstract fun commandLoadEventsInjector(): CommandLoadEvents
|
||||
@ContributesAndroidInjector abstract fun commandClearAlarmsInjector(): CommandClearAlarms
|
||||
@ContributesAndroidInjector abstract fun commandDeactivateInjector(): CommandDeactivate
|
||||
@ContributesAndroidInjector abstract fun commandUpdateTimeInjector(): CommandUpdateTime
|
||||
@ContributesAndroidInjector abstract fun commandLoadHistoryInjector(): CommandLoadHistory
|
||||
@ContributesAndroidInjector abstract fun commandLoadTDDsInjector(): CommandLoadTDDs
|
||||
@ContributesAndroidInjector abstract fun commandReadStatusInjector(): CommandReadStatus
|
||||
|
|
|
@ -1,11 +1,15 @@
|
|||
package info.nightscout.implementation.pump
|
||||
|
||||
import com.google.gson.Gson
|
||||
import com.google.gson.reflect.TypeToken
|
||||
import info.nightscout.androidaps.annotations.OpenForTesting
|
||||
import info.nightscout.implementation.R
|
||||
import info.nightscout.interfaces.pump.DetailedBolusInfo
|
||||
import info.nightscout.interfaces.pump.DetailedBolusInfoStorage
|
||||
import info.nightscout.rx.logging.AAPSLogger
|
||||
import info.nightscout.shared.sharedPreferences.SP
|
||||
import info.nightscout.rx.logging.LTag
|
||||
import info.nightscout.shared.interfaces.ResourceHelper
|
||||
import info.nightscout.shared.utils.T
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
|
@ -14,10 +18,12 @@ import kotlin.math.abs
|
|||
@OpenForTesting
|
||||
@Singleton
|
||||
class DetailedBolusInfoStorageImpl @Inject constructor(
|
||||
val aapsLogger: AAPSLogger
|
||||
val aapsLogger: AAPSLogger,
|
||||
val sp: SP,
|
||||
val rh: ResourceHelper
|
||||
) : DetailedBolusInfoStorage {
|
||||
|
||||
val store = ArrayList<DetailedBolusInfo>()
|
||||
val store = loadStore()
|
||||
|
||||
fun DetailedBolusInfo.toJsonString(): String = Gson().toJson(this)
|
||||
|
||||
|
@ -25,6 +31,7 @@ class DetailedBolusInfoStorageImpl @Inject constructor(
|
|||
override fun add(detailedBolusInfo: DetailedBolusInfo) {
|
||||
aapsLogger.debug("Stored bolus info: ${detailedBolusInfo.toJsonString()}")
|
||||
store.add(detailedBolusInfo)
|
||||
saveStore()
|
||||
}
|
||||
|
||||
@Synchronized
|
||||
|
@ -36,6 +43,7 @@ class DetailedBolusInfoStorageImpl @Inject constructor(
|
|||
if (bolusTime > d.timestamp - T.mins(1).msecs() && bolusTime < d.timestamp + T.mins(1).msecs() && abs(store[i].insulin - bolus) < 0.01) {
|
||||
aapsLogger.debug(LTag.PUMP, "Using & removing bolus info for time $bolusTime: ${store[i]}")
|
||||
store.removeAt(i)
|
||||
saveStore()
|
||||
return d
|
||||
}
|
||||
}
|
||||
|
@ -45,6 +53,7 @@ class DetailedBolusInfoStorageImpl @Inject constructor(
|
|||
if (bolusTime > d.timestamp - T.mins(1).msecs() && bolusTime < d.timestamp + T.mins(1).msecs() && bolus <= store[i].insulin + 0.01) {
|
||||
aapsLogger.debug(LTag.PUMP, "Using TIME-ONLY & removing bolus info for time $bolusTime: ${store[i]}")
|
||||
store.removeAt(i)
|
||||
saveStore()
|
||||
return d
|
||||
}
|
||||
}
|
||||
|
@ -61,4 +70,24 @@ class DetailedBolusInfoStorageImpl @Inject constructor(
|
|||
aapsLogger.debug(LTag.PUMP, "Bolus info not found for time $bolusTime")
|
||||
return null
|
||||
}
|
||||
|
||||
private fun saveStore() {
|
||||
var lastTwoEntries = store
|
||||
// Only save last two entries, to avoid too much data in preferences
|
||||
if (store.size > 2) {
|
||||
lastTwoEntries = ArrayList(store.subList(store.size - 2, store.size))
|
||||
}
|
||||
val jsonString = Gson().toJson(lastTwoEntries)
|
||||
sp.putString(rh.gs(R.string.key_bolus_storage), jsonString)
|
||||
}
|
||||
|
||||
private fun loadStore(): ArrayList<DetailedBolusInfo> {
|
||||
val jsonString = sp.getString(rh.gs(R.string.key_bolus_storage), "")
|
||||
return if (jsonString.isNotEmpty()) {
|
||||
val type = object : TypeToken<List<DetailedBolusInfo>>() {}.type
|
||||
Gson().fromJson(jsonString, type)
|
||||
} else {
|
||||
ArrayList()
|
||||
}
|
||||
}
|
||||
}
|
|
@ -22,7 +22,9 @@ import info.nightscout.implementation.R
|
|||
import info.nightscout.implementation.queue.commands.CommandBolus
|
||||
import info.nightscout.implementation.queue.commands.CommandCancelExtendedBolus
|
||||
import info.nightscout.implementation.queue.commands.CommandCancelTempBasal
|
||||
import info.nightscout.implementation.queue.commands.CommandClearAlarms
|
||||
import info.nightscout.implementation.queue.commands.CommandCustomCommand
|
||||
import info.nightscout.implementation.queue.commands.CommandDeactivate
|
||||
import info.nightscout.implementation.queue.commands.CommandExtendedBolus
|
||||
import info.nightscout.implementation.queue.commands.CommandInsightSetTBROverNotification
|
||||
import info.nightscout.implementation.queue.commands.CommandLoadEvents
|
||||
|
@ -36,6 +38,7 @@ import info.nightscout.implementation.queue.commands.CommandStartPump
|
|||
import info.nightscout.implementation.queue.commands.CommandStopPump
|
||||
import info.nightscout.implementation.queue.commands.CommandTempBasalAbsolute
|
||||
import info.nightscout.implementation.queue.commands.CommandTempBasalPercent
|
||||
import info.nightscout.implementation.queue.commands.CommandUpdateTime
|
||||
import info.nightscout.interfaces.AndroidPermission
|
||||
import info.nightscout.interfaces.Config
|
||||
import info.nightscout.interfaces.constraints.Constraint
|
||||
|
@ -535,6 +538,46 @@ class CommandQueueImplementation @Inject constructor(
|
|||
return true
|
||||
}
|
||||
|
||||
// returns true if command is queued
|
||||
override fun clearAlarms(callback: Callback?): Boolean {
|
||||
if (isRunning(CommandType.CLEAR_ALARMS)) {
|
||||
callback?.result(executingNowError())?.run()
|
||||
return false
|
||||
}
|
||||
// remove all unfinished
|
||||
removeAll(CommandType.CLEAR_ALARMS)
|
||||
// add new command to queue
|
||||
add(CommandClearAlarms(injector, callback))
|
||||
notifyAboutNewCommand()
|
||||
return true
|
||||
}
|
||||
|
||||
override fun deactivate(callback: Callback?): Boolean {
|
||||
if (isRunning(CommandType.DEACTIVATE)) {
|
||||
callback?.result(executingNowError())?.run()
|
||||
return false
|
||||
}
|
||||
// remove all unfinished
|
||||
removeAll(CommandType.DEACTIVATE)
|
||||
// add new command to queue
|
||||
add(CommandDeactivate(injector, callback))
|
||||
notifyAboutNewCommand()
|
||||
return true
|
||||
}
|
||||
|
||||
override fun updateTime(callback: Callback?): Boolean {
|
||||
if (isRunning(CommandType.UPDATE_TIME)) {
|
||||
callback?.result(executingNowError())?.run()
|
||||
return false
|
||||
}
|
||||
// remove all unfinished
|
||||
removeAll(CommandType.UPDATE_TIME)
|
||||
// add new command to queue
|
||||
add(CommandUpdateTime(injector, callback))
|
||||
notifyAboutNewCommand()
|
||||
return true
|
||||
}
|
||||
|
||||
override fun customCommand(customCommand: CustomCommand, callback: Callback?): Boolean {
|
||||
if (isCustomCommandInQueue(customCommand.javaClass)) {
|
||||
callback?.result(executingNowError())?.run()
|
||||
|
|
|
@ -0,0 +1,39 @@
|
|||
package info.nightscout.implementation.queue.commands
|
||||
|
||||
import dagger.android.HasAndroidInjector
|
||||
import info.nightscout.interfaces.plugin.ActivePlugin
|
||||
import info.nightscout.interfaces.pump.Dana
|
||||
import info.nightscout.interfaces.pump.Diaconn
|
||||
import info.nightscout.interfaces.pump.Medtrum
|
||||
import info.nightscout.interfaces.pump.PumpEnactResult
|
||||
import info.nightscout.interfaces.queue.Callback
|
||||
import info.nightscout.interfaces.queue.Command
|
||||
import info.nightscout.rx.logging.LTag
|
||||
import javax.inject.Inject
|
||||
|
||||
class CommandClearAlarms(
|
||||
injector: HasAndroidInjector,
|
||||
callback: Callback?
|
||||
) : Command(injector, CommandType.CLEAR_ALARMS, callback) {
|
||||
|
||||
@Inject lateinit var activePlugin: ActivePlugin
|
||||
|
||||
override fun execute() {
|
||||
val pump = activePlugin.activePump
|
||||
|
||||
if (pump is Medtrum) {
|
||||
val medtrumPump = pump as Medtrum
|
||||
val r = medtrumPump.clearAlarms()
|
||||
aapsLogger.debug(LTag.PUMPQUEUE, "Result success: ${r.success} enacted: ${r.enacted}")
|
||||
callback?.result(r)?.run()
|
||||
}
|
||||
}
|
||||
|
||||
override fun status(): String = rh.gs(info.nightscout.core.ui.R.string.clear_alarms)
|
||||
|
||||
override fun log(): String = "CLEAR ALARMS"
|
||||
override fun cancel() {
|
||||
aapsLogger.debug(LTag.PUMPQUEUE, "Result cancel")
|
||||
callback?.result(PumpEnactResult(injector).success(false).comment(info.nightscout.core.ui.R.string.connectiontimedout))?.run()
|
||||
}
|
||||
}
|
|
@ -0,0 +1,39 @@
|
|||
package info.nightscout.implementation.queue.commands
|
||||
|
||||
import dagger.android.HasAndroidInjector
|
||||
import info.nightscout.interfaces.plugin.ActivePlugin
|
||||
import info.nightscout.interfaces.pump.Dana
|
||||
import info.nightscout.interfaces.pump.Diaconn
|
||||
import info.nightscout.interfaces.pump.Medtrum
|
||||
import info.nightscout.interfaces.pump.PumpEnactResult
|
||||
import info.nightscout.interfaces.queue.Callback
|
||||
import info.nightscout.interfaces.queue.Command
|
||||
import info.nightscout.rx.logging.LTag
|
||||
import javax.inject.Inject
|
||||
|
||||
class CommandDeactivate(
|
||||
injector: HasAndroidInjector,
|
||||
callback: Callback?
|
||||
) : Command(injector, CommandType.DEACTIVATE, callback) {
|
||||
|
||||
@Inject lateinit var activePlugin: ActivePlugin
|
||||
|
||||
override fun execute() {
|
||||
val pump = activePlugin.activePump
|
||||
|
||||
if (pump is Medtrum) {
|
||||
val medtrumPump = pump as Medtrum
|
||||
val r = medtrumPump.deactivate()
|
||||
aapsLogger.debug(LTag.PUMPQUEUE, "Result success: ${r.success} enacted: ${r.enacted}")
|
||||
callback?.result(r)?.run()
|
||||
}
|
||||
}
|
||||
|
||||
override fun status(): String = rh.gs(info.nightscout.core.ui.R.string.deactivate)
|
||||
|
||||
override fun log(): String = "DEACTIVATE"
|
||||
override fun cancel() {
|
||||
aapsLogger.debug(LTag.PUMPQUEUE, "Result cancel")
|
||||
callback?.result(PumpEnactResult(injector).success(false).comment(info.nightscout.core.ui.R.string.connectiontimedout))?.run()
|
||||
}
|
||||
}
|
|
@ -4,6 +4,7 @@ import dagger.android.HasAndroidInjector
|
|||
import info.nightscout.interfaces.plugin.ActivePlugin
|
||||
import info.nightscout.interfaces.pump.Dana
|
||||
import info.nightscout.interfaces.pump.Diaconn
|
||||
import info.nightscout.interfaces.pump.Medtrum
|
||||
import info.nightscout.interfaces.pump.PumpEnactResult
|
||||
import info.nightscout.interfaces.queue.Callback
|
||||
import info.nightscout.interfaces.queue.Command
|
||||
|
@ -32,6 +33,13 @@ class CommandLoadEvents(
|
|||
aapsLogger.debug(LTag.PUMPQUEUE, "Result success: ${r.success} enacted: ${r.enacted}")
|
||||
callback?.result(r)?.run()
|
||||
}
|
||||
|
||||
if (pump is Medtrum) {
|
||||
val medtrumPump = pump as Medtrum
|
||||
val r = medtrumPump.loadEvents()
|
||||
aapsLogger.debug(LTag.PUMPQUEUE, "Result success: ${r.success} enacted: ${r.enacted}")
|
||||
callback?.result(r)?.run()
|
||||
}
|
||||
}
|
||||
|
||||
override fun status(): String = rh.gs(info.nightscout.core.ui.R.string.load_events)
|
||||
|
|
|
@ -4,6 +4,7 @@ import dagger.android.HasAndroidInjector
|
|||
import info.nightscout.interfaces.plugin.ActivePlugin
|
||||
import info.nightscout.interfaces.pump.Dana
|
||||
import info.nightscout.interfaces.pump.Diaconn
|
||||
import info.nightscout.interfaces.pump.Medtrum
|
||||
import info.nightscout.interfaces.pump.PumpEnactResult
|
||||
import info.nightscout.interfaces.queue.Callback
|
||||
import info.nightscout.interfaces.queue.Command
|
||||
|
@ -30,6 +31,12 @@ class CommandSetUserSettings(
|
|||
aapsLogger.debug(LTag.PUMPQUEUE, "Result success: ${r.success} enacted: ${r.enacted}")
|
||||
callback?.result(r)?.run()
|
||||
}
|
||||
|
||||
if (pump is Medtrum) {
|
||||
val r = pump.setUserOptions()
|
||||
aapsLogger.debug(LTag.PUMPQUEUE, "Result success: ${r.success} enacted: ${r.enacted}")
|
||||
callback?.result(r)?.run()
|
||||
}
|
||||
}
|
||||
|
||||
override fun status(): String = rh.gs(info.nightscout.core.ui.R.string.set_user_settings)
|
||||
|
|
|
@ -0,0 +1,39 @@
|
|||
package info.nightscout.implementation.queue.commands
|
||||
|
||||
import dagger.android.HasAndroidInjector
|
||||
import info.nightscout.interfaces.plugin.ActivePlugin
|
||||
import info.nightscout.interfaces.pump.Dana
|
||||
import info.nightscout.interfaces.pump.Diaconn
|
||||
import info.nightscout.interfaces.pump.Medtrum
|
||||
import info.nightscout.interfaces.pump.PumpEnactResult
|
||||
import info.nightscout.interfaces.queue.Callback
|
||||
import info.nightscout.interfaces.queue.Command
|
||||
import info.nightscout.rx.logging.LTag
|
||||
import javax.inject.Inject
|
||||
|
||||
class CommandUpdateTime(
|
||||
injector: HasAndroidInjector,
|
||||
callback: Callback?
|
||||
) : Command(injector, CommandType.UPDATE_TIME, callback) {
|
||||
|
||||
@Inject lateinit var activePlugin: ActivePlugin
|
||||
|
||||
override fun execute() {
|
||||
val pump = activePlugin.activePump
|
||||
|
||||
if (pump is Medtrum) {
|
||||
val medtrumPump = pump as Medtrum
|
||||
val r = medtrumPump.updateTime()
|
||||
aapsLogger.debug(LTag.PUMPQUEUE, "Result success: ${r.success} enacted: ${r.enacted}")
|
||||
callback?.result(r)?.run()
|
||||
}
|
||||
}
|
||||
|
||||
override fun status(): String = rh.gs(info.nightscout.core.ui.R.string.update_time)
|
||||
|
||||
override fun log(): String = "UPDATE TIME"
|
||||
override fun cancel() {
|
||||
aapsLogger.debug(LTag.PUMPQUEUE, "Result cancel")
|
||||
callback?.result(PumpEnactResult(injector).success(false).comment(info.nightscout.core.ui.R.string.connectiontimedout))?.run()
|
||||
}
|
||||
}
|
|
@ -1,5 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="key_bolus_storage" translatable="false">key_bolus_storage</string>
|
||||
<string name="bg_label">BG</string>
|
||||
|
||||
<string name="executing_right_now">Command is executed right now</string>
|
||||
|
|
|
@ -1,14 +1,22 @@
|
|||
package info.nightscout.implementation.pump
|
||||
|
||||
import info.nightscout.androidaps.TestBase
|
||||
import info.nightscout.implementation.R
|
||||
import info.nightscout.interfaces.pump.DetailedBolusInfo
|
||||
import info.nightscout.shared.interfaces.ResourceHelper
|
||||
import info.nightscout.shared.sharedPreferences.SP
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Assert.assertNull
|
||||
import org.junit.jupiter.api.BeforeEach
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.mockito.Mock
|
||||
import org.mockito.Mockito
|
||||
|
||||
class DetailedBolusInfoStorageTest : TestBase() {
|
||||
|
||||
@Mock lateinit var sp: SP
|
||||
@Mock lateinit var rh: ResourceHelper
|
||||
|
||||
private val info1 = DetailedBolusInfo()
|
||||
private val info2 = DetailedBolusInfo()
|
||||
private val info3 = DetailedBolusInfo()
|
||||
|
@ -26,7 +34,8 @@ class DetailedBolusInfoStorageTest : TestBase() {
|
|||
|
||||
@BeforeEach
|
||||
fun prepare() {
|
||||
detailedBolusInfoStorage = DetailedBolusInfoStorageImpl(aapsLogger)
|
||||
Mockito.`when`(sp.getString(rh.gs(R.string.key_bolus_storage), "")).thenReturn("")
|
||||
detailedBolusInfoStorage = DetailedBolusInfoStorageImpl(aapsLogger, sp, rh)
|
||||
}
|
||||
|
||||
private fun setUp() {
|
||||
|
|
|
@ -238,6 +238,19 @@ class CommandQueueImplementationTest : TestBaseWithProfile() {
|
|||
// add loadEvents
|
||||
commandQueue.loadEvents(null)
|
||||
Assertions.assertEquals(4, commandQueue.size())
|
||||
|
||||
// add clearAlarms
|
||||
commandQueue.clearAlarms(null)
|
||||
Assertions.assertEquals(5, commandQueue.size())
|
||||
|
||||
// add deactivate
|
||||
commandQueue.deactivate(null)
|
||||
Assertions.assertEquals(6, commandQueue.size())
|
||||
|
||||
// add updateTime
|
||||
commandQueue.updateTime(null)
|
||||
Assertions.assertEquals(7, commandQueue.size())
|
||||
|
||||
commandQueue.clear()
|
||||
commandQueue.tempBasalAbsolute(0.0, 30, true, validProfile, PumpSync.TemporaryBasalType.NORMAL, null)
|
||||
commandQueue.pickup()
|
||||
|
@ -354,6 +367,54 @@ class CommandQueueImplementationTest : TestBaseWithProfile() {
|
|||
Assertions.assertEquals(1, commandQueue.size())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun isClearAlarmsCommandInQueue() {
|
||||
// given
|
||||
Assertions.assertEquals(0, commandQueue.size())
|
||||
|
||||
// when
|
||||
commandQueue.clearAlarms(null)
|
||||
|
||||
// then
|
||||
Assertions.assertTrue(commandQueue.isLastScheduled(Command.CommandType.CLEAR_ALARMS))
|
||||
Assertions.assertEquals(1, commandQueue.size())
|
||||
// next should be ignored
|
||||
commandQueue.clearAlarms(null)
|
||||
Assertions.assertEquals(1, commandQueue.size())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun isDeactivateCommandInQueue() {
|
||||
// given
|
||||
Assertions.assertEquals(0, commandQueue.size())
|
||||
|
||||
// when
|
||||
commandQueue.deactivate(null)
|
||||
|
||||
// then
|
||||
Assertions.assertTrue(commandQueue.isLastScheduled(Command.CommandType.DEACTIVATE))
|
||||
Assertions.assertEquals(1, commandQueue.size())
|
||||
// next should be ignored
|
||||
commandQueue.deactivate(null)
|
||||
Assertions.assertEquals(1, commandQueue.size())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun isUpdateTimeCommandInQueue() {
|
||||
// given
|
||||
Assertions.assertEquals(0, commandQueue.size())
|
||||
|
||||
// when
|
||||
commandQueue.updateTime(null)
|
||||
|
||||
// then
|
||||
Assertions.assertTrue(commandQueue.isLastScheduled(Command.CommandType.UPDATE_TIME))
|
||||
Assertions.assertEquals(1, commandQueue.size())
|
||||
// next should be ignored
|
||||
commandQueue.updateTime(null)
|
||||
Assertions.assertEquals(1, commandQueue.size())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun isLoadTDDsCommandInQueue() {
|
||||
// given
|
||||
|
|
|
@ -35,6 +35,7 @@ import info.nightscout.interfaces.plugin.ActivePlugin
|
|||
import info.nightscout.interfaces.plugin.PluginBase
|
||||
import info.nightscout.interfaces.plugin.PluginType
|
||||
import info.nightscout.interfaces.profile.ProfileFunction
|
||||
import info.nightscout.interfaces.pump.Medtrum
|
||||
import info.nightscout.interfaces.pump.OmnipodDash
|
||||
import info.nightscout.interfaces.pump.OmnipodEros
|
||||
import info.nightscout.interfaces.queue.CommandQueue
|
||||
|
@ -319,23 +320,24 @@ class SWDefinition @Inject constructor(
|
|||
.text(R.string.readstatus)
|
||||
.action { commandQueue.readStatus(rh.gs(info.nightscout.core.ui.R.string.clicked_connect_to_pump), null) }
|
||||
.visibility {
|
||||
// Hide for Omnipod, because as we don't require a Pod to be paired in the setup wizard,
|
||||
// Hide for Omnipod and Medtrum, because as we don't require a Pod/Patch to be paired in the setup wizard,
|
||||
// Getting the status might not be possible
|
||||
activePlugin.activePump !is OmnipodEros && activePlugin.activePump !is OmnipodDash
|
||||
activePlugin.activePump !is OmnipodEros && activePlugin.activePump !is OmnipodDash && activePlugin.activePump !is Medtrum
|
||||
})
|
||||
.add(SWEventListener(injector, EventPumpStatusChanged::class.java)
|
||||
.visibility { activePlugin.activePump !is OmnipodEros && activePlugin.activePump !is OmnipodDash })
|
||||
.visibility { activePlugin.activePump !is OmnipodEros && activePlugin.activePump !is OmnipodDash && activePlugin.activePump !is Medtrum })
|
||||
.validator { isPumpInitialized() }
|
||||
|
||||
private fun isPumpInitialized(): Boolean {
|
||||
val activePump = activePlugin.activePump
|
||||
|
||||
// For Omnipod, activating a Pod can be done after setup through the Omnipod fragment
|
||||
// For the Eros model, consider the pump initialized when a RL has been configured successfully
|
||||
// For Dash model, consider the pump setup without any extra conditions
|
||||
// For Omnipod and Medtrum, activating a Pod/Patch can be done after setup through the pump fragment
|
||||
// For the Eros, consider the pump initialized when a RL has been configured successfully
|
||||
// For all others, consider the pump setup without any extra conditions
|
||||
return activePump.isInitialized()
|
||||
|| (activePump is OmnipodEros && activePump.isRileyLinkReady())
|
||||
|| activePump is OmnipodDash
|
||||
|| activePump is Medtrum
|
||||
}
|
||||
|
||||
private val screenAps
|
||||
|
|
|
@ -6,6 +6,7 @@ import info.nightscout.shared.utils.DateUtil
|
|||
import java.net.DatagramPacket
|
||||
import java.net.DatagramSocket
|
||||
import java.net.InetAddress
|
||||
import java.security.SecureRandom
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
|
||||
|
@ -195,6 +196,6 @@ class SntpClient @Inject constructor(
|
|||
buffer[offset++] = (fraction shr 16).toByte()
|
||||
buffer[offset++] = (fraction shr 8).toByte()
|
||||
// low order bits should be random data
|
||||
buffer[offset] = (Math.random() * 255.0).toInt().toByte()
|
||||
buffer[offset] = SecureRandom().nextInt(256).toByte()
|
||||
}
|
||||
}
|
|
@ -48,11 +48,15 @@ class ThemeSwitcherPlugin @Inject constructor(
|
|||
}
|
||||
|
||||
fun setThemeMode() {
|
||||
val mode = when (sp.getString(info.nightscout.core.utils.R.string.key_use_dark_mode, "dark")) {
|
||||
val mode = try {
|
||||
when (sp.getString(info.nightscout.core.utils.R.string.key_use_dark_mode, "dark")) {
|
||||
sp.getString(R.string.value_dark_theme, "dark") -> MODE_NIGHT_YES
|
||||
sp.getString(R.string.value_light_theme, "light") -> MODE_NIGHT_NO
|
||||
else -> MODE_NIGHT_FOLLOW_SYSTEM
|
||||
}
|
||||
} catch (ignored: Exception) {
|
||||
MODE_NIGHT_FOLLOW_SYSTEM
|
||||
}
|
||||
AppCompatDelegate.setDefaultNightMode(mode)
|
||||
}
|
||||
|
||||
|
|
|
@ -22,7 +22,7 @@ import info.nightscout.shared.sharedPreferences.SP
|
|||
import info.nightscout.shared.utils.T
|
||||
import io.reactivex.rxjava3.disposables.CompositeDisposable
|
||||
import io.reactivex.rxjava3.kotlin.plusAssign
|
||||
import java.lang.Math.random
|
||||
import java.security.SecureRandom
|
||||
import java.util.Calendar
|
||||
import java.util.GregorianCalendar
|
||||
import javax.inject.Inject
|
||||
|
@ -100,7 +100,7 @@ class RandomBgPlugin @Inject constructor(
|
|||
|
||||
val cal = GregorianCalendar()
|
||||
val currentMinute = cal[Calendar.MINUTE] + (cal[Calendar.HOUR_OF_DAY] % 2) * 60
|
||||
val bgMgdl = min + ((max - min) + (max - min) * sin(currentMinute / period * 2 * PI)) / 2 + (random() - 0.5) * (max - min) * 0.4
|
||||
val bgMgdl = min + ((max - min) + (max - min) * sin(currentMinute / period * 2 * PI)) / 2 + (SecureRandom().nextDouble() - 0.5) * (max - min) * 0.4
|
||||
|
||||
cal[Calendar.MILLISECOND] = 0
|
||||
cal[Calendar.SECOND] = 0
|
||||
|
|
|
@ -11,12 +11,9 @@ 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.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
|
||||
|
@ -24,8 +21,14 @@ 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.DataSyncSelectorV3Impl
|
||||
import info.nightscout.plugins.sync.nsclientV3.workers.*
|
||||
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.tidepool.TidepoolFragment
|
||||
import info.nightscout.plugins.sync.xdrip.DataSyncSelectorXdripImpl
|
||||
import info.nightscout.plugins.sync.xdrip.XdripFragment
|
||||
|
@ -75,8 +78,6 @@ abstract class SyncModule {
|
|||
|
||||
@Binds fun bindProcessedDeviceStatusData(processedDeviceStatusDataImpl: ProcessedDeviceStatusDataImpl): ProcessedDeviceStatusData
|
||||
@Binds fun bindNSSettingsStatus(nsSettingsStatusImpl: NSSettingsStatusImpl): NSSettingsStatus
|
||||
@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
|
||||
|
|
|
@ -123,7 +123,7 @@ class NSClientFragment : DaggerFragment(), MenuProvider, PluginFragment {
|
|||
nsClientPlugin?.listLog?.let {
|
||||
synchronized(it) {
|
||||
it.clear()
|
||||
_binding?.recyclerview?.swapAdapter(RecyclerViewAdapter(it), true)
|
||||
updateLog()
|
||||
}
|
||||
}
|
||||
true
|
||||
|
@ -211,6 +211,7 @@ class NSClientFragment : DaggerFragment(), MenuProvider, PluginFragment {
|
|||
.subscribe({ updateStatus() }, fabricPrivacy::logException)
|
||||
updateStatus()
|
||||
updateQueue()
|
||||
updateLog()
|
||||
}
|
||||
|
||||
@Synchronized
|
||||
|
@ -231,6 +232,9 @@ class NSClientFragment : DaggerFragment(), MenuProvider, PluginFragment {
|
|||
binding.status.text = nsClientPlugin?.status
|
||||
}
|
||||
|
||||
private fun updateLog() {
|
||||
_binding?.recyclerview?.swapAdapter(RecyclerViewAdapter(nsClientPlugin?.listLog ?: arrayListOf()), true)
|
||||
}
|
||||
private inner class RecyclerViewAdapter(private var logList: List<EventNSClientNewLog>) : RecyclerView.Adapter<RecyclerViewAdapter.NsClientLogViewHolder>() {
|
||||
|
||||
override fun onCreateViewHolder(viewGroup: ViewGroup, viewType: Int): NsClientLogViewHolder =
|
||||
|
|
|
@ -0,0 +1,807 @@
|
|||
package info.nightscout.plugins.sync.nsclient
|
||||
|
||||
import info.nightscout.core.utils.waitMillis
|
||||
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.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.events.EventNSClientNewLog
|
||||
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.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.SupervisorJob
|
||||
import kotlinx.coroutines.async
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Singleton
|
||||
class DataSyncSelectorV1 @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
|
||||
) : DataSyncSelector {
|
||||
|
||||
private var scope = CoroutineScope(Dispatchers.IO + SupervisorJob())
|
||||
|
||||
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()
|
||||
|
||||
private var running = false
|
||||
private val sync = Any()
|
||||
override suspend fun doUpload() {
|
||||
synchronized(sync) {
|
||||
if (running) {
|
||||
rxBus.send(EventNSClientNewLog("● RUN", "Already running"))
|
||||
return
|
||||
}
|
||||
running = true
|
||||
}
|
||||
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())
|
||||
val boluses = scope.async { processChangedBoluses() }
|
||||
val carbs = scope.async { processChangedCarbs() }
|
||||
val bcs = scope.async { processChangedBolusCalculatorResults() }
|
||||
val tbs = scope.async { processChangedTemporaryBasals() }
|
||||
val ebs = scope.async { processChangedExtendedBoluses() }
|
||||
val pss = scope.async { processChangedProfileSwitches() }
|
||||
val epss = scope.async { processChangedEffectiveProfileSwitches() }
|
||||
val gvs = scope.async { processChangedGlucoseValues() }
|
||||
val tts = scope.async { processChangedTempTargets() }
|
||||
val foods = scope.async { processChangedFoods() }
|
||||
val tes = scope.async { processChangedTherapyEvents() }
|
||||
val dss = scope.async { processChangedDeviceStatuses() }
|
||||
val oes = scope.async { processChangedOfflineEvents() }
|
||||
val ps = scope.async { processChangedProfileStore() }
|
||||
|
||||
boluses.await()
|
||||
carbs.await()
|
||||
bcs.await()
|
||||
tbs.await()
|
||||
ebs.await()
|
||||
pss.await()
|
||||
epss.await()
|
||||
gvs.await()
|
||||
tts.await()
|
||||
foods.await()
|
||||
tes.await()
|
||||
dss.await()
|
||||
oes.await()
|
||||
ps.await()
|
||||
}
|
||||
rxBus.send(EventNSClientUpdateGuiStatus())
|
||||
running = false
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
private 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)
|
||||
}
|
||||
}
|
||||
|
||||
private 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) {
|
||||
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} ")
|
||||
val dataPair = DataSyncSelector.PairBolus(bolus.first, 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 -> {
|
||||
activePlugin.activeNsClient?.nsAdd("treatments", dataPair, " $startId/$lastDbId")
|
||||
synchronized(dataPair) { dataPair.waitMillis(60000) }
|
||||
cont = dataPair.confirmed
|
||||
}
|
||||
// with nsId = update if it's modified record
|
||||
bolus.first.interfaceIDs.nightscoutId != null && bolus.first.id != bolus.second.id -> {
|
||||
activePlugin.activeNsClient?.nsUpdate("treatments", dataPair, "$startId/$lastDbId")
|
||||
synchronized(dataPair) { dataPair.waitMillis(60000) }
|
||||
cont = dataPair.confirmed
|
||||
}
|
||||
}
|
||||
if (cont) confirmLastBolusIdIfGreater(bolus.second.id)
|
||||
} ?: run {
|
||||
cont = false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private 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)
|
||||
}
|
||||
}
|
||||
|
||||
private 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) {
|
||||
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} ")
|
||||
val dataPair = DataSyncSelector.PairCarbs(carb.first, 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 -> {
|
||||
activePlugin.activeNsClient?.nsAdd("treatments", dataPair, "$startId/$lastDbId")
|
||||
synchronized(dataPair) { dataPair.waitMillis(60000) }
|
||||
cont = dataPair.confirmed
|
||||
}
|
||||
// with nsId = update if it's modified record
|
||||
carb.first.interfaceIDs.nightscoutId != null && carb.first.id != carb.second.id -> {
|
||||
activePlugin.activeNsClient?.nsUpdate("treatments", dataPair, "$startId/$lastDbId")
|
||||
synchronized(dataPair) { dataPair.waitMillis(60000) }
|
||||
cont = dataPair.confirmed
|
||||
}
|
||||
}
|
||||
if (cont) confirmLastCarbsIdIfGreater(carb.second.id)
|
||||
} ?: run {
|
||||
cont = false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private 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)
|
||||
}
|
||||
}
|
||||
|
||||
private 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) {
|
||||
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} ")
|
||||
val dataPair = DataSyncSelector.PairBolusCalculatorResult(bolusCalculatorResult.first, 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 -> {
|
||||
activePlugin.activeNsClient?.nsAdd("treatments", dataPair, "$startId/$lastDbId")
|
||||
synchronized(dataPair) { dataPair.waitMillis(60000) }
|
||||
cont = dataPair.confirmed
|
||||
}
|
||||
// with nsId = update if it's modified record
|
||||
bolusCalculatorResult.first.interfaceIDs.nightscoutId != null && bolusCalculatorResult.first.id != bolusCalculatorResult.second.id -> {
|
||||
activePlugin.activeNsClient?.nsUpdate("treatments", dataPair, "$startId/$lastDbId")
|
||||
synchronized(dataPair) { dataPair.waitMillis(60000) }
|
||||
cont = dataPair.confirmed
|
||||
}
|
||||
}
|
||||
if (cont) confirmLastBolusCalculatorResultsIdIfGreater(bolusCalculatorResult.second.id)
|
||||
} ?: run {
|
||||
cont = false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private 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)
|
||||
}
|
||||
}
|
||||
|
||||
private 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) {
|
||||
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} ")
|
||||
val dataPair = DataSyncSelector.PairTemporaryTarget(tt.first, 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 -> {
|
||||
activePlugin.activeNsClient?.nsAdd("treatments", dataPair, "$startId/$lastDbId")
|
||||
synchronized(dataPair) { dataPair.waitMillis(60000) }
|
||||
cont = dataPair.confirmed
|
||||
}
|
||||
// existing with nsId = update
|
||||
tt.first.interfaceIDs.nightscoutId != null -> {
|
||||
activePlugin.activeNsClient?.nsUpdate("treatments", dataPair, "$startId/$lastDbId")
|
||||
synchronized(dataPair) { dataPair.waitMillis(60000) }
|
||||
cont = dataPair.confirmed
|
||||
}
|
||||
}
|
||||
if (cont) confirmLastTempTargetsIdIfGreater(tt.second.id)
|
||||
} ?: run {
|
||||
cont = false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private 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)
|
||||
}
|
||||
}
|
||||
|
||||
private 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) {
|
||||
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} ")
|
||||
val dataPair = DataSyncSelector.PairFood(food.first, 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 -> {
|
||||
activePlugin.activeNsClient?.nsAdd("food", dataPair, "$startId/$lastDbId")
|
||||
synchronized(dataPair) { dataPair.waitMillis(60000) }
|
||||
cont = dataPair.confirmed
|
||||
}
|
||||
// with nsId = update
|
||||
food.first.interfaceIDs.nightscoutId != null -> {
|
||||
activePlugin.activeNsClient?.nsUpdate("food", dataPair, "$startId/$lastDbId")
|
||||
synchronized(dataPair) { dataPair.waitMillis(60000) }
|
||||
cont = dataPair.confirmed
|
||||
}
|
||||
}
|
||||
if (cont) confirmLastFoodIdIfGreater(food.second.id)
|
||||
} ?: run {
|
||||
cont = false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private 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)
|
||||
}
|
||||
}
|
||||
|
||||
private 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) {
|
||||
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} ")
|
||||
val dataPair = DataSyncSelector.PairGlucoseValue(gv.first, 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 -> {
|
||||
activePlugin.activeNsClient?.nsAdd("entries", dataPair, "$startId/$lastDbId")
|
||||
synchronized(dataPair) { dataPair.waitMillis(60000) }
|
||||
cont = dataPair.confirmed
|
||||
}
|
||||
// with nsId = update
|
||||
else -> {// gv.first.interfaceIDs.nightscoutId != null
|
||||
activePlugin.activeNsClient?.nsUpdate("entries", dataPair, "$startId/$lastDbId")
|
||||
synchronized(dataPair) { dataPair.waitMillis(60000) }
|
||||
cont = dataPair.confirmed
|
||||
}
|
||||
}
|
||||
}
|
||||
if (cont) confirmLastGlucoseValueIdIfGreater(gv.second.id)
|
||||
} ?: run {
|
||||
cont = false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private 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)
|
||||
}
|
||||
}
|
||||
|
||||
private 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) {
|
||||
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} ")
|
||||
val dataPair = DataSyncSelector.PairTherapyEvent(te.first, 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 -> {
|
||||
activePlugin.activeNsClient?.nsAdd("treatments", dataPair, "$startId/$lastDbId")
|
||||
synchronized(dataPair) { dataPair.waitMillis(60000) }
|
||||
cont = dataPair.confirmed
|
||||
}
|
||||
// nsId = update
|
||||
te.first.interfaceIDs.nightscoutId != null -> {
|
||||
activePlugin.activeNsClient?.nsUpdate("treatments", dataPair, "$startId/$lastDbId")
|
||||
synchronized(dataPair) { dataPair.waitMillis(60000) }
|
||||
cont = dataPair.confirmed
|
||||
}
|
||||
}
|
||||
if (cont) confirmLastTherapyEventIdIfGreater(te.second.id)
|
||||
} ?: run {
|
||||
cont = false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private 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)
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun processChangedDeviceStatuses() {
|
||||
var cont = true
|
||||
while (cont) {
|
||||
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) {
|
||||
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")
|
||||
val dataPair = DataSyncSelector.PairDeviceStatus(deviceStatus, lastDbId)
|
||||
activePlugin.activeNsClient?.nsAdd("devicestatus", dataPair, "$startId/$lastDbId")
|
||||
synchronized(dataPair) { dataPair.waitMillis(60000) }
|
||||
cont = dataPair.confirmed
|
||||
if (cont) confirmLastDeviceStatusIdIfGreater(deviceStatus.id)
|
||||
} ?: run {
|
||||
cont = false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private 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)
|
||||
}
|
||||
}
|
||||
|
||||
private 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) {
|
||||
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} ")
|
||||
val dataPair = DataSyncSelector.PairTemporaryBasal(tb.first, tb.second.id)
|
||||
val profile = profileFunction.getProfile(tb.first.timestamp)
|
||||
if (profile != null) {
|
||||
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 -> {
|
||||
activePlugin.activeNsClient?.nsAdd("treatments", dataPair, "$startId/$lastDbId", profile)
|
||||
synchronized(dataPair) { dataPair.waitMillis(60000) }
|
||||
cont = dataPair.confirmed
|
||||
}
|
||||
// with nsId = update
|
||||
tb.first.interfaceIDs.nightscoutId != null -> {
|
||||
activePlugin.activeNsClient?.nsUpdate("treatments", dataPair, "$startId/$lastDbId", profile)
|
||||
synchronized(dataPair) { dataPair.waitMillis(60000) }
|
||||
cont = dataPair.confirmed
|
||||
}
|
||||
}
|
||||
} else aapsLogger.info(LTag.NSCLIENT, "Ignoring TemporaryBasal. No profile: ${tb.second.id} ")
|
||||
if (cont) confirmLastTemporaryBasalIdIfGreater(tb.second.id)
|
||||
} ?: run {
|
||||
cont = false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private 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)
|
||||
}
|
||||
}
|
||||
|
||||
private 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) {
|
||||
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 dataPair = DataSyncSelector.PairExtendedBolus(eb.first, 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 -> {
|
||||
activePlugin.activeNsClient?.nsAdd("treatments", dataPair, "$startId/$lastDbId", profile)
|
||||
synchronized(dataPair) { dataPair.waitMillis(60000) }
|
||||
cont = dataPair.confirmed
|
||||
}
|
||||
// with nsId = update
|
||||
eb.first.interfaceIDs.nightscoutId != null -> {
|
||||
activePlugin.activeNsClient?.nsUpdate("treatments", dataPair, "$startId/$lastDbId", profile)
|
||||
synchronized(dataPair) { dataPair.waitMillis(60000) }
|
||||
cont = dataPair.confirmed
|
||||
}
|
||||
}
|
||||
} else aapsLogger.info(LTag.NSCLIENT, "Ignoring ExtendedBolus. No profile: ${eb.second.id} ")
|
||||
if (cont) confirmLastExtendedBolusIdIfGreater(eb.second.id)
|
||||
} ?: run {
|
||||
cont = false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private 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)
|
||||
}
|
||||
}
|
||||
|
||||
private 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) {
|
||||
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} ")
|
||||
val dataPair = DataSyncSelector.PairProfileSwitch(ps.first, 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 -> {
|
||||
activePlugin.activeNsClient?.nsAdd("treatments", dataPair, "$startId/$lastDbId")
|
||||
synchronized(dataPair) { dataPair.waitMillis(60000) }
|
||||
cont = dataPair.confirmed
|
||||
}
|
||||
// with nsId = update
|
||||
ps.first.interfaceIDs.nightscoutId != null -> {
|
||||
activePlugin.activeNsClient?.nsUpdate("treatments", dataPair, "$startId/$lastDbId")
|
||||
synchronized(dataPair) { dataPair.waitMillis(60000) }
|
||||
cont = dataPair.confirmed
|
||||
}
|
||||
}
|
||||
if (cont) confirmLastProfileSwitchIdIfGreater(ps.second.id)
|
||||
} ?: run {
|
||||
cont = false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private 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)
|
||||
}
|
||||
}
|
||||
|
||||
private 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) {
|
||||
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} ")
|
||||
val dataPair = DataSyncSelector.PairEffectiveProfileSwitch(ps.first, 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 -> {
|
||||
activePlugin.activeNsClient?.nsAdd("treatments", dataPair, "$startId/$lastDbId")
|
||||
synchronized(dataPair) { dataPair.waitMillis(60000) }
|
||||
cont = dataPair.confirmed
|
||||
}
|
||||
// with nsId = update
|
||||
ps.first.interfaceIDs.nightscoutId != null -> {
|
||||
activePlugin.activeNsClient?.nsUpdate("treatments", dataPair, "$startId/$lastDbId")
|
||||
synchronized(dataPair) { dataPair.waitMillis(60000) }
|
||||
cont = dataPair.confirmed
|
||||
}
|
||||
}
|
||||
if (cont) confirmLastEffectiveProfileSwitchIdIfGreater(ps.second.id)
|
||||
} ?: run {
|
||||
cont = false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private 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)
|
||||
}
|
||||
}
|
||||
|
||||
private 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) {
|
||||
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} ")
|
||||
val dataPair = DataSyncSelector.PairOfflineEvent(oe.first, 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 -> {
|
||||
activePlugin.activeNsClient?.nsAdd("treatments", dataPair, "$startId/$lastDbId")
|
||||
synchronized(dataPair) { dataPair.waitMillis(60000) }
|
||||
cont = dataPair.confirmed
|
||||
}
|
||||
// existing with nsId = update
|
||||
oe.first.interfaceIDs.nightscoutId != null -> {
|
||||
activePlugin.activeNsClient?.nsUpdate("treatments", dataPair, "$startId/$lastDbId")
|
||||
synchronized(dataPair) { dataPair.waitMillis(60000) }
|
||||
cont = dataPair.confirmed
|
||||
}
|
||||
}
|
||||
if (cont) confirmLastOfflineEventIdIfGreater(oe.second.id)
|
||||
} ?: run {
|
||||
cont = false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun confirmLastProfileStore(lastSynced: Long) {
|
||||
sp.putLong(R.string.key_ns_profile_store_last_synced_timestamp, lastSynced)
|
||||
}
|
||||
|
||||
private 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 dataPair = DataSyncSelector.PairProfileStore(profileJson, dateUtil.now())
|
||||
activePlugin.activeNsClient?.nsAdd("profile", dataPair, "")
|
||||
synchronized(dataPair) { dataPair.waitMillis(60000) }
|
||||
val now = dateUtil.now()
|
||||
val cont = dataPair.confirmed
|
||||
if (cont) confirmLastProfileStore(now)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,737 +0,0 @@
|
|||
package info.nightscout.plugins.sync.nsclient
|
||||
|
||||
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
|
||||
import info.nightscout.shared.utils.DateUtil
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Singleton
|
||||
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,
|
||||
private val rxBus: RxBus
|
||||
) : DataSyncSelectorV1 {
|
||||
|
||||
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())
|
||||
processChangedBoluses()
|
||||
processChangedCarbs()
|
||||
processChangedBolusCalculatorResults()
|
||||
processChangedTemporaryBasals()
|
||||
processChangedExtendedBoluses()
|
||||
processChangedProfileSwitches()
|
||||
processChangedEffectiveProfileSwitches()
|
||||
processChangedGlucoseValues()
|
||||
processChangedTempTargets()
|
||||
processChangedFoods()
|
||||
processChangedTherapyEvents()
|
||||
processChangedDeviceStatuses()
|
||||
processChangedOfflineEvents()
|
||||
processChangedProfileStore()
|
||||
}
|
||||
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)
|
||||
}
|
||||
|
||||
override 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)
|
||||
}
|
||||
}
|
||||
|
||||
override tailrec suspend fun processChangedBoluses() {
|
||||
if (isPaused) return
|
||||
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 {
|
||||
// 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} ")
|
||||
confirmLastBolusIdIfGreater(bolus.second.id)
|
||||
processChangedBoluses()
|
||||
return
|
||||
}
|
||||
// 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} ")
|
||||
confirmLastBolusIdIfGreater(bolus.second.id)
|
||||
processChangedBoluses()
|
||||
return
|
||||
}
|
||||
// without nsId = create new
|
||||
bolus.first.interfaceIDs.nightscoutId == null ->
|
||||
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")
|
||||
}
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
override 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)
|
||||
}
|
||||
}
|
||||
|
||||
override tailrec suspend fun processChangedCarbs() {
|
||||
if (isPaused) return
|
||||
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 {
|
||||
// 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} ")
|
||||
confirmLastCarbsIdIfGreater(carb.second.id)
|
||||
processChangedCarbs()
|
||||
return
|
||||
}
|
||||
// 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} ")
|
||||
confirmLastCarbsIdIfGreater(carb.second.id)
|
||||
processChangedCarbs()
|
||||
return
|
||||
}
|
||||
// without nsId = create new
|
||||
carb.first.interfaceIDs.nightscoutId == null ->
|
||||
activePlugin.activeNsClient?.nsAdd("treatments", DataSyncSelector.PairCarbs(carb.first, carb.second.id), "$startId/$lastDbId")
|
||||
// with nsId = update if it's modified record
|
||||
carb.first.interfaceIDs.nightscoutId != null && carb.first.id != carb.second.id ->
|
||||
activePlugin.activeNsClient?.nsUpdate(
|
||||
"treatments",
|
||||
DataSyncSelector.PairCarbs(carb.first, carb.second.id),
|
||||
"$startId/$lastDbId"
|
||||
)
|
||||
}
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
override 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)
|
||||
}
|
||||
}
|
||||
|
||||
override tailrec suspend fun processChangedBolusCalculatorResults() {
|
||||
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) {
|
||||
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} ")
|
||||
confirmLastBolusCalculatorResultsIdIfGreater(bolusCalculatorResult.second.id)
|
||||
processChangedBolusCalculatorResults()
|
||||
return
|
||||
}
|
||||
// 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} ")
|
||||
confirmLastBolusCalculatorResultsIdIfGreater(bolusCalculatorResult.second.id)
|
||||
processChangedBolusCalculatorResults()
|
||||
return
|
||||
}
|
||||
// without nsId = create new
|
||||
bolusCalculatorResult.first.interfaceIDs.nightscoutId == null ->
|
||||
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")
|
||||
}
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
override 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)
|
||||
}
|
||||
}
|
||||
|
||||
override tailrec suspend fun processChangedTempTargets() {
|
||||
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) {
|
||||
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} ")
|
||||
confirmLastTempTargetsIdIfGreater(tt.second.id)
|
||||
processChangedTempTargets()
|
||||
return
|
||||
}
|
||||
// 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} ")
|
||||
confirmLastTempTargetsIdIfGreater(tt.second.id)
|
||||
processChangedTempTargets()
|
||||
return
|
||||
}
|
||||
// without nsId = create new
|
||||
tt.first.interfaceIDs.nightscoutId == null ->
|
||||
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")
|
||||
}
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
override 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)
|
||||
}
|
||||
}
|
||||
|
||||
override tailrec suspend fun processChangedFoods() {
|
||||
if (isPaused) return
|
||||
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 {
|
||||
// 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} ")
|
||||
confirmLastFoodIdIfGreater(food.second.id)
|
||||
processChangedFoods()
|
||||
return
|
||||
}
|
||||
// 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} ")
|
||||
confirmLastFoodIdIfGreater(food.second.id)
|
||||
processChangedFoods()
|
||||
return
|
||||
}
|
||||
// without nsId = create new
|
||||
food.first.interfaceIDs.nightscoutId == null ->
|
||||
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")
|
||||
}
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
override 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)
|
||||
}
|
||||
}
|
||||
|
||||
override tailrec suspend fun processChangedGlucoseValues() {
|
||||
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) {
|
||||
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} ")
|
||||
confirmLastGlucoseValueIdIfGreater(gv.second.id)
|
||||
processChangedGlucoseValues()
|
||||
return
|
||||
}
|
||||
// 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} ")
|
||||
confirmLastGlucoseValueIdIfGreater(gv.second.id)
|
||||
processChangedGlucoseValues()
|
||||
return
|
||||
}
|
||||
// without nsId = create new
|
||||
gv.first.interfaceIDs.nightscoutId == null ->
|
||||
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")
|
||||
}
|
||||
} else {
|
||||
confirmLastGlucoseValueIdIfGreater(gv.second.id)
|
||||
processChangedGlucoseValues()
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override 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)
|
||||
}
|
||||
}
|
||||
|
||||
override tailrec suspend fun processChangedTherapyEvents() {
|
||||
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) {
|
||||
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} ")
|
||||
confirmLastTherapyEventIdIfGreater(te.second.id)
|
||||
processChangedTherapyEvents()
|
||||
return
|
||||
}
|
||||
// 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} ")
|
||||
confirmLastTherapyEventIdIfGreater(te.second.id)
|
||||
processChangedTherapyEvents()
|
||||
return
|
||||
}
|
||||
// without nsId = create new
|
||||
te.first.interfaceIDs.nightscoutId == null ->
|
||||
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")
|
||||
}
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
override 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)
|
||||
}
|
||||
}
|
||||
|
||||
override 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) {
|
||||
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 {
|
||||
// without nsId = create new
|
||||
deviceStatus.interfaceIDs.nightscoutId == null ->
|
||||
activePlugin.activeNsClient?.nsAdd("devicestatus", DataSyncSelector.PairDeviceStatus(deviceStatus, lastDbId), "$startId/$lastDbId")
|
||||
// with nsId = ignore
|
||||
deviceStatus.interfaceIDs.nightscoutId != null -> Any()
|
||||
}
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
override 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)
|
||||
}
|
||||
}
|
||||
|
||||
override tailrec suspend fun processChangedTemporaryBasals() {
|
||||
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) {
|
||||
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} ")
|
||||
val profile = profileFunction.getProfile(tb.first.timestamp)
|
||||
if (profile != null) {
|
||||
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} ")
|
||||
confirmLastTemporaryBasalIdIfGreater(tb.second.id)
|
||||
processChangedTemporaryBasals()
|
||||
return
|
||||
}
|
||||
// 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} ")
|
||||
confirmLastTemporaryBasalIdIfGreater(tb.second.id)
|
||||
processChangedTemporaryBasals()
|
||||
return
|
||||
}
|
||||
// without nsId = create new
|
||||
tb.first.interfaceIDs.nightscoutId == null ->
|
||||
activePlugin.activeNsClient?.nsAdd("treatments", DataSyncSelector.PairTemporaryBasal(tb.first, tb.second.id), "$startId/$lastDbId", profile)
|
||||
// with nsId = update
|
||||
tb.first.interfaceIDs.nightscoutId != null ->
|
||||
activePlugin.activeNsClient?.nsUpdate("treatments", DataSyncSelector.PairTemporaryBasal(tb.first, tb.second.id), "$startId/$lastDbId", profile)
|
||||
}
|
||||
return
|
||||
} else {
|
||||
aapsLogger.info(LTag.NSCLIENT, "Ignoring TemporaryBasal. No profile: ${tb.second.id} ")
|
||||
confirmLastTemporaryBasalIdIfGreater(tb.second.id)
|
||||
processChangedTemporaryBasals()
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override 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)
|
||||
}
|
||||
}
|
||||
|
||||
override tailrec suspend fun processChangedExtendedBoluses() {
|
||||
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) {
|
||||
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} ")
|
||||
confirmLastExtendedBolusIdIfGreater(eb.second.id)
|
||||
processChangedExtendedBoluses()
|
||||
return
|
||||
}
|
||||
// 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} ")
|
||||
confirmLastExtendedBolusIdIfGreater(eb.second.id)
|
||||
processChangedExtendedBoluses()
|
||||
return
|
||||
}
|
||||
// without nsId = create new
|
||||
eb.first.interfaceIDs.nightscoutId == null ->
|
||||
activePlugin.activeNsClient?.nsAdd("treatments", DataSyncSelector.PairExtendedBolus(eb.first, eb.second.id), "$startId/$lastDbId", profile)
|
||||
// with nsId = update
|
||||
eb.first.interfaceIDs.nightscoutId != null ->
|
||||
activePlugin.activeNsClient?.nsUpdate("treatments", DataSyncSelector.PairExtendedBolus(eb.first, eb.second.id), "$startId/$lastDbId", profile)
|
||||
}
|
||||
return
|
||||
} else {
|
||||
aapsLogger.info(LTag.NSCLIENT, "Ignoring ExtendedBolus. No profile: ${eb.second.id} ")
|
||||
confirmLastExtendedBolusIdIfGreater(eb.second.id)
|
||||
processChangedExtendedBoluses()
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override 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)
|
||||
}
|
||||
}
|
||||
|
||||
override tailrec suspend fun processChangedProfileSwitches() {
|
||||
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) {
|
||||
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} ")
|
||||
confirmLastProfileSwitchIdIfGreater(ps.second.id)
|
||||
processChangedProfileSwitches()
|
||||
return
|
||||
}
|
||||
// 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} ")
|
||||
confirmLastProfileSwitchIdIfGreater(ps.second.id)
|
||||
processChangedProfileSwitches()
|
||||
return
|
||||
}
|
||||
// without nsId = create new
|
||||
ps.first.interfaceIDs.nightscoutId == null ->
|
||||
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")
|
||||
}
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
override 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)
|
||||
}
|
||||
}
|
||||
|
||||
override tailrec suspend fun processChangedEffectiveProfileSwitches() {
|
||||
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) {
|
||||
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} ")
|
||||
confirmLastEffectiveProfileSwitchIdIfGreater(ps.second.id)
|
||||
processChangedEffectiveProfileSwitches()
|
||||
return
|
||||
}
|
||||
// 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} ")
|
||||
confirmLastEffectiveProfileSwitchIdIfGreater(ps.second.id)
|
||||
processChangedEffectiveProfileSwitches()
|
||||
return
|
||||
}
|
||||
// without nsId = create new
|
||||
ps.first.interfaceIDs.nightscoutId == null ->
|
||||
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")
|
||||
}
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
override 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)
|
||||
}
|
||||
}
|
||||
|
||||
override tailrec suspend fun processChangedOfflineEvents() {
|
||||
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) {
|
||||
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} ")
|
||||
confirmLastOfflineEventIdIfGreater(oe.second.id)
|
||||
processChangedOfflineEvents()
|
||||
return
|
||||
}
|
||||
// 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} ")
|
||||
confirmLastOfflineEventIdIfGreater(oe.second.id)
|
||||
processChangedOfflineEvents()
|
||||
return
|
||||
}
|
||||
// without nsId = create new
|
||||
oe.first.interfaceIDs.nightscoutId == null ->
|
||||
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")
|
||||
}
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
override fun confirmLastProfileStore(lastSynced: Long) {
|
||||
sp.putLong(R.string.key_ns_profile_store_last_synced_timestamp, lastSynced)
|
||||
}
|
||||
|
||||
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)
|
||||
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())
|
||||
activePlugin.activeNsClient?.nsAdd("profile", DataSyncSelector.PairProfileStore(profileJson, dateUtil.now()), "")
|
||||
}
|
||||
}
|
||||
}
|
|
@ -5,7 +5,6 @@ import android.content.Context
|
|||
import android.content.Intent
|
||||
import android.content.ServiceConnection
|
||||
import android.os.IBinder
|
||||
import android.provider.ContactsContract
|
||||
import androidx.preference.PreferenceFragmentCompat
|
||||
import androidx.preference.PreferenceScreen
|
||||
import androidx.preference.SwitchPreference
|
||||
|
@ -24,7 +23,6 @@ import info.nightscout.interfaces.profile.Profile
|
|||
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.plugins.sync.R
|
||||
|
|
|
@ -25,7 +25,6 @@ import info.nightscout.interfaces.notifications.Notification
|
|||
import info.nightscout.interfaces.nsclient.NSAlarm
|
||||
import info.nightscout.interfaces.nsclient.NSSettingsStatus
|
||||
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
|
||||
|
@ -34,6 +33,7 @@ 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.EventNSClientUpdateGuiStatus
|
||||
import info.nightscout.plugins.sync.nsclient.DataSyncSelectorV1
|
||||
import info.nightscout.plugins.sync.nsclient.NSClientPlugin
|
||||
import info.nightscout.plugins.sync.nsclient.acks.NSAddAck
|
||||
import info.nightscout.plugins.sync.nsclient.acks.NSAuthAck
|
||||
|
@ -179,6 +179,18 @@ import javax.inject.Inject
|
|||
.toObservable(EventNewHistoryData::class.java)
|
||||
.observeOn(aapsSchedulers.io)
|
||||
.subscribe({ resend("NEW_DATA") }, fabricPrivacy::logException)
|
||||
disposable += rxBus
|
||||
.toObservable(EventDeviceStatusChange::class.java)
|
||||
.observeOn(aapsSchedulers.io)
|
||||
.subscribe({ resend("EventDeviceStatusChange") }, fabricPrivacy::logException)
|
||||
disposable += rxBus
|
||||
.toObservable(EventTherapyEventChange::class.java)
|
||||
.observeOn(aapsSchedulers.io)
|
||||
.subscribe({ resend("EventTherapyEventChange") }, fabricPrivacy::logException)
|
||||
disposable += rxBus
|
||||
.toObservable(EventOfflineChange::class.java)
|
||||
.observeOn(aapsSchedulers.io)
|
||||
.subscribe({ resend("EventOfflineChange") }, fabricPrivacy::logException)
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
|
@ -541,6 +553,7 @@ import javax.inject.Inject
|
|||
}
|
||||
}
|
||||
rxBus.send(EventNSClientNewLog("◄ LAST", dateUtil.dateAndTimeString(latestDateInReceivedData)))
|
||||
resend("LAST")
|
||||
} catch (e: JSONException) {
|
||||
aapsLogger.error("Unhandled exception", e)
|
||||
}
|
||||
|
@ -551,7 +564,7 @@ import javax.inject.Inject
|
|||
}
|
||||
}
|
||||
|
||||
fun dbUpdate(collection: String, _id: String?, data: JSONObject?, originalObject: Any, progress: String) {
|
||||
fun dbUpdate(collection: String, @Suppress("LocalVariableName") _id: String?, data: JSONObject?, originalObject: Any, progress: String) {
|
||||
try {
|
||||
if (_id == null) return
|
||||
if (!isConnected || !hasWriteAuth) return
|
||||
|
@ -595,10 +608,10 @@ import javax.inject.Inject
|
|||
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@async
|
||||
}
|
||||
// if (lastAckTime > System.currentTimeMillis() - 10 * 1000L) {
|
||||
// aapsLogger.debug(LTag.NSCLIENT, "Skipping resend by lastAckTime: " + (System.currentTimeMillis() - lastAckTime) / 1000L + " sec")
|
||||
// return@async
|
||||
// }
|
||||
rxBus.send(EventNSClientNewLog("● QUEUE", "Resend started: $reason"))
|
||||
dataSyncSelectorV1.doUpload()
|
||||
rxBus.send(EventNSClientNewLog("● QUEUE", "Resend ended: $reason"))
|
||||
|
|
|
@ -4,6 +4,7 @@ import android.content.Context
|
|||
import android.os.SystemClock
|
||||
import androidx.work.WorkerParameters
|
||||
import androidx.work.workDataOf
|
||||
import info.nightscout.core.utils.notify
|
||||
import info.nightscout.core.utils.receivers.DataWorkerStorage
|
||||
import info.nightscout.core.utils.worker.LoggingWorker
|
||||
import info.nightscout.database.impl.AppRepository
|
||||
|
@ -22,7 +23,6 @@ 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
|
||||
|
@ -40,7 +40,6 @@ class NSClientAddAckWorker(
|
|||
@Inject lateinit var dataWorkerStorage: DataWorkerStorage
|
||||
@Inject lateinit var repository: AppRepository
|
||||
@Inject lateinit var rxBus: RxBus
|
||||
@Inject lateinit var dataSyncSelectorV1: DataSyncSelectorV1
|
||||
@Inject lateinit var aapsSchedulers: AapsSchedulers
|
||||
@Inject lateinit var sp: SP
|
||||
@Inject lateinit var storeDataForDb: StoreDataForDb
|
||||
|
@ -60,152 +59,128 @@ class NSClientAddAckWorker(
|
|||
is PairTemporaryTarget -> {
|
||||
val pair = ack.originalObject
|
||||
pair.value.interfaceIDs.nightscoutId = ack.id
|
||||
pair.confirmed = true
|
||||
storeDataForDb.nsIdTemporaryTargets.add(pair.value)
|
||||
dataSyncSelectorV1.confirmLastTempTargetsIdIfGreater(pair.id)
|
||||
storeDataForDb.scheduleNsIdUpdate()
|
||||
rxBus.send(EventNSClientNewLog("◄ DBADD", "Acked TemporaryTarget " + pair.value.interfaceIDs.nightscoutId))
|
||||
// Send new if waiting
|
||||
dataSyncSelectorV1.processChangedTempTargets()
|
||||
}
|
||||
|
||||
is PairGlucoseValue -> {
|
||||
val pair = ack.originalObject
|
||||
pair.value.interfaceIDs.nightscoutId = ack.id
|
||||
pair.confirmed = true
|
||||
storeDataForDb.nsIdGlucoseValues.add(pair.value)
|
||||
dataSyncSelectorV1.confirmLastGlucoseValueIdIfGreater(pair.id)
|
||||
storeDataForDb.scheduleNsIdUpdate()
|
||||
rxBus.send(EventNSClientNewLog("◄ DBADD", "Acked GlucoseValue " + pair.value.interfaceIDs.nightscoutId))
|
||||
// Send new if waiting
|
||||
dataSyncSelectorV1.processChangedGlucoseValues()
|
||||
}
|
||||
|
||||
is PairFood -> {
|
||||
val pair = ack.originalObject
|
||||
pair.value.interfaceIDs.nightscoutId = ack.id
|
||||
pair.confirmed = true
|
||||
storeDataForDb.nsIdFoods.add(pair.value)
|
||||
dataSyncSelectorV1.confirmLastFoodIdIfGreater(pair.id)
|
||||
storeDataForDb.scheduleNsIdUpdate()
|
||||
rxBus.send(EventNSClientNewLog("◄ DBADD", "Acked Food " + pair.value.interfaceIDs.nightscoutId))
|
||||
// Send new if waiting
|
||||
dataSyncSelectorV1.processChangedFoods()
|
||||
}
|
||||
|
||||
is PairTherapyEvent -> {
|
||||
val pair = ack.originalObject
|
||||
pair.value.interfaceIDs.nightscoutId = ack.id
|
||||
pair.confirmed = true
|
||||
storeDataForDb.nsIdTherapyEvents.add(pair.value)
|
||||
dataSyncSelectorV1.confirmLastTherapyEventIdIfGreater(pair.id)
|
||||
storeDataForDb.scheduleNsIdUpdate()
|
||||
rxBus.send(EventNSClientNewLog("◄ DBADD", "Acked TherapyEvent " + pair.value.interfaceIDs.nightscoutId))
|
||||
// Send new if waiting
|
||||
dataSyncSelectorV1.processChangedTherapyEvents()
|
||||
}
|
||||
|
||||
is PairBolus -> {
|
||||
val pair = ack.originalObject
|
||||
pair.value.interfaceIDs.nightscoutId = ack.id
|
||||
pair.confirmed = true
|
||||
storeDataForDb.nsIdBoluses.add(pair.value)
|
||||
dataSyncSelectorV1.confirmLastBolusIdIfGreater(pair.id)
|
||||
storeDataForDb.scheduleNsIdUpdate()
|
||||
rxBus.send(EventNSClientNewLog("◄ DBADD", "Acked Bolus " + pair.value.interfaceIDs.nightscoutId))
|
||||
// Send new if waiting
|
||||
dataSyncSelectorV1.processChangedBoluses()
|
||||
}
|
||||
|
||||
is PairCarbs -> {
|
||||
val pair = ack.originalObject
|
||||
pair.value.interfaceIDs.nightscoutId = ack.id
|
||||
pair.confirmed = true
|
||||
storeDataForDb.nsIdCarbs.add(pair.value)
|
||||
dataSyncSelectorV1.confirmLastCarbsIdIfGreater(pair.id)
|
||||
storeDataForDb.scheduleNsIdUpdate()
|
||||
rxBus.send(EventNSClientNewLog("◄ DBADD", "Acked Carbs " + pair.value.interfaceIDs.nightscoutId))
|
||||
// Send new if waiting
|
||||
dataSyncSelectorV1.processChangedCarbs()
|
||||
}
|
||||
|
||||
is PairBolusCalculatorResult -> {
|
||||
val pair = ack.originalObject
|
||||
pair.value.interfaceIDs.nightscoutId = ack.id
|
||||
storeDataForDb.nsIdBolusCalculatorResults.add(pair.value)
|
||||
dataSyncSelectorV1.confirmLastBolusCalculatorResultsIdIfGreater(pair.id)
|
||||
storeDataForDb.scheduleNsIdUpdate()
|
||||
rxBus.send(EventNSClientNewLog("◄ DBADD", "Acked BolusCalculatorResult " + pair.value.interfaceIDs.nightscoutId))
|
||||
// Send new if waiting
|
||||
dataSyncSelectorV1.processChangedBolusCalculatorResults()
|
||||
}
|
||||
|
||||
is PairTemporaryBasal -> {
|
||||
val pair = ack.originalObject
|
||||
pair.value.interfaceIDs.nightscoutId = ack.id
|
||||
pair.confirmed = true
|
||||
storeDataForDb.nsIdTemporaryBasals.add(pair.value)
|
||||
dataSyncSelectorV1.confirmLastTemporaryBasalIdIfGreater(pair.id)
|
||||
storeDataForDb.scheduleNsIdUpdate()
|
||||
rxBus.send(EventNSClientNewLog("◄ DBADD", "Acked TemporaryBasal " + pair.value.interfaceIDs.nightscoutId))
|
||||
// Send new if waiting
|
||||
dataSyncSelectorV1.processChangedTemporaryBasals()
|
||||
}
|
||||
|
||||
is PairExtendedBolus -> {
|
||||
val pair = ack.originalObject
|
||||
pair.value.interfaceIDs.nightscoutId = ack.id
|
||||
pair.confirmed = true
|
||||
storeDataForDb.nsIdExtendedBoluses.add(pair.value)
|
||||
dataSyncSelectorV1.confirmLastExtendedBolusIdIfGreater(pair.id)
|
||||
storeDataForDb.scheduleNsIdUpdate()
|
||||
rxBus.send(EventNSClientNewLog("◄ DBADD", "Acked ExtendedBolus " + pair.value.interfaceIDs.nightscoutId))
|
||||
// Send new if waiting
|
||||
dataSyncSelectorV1.processChangedExtendedBoluses()
|
||||
}
|
||||
|
||||
is PairProfileSwitch -> {
|
||||
val pair = ack.originalObject
|
||||
pair.value.interfaceIDs.nightscoutId = ack.id
|
||||
pair.confirmed = true
|
||||
storeDataForDb.nsIdProfileSwitches.add(pair.value)
|
||||
dataSyncSelectorV1.confirmLastProfileSwitchIdIfGreater(pair.id)
|
||||
storeDataForDb.scheduleNsIdUpdate()
|
||||
rxBus.send(EventNSClientNewLog("◄ DBADD", "Acked ProfileSwitch " + pair.value.interfaceIDs.nightscoutId))
|
||||
// Send new if waiting
|
||||
dataSyncSelectorV1.processChangedProfileSwitches()
|
||||
}
|
||||
|
||||
is PairEffectiveProfileSwitch -> {
|
||||
val pair = ack.originalObject
|
||||
pair.value.interfaceIDs.nightscoutId = ack.id
|
||||
pair.confirmed = true
|
||||
storeDataForDb.nsIdEffectiveProfileSwitches.add(pair.value)
|
||||
dataSyncSelectorV1.confirmLastEffectiveProfileSwitchIdIfGreater(pair.id)
|
||||
storeDataForDb.scheduleNsIdUpdate()
|
||||
rxBus.send(EventNSClientNewLog("◄ DBADD", "Acked EffectiveProfileSwitch " + pair.value.interfaceIDs.nightscoutId))
|
||||
// Send new if waiting
|
||||
dataSyncSelectorV1.processChangedEffectiveProfileSwitches()
|
||||
}
|
||||
|
||||
is DataSyncSelector.PairDeviceStatus -> {
|
||||
val pair = ack.originalObject
|
||||
pair.value.interfaceIDs.nightscoutId = ack.id
|
||||
pair.confirmed = true
|
||||
storeDataForDb.nsIdDeviceStatuses.add(pair.value)
|
||||
dataSyncSelectorV1.confirmLastDeviceStatusIdIfGreater(pair.value.id)
|
||||
storeDataForDb.scheduleNsIdUpdate()
|
||||
rxBus.send(EventNSClientNewLog("◄ DBADD", "Acked DeviceStatus " + pair.value.interfaceIDs.nightscoutId))
|
||||
// Send new if waiting
|
||||
dataSyncSelectorV1.processChangedDeviceStatuses()
|
||||
}
|
||||
|
||||
is PairProfileStore -> {
|
||||
dataSyncSelectorV1.confirmLastProfileStore(ack.originalObject.id)
|
||||
val pair = ack.originalObject
|
||||
pair.confirmed = true
|
||||
rxBus.send(EventNSClientNewLog("◄ DBADD", "Acked ProfileStore " + ack.id))
|
||||
}
|
||||
|
||||
is PairOfflineEvent -> {
|
||||
val pair = ack.originalObject
|
||||
pair.value.interfaceIDs.nightscoutId = ack.id
|
||||
pair.confirmed = true
|
||||
storeDataForDb.nsIdOfflineEvents.add(pair.value)
|
||||
dataSyncSelectorV1.confirmLastOfflineEventIdIfGreater(pair.id)
|
||||
storeDataForDb.scheduleNsIdUpdate()
|
||||
rxBus.send(EventNSClientNewLog("◄ DBADD", "Acked OfflineEvent " + pair.value.interfaceIDs.nightscoutId))
|
||||
// Send new if waiting
|
||||
dataSyncSelectorV1.processChangedOfflineEvents()
|
||||
}
|
||||
|
||||
}
|
||||
ack.originalObject?.let { synchronized(it) { it.notify() } }
|
||||
return ret
|
||||
}
|
||||
}
|
|
@ -3,6 +3,7 @@ package info.nightscout.plugins.sync.nsclient.workers
|
|||
import android.content.Context
|
||||
import androidx.work.WorkerParameters
|
||||
import androidx.work.workDataOf
|
||||
import info.nightscout.core.utils.notify
|
||||
import info.nightscout.core.utils.receivers.DataWorkerStorage
|
||||
import info.nightscout.core.utils.worker.LoggingWorker
|
||||
import info.nightscout.database.impl.AppRepository
|
||||
|
@ -18,7 +19,6 @@ 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,6 @@ class NSClientUpdateRemoveAckWorker(
|
|||
@Inject lateinit var dataWorkerStorage: DataWorkerStorage
|
||||
@Inject lateinit var repository: AppRepository
|
||||
@Inject lateinit var rxBus: RxBus
|
||||
@Inject lateinit var dataSyncSelectorV1: DataSyncSelectorV1
|
||||
@Inject lateinit var aapsSchedulers: AapsSchedulers
|
||||
|
||||
override suspend fun doWorkAndLog(): Result {
|
||||
|
@ -47,112 +46,89 @@ class NSClientUpdateRemoveAckWorker(
|
|||
when (ack.originalObject) {
|
||||
is PairTemporaryTarget -> {
|
||||
val pair = ack.originalObject
|
||||
dataSyncSelectorV1.confirmLastTempTargetsIdIfGreater(pair.id)
|
||||
pair.confirmed = true
|
||||
rxBus.send(EventNSClientNewLog("◄ DBUPDATE", "Acked TemporaryTarget" + ack._id))
|
||||
// Send new if waiting
|
||||
dataSyncSelectorV1.processChangedTempTargets()
|
||||
ret = Result.success(workDataOf("ProcessedData" to pair.toString()))
|
||||
}
|
||||
|
||||
is PairGlucoseValue -> {
|
||||
val pair = ack.originalObject
|
||||
dataSyncSelectorV1.confirmLastGlucoseValueIdIfGreater(pair.id)
|
||||
pair.confirmed = true
|
||||
rxBus.send(EventNSClientNewLog("◄ DBUPDATE", "Acked GlucoseValue " + ack._id))
|
||||
// Send new if waiting
|
||||
dataSyncSelectorV1.processChangedGlucoseValues()
|
||||
ret = Result.success(workDataOf("ProcessedData" to pair.toString()))
|
||||
}
|
||||
|
||||
is PairFood -> {
|
||||
val pair = ack.originalObject
|
||||
dataSyncSelectorV1.confirmLastFoodIdIfGreater(pair.id)
|
||||
pair.confirmed = true
|
||||
rxBus.send(EventNSClientNewLog("◄ DBUPDATE", "Acked Food " + ack._id))
|
||||
// Send new if waiting
|
||||
dataSyncSelectorV1.processChangedFoods()
|
||||
ret = Result.success(workDataOf("ProcessedData" to pair.toString()))
|
||||
}
|
||||
|
||||
is PairTherapyEvent -> {
|
||||
val pair = ack.originalObject
|
||||
dataSyncSelectorV1.confirmLastTherapyEventIdIfGreater(pair.id)
|
||||
pair.confirmed = true
|
||||
rxBus.send(EventNSClientNewLog("◄ DBUPDATE", "Acked TherapyEvent " + ack._id))
|
||||
// Send new if waiting
|
||||
dataSyncSelectorV1.processChangedTherapyEvents()
|
||||
ret = Result.success(workDataOf("ProcessedData" to pair.toString()))
|
||||
}
|
||||
|
||||
is PairBolus -> {
|
||||
val pair = ack.originalObject
|
||||
dataSyncSelectorV1.confirmLastBolusIdIfGreater(pair.id)
|
||||
pair.confirmed = true
|
||||
rxBus.send(EventNSClientNewLog("◄ DBUPDATE", "Acked Bolus " + ack._id))
|
||||
// Send new if waiting
|
||||
dataSyncSelectorV1.processChangedBoluses()
|
||||
ret = Result.success(workDataOf("ProcessedData" to pair.toString()))
|
||||
}
|
||||
|
||||
is PairCarbs -> {
|
||||
val pair = ack.originalObject
|
||||
dataSyncSelectorV1.confirmLastCarbsIdIfGreater(pair.id)
|
||||
pair.confirmed = true
|
||||
rxBus.send(EventNSClientNewLog("◄ DBUPDATE", "Acked Carbs " + ack._id))
|
||||
// Send new if waiting
|
||||
dataSyncSelectorV1.processChangedCarbs()
|
||||
ret = Result.success(workDataOf("ProcessedData" to pair.toString()))
|
||||
}
|
||||
|
||||
is PairBolusCalculatorResult -> {
|
||||
val pair = ack.originalObject
|
||||
dataSyncSelectorV1.confirmLastBolusCalculatorResultsIdIfGreater(pair.id)
|
||||
pair.confirmed = true
|
||||
rxBus.send(EventNSClientNewLog("◄ DBUPDATE", "Acked BolusCalculatorResult " + ack._id))
|
||||
// Send new if waiting
|
||||
dataSyncSelectorV1.processChangedBolusCalculatorResults()
|
||||
ret = Result.success(workDataOf("ProcessedData" to pair.toString()))
|
||||
}
|
||||
|
||||
is PairTemporaryBasal -> {
|
||||
val pair = ack.originalObject
|
||||
dataSyncSelectorV1.confirmLastTemporaryBasalIdIfGreater(pair.id)
|
||||
pair.confirmed = true
|
||||
rxBus.send(EventNSClientNewLog("◄ DBUPDATE", "Acked TemporaryBasal " + ack._id))
|
||||
// Send new if waiting
|
||||
dataSyncSelectorV1.processChangedTemporaryBasals()
|
||||
ret = Result.success(workDataOf("ProcessedData" to pair.toString()))
|
||||
}
|
||||
|
||||
is PairExtendedBolus -> {
|
||||
val pair = ack.originalObject
|
||||
dataSyncSelectorV1.confirmLastExtendedBolusIdIfGreater(pair.id)
|
||||
pair.confirmed = true
|
||||
rxBus.send(EventNSClientNewLog("◄ DBUPDATE", "Acked ExtendedBolus " + ack._id))
|
||||
// Send new if waiting
|
||||
dataSyncSelectorV1.processChangedExtendedBoluses()
|
||||
ret = Result.success(workDataOf("ProcessedData" to pair.toString()))
|
||||
}
|
||||
|
||||
is PairProfileSwitch -> {
|
||||
val pair = ack.originalObject
|
||||
dataSyncSelectorV1.confirmLastProfileSwitchIdIfGreater(pair.id)
|
||||
pair.confirmed = true
|
||||
rxBus.send(EventNSClientNewLog("◄ DBUPDATE", "Acked ProfileSwitch " + ack._id))
|
||||
// Send new if waiting
|
||||
dataSyncSelectorV1.processChangedProfileSwitches()
|
||||
ret = Result.success(workDataOf("ProcessedData" to pair.toString()))
|
||||
}
|
||||
|
||||
is PairEffectiveProfileSwitch -> {
|
||||
val pair = ack.originalObject
|
||||
dataSyncSelectorV1.confirmLastEffectiveProfileSwitchIdIfGreater(pair.id)
|
||||
pair.confirmed = true
|
||||
rxBus.send(EventNSClientNewLog("◄ DBUPDATE", "Acked EffectiveProfileSwitch " + ack._id))
|
||||
// Send new if waiting
|
||||
dataSyncSelectorV1.processChangedEffectiveProfileSwitches()
|
||||
ret = Result.success(workDataOf("ProcessedData" to pair.toString()))
|
||||
}
|
||||
|
||||
is PairOfflineEvent -> {
|
||||
val pair = ack.originalObject
|
||||
dataSyncSelectorV1.confirmLastOfflineEventIdIfGreater(pair.id)
|
||||
pair.confirmed = true
|
||||
rxBus.send(EventNSClientNewLog("◄ DBUPDATE", "Acked OfflineEvent" + ack._id))
|
||||
// Send new if waiting
|
||||
dataSyncSelectorV1.processChangedOfflineEvents()
|
||||
ret = Result.success(workDataOf("ProcessedData" to pair.toString()))
|
||||
}
|
||||
}
|
||||
ack.originalObject?.let { synchronized(it) { it.notify() } }
|
||||
return ret
|
||||
}
|
||||
}
|
|
@ -7,7 +7,6 @@ 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
|
||||
|
@ -22,7 +21,7 @@ import javax.inject.Singleton
|
|||
|
||||
@OpenForTesting
|
||||
@Singleton
|
||||
class DataSyncSelectorV3Impl @Inject constructor(
|
||||
class DataSyncSelectorV3 @Inject constructor(
|
||||
private val sp: SP,
|
||||
private val aapsLogger: AAPSLogger,
|
||||
private val dateUtil: DateUtil,
|
||||
|
@ -32,7 +31,7 @@ class DataSyncSelectorV3Impl @Inject constructor(
|
|||
private val rxBus: RxBus,
|
||||
private val storeDataForDb: StoreDataForDb,
|
||||
private val config: Config
|
||||
) : DataSyncSelectorV3 {
|
||||
) : DataSyncSelector {
|
||||
|
||||
class QueueCounter(
|
||||
var bolusesRemaining: Long = -1L,
|
||||
|
@ -127,14 +126,14 @@ class DataSyncSelectorV3Impl @Inject constructor(
|
|||
else sp.remove(R.string.key_ns_device_status_last_synced_id)
|
||||
}
|
||||
|
||||
fun confirmLastBolusIdIfGreater(lastSynced: Long) {
|
||||
private 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() {
|
||||
private suspend fun processChangedBoluses() {
|
||||
var cont = true
|
||||
while (cont) {
|
||||
if (isPaused) return
|
||||
|
@ -170,14 +169,14 @@ class DataSyncSelectorV3Impl @Inject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
fun confirmLastCarbsIdIfGreater(lastSynced: Long) {
|
||||
private 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() {
|
||||
private suspend fun processChangedCarbs() {
|
||||
var cont = true
|
||||
while (cont) {
|
||||
if (isPaused) return
|
||||
|
@ -213,14 +212,14 @@ class DataSyncSelectorV3Impl @Inject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
fun confirmLastBolusCalculatorResultsIdIfGreater(lastSynced: Long) {
|
||||
private 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() {
|
||||
private suspend fun processChangedBolusCalculatorResults() {
|
||||
var cont = true
|
||||
while (cont) {
|
||||
if (isPaused) return
|
||||
|
@ -264,14 +263,14 @@ class DataSyncSelectorV3Impl @Inject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
fun confirmLastTempTargetsIdIfGreater(lastSynced: Long) {
|
||||
private 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() {
|
||||
private suspend fun processChangedTempTargets() {
|
||||
var cont = true
|
||||
while (cont) {
|
||||
if (isPaused) return
|
||||
|
@ -307,14 +306,14 @@ class DataSyncSelectorV3Impl @Inject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
fun confirmLastFoodIdIfGreater(lastSynced: Long) {
|
||||
private 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() {
|
||||
private suspend fun processChangedFoods() {
|
||||
var cont = true
|
||||
while (cont) {
|
||||
if (isPaused) return
|
||||
|
@ -350,14 +349,14 @@ class DataSyncSelectorV3Impl @Inject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
fun confirmLastGlucoseValueIdIfGreater(lastSynced: Long) {
|
||||
private 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() {
|
||||
private suspend fun processChangedGlucoseValues() {
|
||||
var cont = true
|
||||
while (cont) {
|
||||
if (isPaused) return
|
||||
|
@ -395,14 +394,14 @@ class DataSyncSelectorV3Impl @Inject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
fun confirmLastTherapyEventIdIfGreater(lastSynced: Long) {
|
||||
private 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() {
|
||||
private suspend fun processChangedTherapyEvents() {
|
||||
var cont = true
|
||||
while (cont) {
|
||||
if (isPaused) return
|
||||
|
@ -438,14 +437,16 @@ class DataSyncSelectorV3Impl @Inject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
fun confirmLastDeviceStatusIdIfGreater(lastSynced: Long) {
|
||||
private 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() {
|
||||
private suspend fun processChangedDeviceStatuses() {
|
||||
var cont = true
|
||||
while (cont) {
|
||||
if (isPaused) return
|
||||
val lastDbId = appRepository.getLastDeviceStatusId() ?: 0L
|
||||
var startId = sp.getLong(R.string.key_ns_device_status_last_synced_id, 0)
|
||||
|
@ -458,24 +459,23 @@ class DataSyncSelectorV3Impl @Inject constructor(
|
|||
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)
|
||||
}
|
||||
cont = activePlugin.activeNsClient?.nsAdd("devicestatus", DataSyncSelector.PairDeviceStatus(deviceStatus, lastDbId), "$startId/$lastDbId") ?: false
|
||||
if (cont) confirmLastDeviceStatusIdIfGreater(deviceStatus.id)
|
||||
// with nsId = ignore
|
||||
} ?: run {
|
||||
cont = false
|
||||
}
|
||||
}
|
||||
queueCounter.dssRemaining = 0
|
||||
}
|
||||
|
||||
fun confirmLastTemporaryBasalIdIfGreater(lastSynced: Long) {
|
||||
private 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() {
|
||||
private suspend fun processChangedTemporaryBasals() {
|
||||
var cont = true
|
||||
while (cont) {
|
||||
if (isPaused) return
|
||||
|
@ -512,14 +512,14 @@ class DataSyncSelectorV3Impl @Inject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
fun confirmLastExtendedBolusIdIfGreater(lastSynced: Long) {
|
||||
private 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() {
|
||||
private suspend fun processChangedExtendedBoluses() {
|
||||
var cont = true
|
||||
while (cont) {
|
||||
if (isPaused) return
|
||||
|
@ -558,14 +558,14 @@ class DataSyncSelectorV3Impl @Inject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
fun confirmLastProfileSwitchIdIfGreater(lastSynced: Long) {
|
||||
private 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() {
|
||||
private suspend fun processChangedProfileSwitches() {
|
||||
var cont = true
|
||||
while (cont) {
|
||||
if (isPaused) return
|
||||
|
@ -601,14 +601,14 @@ class DataSyncSelectorV3Impl @Inject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
fun confirmLastEffectiveProfileSwitchIdIfGreater(lastSynced: Long) {
|
||||
private 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() {
|
||||
private suspend fun processChangedEffectiveProfileSwitches() {
|
||||
var cont = true
|
||||
while (cont) {
|
||||
if (isPaused) return
|
||||
|
@ -644,14 +644,14 @@ class DataSyncSelectorV3Impl @Inject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
fun confirmLastOfflineEventIdIfGreater(lastSynced: Long) {
|
||||
private 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() {
|
||||
private suspend fun processChangedOfflineEvents() {
|
||||
var cont = true
|
||||
while (cont) {
|
||||
if (isPaused) return
|
||||
|
@ -687,11 +687,11 @@ class DataSyncSelectorV3Impl @Inject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
fun confirmLastProfileStore(lastSynced: Long) {
|
||||
private fun confirmLastProfileStore(lastSynced: Long) {
|
||||
sp.putLong(R.string.key_ns_profile_store_last_synced_timestamp, lastSynced)
|
||||
}
|
||||
|
||||
suspend fun processChangedProfileStore() {
|
||||
private 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)
|
|
@ -30,7 +30,6 @@ import info.nightscout.interfaces.plugin.PluginType
|
|||
import info.nightscout.interfaces.profile.Profile
|
||||
import info.nightscout.interfaces.source.NSClientSource
|
||||
import info.nightscout.interfaces.sync.DataSyncSelector
|
||||
import info.nightscout.interfaces.sync.DataSyncSelectorV3
|
||||
import info.nightscout.interfaces.sync.NsClient
|
||||
import info.nightscout.interfaces.sync.Sync
|
||||
import info.nightscout.interfaces.ui.UiInteraction
|
||||
|
@ -66,11 +65,14 @@ import info.nightscout.plugins.sync.nsclientV3.workers.LoadTreatmentsWorker
|
|||
import info.nightscout.rx.AapsSchedulers
|
||||
import info.nightscout.rx.bus.RxBus
|
||||
import info.nightscout.rx.events.EventAppExit
|
||||
import info.nightscout.rx.events.EventDeviceStatusChange
|
||||
import info.nightscout.rx.events.EventDismissNotification
|
||||
import info.nightscout.rx.events.EventNSClientNewLog
|
||||
import info.nightscout.rx.events.EventNewHistoryData
|
||||
import info.nightscout.rx.events.EventOfflineChange
|
||||
import info.nightscout.rx.events.EventPreferenceChange
|
||||
import info.nightscout.rx.events.EventSWSyncStatus
|
||||
import info.nightscout.rx.events.EventTherapyEventChange
|
||||
import info.nightscout.rx.logging.AAPSLogger
|
||||
import info.nightscout.rx.logging.LTag
|
||||
import info.nightscout.sdk.NSAndroidClientImpl
|
||||
|
@ -224,6 +226,18 @@ class NSClientV3Plugin @Inject constructor(
|
|||
.toObservable(EventNewHistoryData::class.java)
|
||||
.observeOn(aapsSchedulers.io)
|
||||
.subscribe({ executeUpload("NEW_DATA", forceNew = false) }, fabricPrivacy::logException)
|
||||
disposable += rxBus
|
||||
.toObservable(EventDeviceStatusChange::class.java)
|
||||
.observeOn(aapsSchedulers.io)
|
||||
.subscribe({ executeUpload("EventDeviceStatusChange", forceNew = false) }, fabricPrivacy::logException)
|
||||
disposable += rxBus
|
||||
.toObservable(EventTherapyEventChange::class.java)
|
||||
.observeOn(aapsSchedulers.io)
|
||||
.subscribe({ executeUpload("EventTherapyEventChange", forceNew = false) }, fabricPrivacy::logException)
|
||||
disposable += rxBus
|
||||
.toObservable(EventOfflineChange::class.java)
|
||||
.observeOn(aapsSchedulers.io)
|
||||
.subscribe({ executeUpload("EventOfflineChange", forceNew = false) }, fabricPrivacy::logException)
|
||||
|
||||
runLoop = Runnable {
|
||||
var refreshInterval = T.mins(5).msecs()
|
||||
|
|
|
@ -5,7 +5,7 @@ import androidx.work.WorkerParameters
|
|||
import info.nightscout.androidaps.annotations.OpenForTesting
|
||||
import info.nightscout.core.utils.worker.LoggingWorker
|
||||
import info.nightscout.interfaces.plugin.ActivePlugin
|
||||
import info.nightscout.interfaces.sync.DataSyncSelectorV3
|
||||
import info.nightscout.plugins.sync.nsclientV3.DataSyncSelectorV3
|
||||
import info.nightscout.plugins.sync.nsclientV3.NSClientV3Plugin
|
||||
import info.nightscout.rx.bus.RxBus
|
||||
import info.nightscout.rx.events.EventNSClientNewLog
|
||||
|
|
|
@ -45,7 +45,7 @@ internal class NSClientV3PluginTest : TestBaseWithProfile() {
|
|||
|
||||
@Mock lateinit var receiverDelegate: ReceiverDelegate
|
||||
@Mock lateinit var uiInteraction: UiInteraction
|
||||
@Mock lateinit var dataSyncSelectorV3: DataSyncSelectorV3Impl
|
||||
@Mock lateinit var dataSyncSelectorV3: DataSyncSelectorV3
|
||||
@Mock lateinit var nsAndroidClient: NSAndroidClient
|
||||
@Mock lateinit var uel: UserEntryLogger
|
||||
@Mock lateinit var nsClientSource: NSClientSource
|
||||
|
|
|
@ -8,7 +8,7 @@ import info.nightscout.androidaps.TestBase
|
|||
import info.nightscout.core.utils.fabric.FabricPrivacy
|
||||
import info.nightscout.interfaces.plugin.ActivePlugin
|
||||
import info.nightscout.interfaces.sync.NsClient
|
||||
import info.nightscout.plugins.sync.nsclientV3.DataSyncSelectorV3Impl
|
||||
import info.nightscout.plugins.sync.nsclientV3.DataSyncSelectorV3
|
||||
import info.nightscout.plugins.sync.nsclientV3.NSClientV3Plugin
|
||||
import info.nightscout.rx.bus.RxBus
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
|
@ -24,7 +24,7 @@ import org.mockito.Mockito.`when`
|
|||
internal class DataSyncWorkerTest : TestBase() {
|
||||
|
||||
@Mock lateinit var fabricPrivacy: FabricPrivacy
|
||||
@Mock lateinit var dataSyncSelectorV3: DataSyncSelectorV3Impl
|
||||
@Mock lateinit var dataSyncSelectorV3: DataSyncSelectorV3
|
||||
@Mock lateinit var activePlugin: ActivePlugin
|
||||
@Mock lateinit var nsClient: NsClient
|
||||
@Mock lateinit var rxBus: RxBus
|
||||
|
|
|
@ -17,11 +17,11 @@ import info.nightscout.interfaces.Config
|
|||
import info.nightscout.interfaces.nsclient.StoreDataForDb
|
||||
import info.nightscout.interfaces.receivers.ReceiverStatusStore
|
||||
import info.nightscout.interfaces.source.NSClientSource
|
||||
import info.nightscout.interfaces.sync.DataSyncSelectorV3
|
||||
import info.nightscout.interfaces.ui.UiInteraction
|
||||
import info.nightscout.plugins.sync.nsShared.NsIncomingDataProcessor
|
||||
import info.nightscout.plugins.sync.nsclient.ReceiverDelegate
|
||||
import info.nightscout.plugins.sync.nsclient.data.NSDeviceStatusHandler
|
||||
import info.nightscout.plugins.sync.nsclientV3.DataSyncSelectorV3
|
||||
import info.nightscout.plugins.sync.nsclientV3.NSClientV3Plugin
|
||||
import info.nightscout.plugins.sync.nsclientV3.extensions.toNSSvgV3
|
||||
import info.nightscout.rx.bus.RxBus
|
||||
|
|
|
@ -1102,7 +1102,17 @@ class ComboV2Plugin @Inject constructor (
|
|||
reportFinishedBolus(R.string.combov2_bolus_delivery_failed, pumpEnactResult, succeeded = false)
|
||||
} finally {
|
||||
// The delivery was enacted if even a partial amount was infused.
|
||||
pumpEnactResult.enacted = acquiredPump.lastBolusFlow.value?.let { it.bolusAmount > 0 } ?: false
|
||||
acquiredPump.lastBolusFlow.value?.also {
|
||||
pumpEnactResult.enacted = (it.bolusAmount > 0)
|
||||
pumpEnactResult.bolusDelivered = it.bolusAmount.cctlBolusToIU()
|
||||
} ?: run {
|
||||
pumpEnactResult.enacted = false
|
||||
pumpEnactResult.bolusDelivered = 0.0
|
||||
}
|
||||
aapsLogger.debug(
|
||||
LTag.PUMP,
|
||||
"Pump enact result: success ${pumpEnactResult.success} enacted ${pumpEnactResult.enacted} bolusDelivered ${pumpEnactResult.bolusDelivered}"
|
||||
)
|
||||
bolusJob = null
|
||||
bolusProgressJob.cancelAndJoin()
|
||||
}
|
||||
|
@ -2216,7 +2226,7 @@ class ComboV2Plugin @Inject constructor (
|
|||
// only shows up in the Combo fragment.
|
||||
if (newState == DriverState.Suspended) {
|
||||
uiInteraction.addNotification(
|
||||
Notification.COMBO_PUMP_SUSPENDED,
|
||||
Notification.PUMP_SUSPENDED,
|
||||
text = rh.gs(R.string.combov2_pump_is_suspended),
|
||||
level = Notification.NORMAL
|
||||
)
|
||||
|
|
|
@ -171,6 +171,7 @@ public class SerialIOThread extends Thread {
|
|||
aapsLogger.error(LTag.PUMPBTCOMM, "Reply not received " + message.getMessageName());
|
||||
if (message.getCommand() == 0xF0F1) {
|
||||
danaPump.setNewPump(false);
|
||||
danaPump.reset();
|
||||
aapsLogger.debug(LTag.PUMPBTCOMM, "Old firmware detected");
|
||||
}
|
||||
}
|
||||
|
|
1
pump/medtrum/.gitignore
vendored
Normal file
1
pump/medtrum/.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
/build
|
33
pump/medtrum/build.gradle
Normal file
33
pump/medtrum/build.gradle
Normal file
|
@ -0,0 +1,33 @@
|
|||
plugins {
|
||||
id 'com.android.library'
|
||||
id 'kotlin-android'
|
||||
id 'kotlin-kapt'
|
||||
id 'kotlin-allopen'
|
||||
}
|
||||
|
||||
apply from: "${project.rootDir}/core/main/android_dependencies.gradle"
|
||||
apply from: "${project.rootDir}/core/main/android_module_dependencies.gradle"
|
||||
apply from: "${project.rootDir}/core/main/allopen_dependencies.gradle"
|
||||
apply from: "${project.rootDir}/core/main/test_dependencies.gradle"
|
||||
apply from: "${project.rootDir}/core/main/jacoco_global.gradle"
|
||||
|
||||
android {
|
||||
namespace 'info.nightscout.pump.medtrum'
|
||||
dataBinding {
|
||||
enabled = true
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation project(':app-wear-shared:shared')
|
||||
implementation project(':database:entities')
|
||||
implementation project(':core:libraries')
|
||||
implementation project(':core:interfaces')
|
||||
implementation project(':core:main')
|
||||
implementation project(':core:ui')
|
||||
implementation project(':core:validators')
|
||||
implementation project(':pump:pump-common')
|
||||
implementation project(':core:utils')
|
||||
|
||||
testImplementation project(':core:main')
|
||||
}
|
0
pump/medtrum/consumer-rules.pro
Normal file
0
pump/medtrum/consumer-rules.pro
Normal file
21
pump/medtrum/proguard-rules.pro
vendored
Normal file
21
pump/medtrum/proguard-rules.pro
vendored
Normal file
|
@ -0,0 +1,21 @@
|
|||
# Add project specific ProGuard rules here.
|
||||
# You can control the set of applied configuration files using the
|
||||
# proguardFiles setting in build.gradle.
|
||||
#
|
||||
# For more details, see
|
||||
# http://developer.android.com/guide/developing/tools/proguard.html
|
||||
|
||||
# If your project uses WebView with JS, uncomment the following
|
||||
# and specify the fully qualified class name to the JavaScript interface
|
||||
# class:
|
||||
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
|
||||
# public *;
|
||||
#}
|
||||
|
||||
# Uncomment this to preserve the line number information for
|
||||
# debugging stack traces.
|
||||
#-keepattributes SourceFile,LineNumberTable
|
||||
|
||||
# If you keep the line number information, uncomment this to
|
||||
# hide the original source file name.
|
||||
#-renamesourcefileattribute SourceFile
|
17
pump/medtrum/src/main/AndroidManifest.xml
Normal file
17
pump/medtrum/src/main/AndroidManifest.xml
Normal file
|
@ -0,0 +1,17 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
<uses-permission android:name="android.permission.BLUETOOTH" />
|
||||
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
|
||||
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
|
||||
<uses-permission android:name="android.permission.BLUETOOTH_SCAN" />
|
||||
|
||||
<application>
|
||||
<activity android:name=".ui.MedtrumActivity" />
|
||||
<service
|
||||
android:name=".services.MedtrumService"
|
||||
android:enabled="true"
|
||||
android:exported="false" />
|
||||
</application>
|
||||
|
||||
</manifest>
|
|
@ -0,0 +1,494 @@
|
|||
package info.nightscout.pump.medtrum
|
||||
|
||||
import android.content.ComponentName
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.ServiceConnection
|
||||
import android.os.IBinder
|
||||
import android.text.format.DateFormat
|
||||
import androidx.preference.EditTextPreference
|
||||
import androidx.preference.ListPreference
|
||||
import androidx.preference.PreferenceFragmentCompat
|
||||
import dagger.android.HasAndroidInjector
|
||||
import info.nightscout.core.ui.toast.ToastUtils
|
||||
import info.nightscout.core.utils.fabric.FabricPrivacy
|
||||
import info.nightscout.interfaces.constraints.Constraint
|
||||
import info.nightscout.interfaces.constraints.Constraints
|
||||
import info.nightscout.interfaces.notifications.Notification
|
||||
import info.nightscout.interfaces.plugin.PluginDescription
|
||||
import info.nightscout.interfaces.plugin.PluginType
|
||||
import info.nightscout.interfaces.profile.Profile
|
||||
import info.nightscout.interfaces.pump.DetailedBolusInfo
|
||||
import info.nightscout.interfaces.pump.Medtrum
|
||||
import info.nightscout.interfaces.pump.Pump
|
||||
import info.nightscout.interfaces.pump.PumpEnactResult
|
||||
import info.nightscout.interfaces.pump.PumpPluginBase
|
||||
import info.nightscout.interfaces.pump.PumpSync
|
||||
import info.nightscout.interfaces.pump.TemporaryBasalStorage
|
||||
import info.nightscout.interfaces.pump.actions.CustomAction
|
||||
import info.nightscout.interfaces.pump.actions.CustomActionType
|
||||
import info.nightscout.interfaces.pump.defs.ManufacturerType
|
||||
import info.nightscout.interfaces.pump.defs.PumpDescription
|
||||
import info.nightscout.interfaces.pump.defs.PumpType
|
||||
import info.nightscout.interfaces.queue.Callback
|
||||
import info.nightscout.interfaces.queue.CommandQueue
|
||||
import info.nightscout.interfaces.queue.CustomCommand
|
||||
import info.nightscout.interfaces.ui.UiInteraction
|
||||
import info.nightscout.interfaces.utils.DecimalFormatter
|
||||
import info.nightscout.interfaces.utils.TimeChangeType
|
||||
import info.nightscout.pump.medtrum.comm.enums.MedtrumPumpState
|
||||
import info.nightscout.pump.medtrum.ui.MedtrumOverviewFragment
|
||||
import info.nightscout.pump.medtrum.services.MedtrumService
|
||||
import info.nightscout.rx.AapsSchedulers
|
||||
import info.nightscout.rx.bus.RxBus
|
||||
import info.nightscout.rx.events.EventAppExit
|
||||
import info.nightscout.rx.events.EventDismissNotification
|
||||
import info.nightscout.rx.events.EventOverviewBolusProgress
|
||||
import info.nightscout.rx.logging.AAPSLogger
|
||||
import info.nightscout.rx.logging.LTag
|
||||
import info.nightscout.shared.interfaces.ResourceHelper
|
||||
import info.nightscout.shared.utils.DateUtil
|
||||
import info.nightscout.shared.utils.T
|
||||
import io.reactivex.rxjava3.disposables.CompositeDisposable
|
||||
import io.reactivex.rxjava3.kotlin.plusAssign
|
||||
import org.json.JSONException
|
||||
import org.json.JSONObject
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
import kotlin.math.abs
|
||||
|
||||
@Singleton class MedtrumPlugin @Inject constructor(
|
||||
injector: HasAndroidInjector,
|
||||
aapsLogger: AAPSLogger,
|
||||
rh: ResourceHelper,
|
||||
commandQueue: CommandQueue,
|
||||
private val constraintChecker: Constraints,
|
||||
private val aapsSchedulers: AapsSchedulers,
|
||||
private val rxBus: RxBus,
|
||||
private val context: Context,
|
||||
private val fabricPrivacy: FabricPrivacy,
|
||||
private val dateUtil: DateUtil,
|
||||
private val medtrumPump: MedtrumPump,
|
||||
private val uiInteraction: UiInteraction,
|
||||
private val pumpSync: PumpSync,
|
||||
private val temporaryBasalStorage: TemporaryBasalStorage
|
||||
) : PumpPluginBase(
|
||||
PluginDescription()
|
||||
.mainType(PluginType.PUMP)
|
||||
.fragmentClass(MedtrumOverviewFragment::class.java.name)
|
||||
.pluginIcon(info.nightscout.core.ui.R.drawable.ic_medtrum_128)
|
||||
.pluginName(R.string.medtrum)
|
||||
.shortName(R.string.medtrum_pump_shortname)
|
||||
.preferencesId(R.xml.pref_medtrum_pump)
|
||||
.description(R.string.medtrum_pump_description), injector, aapsLogger, rh, commandQueue
|
||||
), Pump, Medtrum {
|
||||
|
||||
private val disposable = CompositeDisposable()
|
||||
private var medtrumService: MedtrumService? = null
|
||||
|
||||
override fun onStart() {
|
||||
super.onStart()
|
||||
aapsLogger.debug(LTag.PUMP, "MedtrumPlugin onStart()")
|
||||
val intent = Intent(context, MedtrumService::class.java)
|
||||
context.bindService(intent, mConnection, Context.BIND_AUTO_CREATE)
|
||||
disposable += rxBus
|
||||
.toObservable(EventAppExit::class.java)
|
||||
.observeOn(aapsSchedulers.io)
|
||||
.subscribe({ context.unbindService(mConnection) }, fabricPrivacy::logException)
|
||||
}
|
||||
|
||||
override fun onStop() {
|
||||
aapsLogger.debug(LTag.PUMP, "MedtrumPlugin onStop()")
|
||||
context.unbindService(mConnection)
|
||||
disposable.clear()
|
||||
super.onStop()
|
||||
}
|
||||
|
||||
private val mConnection: ServiceConnection = object : ServiceConnection {
|
||||
override fun onServiceDisconnected(name: ComponentName) {
|
||||
aapsLogger.debug(LTag.PUMP, "Service is disconnected")
|
||||
medtrumService = null
|
||||
}
|
||||
|
||||
override fun onServiceConnected(name: ComponentName, service: IBinder) {
|
||||
aapsLogger.debug(LTag.PUMP, "Service is connected")
|
||||
val mLocalBinder = service as MedtrumService.LocalBinder
|
||||
medtrumService = mLocalBinder.serviceInstance
|
||||
}
|
||||
}
|
||||
|
||||
fun getService(): MedtrumService? {
|
||||
return medtrumService
|
||||
}
|
||||
|
||||
override fun preprocessPreferences(preferenceFragment: PreferenceFragmentCompat) {
|
||||
super.preprocessPreferences(preferenceFragment)
|
||||
preferenceFragment.findPreference<EditTextPreference>(rh.gs(R.string.key_sn_input))?.isEnabled = !isInitialized()
|
||||
|
||||
val alarmSetting = preferenceFragment.findPreference<ListPreference>(rh.gs(R.string.key_alarm_setting))
|
||||
val allAlarmEntries = preferenceFragment.resources.getStringArray(R.array.alarmSettings)
|
||||
val allAlarmValues = preferenceFragment.resources.getStringArray(R.array.alarmSettingsValues)
|
||||
|
||||
if (allAlarmEntries.size < 8 || allAlarmValues.size < 8) {
|
||||
aapsLogger.error(LTag.PUMP, "Alarm settings array is not complete")
|
||||
return
|
||||
}
|
||||
|
||||
when (medtrumPump.pumpType()) {
|
||||
PumpType.MEDTRUM_NANO -> {
|
||||
alarmSetting?.entries = arrayOf(allAlarmEntries[6], allAlarmEntries[7]) // "Beep", "Silent"
|
||||
alarmSetting?.entryValues = arrayOf(allAlarmValues[6], allAlarmValues[7]) // "6", "7"
|
||||
}
|
||||
|
||||
else -> {
|
||||
// Use Nano settings for unknown pumps
|
||||
alarmSetting?.entries = arrayOf(allAlarmEntries[6], allAlarmEntries[7]) // "Beep", "Silent"
|
||||
alarmSetting?.entryValues = arrayOf(allAlarmValues[6], allAlarmValues[7]) // "6", "7"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun isInitialized(): Boolean {
|
||||
return medtrumPump.pumpState > MedtrumPumpState.EJECTED && medtrumPump.pumpState < MedtrumPumpState.STOPPED
|
||||
}
|
||||
|
||||
override fun isSuspended(): Boolean {
|
||||
return medtrumPump.pumpState < MedtrumPumpState.ACTIVE || medtrumPump.pumpState > MedtrumPumpState.ACTIVE_ALT
|
||||
}
|
||||
|
||||
override fun isBusy(): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
override fun isConnected(): Boolean {
|
||||
// This is a workaround to prevent AAPS to trigger connects when we have no patch activated
|
||||
return if (!isInitialized()) true else medtrumService?.isConnected ?: false
|
||||
}
|
||||
|
||||
override fun isConnecting(): Boolean = medtrumService?.isConnecting ?: false
|
||||
override fun isHandshakeInProgress(): Boolean = false
|
||||
|
||||
override fun finishHandshaking() {
|
||||
}
|
||||
|
||||
override fun connect(reason: String) {
|
||||
if (isInitialized()) {
|
||||
aapsLogger.debug(LTag.PUMP, "Medtrum connect - reason:$reason")
|
||||
if (medtrumService != null) {
|
||||
aapsLogger.debug(LTag.PUMP, "Medtrum connect - Attempt connection!")
|
||||
val success = medtrumService?.connect(reason) ?: false
|
||||
if (!success) ToastUtils.errorToast(context, info.nightscout.core.ui.R.string.ble_not_supported_or_not_paired)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun disconnect(reason: String) {
|
||||
if (isInitialized()) {
|
||||
aapsLogger.debug(LTag.PUMP, "Medtrum disconnect from: $reason")
|
||||
medtrumService?.disconnect(reason)
|
||||
}
|
||||
}
|
||||
|
||||
override fun stopConnecting() {
|
||||
if (isInitialized()) {
|
||||
aapsLogger.debug(LTag.PUMP, "Medtrum stopConnecting")
|
||||
medtrumService?.stopConnecting()
|
||||
}
|
||||
}
|
||||
|
||||
override fun getPumpStatus(reason: String) {
|
||||
aapsLogger.debug(LTag.PUMP, "Medtrum getPumpStatus - reason:$reason")
|
||||
if (isInitialized()) {
|
||||
val connectionOK = medtrumService?.readPumpStatus() ?: false
|
||||
if (connectionOK == false) {
|
||||
aapsLogger.error(LTag.PUMP, "Medtrum getPumpStatus failed")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun setNewBasalProfile(profile: Profile): PumpEnactResult {
|
||||
// New profile will be set when patch is activated
|
||||
if (!isInitialized()) return PumpEnactResult(injector).success(true).enacted(true)
|
||||
|
||||
return if (medtrumService?.updateBasalsInPump(profile) == true) {
|
||||
rxBus.send(EventDismissNotification(Notification.FAILED_UPDATE_PROFILE))
|
||||
uiInteraction.addNotificationValidFor(Notification.PROFILE_SET_OK, rh.gs(info.nightscout.core.ui.R.string.profile_set_ok), Notification.INFO, 60)
|
||||
PumpEnactResult(injector).success(true).enacted(true)
|
||||
} else {
|
||||
uiInteraction.addNotification(Notification.FAILED_UPDATE_PROFILE, rh.gs(info.nightscout.core.ui.R.string.failed_update_basal_profile), Notification.URGENT)
|
||||
PumpEnactResult(injector)
|
||||
}
|
||||
}
|
||||
|
||||
override fun isThisProfileSet(profile: Profile): Boolean {
|
||||
if (!isInitialized()) return true
|
||||
var result = false
|
||||
val profileBytes = medtrumPump.buildMedtrumProfileArray(profile)
|
||||
if (profileBytes?.size == medtrumPump.actualBasalProfile.size) {
|
||||
result = true
|
||||
for (i in profileBytes.indices) {
|
||||
if (profileBytes[i] != medtrumPump.actualBasalProfile[i]) {
|
||||
result = false
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
override fun lastDataTime(): Long = medtrumPump.lastConnection
|
||||
override val baseBasalRate: Double
|
||||
get() = medtrumPump.baseBasalRate
|
||||
|
||||
override val reservoirLevel: Double
|
||||
get() = medtrumPump.reservoir
|
||||
|
||||
override val batteryLevel: Int
|
||||
get() = 0 // We cannot determine battery level (yet)
|
||||
|
||||
@Synchronized
|
||||
override fun deliverTreatment(detailedBolusInfo: DetailedBolusInfo): PumpEnactResult {
|
||||
aapsLogger.debug(LTag.PUMP, "deliverTreatment: " + detailedBolusInfo.insulin + "U")
|
||||
if (!isInitialized()) return PumpEnactResult(injector).success(false).enacted(false)
|
||||
detailedBolusInfo.insulin = constraintChecker.applyBolusConstraints(Constraint(detailedBolusInfo.insulin)).value()
|
||||
return if (detailedBolusInfo.insulin > 0 && detailedBolusInfo.carbs == 0.0) {
|
||||
aapsLogger.debug(LTag.PUMP, "deliverTreatment: Delivering bolus: " + detailedBolusInfo.insulin + "U")
|
||||
val t = EventOverviewBolusProgress.Treatment(0.0, 0, detailedBolusInfo.bolusType == DetailedBolusInfo.BolusType.SMB, detailedBolusInfo.id)
|
||||
val connectionOK = medtrumService?.setBolus(detailedBolusInfo, t) ?: false
|
||||
val result = PumpEnactResult(injector)
|
||||
result.success = connectionOK && abs(detailedBolusInfo.insulin - t.insulin) < pumpDescription.bolusStep
|
||||
result.bolusDelivered = t.insulin
|
||||
if (!result.success) {
|
||||
// Note: There are no error codes
|
||||
result.comment = "failed"
|
||||
} else {
|
||||
result.comment = "ok"
|
||||
}
|
||||
aapsLogger.debug(LTag.PUMP, "deliverTreatment: OK. Success: ${result.success} Asked: ${detailedBolusInfo.insulin} Delivered: ${result.bolusDelivered}")
|
||||
result
|
||||
} else {
|
||||
aapsLogger.debug(LTag.PUMP, "deliverTreatment: Invalid input")
|
||||
val result = PumpEnactResult(injector)
|
||||
result.success = false
|
||||
result.bolusDelivered = 0.0
|
||||
result.comment = rh.gs(info.nightscout.core.ui.R.string.invalid_input)
|
||||
aapsLogger.error("deliverTreatment: Invalid input")
|
||||
result
|
||||
}
|
||||
}
|
||||
|
||||
override fun stopBolusDelivering() {
|
||||
if (!isInitialized()) return
|
||||
|
||||
aapsLogger.info(LTag.PUMP, "stopBolusDelivering")
|
||||
medtrumService?.stopBolus()
|
||||
}
|
||||
|
||||
@Synchronized
|
||||
override fun setTempBasalAbsolute(absoluteRate: Double, durationInMinutes: Int, profile: Profile, enforceNew: Boolean, tbrType: PumpSync.TemporaryBasalType): PumpEnactResult {
|
||||
if (!isInitialized()) return PumpEnactResult(injector).success(false).enacted(false)
|
||||
|
||||
aapsLogger.info(LTag.PUMP, "setTempBasalAbsolute - absoluteRate: $absoluteRate, durationInMinutes: $durationInMinutes, enforceNew: $enforceNew")
|
||||
// round rate to pump rate
|
||||
val pumpRate = constraintChecker.applyBasalConstraints(Constraint(absoluteRate), profile).value()
|
||||
temporaryBasalStorage.add(PumpSync.PumpState.TemporaryBasal(dateUtil.now(), T.mins(durationInMinutes.toLong()).msecs(), pumpRate, true, tbrType, 0L, 0L))
|
||||
val connectionOK = medtrumService?.setTempBasal(pumpRate, durationInMinutes) ?: false
|
||||
if (connectionOK
|
||||
&& medtrumPump.tempBasalInProgress
|
||||
&& Math.abs(medtrumPump.tempBasalAbsoluteRate - pumpRate) <= 0.05
|
||||
) {
|
||||
|
||||
return PumpEnactResult(injector).success(true).enacted(true).duration(durationInMinutes).absolute(medtrumPump.tempBasalAbsoluteRate)
|
||||
.isPercent(false)
|
||||
.isTempCancel(false)
|
||||
} else {
|
||||
aapsLogger.error(
|
||||
LTag.PUMP,
|
||||
"setTempBasalAbsolute failed, connectionOK: $connectionOK, tempBasalInProgress: ${medtrumPump.tempBasalInProgress}, tempBasalAbsoluteRate: ${medtrumPump.tempBasalAbsoluteRate}"
|
||||
)
|
||||
return PumpEnactResult(injector).success(false).enacted(false).comment("Medtrum setTempBasalAbsolute failed")
|
||||
}
|
||||
}
|
||||
|
||||
override fun setTempBasalPercent(percent: Int, durationInMinutes: Int, profile: Profile, enforceNew: Boolean, tbrType: PumpSync.TemporaryBasalType): PumpEnactResult {
|
||||
aapsLogger.info(LTag.PUMP, "setTempBasalPercent - percent: $percent, durationInMinutes: $durationInMinutes, enforceNew: $enforceNew")
|
||||
return PumpEnactResult(injector).success(false).enacted(false).comment("Medtrum driver does not support percentage temp basals")
|
||||
}
|
||||
|
||||
override fun setExtendedBolus(insulin: Double, durationInMinutes: Int): PumpEnactResult {
|
||||
aapsLogger.info(LTag.PUMP, "setExtendedBolus - insulin: $insulin, durationInMinutes: $durationInMinutes")
|
||||
return PumpEnactResult(injector).success(false).enacted(false).comment("Medtrum driver does not support extended boluses")
|
||||
}
|
||||
|
||||
override fun cancelTempBasal(enforceNew: Boolean): PumpEnactResult {
|
||||
if (!isInitialized()) return PumpEnactResult(injector).success(false).enacted(false)
|
||||
|
||||
aapsLogger.info(LTag.PUMP, "cancelTempBasal - enforceNew: $enforceNew")
|
||||
val connectionOK = medtrumService?.cancelTempBasal() ?: false
|
||||
if (connectionOK && !medtrumPump.tempBasalInProgress) {
|
||||
return PumpEnactResult(injector).success(true).enacted(true).isTempCancel(true)
|
||||
} else {
|
||||
aapsLogger.error(LTag.PUMP, "cancelTempBasal failed, connectionOK: $connectionOK, tempBasalInProgress: ${medtrumPump.tempBasalInProgress}")
|
||||
return PumpEnactResult(injector).success(false).enacted(false).comment("Medtrum cancelTempBasal failed")
|
||||
}
|
||||
}
|
||||
|
||||
override fun cancelExtendedBolus(): PumpEnactResult {
|
||||
return PumpEnactResult(injector)
|
||||
}
|
||||
|
||||
override fun getJSONStatus(profile: Profile, profileName: String, version: String): JSONObject {
|
||||
val now = System.currentTimeMillis()
|
||||
if (medtrumPump.lastConnection + 60 * 60 * 1000L < System.currentTimeMillis()) {
|
||||
return JSONObject()
|
||||
}
|
||||
val pumpJson = JSONObject()
|
||||
val status = JSONObject()
|
||||
val extended = JSONObject()
|
||||
try {
|
||||
status.put(
|
||||
"status", if (!isSuspended()) "normal"
|
||||
else if (isInitialized() && isSuspended()) "suspended"
|
||||
else "no active patch"
|
||||
)
|
||||
status.put("timestamp", dateUtil.toISOString(medtrumPump.lastConnection))
|
||||
if (medtrumPump.lastBolusTime != 0L) {
|
||||
extended.put("lastBolus", dateUtil.dateAndTimeString(medtrumPump.lastBolusTime))
|
||||
extended.put("lastBolusAmount", medtrumPump.lastBolusAmount)
|
||||
}
|
||||
val tb = pumpSync.expectedPumpState().temporaryBasal
|
||||
if (tb != null) {
|
||||
extended.put("TempBasalAbsoluteRate", tb.convertedToAbsolute(now, profile))
|
||||
extended.put("TempBasalStart", dateUtil.dateAndTimeString(tb.timestamp))
|
||||
extended.put("TempBasalRemaining", tb.plannedRemainingMinutes)
|
||||
}
|
||||
extended.put("BaseBasalRate", baseBasalRate)
|
||||
try {
|
||||
extended.put("ActiveProfile", profileName)
|
||||
} catch (ignored: Exception) {
|
||||
}
|
||||
pumpJson.put("status", status)
|
||||
pumpJson.put("extended", extended)
|
||||
pumpJson.put("reservoir", medtrumPump.reservoir.toInt())
|
||||
pumpJson.put("clock", dateUtil.toISOString(now))
|
||||
} catch (e: JSONException) {
|
||||
aapsLogger.error(LTag.PUMP, "Unhandled exception: $e")
|
||||
}
|
||||
return pumpJson
|
||||
}
|
||||
|
||||
override fun manufacturer(): ManufacturerType {
|
||||
return ManufacturerType.Medtrum
|
||||
}
|
||||
|
||||
override fun model(): PumpType {
|
||||
return medtrumPump.pumpType()
|
||||
}
|
||||
|
||||
override fun serialNumber(): String {
|
||||
// Load from SP here, because this value will be get before pump is initialized
|
||||
return medtrumPump.pumpSNFromSP.toString(radix = 16)
|
||||
}
|
||||
|
||||
override val pumpDescription: PumpDescription
|
||||
get() = PumpDescription(medtrumPump.pumpType())
|
||||
|
||||
override fun shortStatus(veryShort: Boolean): String {
|
||||
var ret = ""
|
||||
if (medtrumPump.lastConnection != 0L) {
|
||||
val agoMillis = System.currentTimeMillis() - medtrumPump.lastConnection
|
||||
val agoMin = (agoMillis / 60.0 / 1000.0).toInt()
|
||||
ret += "LastConn: $agoMin minAgo\n"
|
||||
}
|
||||
if (medtrumPump.lastBolusTime != 0L)
|
||||
ret += "LastBolus: ${DecimalFormatter.to2Decimal(medtrumPump.lastBolusAmount)}U @${DateFormat.format("HH:mm", medtrumPump.lastBolusTime)}\n"
|
||||
|
||||
if (medtrumPump.tempBasalInProgress)
|
||||
ret += "Temp: ${medtrumPump.temporaryBasalToString()}\n"
|
||||
|
||||
ret += "Res: ${DecimalFormatter.to0Decimal(medtrumPump.reservoir)}U\n"
|
||||
return ret
|
||||
}
|
||||
|
||||
override val isFakingTempsByExtendedBoluses: Boolean = false
|
||||
|
||||
override fun loadTDDs(): PumpEnactResult {
|
||||
return PumpEnactResult(injector) // Note: Can implement this if we implement history fully (no priority)
|
||||
}
|
||||
|
||||
override fun getCustomActions(): List<CustomAction>? {
|
||||
return null
|
||||
}
|
||||
|
||||
override fun executeCustomAction(customActionType: CustomActionType) {
|
||||
}
|
||||
|
||||
override fun executeCustomCommand(customCommand: CustomCommand): PumpEnactResult? {
|
||||
return null
|
||||
}
|
||||
|
||||
override fun canHandleDST(): Boolean {
|
||||
return true
|
||||
}
|
||||
|
||||
override fun timezoneOrDSTChanged(timeChangeType: TimeChangeType) {
|
||||
medtrumPump.needCheckTimeUpdate = true
|
||||
if (isInitialized()) {
|
||||
commandQueue.updateTime(object : Callback() {
|
||||
override fun run() {
|
||||
if (this.result.success == false) {
|
||||
aapsLogger.error(LTag.PUMP, "Medtrum time update failed")
|
||||
// Only notify here on failure (connection may be failed), service will handle success
|
||||
medtrumService?.timeUpdateNotification(false)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// Medtrum interface
|
||||
override fun loadEvents(): PumpEnactResult {
|
||||
if (!isInitialized()) {
|
||||
val result = PumpEnactResult(injector).success(false)
|
||||
result.comment = "pump not initialized"
|
||||
return result
|
||||
}
|
||||
val connectionOK = medtrumService?.loadEvents() ?: false
|
||||
return PumpEnactResult(injector).success(connectionOK)
|
||||
}
|
||||
|
||||
override fun setUserOptions(): PumpEnactResult {
|
||||
if (!isInitialized()) {
|
||||
val result = PumpEnactResult(injector).success(false)
|
||||
result.comment = "pump not initialized"
|
||||
return result
|
||||
}
|
||||
val connectionOK = medtrumService?.setUserSettings() ?: false
|
||||
return PumpEnactResult(injector).success(connectionOK)
|
||||
}
|
||||
|
||||
override fun clearAlarms(): PumpEnactResult {
|
||||
if (!isInitialized()) {
|
||||
val result = PumpEnactResult(injector).success(false)
|
||||
result.comment = "pump not initialized"
|
||||
return result
|
||||
}
|
||||
val connectionOK = medtrumService?.clearAlarms() ?: false
|
||||
return PumpEnactResult(injector).success(connectionOK)
|
||||
}
|
||||
|
||||
override fun deactivate(): PumpEnactResult {
|
||||
val connectionOK = medtrumService?.deactivatePatch() ?: false
|
||||
return PumpEnactResult(injector).success(connectionOK)
|
||||
}
|
||||
|
||||
override fun updateTime(): PumpEnactResult {
|
||||
if (!isInitialized()) {
|
||||
val result = PumpEnactResult(injector).success(false)
|
||||
result.comment = "pump not initialized"
|
||||
return result
|
||||
}
|
||||
val connectionOK = medtrumService?.updateTimeIfNeeded() ?: false
|
||||
return PumpEnactResult(injector).success(connectionOK)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,539 @@
|
|||
package info.nightscout.pump.medtrum
|
||||
|
||||
import android.util.Base64
|
||||
import info.nightscout.interfaces.profile.Profile
|
||||
import info.nightscout.interfaces.pump.PumpSync
|
||||
import info.nightscout.interfaces.pump.TemporaryBasalStorage
|
||||
import info.nightscout.interfaces.pump.defs.PumpType
|
||||
import info.nightscout.pump.medtrum.code.ConnectionState
|
||||
import info.nightscout.pump.medtrum.comm.enums.AlarmSetting
|
||||
import info.nightscout.pump.medtrum.comm.enums.AlarmState
|
||||
import info.nightscout.pump.medtrum.comm.enums.BasalType
|
||||
import info.nightscout.pump.medtrum.comm.enums.MedtrumPumpState
|
||||
import info.nightscout.pump.medtrum.extension.toByteArray
|
||||
import info.nightscout.pump.medtrum.extension.toInt
|
||||
import info.nightscout.rx.events.EventOverviewBolusProgress
|
||||
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 info.nightscout.shared.utils.DateUtil
|
||||
import info.nightscout.shared.utils.T
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import java.util.*
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
import kotlin.math.round
|
||||
|
||||
@Singleton
|
||||
class MedtrumPump @Inject constructor(
|
||||
private val aapsLogger: AAPSLogger,
|
||||
private val rh: ResourceHelper,
|
||||
private val sp: SP,
|
||||
private val dateUtil: DateUtil,
|
||||
private val pumpSync: PumpSync,
|
||||
private val temporaryBasalStorage: TemporaryBasalStorage
|
||||
) {
|
||||
|
||||
companion object {
|
||||
|
||||
const val FAKE_TBR_LENGTH = 4800L
|
||||
}
|
||||
|
||||
// Connection state flow
|
||||
private val _connectionState = MutableStateFlow(ConnectionState.DISCONNECTED)
|
||||
val connectionStateFlow: StateFlow<ConnectionState> = _connectionState
|
||||
var connectionState: ConnectionState
|
||||
get() = _connectionState.value
|
||||
set(value) {
|
||||
_connectionState.value = value
|
||||
}
|
||||
|
||||
// Pump state flow
|
||||
private val _pumpState = MutableStateFlow(MedtrumPumpState.NONE)
|
||||
val pumpStateFlow: StateFlow<MedtrumPumpState> = _pumpState
|
||||
var pumpState: MedtrumPumpState
|
||||
get() = _pumpState.value
|
||||
set(value) {
|
||||
_pumpState.value = value
|
||||
sp.putInt(R.string.key_pump_state, value.state.toInt())
|
||||
}
|
||||
|
||||
// Active alarms
|
||||
private var _activeAlarms: EnumSet<AlarmState> = EnumSet.noneOf(AlarmState::class.java)
|
||||
var activeAlarms: EnumSet<AlarmState>
|
||||
get() = _activeAlarms
|
||||
set(value) {
|
||||
_activeAlarms = value
|
||||
}
|
||||
|
||||
// Prime progress as state flow
|
||||
private val _primeProgress = MutableStateFlow(0)
|
||||
val primeProgressFlow: StateFlow<Int> = _primeProgress
|
||||
var primeProgress: Int
|
||||
get() = _primeProgress.value
|
||||
set(value) {
|
||||
_primeProgress.value = value
|
||||
}
|
||||
|
||||
private var _lastBasalType: MutableStateFlow<BasalType> = MutableStateFlow(BasalType.NONE)
|
||||
val lastBasalTypeFlow: StateFlow<BasalType> = _lastBasalType
|
||||
val lastBasalType: BasalType
|
||||
get() = _lastBasalType.value
|
||||
|
||||
private val _lastBasalRate = MutableStateFlow(0.0)
|
||||
val lastBasalRateFlow: StateFlow<Double> = _lastBasalRate
|
||||
val lastBasalRate: Double
|
||||
get() = _lastBasalRate.value
|
||||
|
||||
private val _reservoir = MutableStateFlow(0.0)
|
||||
val reservoirFlow: StateFlow<Double> = _reservoir
|
||||
var reservoir: Double
|
||||
get() = _reservoir.value
|
||||
set(value) {
|
||||
_reservoir.value = value
|
||||
}
|
||||
|
||||
var batteryVoltage_A = 0.0 // Not used in UI
|
||||
private val _batteryVoltage_B = MutableStateFlow(0.0)
|
||||
val batteryVoltage_BFlow: StateFlow<Double> = _batteryVoltage_B
|
||||
var batteryVoltage_B: Double
|
||||
get() = _batteryVoltage_B.value
|
||||
set(value) {
|
||||
_batteryVoltage_B.value = value
|
||||
}
|
||||
|
||||
/** Stuff stored in SP */
|
||||
private var _patchSessionToken = 0L
|
||||
var patchSessionToken: Long
|
||||
get() = _patchSessionToken
|
||||
set(value) {
|
||||
_patchSessionToken = value
|
||||
sp.putLong(R.string.key_session_token, value)
|
||||
}
|
||||
|
||||
private var _patchId = 0L
|
||||
var patchId: Long
|
||||
get() = _patchId
|
||||
set(value) {
|
||||
_patchId = value
|
||||
sp.putLong(R.string.key_patch_id, value)
|
||||
}
|
||||
|
||||
private var _currentSequenceNumber = 0
|
||||
var currentSequenceNumber: Int
|
||||
get() = _currentSequenceNumber
|
||||
set(value) {
|
||||
_currentSequenceNumber = value
|
||||
sp.putInt(R.string.key_current_sequence_number, value)
|
||||
}
|
||||
|
||||
private var _syncedSequenceNumber = 0
|
||||
var syncedSequenceNumber: Int
|
||||
get() = _syncedSequenceNumber
|
||||
set(value) {
|
||||
_syncedSequenceNumber = value
|
||||
sp.putInt(R.string.key_synced_sequence_number, value)
|
||||
}
|
||||
|
||||
private var _actualBasalProfile = byteArrayOf(0)
|
||||
var actualBasalProfile: ByteArray
|
||||
get() = _actualBasalProfile
|
||||
set(value) {
|
||||
_actualBasalProfile = value
|
||||
val encodedString = Base64.encodeToString(value, Base64.DEFAULT)
|
||||
sp.putString(R.string.key_actual_basal_profile, encodedString ?: "")
|
||||
}
|
||||
|
||||
private var _lastBolusTime = 0L // Time in ms!
|
||||
var lastBolusTime: Long
|
||||
get() = _lastBolusTime
|
||||
set(value) {
|
||||
_lastBolusTime = value
|
||||
sp.putLong(R.string.key_last_bolus_time, value)
|
||||
}
|
||||
|
||||
private var _lastBolusAmount = 0.0
|
||||
var lastBolusAmount: Double
|
||||
get() = _lastBolusAmount
|
||||
set(value) {
|
||||
_lastBolusAmount = value
|
||||
sp.putDouble(R.string.key_last_bolus_amount, value)
|
||||
}
|
||||
|
||||
private var _lastConnection = 0L // Time in ms!
|
||||
var lastConnection: Long
|
||||
get() = _lastConnection
|
||||
set(value) {
|
||||
_lastConnection = value
|
||||
sp.putLong(R.string.key_last_connection, value)
|
||||
}
|
||||
|
||||
private var _deviceType: Int = 80 // As reported by pump
|
||||
var deviceType: Int
|
||||
get() = _deviceType
|
||||
set(value) {
|
||||
_deviceType = value
|
||||
sp.putInt(R.string.key_device_type, value)
|
||||
}
|
||||
|
||||
private var _swVersion: String = "" // As reported by pump
|
||||
var swVersion: String
|
||||
get() = _swVersion
|
||||
set(value) {
|
||||
_swVersion = value
|
||||
sp.putString(R.string.key_sw_version, value)
|
||||
}
|
||||
|
||||
private var _patchStartTime = 0L // Time in ms!
|
||||
var patchStartTime: Long
|
||||
get() = _patchStartTime
|
||||
set(value) {
|
||||
_patchStartTime = value
|
||||
sp.putLong(R.string.key_patch_start_time, value)
|
||||
}
|
||||
|
||||
private var _pumpTimeZoneOffset = 0 // As reported by pump
|
||||
var pumpTimeZoneOffset: Int
|
||||
get() = _pumpTimeZoneOffset
|
||||
set(value) {
|
||||
_pumpTimeZoneOffset = value
|
||||
sp.putInt(R.string.key_pump_time_zone_offset, value)
|
||||
}
|
||||
|
||||
private var _pumpSN = 0L
|
||||
val pumpSN: Long
|
||||
get() = _pumpSN
|
||||
|
||||
val pumpSNFromSP: Long
|
||||
get() =
|
||||
try {
|
||||
sp.getString(R.string.key_sn_input, "0").toLong(radix = 16)
|
||||
} catch (e: NumberFormatException) {
|
||||
aapsLogger.debug(LTag.PUMP, "pumpSNFromSP: Invalid input!")
|
||||
0L
|
||||
}
|
||||
|
||||
var needCheckTimeUpdate = false
|
||||
var lastTimeReceivedFromPump = 0L // Time in ms!
|
||||
var suspendTime = 0L // Time in ms!
|
||||
var patchAge = 0L // Time in seconds?! // As reported by pump, not used (yet)
|
||||
|
||||
// bolus status
|
||||
var bolusingTreatment: EventOverviewBolusProgress.Treatment? = null // actually delivered treatment
|
||||
var bolusAmountToBeDelivered = 0.0 // amount to be delivered
|
||||
var bolusProgressLastTimeStamp: Long = 0 // timestamp of last bolus progress message
|
||||
var bolusStopped = false // bolus stopped by user
|
||||
var bolusDone = false // Bolus completed or stopped on pump
|
||||
|
||||
// Last basal status update (from pump)
|
||||
private var _lastBasalSequence = 0
|
||||
val lastBasalSequence: Int
|
||||
get() = _lastBasalSequence
|
||||
|
||||
private var _lastBasalPatchId = 0L
|
||||
val lastBasalPatchId: Long
|
||||
get() = _lastBasalPatchId
|
||||
|
||||
private var _lastBasalStartTime = 0L
|
||||
val lastBasalStartTime: Long
|
||||
get() = _lastBasalStartTime
|
||||
|
||||
val baseBasalRate: Double
|
||||
get() = getHourlyBasalFromMedtrumProfileArray(actualBasalProfile, dateUtil.now())
|
||||
|
||||
// TBR status
|
||||
val tempBasalInProgress: Boolean
|
||||
get() = lastBasalType == BasalType.ABSOLUTE_TEMP || lastBasalType == BasalType.RELATIVE_TEMP
|
||||
val tempBasalAbsoluteRate: Double
|
||||
get() = if (tempBasalInProgress) lastBasalRate else 0.0
|
||||
|
||||
// Last stop status update
|
||||
var lastStopSequence = 0
|
||||
var lastStopPatchId = 0L
|
||||
|
||||
// User settings (desired values, to be set on pump)
|
||||
var desiredPatchExpiration = false
|
||||
var desiredAlarmSetting = AlarmSetting.LIGHT_VIBRATE_AND_BEEP
|
||||
var desiredHourlyMaxInsulin: Int = 40
|
||||
var desiredDailyMaxInsulin: Int = 180
|
||||
|
||||
init {
|
||||
// Load stuff from SP
|
||||
_patchSessionToken = sp.getLong(R.string.key_session_token, 0L)
|
||||
_lastConnection = sp.getLong(R.string.key_last_connection, 0L)
|
||||
_lastBolusTime = sp.getLong(R.string.key_last_bolus_time, 0L)
|
||||
_lastBolusAmount = sp.getDouble(R.string.key_last_bolus_amount, 0.0)
|
||||
_currentSequenceNumber = sp.getInt(R.string.key_current_sequence_number, 0)
|
||||
_patchId = sp.getLong(R.string.key_patch_id, 0L)
|
||||
_syncedSequenceNumber = sp.getInt(R.string.key_synced_sequence_number, 0)
|
||||
_pumpState.value = MedtrumPumpState.fromByte(sp.getInt(R.string.key_pump_state, MedtrumPumpState.NONE.state.toInt()).toByte())
|
||||
_deviceType = sp.getInt(R.string.key_device_type, 0)
|
||||
_swVersion = sp.getString(R.string.key_sw_version, "")
|
||||
_patchStartTime = sp.getLong(R.string.key_patch_start_time, 0L)
|
||||
_pumpTimeZoneOffset = sp.getInt(R.string.key_pump_time_zone_offset, 0)
|
||||
|
||||
loadActiveAlarms()
|
||||
|
||||
val encodedString = sp.getString(R.string.key_actual_basal_profile, "0")
|
||||
try {
|
||||
_actualBasalProfile = Base64.decode(encodedString, Base64.DEFAULT)
|
||||
} catch (e: Exception) {
|
||||
aapsLogger.error(LTag.PUMP, "Error decoding basal profile from SP: $encodedString")
|
||||
}
|
||||
}
|
||||
|
||||
fun pumpType(): PumpType =
|
||||
when (deviceType) {
|
||||
80, 88 -> PumpType.MEDTRUM_NANO
|
||||
else -> PumpType.MEDTRUM_UNTESTED
|
||||
}
|
||||
|
||||
fun loadUserSettingsFromSP() {
|
||||
desiredPatchExpiration = sp.getBoolean(info.nightscout.pump.medtrum.R.string.key_patch_expiration, false)
|
||||
val alarmSettingCode = sp.getString(info.nightscout.pump.medtrum.R.string.key_alarm_setting, AlarmSetting.LIGHT_VIBRATE_AND_BEEP.code.toString()).toByte()
|
||||
desiredAlarmSetting = AlarmSetting.values().firstOrNull { it.code == alarmSettingCode } ?: AlarmSetting.LIGHT_VIBRATE_AND_BEEP
|
||||
desiredHourlyMaxInsulin = sp.getInt(info.nightscout.pump.medtrum.R.string.key_hourly_max_insulin, 40)
|
||||
desiredDailyMaxInsulin = sp.getInt(info.nightscout.pump.medtrum.R.string.key_daily_max_insulin, 180)
|
||||
_pumpSN = pumpSNFromSP
|
||||
|
||||
}
|
||||
|
||||
fun buildMedtrumProfileArray(nsProfile: Profile): ByteArray? {
|
||||
val list = nsProfile.getBasalValues()
|
||||
var basals = byteArrayOf()
|
||||
for (item in list) {
|
||||
val rate = round(item.value / 0.05).toInt()
|
||||
val time = item.timeAsSeconds / 60
|
||||
if (rate > 0xFFF || time > 0xFFF) {
|
||||
aapsLogger.error(LTag.PUMP, "buildMedtrumProfileArray: rate or time too large: $rate, $time")
|
||||
return null
|
||||
}
|
||||
basals += ((rate shl 12) + time).toByteArray(3)
|
||||
aapsLogger.debug(LTag.PUMP, "buildMedtrumProfileArray: value: ${item.value} time: ${item.timeAsSeconds}, converted: $rate, $time")
|
||||
}
|
||||
return (list.size).toByteArray(1) + basals
|
||||
}
|
||||
|
||||
fun getHourlyBasalFromMedtrumProfileArray(basalProfile: ByteArray, timestamp: Long): Double {
|
||||
val basalCount = basalProfile[0].toInt()
|
||||
var basal = 0.0
|
||||
if (basalProfile.size < 4 || (basalProfile.size - 1) % 3 != 0 || basalCount > 24) {
|
||||
aapsLogger.debug(LTag.PUMP, "getHourlyBasalFromMedtrumProfileArray: No valid basal profile set")
|
||||
return basal
|
||||
}
|
||||
|
||||
val date = GregorianCalendar()
|
||||
date.timeInMillis = timestamp
|
||||
val hourOfDayMinutes = date.get(GregorianCalendar.HOUR_OF_DAY) * 60 + date.get(GregorianCalendar.MINUTE)
|
||||
|
||||
for (index in 0 until basalCount) {
|
||||
val currentIndex = 1 + (index * 3)
|
||||
val nextIndex = currentIndex + 3
|
||||
val rateAndTime = basalProfile.copyOfRange(currentIndex, nextIndex).toInt()
|
||||
val rate = (rateAndTime shr 12) * 0.05
|
||||
val startMinutes = rateAndTime and 0xFFF
|
||||
|
||||
val endMinutes = if (nextIndex < basalProfile.size) {
|
||||
val nextRateAndTime = basalProfile.copyOfRange(nextIndex, nextIndex + 3).toInt()
|
||||
nextRateAndTime and 0xFFF
|
||||
} else {
|
||||
24 * 60
|
||||
}
|
||||
|
||||
if (hourOfDayMinutes in startMinutes until endMinutes) {
|
||||
basal = rate
|
||||
aapsLogger.debug(LTag.PUMP, "getHourlyBasalFromMedtrumProfileArray: basal: $basal")
|
||||
break
|
||||
}
|
||||
// aapsLogger.debug(LTag.PUMP, "getHourlyBasalFromMedtrumProfileArray: rate: $rate, startMinutes: $startMinutes, endMinutes: $endMinutes")
|
||||
}
|
||||
return basal
|
||||
}
|
||||
|
||||
fun handleBolusStatusUpdate(bolusType: Int, bolusCompleted: Boolean, amountDelivered: Double) {
|
||||
aapsLogger.debug(LTag.PUMP, "handleBolusStatusUpdate: bolusType: $bolusType bolusCompleted: $bolusCompleted amountDelivered: $amountDelivered")
|
||||
bolusProgressLastTimeStamp = dateUtil.now()
|
||||
bolusingTreatment?.insulin = amountDelivered
|
||||
bolusDone = bolusCompleted
|
||||
}
|
||||
|
||||
fun handleBasalStatusUpdate(basalType: BasalType, basalValue: Double, basalSequence: Int, basalPatchId: Long, basalStartTime: Long) {
|
||||
handleBasalStatusUpdate(basalType, basalValue, basalSequence, basalPatchId, basalStartTime, dateUtil.now())
|
||||
}
|
||||
|
||||
fun handleBasalStatusUpdate(basalType: BasalType, basalRate: Double, basalSequence: Int, basalPatchId: Long, basalStartTime: Long, receivedTime: Long) {
|
||||
aapsLogger.debug(
|
||||
LTag.PUMP,
|
||||
"handleBasalStatusUpdate: basalType: $basalType basalValue: $basalRate basalSequence: $basalSequence basalPatchId: $basalPatchId basalStartTime: $basalStartTime " + "receivedTime: $receivedTime"
|
||||
)
|
||||
@Suppress("UNNECESSARY_SAFE_CALL") // Safe call to allow mocks to return null
|
||||
val expectedTemporaryBasal = pumpSync.expectedPumpState()?.temporaryBasal
|
||||
if (basalType.isTempBasal() && expectedTemporaryBasal?.pumpId != basalStartTime) {
|
||||
// Note: temporaryBasalInfo will be removed from temporaryBasalStorage after this call
|
||||
val temporaryBasalInfo = temporaryBasalStorage.findTemporaryBasal(basalStartTime, basalRate)
|
||||
|
||||
// If duration is unknown, no way to get it now, set patch lifetime as duration
|
||||
val duration = temporaryBasalInfo?.duration ?: T.mins(FAKE_TBR_LENGTH).msecs()
|
||||
val adjustedBasalRate = if (basalType == BasalType.ABSOLUTE_TEMP) {
|
||||
basalRate
|
||||
} else {
|
||||
(basalRate / baseBasalRate) * 100 // calculate the percentage of the original basal rate
|
||||
}
|
||||
val newRecord = pumpSync.syncTemporaryBasalWithPumpId(
|
||||
timestamp = basalStartTime,
|
||||
rate = adjustedBasalRate,
|
||||
duration = duration,
|
||||
isAbsolute = (basalType == BasalType.ABSOLUTE_TEMP),
|
||||
type = temporaryBasalInfo?.type,
|
||||
pumpId = basalStartTime,
|
||||
pumpType = pumpType(),
|
||||
pumpSerial = pumpSN.toString(radix = 16)
|
||||
)
|
||||
aapsLogger.debug(
|
||||
LTag.PUMPCOMM,
|
||||
"handleBasalStatusUpdate: ${if (newRecord) "**NEW** " else ""}EVENT TEMP_START ($basalType) ${dateUtil.dateAndTimeString(basalStartTime)} ($basalStartTime) " + "Rate: $basalRate Duration: ${duration} temporaryBasalInfo: $temporaryBasalInfo, expectedTemporaryBasal: $expectedTemporaryBasal"
|
||||
)
|
||||
} else if (basalType.isSuspendedByPump() && expectedTemporaryBasal?.pumpId != basalStartTime) {
|
||||
val newRecord = pumpSync.syncTemporaryBasalWithPumpId(
|
||||
timestamp = basalStartTime,
|
||||
rate = 0.0,
|
||||
duration = T.mins(FAKE_TBR_LENGTH).msecs(),
|
||||
isAbsolute = true,
|
||||
type = PumpSync.TemporaryBasalType.PUMP_SUSPEND,
|
||||
pumpId = basalStartTime,
|
||||
pumpType = pumpType(),
|
||||
pumpSerial = pumpSN.toString(radix = 16)
|
||||
)
|
||||
aapsLogger.debug(
|
||||
LTag.PUMPCOMM,
|
||||
"handleBasalStatusUpdate: ${if (newRecord) "**NEW** " else ""}EVENT TEMP_START ($basalType) ${dateUtil.dateAndTimeString(basalStartTime)} ($basalStartTime) expectedTemporaryBasal: $expectedTemporaryBasal"
|
||||
)
|
||||
} else if (basalType == BasalType.NONE && expectedTemporaryBasal?.rate != basalRate && expectedTemporaryBasal?.duration != T.mins(FAKE_TBR_LENGTH).msecs()) {
|
||||
// Pump suspended, set fake TBR
|
||||
setFakeTBR()
|
||||
} else if (basalType == BasalType.STANDARD) {
|
||||
if (expectedTemporaryBasal != null) {
|
||||
// Pump resumed, sync end
|
||||
val success = pumpSync.syncStopTemporaryBasalWithPumpId(
|
||||
timestamp = basalStartTime + 250, // Time of normal basal start = time of tbr end
|
||||
endPumpId = basalStartTime + 250, // +250ms Make sure there is time between start and stop of TBR
|
||||
pumpType = pumpType(),
|
||||
pumpSerial = pumpSN.toString(radix = 16)
|
||||
)
|
||||
aapsLogger.debug(LTag.PUMPCOMM, "handleBasalStatusUpdate: EVENT TEMP_END ${dateUtil.dateAndTimeString(basalStartTime)} ($basalStartTime) success: $success")
|
||||
}
|
||||
}
|
||||
|
||||
// Update medtrum pump state
|
||||
_lastBasalType.value = basalType
|
||||
_lastBasalRate.value = basalRate
|
||||
_lastBasalSequence = basalSequence
|
||||
if (basalSequence > currentSequenceNumber) {
|
||||
currentSequenceNumber = basalSequence
|
||||
}
|
||||
_lastBasalPatchId = basalPatchId
|
||||
if (basalPatchId != patchId) {
|
||||
aapsLogger.error(LTag.PUMP, "handleBasalStatusUpdate: WTF? PatchId in status update does not match current patchId!")
|
||||
}
|
||||
_lastBasalStartTime = basalStartTime
|
||||
}
|
||||
|
||||
fun handleStopStatusUpdate(stopSequence: Int, stopPatchId: Long) {
|
||||
aapsLogger.debug(LTag.PUMP, "handleStopStatusUpdate: stopSequence: $stopSequence stopPatchId: $stopPatchId")
|
||||
lastStopSequence = stopSequence
|
||||
if (stopSequence > currentSequenceNumber) {
|
||||
currentSequenceNumber = stopSequence
|
||||
}
|
||||
lastStopPatchId = stopPatchId
|
||||
if (stopPatchId != patchId) {
|
||||
aapsLogger.error(LTag.PUMP, "handleStopStatusUpdate: WTF? PatchId in status update does not match current patchId!")
|
||||
}
|
||||
}
|
||||
|
||||
fun setFakeTBRIfNeeded() {
|
||||
val expectedTemporaryBasal = pumpSync.expectedPumpState().temporaryBasal
|
||||
if (expectedTemporaryBasal?.duration != T.mins(FAKE_TBR_LENGTH).msecs()) {
|
||||
setFakeTBR()
|
||||
}
|
||||
}
|
||||
|
||||
private fun setFakeTBR() {
|
||||
val newRecord = pumpSync.syncTemporaryBasalWithPumpId(
|
||||
timestamp = dateUtil.now(),
|
||||
rate = 0.0,
|
||||
duration = T.mins(FAKE_TBR_LENGTH).msecs(),
|
||||
isAbsolute = true,
|
||||
type = PumpSync.TemporaryBasalType.PUMP_SUSPEND,
|
||||
pumpId = dateUtil.now(),
|
||||
pumpType = pumpType(),
|
||||
pumpSerial = pumpSN.toString(radix = 16)
|
||||
)
|
||||
aapsLogger.debug(
|
||||
LTag.PUMPCOMM,
|
||||
"handleBasalStatusUpdate: ${if (newRecord) "**NEW** " else ""}EVENT TEMP_START (FAKE)"
|
||||
)
|
||||
}
|
||||
|
||||
fun temporaryBasalToString(): String {
|
||||
if (!tempBasalInProgress) return ""
|
||||
return tempBasalAbsoluteRate.toString() + "U/h"
|
||||
}
|
||||
|
||||
fun addAlarm(alarm: AlarmState) {
|
||||
activeAlarms.add(alarm)
|
||||
saveActiveAlarms()
|
||||
}
|
||||
|
||||
fun removeAlarm(alarm: AlarmState) {
|
||||
activeAlarms.remove(alarm)
|
||||
saveActiveAlarms()
|
||||
}
|
||||
|
||||
fun clearAlarmState() {
|
||||
activeAlarms.clear()
|
||||
saveActiveAlarms()
|
||||
}
|
||||
|
||||
fun alarmStateToString(alarmState: AlarmState): String {
|
||||
val stringId = when (alarmState) {
|
||||
AlarmState.NONE -> R.string.alarm_none
|
||||
AlarmState.PUMP_LOW_BATTERY -> R.string.alarm_pump_low_battery
|
||||
AlarmState.PUMP_LOW_RESERVOIR -> R.string.alarm_pump_low_reservoir
|
||||
AlarmState.PUMP_EXPIRES_SOON -> R.string.alarm_pump_expires_soon
|
||||
AlarmState.LOWBG_SUSPENDED -> R.string.alarm_lowbg_suspended
|
||||
AlarmState.LOWBG_SUSPENDED2 -> R.string.alarm_lowbg_suspended2
|
||||
AlarmState.AUTO_SUSPENDED -> R.string.alarm_auto_suspended
|
||||
AlarmState.HMAX_SUSPENDED -> R.string.alarm_hmax_suspended
|
||||
AlarmState.DMAX_SUSPENDED -> R.string.alarm_dmax_suspended
|
||||
AlarmState.SUSPENDED -> R.string.alarm_suspended
|
||||
AlarmState.PAUSED -> R.string.alarm_paused
|
||||
AlarmState.OCCLUSION -> R.string.alarm_occlusion
|
||||
AlarmState.EXPIRED -> R.string.alarm_expired
|
||||
AlarmState.RESERVOIR_EMPTY -> R.string.alarm_reservoir_empty
|
||||
AlarmState.PATCH_FAULT -> R.string.alarm_patch_fault
|
||||
AlarmState.PATCH_FAULT2 -> R.string.alarm_patch_fault2
|
||||
AlarmState.BASE_FAULT -> R.string.alarm_base_fault
|
||||
AlarmState.BATTERY_OUT -> R.string.alarm_battery_out
|
||||
AlarmState.NO_CALIBRATION -> R.string.alarm_no_calibration
|
||||
}
|
||||
return rh.gs(stringId)
|
||||
}
|
||||
|
||||
private fun saveActiveAlarms() {
|
||||
val alarmsStr = activeAlarms.joinToString(separator = ",") { it.name }
|
||||
sp.putString(R.string.key_active_alarms, alarmsStr)
|
||||
}
|
||||
|
||||
private fun loadActiveAlarms() {
|
||||
val alarmsStr = sp.getString(R.string.key_active_alarms, "")
|
||||
if (alarmsStr.isNullOrEmpty()) {
|
||||
activeAlarms = EnumSet.noneOf(AlarmState::class.java)
|
||||
} else {
|
||||
activeAlarms = alarmsStr.split(",")
|
||||
.mapNotNull { AlarmState.values().find { alarm -> alarm.name == it } }
|
||||
.let { EnumSet.copyOf(it) }
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
package info.nightscout.pump.medtrum.bindingadapters
|
||||
|
||||
import android.view.View
|
||||
import java.util.concurrent.atomic.AtomicBoolean
|
||||
|
||||
class OnSafeClickListener(
|
||||
private val clickListener: View.OnClickListener,
|
||||
private val intervalMs: Long = MIN_CLICK_INTERVAL
|
||||
) : View.OnClickListener {
|
||||
private var canClick = AtomicBoolean(true)
|
||||
|
||||
override fun onClick(v: View?) {
|
||||
if (canClick.getAndSet(false)) {
|
||||
v?.run {
|
||||
postDelayed({
|
||||
canClick.set(true)
|
||||
}, intervalMs)
|
||||
clickListener.onClick(v)
|
||||
}
|
||||
}
|
||||
}
|
||||
companion object {
|
||||
// Set duplicate click prevention time
|
||||
private const val MIN_CLICK_INTERVAL: Long = 1000
|
||||
}
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
package info.nightscout.pump.medtrum.bindingadapters
|
||||
|
||||
import android.view.View
|
||||
import android.widget.TextView
|
||||
import androidx.annotation.ColorRes
|
||||
import androidx.databinding.BindingAdapter
|
||||
import info.nightscout.pump.medtrum.extension.setVisibleOrGone
|
||||
|
||||
@BindingAdapter("android:visibility")
|
||||
fun setVisibility(view: View, visible: Boolean) {
|
||||
view.setVisibleOrGone(visible)
|
||||
}
|
||||
|
||||
@BindingAdapter("visibleOrGone")
|
||||
fun setVisibleOrGone(view: View, visibleOrGone: Boolean) {
|
||||
view.setVisibleOrGone(visibleOrGone)
|
||||
}
|
||||
|
||||
@BindingAdapter("onSafeClick")
|
||||
fun View.setOnSafeClickListener(clickListener: View.OnClickListener?) {
|
||||
clickListener?.also {
|
||||
setOnClickListener(OnSafeClickListener(it))
|
||||
} ?: setOnClickListener(null)
|
||||
}
|
||||
|
||||
@BindingAdapter("textColor")
|
||||
fun setTextColor(view: TextView, @ColorRes colorResId: Int) {
|
||||
view.setTextColor(view.context.getColor(colorResId))
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
package info.nightscout.pump.medtrum.code
|
||||
|
||||
enum class ConnectionState {
|
||||
CONNECTED,
|
||||
DISCONNECTED,
|
||||
CONNECTING,
|
||||
DISCONNECTING;
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
package info.nightscout.pump.medtrum.code
|
||||
|
||||
enum class EventType {
|
||||
CHANGE_PATCH_CLICKED,
|
||||
PROFILE_NOT_SET,
|
||||
;
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
package info.nightscout.pump.medtrum.code
|
||||
|
||||
enum class PatchStep {
|
||||
START_DEACTIVATION,
|
||||
DEACTIVATE,
|
||||
FORCE_DEACTIVATION,
|
||||
DEACTIVATION_COMPLETE,
|
||||
PREPARE_PATCH,
|
||||
PREPARE_PATCH_CONNECT,
|
||||
PRIME,
|
||||
PRIMING,
|
||||
PRIME_COMPLETE,
|
||||
ATTACH_PATCH,
|
||||
ACTIVATE,
|
||||
ACTIVATE_COMPLETE,
|
||||
RETRY_ACTIVATION,
|
||||
RETRY_ACTIVATION_CONNECT,
|
||||
ERROR,
|
||||
CANCEL,
|
||||
COMPLETE;
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
package info.nightscout.pump.medtrum.comm
|
||||
|
||||
import kotlin.experimental.and
|
||||
import info.nightscout.pump.medtrum.extension.toLong
|
||||
|
||||
class ManufacturerData(private val manufacturerDataBytes: ByteArray) {
|
||||
private var deviceID: Long = 0
|
||||
private var deviceType = 0
|
||||
private var version = 0
|
||||
|
||||
init {
|
||||
setData(manufacturerDataBytes)
|
||||
}
|
||||
|
||||
fun setData(inputData: ByteArray) {
|
||||
var index = 0
|
||||
val deviceIDBytes: ByteArray = inputData.copyOfRange(index, index + 4)
|
||||
deviceID = deviceIDBytes.toLong()
|
||||
index += 4
|
||||
deviceType = (inputData[index] and 0xff.toByte()).toInt()
|
||||
index += 1
|
||||
version = (inputData[index] and 0xff.toByte()).toInt()
|
||||
}
|
||||
|
||||
fun getDeviceSN(): Long{
|
||||
return deviceID
|
||||
}
|
||||
|
||||
fun getDeviceType(): Int {
|
||||
return deviceType
|
||||
}
|
||||
|
||||
fun getVersion(): Int {
|
||||
return version
|
||||
}
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
package info.nightscout.pump.medtrum.comm
|
||||
|
||||
class ReadDataPacket(data: ByteArray) {
|
||||
|
||||
private var totalData = data.copyOfRange(0, data.size - 1) // Strip crc
|
||||
private var dataSize: Byte = data[0]
|
||||
|
||||
fun addData(newData: ByteArray) {
|
||||
totalData += newData.copyOfRange(4, newData.size - 1) // Strip header and crc
|
||||
}
|
||||
|
||||
fun allDataReceived(): Boolean {
|
||||
return (totalData.size >= dataSize)
|
||||
}
|
||||
|
||||
fun getData(): ByteArray {
|
||||
return totalData
|
||||
}
|
||||
}
|
|
@ -0,0 +1,65 @@
|
|||
package info.nightscout.pump.medtrum.comm
|
||||
|
||||
class WriteCommandPackets(data: ByteArray, sequenceNumber: Int) {
|
||||
|
||||
private val CRC_8_TABLE: IntArray = intArrayOf(0, 155, 173, 54, 193, 90, 108, 247, 25, 130, 180, 47, 216, 67, 117, 238, 50, 169, 159, 4, 243, 104, 94, 197, 43, 176, 134, 29, 234, 113, 71, 220, 100, 255, 201, 82, 165, 62, 8, 147, 125, 230, 208, 75, 188, 39, 17, 138, 86, 205, 251, 96, 151, 12, 58, 161, 79, 212, 226, 121, 142, 21, 35, 184, 200, 83, 101, 254, 9, 146, 164, 63, 209, 74, 124, 231, 16, 139, 189, 38, 250, 97, 87, 204, 59, 160, 150, 13, 227, 120, 78, 213, 34, 185, 143, 20, 172, 55, 1, 154, 109, 246, 192, 91, 181, 46, 24, 131, 116, 239, 217, 66, 158, 5, 51, 168, 95, 196, 242, 105, 135, 28, 42, 177, 70, 221, 235, 112, 11, 144, 166, 61, 202, 81, 103, 252, 18, 137, 191, 36, 211, 72, 126, 229, 57, 162, 148, 15, 248, 99, 85, 206, 32, 187, 141, 22, 225, 122, 76, 215, 111, 244, 194, 89, 174, 53, 3, 152, 118, 237, 219, 64, 183, 44, 26, 129, 93, 198, 240, 107, 156, 7, 49, 170, 68, 223, 233, 114, 133, 30, 40, 179, 195, 88, 110, 245, 2, 153, 175, 52, 218, 65, 119, 236, 27, 128, 182, 45, 241, 106, 92, 199, 48, 171, 157, 6, 232, 115, 69, 222, 41, 178, 132, 31, 167, 60, 10, 145, 102, 253, 203, 80, 190, 37, 19, 136, 127, 228, 210, 73, 149, 14, 56, 163, 84, 207, 249, 98, 140, 23, 33, 186, 77, 214, 224, 123)
|
||||
|
||||
private val packages = mutableListOf<ByteArray>()
|
||||
private var index = 0
|
||||
|
||||
init {
|
||||
// PackageIndex: 0 initially, if there are multiple packets, for the first packet it is set to 0 (not included in CRC calculation but sent in actual header)
|
||||
var pkgIndex = 0
|
||||
var header = byteArrayOf(
|
||||
(data.size + 4).toByte(),
|
||||
data[0],
|
||||
sequenceNumber.toByte(),
|
||||
pkgIndex.toByte()
|
||||
)
|
||||
|
||||
var tmp: ByteArray = header + data.copyOfRange(1, data.size)
|
||||
var totalCommand: ByteArray = tmp + calcCrc8(tmp, tmp.size).toByte()
|
||||
|
||||
if ((totalCommand.size - header.size) <= 15) {
|
||||
packages.add(totalCommand + 0.toByte())
|
||||
} else {
|
||||
pkgIndex = 1
|
||||
var remainingCommand = totalCommand.copyOfRange(4, totalCommand.size)
|
||||
|
||||
while (remainingCommand.size > 15) {
|
||||
header[3] = pkgIndex.toByte()
|
||||
tmp = header + remainingCommand.copyOfRange(0, 15)
|
||||
packages.add(tmp + calcCrc8(tmp, tmp.size).toByte())
|
||||
|
||||
remainingCommand = remainingCommand.copyOfRange(15, remainingCommand.size)
|
||||
pkgIndex = (pkgIndex + 1) % 256
|
||||
}
|
||||
|
||||
// Add last package
|
||||
header[3] = pkgIndex.toByte()
|
||||
tmp = header + remainingCommand
|
||||
packages.add(tmp + calcCrc8(tmp, tmp.size).toByte())
|
||||
}
|
||||
}
|
||||
|
||||
fun getNextPacket(): ByteArray? {
|
||||
var ret: ByteArray? = null
|
||||
if (index < packages.size) {
|
||||
ret = packages[index]
|
||||
index++
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
fun allPacketsConsumed(): Boolean {
|
||||
return !(index < packages.size)
|
||||
}
|
||||
|
||||
private fun calcCrc8(value: ByteArray, size: Int): Int {
|
||||
var crc8 = 0
|
||||
for (i in 0 until size) {
|
||||
crc8 = CRC_8_TABLE[(value[i].toInt() and 255) xor (crc8 and 255)].toInt() and 255
|
||||
}
|
||||
return crc8
|
||||
}
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
package info.nightscout.pump.medtrum.comm.enums
|
||||
|
||||
enum class AlarmSetting(val code: Byte) {
|
||||
LIGHT_VIBRATE_AND_BEEP(0),
|
||||
LIGHT_AND_VIBRATE(1),
|
||||
LIGHT_AND_BEEP(2),
|
||||
LIGHT_ONLY(3),
|
||||
VIBRATE_AND_BEEP(4),
|
||||
VIBRATE_ONLY(5),
|
||||
BEEP_ONLY(6),
|
||||
NONE(7)
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
package info.nightscout.pump.medtrum.comm.enums
|
||||
|
||||
enum class AlarmState {
|
||||
NONE,
|
||||
PUMP_LOW_BATTERY, // Mapped from error flag 1
|
||||
PUMP_LOW_RESERVOIR, // Mapped from error flag 2
|
||||
PUMP_EXPIRES_SOON, // Mapped from error flag 3
|
||||
LOWBG_SUSPENDED, // Mapped from pump status 64
|
||||
LOWBG_SUSPENDED2, // Mapped from pump status 65
|
||||
AUTO_SUSPENDED, // Mapped from pump status 66
|
||||
HMAX_SUSPENDED, // Mapped from pump status 67
|
||||
DMAX_SUSPENDED, // Mapped from pump status 68
|
||||
SUSPENDED, // Mapped from pump status 69
|
||||
PAUSED, // Mapped from pump status 70
|
||||
OCCLUSION, // Mapped from pump status 96
|
||||
EXPIRED, // Mapped from pump status 97
|
||||
RESERVOIR_EMPTY, // Mapped from pump status 98
|
||||
PATCH_FAULT, // Mapped from pump status 99
|
||||
PATCH_FAULT2, // Mapped from pump status 100
|
||||
BASE_FAULT, // Mapped from pump status 101
|
||||
BATTERY_OUT, // Mapped from pump status 102
|
||||
NO_CALIBRATION // Mapped from pump status 103
|
||||
}
|
|
@ -0,0 +1,54 @@
|
|||
package info.nightscout.pump.medtrum.comm.enums
|
||||
|
||||
enum class BasalType {
|
||||
NONE,
|
||||
STANDARD,
|
||||
EXERCISE,
|
||||
HOLIDAY,
|
||||
PROGRAM_A,
|
||||
PROGRAM_B,
|
||||
ABSOLUTE_TEMP,
|
||||
RELATIVE_TEMP,
|
||||
PROGRAM_C,
|
||||
PROGRAM_D,
|
||||
SICK,
|
||||
AUTO,
|
||||
NEW,
|
||||
SUSPEND_LOW_GLUCOSE,
|
||||
SUSPEND_PREDICT_LOW_GLUCOSE,
|
||||
SUSPEND_AUTO,
|
||||
SUSPEND_MORE_THAN_MAX_PER_HOUR,
|
||||
SUSPEND_MORE_THAN_MAX_PER_DAY,
|
||||
SUSPEND_MANUAL,
|
||||
SUSPEND_KEY_LOST,
|
||||
STOP_OCCLUSION,
|
||||
STOP_EXPIRED,
|
||||
STOP_EMPTY,
|
||||
STOP_PATCH_FAULT,
|
||||
STOP_PATCH_FAULT2,
|
||||
STOP_BASE_FAULT,
|
||||
STOP_DISCARD,
|
||||
STOP_BATTERY_EXHAUSTED,
|
||||
STOP,
|
||||
PAUSE_INTERRUPT,
|
||||
PRIME,
|
||||
AUTO_MODE_START,
|
||||
AUTO_MODE_EXIT,
|
||||
AUTO_MODE_TARGET_100,
|
||||
AUTO_MODE_TARGET_110,
|
||||
AUTO_MODE_TARGET_120,
|
||||
AUTO_MODE_BREAKFAST,
|
||||
AUTO_MODE_LUNCH,
|
||||
AUTO_MODE_DINNER,
|
||||
AUTO_MODE_SNACK,
|
||||
AUTO_MODE_EXERCISE_START,
|
||||
AUTO_MODE_EXERCISE_EXIT;
|
||||
|
||||
fun isTempBasal(): Boolean {
|
||||
return this == ABSOLUTE_TEMP || this == RELATIVE_TEMP
|
||||
}
|
||||
|
||||
fun isSuspendedByPump(): Boolean {
|
||||
return this in SUSPEND_LOW_GLUCOSE..STOP
|
||||
}
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
package info.nightscout.pump.medtrum.comm.enums
|
||||
|
||||
enum class BolusType {
|
||||
NONE,
|
||||
NORMAL,
|
||||
EXTENDED,
|
||||
COMBI;
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
package info.nightscout.pump.medtrum.comm.enums
|
||||
|
||||
enum class CommandType(val code: Byte) {
|
||||
SYNCHRONIZE(3),
|
||||
SUBSCRIBE(4),
|
||||
AUTH_REQ(5),
|
||||
GET_DEVICE_TYPE(6),
|
||||
SET_TIME(10),
|
||||
GET_TIME(11),
|
||||
SET_TIME_ZONE(12),
|
||||
PRIME(16),
|
||||
ACTIVATE(18),
|
||||
SET_BOLUS(19),
|
||||
CANCEL_BOLUS(20),
|
||||
SET_BASAL_PROFILE(21),
|
||||
SET_TEMP_BASAL(24),
|
||||
CANCEL_TEMP_BASAL(25),
|
||||
RESUME_PUMP(29),
|
||||
POLL_PATCH(30),
|
||||
STOP_PATCH(31),
|
||||
READ_BOLUS_STATE(34),
|
||||
SET_PATCH(35),
|
||||
SET_BOLUS_MOTOR(36),
|
||||
GET_RECORD(99),
|
||||
CLEAR_ALARM(115)
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
package info.nightscout.pump.medtrum.comm.enums
|
||||
|
||||
enum class MedtrumPumpState(val state: Byte) {
|
||||
NONE(0),
|
||||
IDLE(1),
|
||||
FILLED(2),
|
||||
PRIMING(3),
|
||||
PRIMED(4),
|
||||
EJECTING(5),
|
||||
EJECTED(6),
|
||||
ACTIVE(32),
|
||||
ACTIVE_ALT(33),
|
||||
LOWBG_SUSPENDED(64),
|
||||
LOWBG_SUSPENDED2(65),
|
||||
AUTO_SUSPENDED(66),
|
||||
HMAX_SUSPENDED(67),
|
||||
DMAX_SUSPENDED(68),
|
||||
SUSPENDED(69),
|
||||
PAUSED(70),
|
||||
OCCLUSION(96),
|
||||
EXPIRED(97),
|
||||
RESERVOIR_EMPTY(98),
|
||||
PATCH_FAULT(99),
|
||||
PATCH_FAULT2(100),
|
||||
BASE_FAULT(101),
|
||||
BATTERY_OUT(102),
|
||||
NO_CALIBRATION(103),
|
||||
STOPPED(128.toByte());
|
||||
|
||||
companion object {
|
||||
fun fromByte(state: Byte) = values().find { it.state == state }
|
||||
?: throw IllegalAccessException("")
|
||||
}
|
||||
}
|
|
@ -0,0 +1,122 @@
|
|||
package info.nightscout.pump.medtrum.comm.packets
|
||||
|
||||
import dagger.android.HasAndroidInjector
|
||||
import info.nightscout.interfaces.pump.DetailedBolusInfo
|
||||
import info.nightscout.interfaces.pump.PumpSync
|
||||
import info.nightscout.pump.medtrum.MedtrumPump
|
||||
import info.nightscout.pump.medtrum.comm.enums.CommandType.ACTIVATE
|
||||
import info.nightscout.pump.medtrum.comm.enums.BasalType
|
||||
import info.nightscout.pump.medtrum.extension.toByteArray
|
||||
import info.nightscout.pump.medtrum.extension.toByte
|
||||
import info.nightscout.interfaces.stats.TddCalculator
|
||||
import info.nightscout.pump.medtrum.extension.toInt
|
||||
import info.nightscout.pump.medtrum.extension.toLong
|
||||
import info.nightscout.pump.medtrum.util.MedtrumTimeUtil
|
||||
import javax.inject.Inject
|
||||
import kotlin.math.round
|
||||
|
||||
class ActivatePacket(injector: HasAndroidInjector, private val basalProfile: ByteArray) : MedtrumPacket(injector) {
|
||||
|
||||
@Inject lateinit var medtrumPump: MedtrumPump
|
||||
@Inject lateinit var tddCalculator: TddCalculator
|
||||
@Inject lateinit var pumpSync: PumpSync
|
||||
|
||||
companion object {
|
||||
|
||||
private const val RESP_PATCH_ID_START = 6
|
||||
private const val RESP_PATCH_ID_END = RESP_PATCH_ID_START + 4
|
||||
private const val RESP_TIME_START = 10
|
||||
private const val RESP_TIME_END = RESP_TIME_START + 4
|
||||
private const val RESP_BASAL_TYPE_START = 14
|
||||
private const val RESP_BASAL_TYPE_END = RESP_BASAL_TYPE_START + 1
|
||||
private const val RESP_BASAL_VALUE_START = 15
|
||||
private const val RESP_BASAL_VALUE_END = RESP_BASAL_VALUE_START + 2
|
||||
private const val RESP_BASAL_SEQUENCE_START = 17
|
||||
private const val RESP_BASAL_SEQUENCE_END = RESP_BASAL_SEQUENCE_START + 2
|
||||
private const val RESP_BASAL_PATCH_ID_START = 19
|
||||
private const val RESP_BASAL_PATCH_ID_END = RESP_BASAL_PATCH_ID_START + 2
|
||||
private const val RESP_BASAL_START_TIME_START = 21
|
||||
private const val RESP_BASAL_START_TIME_END = RESP_BASAL_START_TIME_START + 4
|
||||
}
|
||||
|
||||
init {
|
||||
opCode = ACTIVATE.code
|
||||
expectedMinRespLength = RESP_BASAL_START_TIME_END
|
||||
}
|
||||
|
||||
override fun getRequest(): ByteArray {
|
||||
/**
|
||||
* byte 0: opCode
|
||||
* byte 1: autoSuspendEnable // Value for auto mode, not used for AAPS
|
||||
* byte 2: autoSuspendTime // Value for auto mode, not used for AAPS
|
||||
* byte 3: expirationTimer // Expiration timer, 0 = no expiration 1 = 12 hour reminder and expiration after 3 days
|
||||
* byte 4: alarmSetting // See AlarmSetting
|
||||
* byte 5: lowSuspend // Value for auto mode, not used for AAPS
|
||||
* byte 6: predictiveLowSuspend // Value for auto mode, not used for AAPS
|
||||
* byte 7: predictiveLowSuspendRange // Value for auto mode, not used for AAPS
|
||||
* byte 8-9: hourlyMaxInsulin // Max hourly dose of insulin, divided by 0.05
|
||||
* byte 10-11: daylyMaxSet // Max daily dose of insulin, divided by 0.05
|
||||
* byte 12-13: tddToday // Current TDD (of present day), divided by 0.05
|
||||
* byte 14: 1 // Always 1
|
||||
* bytes 15 - end // Basal profile > see MedtrumPump
|
||||
*/
|
||||
|
||||
val autoSuspendEnable: Byte = 0
|
||||
val autoSuspendTime: Byte = 12 // Not sure why, but pump needs this in order to activate
|
||||
|
||||
val patchExpiration: Byte = medtrumPump.desiredPatchExpiration.toByte()
|
||||
val alarmSetting: Byte = medtrumPump.desiredAlarmSetting.code
|
||||
|
||||
val lowSuspend: Byte = 0
|
||||
val predictiveLowSuspend: Byte = 0
|
||||
val predictiveLowSuspendRange: Byte = 30 // Not sure why, but pump needs this in order to activate
|
||||
|
||||
val hourlyMaxInsulin: Int = round(medtrumPump.desiredHourlyMaxInsulin / 0.05).toInt()
|
||||
val dailyMaxInsulin: Int = round(medtrumPump.desiredDailyMaxInsulin / 0.05).toInt()
|
||||
val currentTDD: Double = tddCalculator.calculateToday()?.totalAmount?.div(0.05) ?: 0.0
|
||||
|
||||
return byteArrayOf(opCode) + autoSuspendEnable + autoSuspendTime + patchExpiration + alarmSetting + lowSuspend + predictiveLowSuspend + predictiveLowSuspendRange + hourlyMaxInsulin.toByteArray(
|
||||
2
|
||||
) + dailyMaxInsulin.toByteArray(2) + currentTDD.toInt().toByteArray(2) + 1.toByte() + basalProfile
|
||||
}
|
||||
|
||||
override fun handleResponse(data: ByteArray): Boolean {
|
||||
val success = super.handleResponse(data)
|
||||
if (success) {
|
||||
val medtrumTimeUtil = MedtrumTimeUtil()
|
||||
|
||||
val patchId = data.copyOfRange(RESP_PATCH_ID_START, RESP_PATCH_ID_END).toLong()
|
||||
val time = medtrumTimeUtil.convertPumpTimeToSystemTimeMillis(data.copyOfRange(RESP_TIME_START, RESP_TIME_END).toLong())
|
||||
val basalType = enumValues<BasalType>()[data.copyOfRange(RESP_BASAL_TYPE_START, RESP_BASAL_TYPE_END).toInt()]
|
||||
val basalValue = data.copyOfRange(RESP_BASAL_VALUE_START, RESP_BASAL_VALUE_END).toInt() * 0.05
|
||||
val basalSequence = data.copyOfRange(RESP_BASAL_SEQUENCE_START, RESP_BASAL_SEQUENCE_END).toInt()
|
||||
val basalPatchId = data.copyOfRange(RESP_BASAL_PATCH_ID_START, RESP_BASAL_PATCH_ID_END).toLong()
|
||||
val basalStartTime = medtrumTimeUtil.convertPumpTimeToSystemTimeMillis(data.copyOfRange(RESP_BASAL_START_TIME_START, RESP_BASAL_START_TIME_END).toLong())
|
||||
|
||||
medtrumPump.patchId = patchId
|
||||
medtrumPump.lastTimeReceivedFromPump = time
|
||||
medtrumPump.currentSequenceNumber = basalSequence // We are activated, set the new seq nr
|
||||
medtrumPump.syncedSequenceNumber = basalSequence // We are activated, reset the synced seq nr ()
|
||||
|
||||
// Sync canula change
|
||||
pumpSync.insertTherapyEventIfNewWithTimestamp(
|
||||
timestamp = System.currentTimeMillis(),
|
||||
type = DetailedBolusInfo.EventType.CANNULA_CHANGE,
|
||||
pumpType = medtrumPump.pumpType(),
|
||||
pumpSerial = medtrumPump.pumpSN.toString(radix = 16)
|
||||
)
|
||||
pumpSync.insertTherapyEventIfNewWithTimestamp(
|
||||
timestamp = System.currentTimeMillis(),
|
||||
type = DetailedBolusInfo.EventType.INSULIN_CHANGE,
|
||||
pumpType = medtrumPump.pumpType(),
|
||||
pumpSerial = medtrumPump.pumpSN.toString(radix = 16)
|
||||
)
|
||||
|
||||
// Update the actual basal profile
|
||||
medtrumPump.actualBasalProfile = basalProfile
|
||||
medtrumPump.handleBasalStatusUpdate(basalType, basalValue, basalSequence, basalPatchId, basalStartTime, time)
|
||||
}
|
||||
|
||||
return success
|
||||
}
|
||||
}
|
|
@ -0,0 +1,57 @@
|
|||
package info.nightscout.pump.medtrum.comm.packets
|
||||
|
||||
import dagger.android.HasAndroidInjector
|
||||
import info.nightscout.pump.medtrum.MedtrumPump
|
||||
import info.nightscout.pump.medtrum.comm.enums.CommandType.AUTH_REQ
|
||||
import info.nightscout.pump.medtrum.encryption.Crypt
|
||||
import info.nightscout.pump.medtrum.extension.toByteArray
|
||||
import info.nightscout.pump.medtrum.extension.toInt
|
||||
import info.nightscout.rx.logging.LTag
|
||||
import javax.inject.Inject
|
||||
|
||||
class AuthorizePacket(injector: HasAndroidInjector) : MedtrumPacket(injector) {
|
||||
|
||||
@Inject lateinit var medtrumPump: MedtrumPump
|
||||
|
||||
companion object {
|
||||
|
||||
private const val RESP_DEVICE_TYPE_START = 7
|
||||
private const val RESP_DEVICE_TYPE_END = RESP_DEVICE_TYPE_START + 1
|
||||
private const val RESP_VERSION_X_START = 8
|
||||
private const val RESP_VERSION_X_END = RESP_VERSION_X_START + 1
|
||||
private const val RESP_VERSION_Y_START = 9
|
||||
private const val RESP_VERSION_Y_END = RESP_VERSION_Y_START + 1
|
||||
private const val RESP_VERSION_Z_START = 10
|
||||
private const val RESP_VERSION_Z_END = RESP_VERSION_Z_START + 1
|
||||
}
|
||||
|
||||
init {
|
||||
opCode = AUTH_REQ.code
|
||||
expectedMinRespLength = RESP_VERSION_Z_END
|
||||
}
|
||||
|
||||
override fun getRequest(): ByteArray {
|
||||
val role = 2 // Fixed to 2 for pump
|
||||
val key = Crypt().keyGen(medtrumPump.pumpSN)
|
||||
return byteArrayOf(opCode) + byteArrayOf(role.toByte()) + medtrumPump.patchSessionToken.toByteArray(4) + key.toByteArray(4)
|
||||
}
|
||||
|
||||
override fun handleResponse(data: ByteArray): Boolean {
|
||||
val success = super.handleResponse(data)
|
||||
if (success) {
|
||||
val deviceType = data.copyOfRange(RESP_DEVICE_TYPE_START, RESP_DEVICE_TYPE_END).toInt()
|
||||
val swVersion = "" + data.copyOfRange(RESP_VERSION_X_START, RESP_VERSION_X_END).toInt() + "." + data.copyOfRange(RESP_VERSION_Y_START, RESP_VERSION_Y_END).toInt() + "." + data.copyOfRange(
|
||||
RESP_VERSION_Z_START, RESP_VERSION_Z_END
|
||||
).toInt()
|
||||
|
||||
if (medtrumPump.deviceType != deviceType) {
|
||||
medtrumPump.deviceType = deviceType
|
||||
}
|
||||
if (medtrumPump.swVersion != swVersion) {
|
||||
medtrumPump.swVersion = swVersion
|
||||
}
|
||||
aapsLogger.debug(LTag.PUMPCOMM, "GetDeviceTypeState: deviceType: ${deviceType}, swVersion: ${swVersion}")
|
||||
}
|
||||
return success
|
||||
}
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
package info.nightscout.pump.medtrum.comm.packets
|
||||
|
||||
import dagger.android.HasAndroidInjector
|
||||
import info.nightscout.pump.medtrum.comm.enums.CommandType.CANCEL_BOLUS
|
||||
|
||||
class CancelBolusPacket(injector: HasAndroidInjector) : MedtrumPacket(injector) {
|
||||
|
||||
init {
|
||||
opCode = CANCEL_BOLUS.code
|
||||
}
|
||||
|
||||
override fun getRequest(): ByteArray {
|
||||
// Bolus types:
|
||||
// 1 = normal
|
||||
// 2 = Extended
|
||||
// 3 = Combi
|
||||
val bolusType: Byte = 1 // Only support for normal bolus for now
|
||||
return byteArrayOf(opCode) + bolusType
|
||||
}
|
||||
}
|
|
@ -0,0 +1,51 @@
|
|||
package info.nightscout.pump.medtrum.comm.packets
|
||||
|
||||
import dagger.android.HasAndroidInjector
|
||||
import info.nightscout.pump.medtrum.MedtrumPump
|
||||
import info.nightscout.pump.medtrum.comm.enums.CommandType.CANCEL_TEMP_BASAL
|
||||
import info.nightscout.pump.medtrum.comm.enums.BasalType
|
||||
import info.nightscout.pump.medtrum.extension.toInt
|
||||
import info.nightscout.pump.medtrum.extension.toLong
|
||||
import info.nightscout.pump.medtrum.util.MedtrumTimeUtil
|
||||
import info.nightscout.rx.logging.LTag
|
||||
import info.nightscout.shared.utils.DateUtil
|
||||
import javax.inject.Inject
|
||||
|
||||
class CancelTempBasalPacket(injector: HasAndroidInjector) : MedtrumPacket(injector) {
|
||||
|
||||
@Inject lateinit var medtrumPump: MedtrumPump
|
||||
@Inject lateinit var dateUtil: DateUtil
|
||||
|
||||
companion object {
|
||||
|
||||
private const val RESP_BASAL_TYPE_START = 6
|
||||
private const val RESP_BASAL_TYPE_END = RESP_BASAL_TYPE_START + 1
|
||||
private const val RESP_BASAL_RATE_START = RESP_BASAL_TYPE_END
|
||||
private const val RESP_BASAL_RATE_END = RESP_BASAL_RATE_START + 2
|
||||
private const val RESP_BASAL_SEQUENCE_START = RESP_BASAL_RATE_END
|
||||
private const val RESP_BASAL_SEQUENCE_END = RESP_BASAL_SEQUENCE_START + 2
|
||||
private const val RESP_BASAL_PATCH_ID_START = RESP_BASAL_SEQUENCE_END
|
||||
private const val RESP_BASAL_PATCH_ID_END = RESP_BASAL_PATCH_ID_START + 2
|
||||
private const val RESP_BASAL_START_TIME_START = RESP_BASAL_PATCH_ID_END
|
||||
private const val RESP_BASAL_START_TIME_END = RESP_BASAL_START_TIME_START + 4
|
||||
}
|
||||
|
||||
init {
|
||||
opCode = CANCEL_TEMP_BASAL.code
|
||||
expectedMinRespLength = RESP_BASAL_START_TIME_END
|
||||
}
|
||||
|
||||
override fun handleResponse(data: ByteArray): Boolean {
|
||||
val success = super.handleResponse(data)
|
||||
if (success) {
|
||||
val basalType = enumValues<BasalType>()[data.copyOfRange(RESP_BASAL_TYPE_START, RESP_BASAL_TYPE_END).toInt()]
|
||||
val basalRate = data.copyOfRange(RESP_BASAL_RATE_START, RESP_BASAL_RATE_END).toInt() * 0.05
|
||||
val basalSequence = data.copyOfRange(RESP_BASAL_SEQUENCE_START, RESP_BASAL_SEQUENCE_END).toInt()
|
||||
val basalPatchId = data.copyOfRange(RESP_BASAL_PATCH_ID_START, RESP_BASAL_PATCH_ID_END).toLong()
|
||||
val basalStartTime = MedtrumTimeUtil().convertPumpTimeToSystemTimeMillis(data.copyOfRange(RESP_BASAL_START_TIME_START, RESP_BASAL_START_TIME_END).toLong())
|
||||
|
||||
medtrumPump.handleBasalStatusUpdate(basalType, basalRate, basalSequence, basalPatchId, basalStartTime)
|
||||
}
|
||||
return success
|
||||
}
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
package info.nightscout.pump.medtrum.comm.packets
|
||||
|
||||
import dagger.android.HasAndroidInjector
|
||||
import info.nightscout.pump.medtrum.comm.enums.CommandType.CLEAR_ALARM
|
||||
import info.nightscout.pump.medtrum.extension.toByteArray
|
||||
|
||||
class ClearPumpAlarmPacket(injector: HasAndroidInjector, val clearType: Int) : MedtrumPacket(injector) {
|
||||
|
||||
init {
|
||||
opCode = CLEAR_ALARM.code
|
||||
}
|
||||
|
||||
override fun getRequest(): ByteArray {
|
||||
return byteArrayOf(opCode) + clearType.toByteArray(2)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
package info.nightscout.pump.medtrum.comm.packets
|
||||
|
||||
import dagger.android.HasAndroidInjector
|
||||
import info.nightscout.pump.medtrum.comm.enums.CommandType.GET_DEVICE_TYPE
|
||||
import info.nightscout.pump.medtrum.extension.toInt
|
||||
import info.nightscout.pump.medtrum.extension.toLong
|
||||
|
||||
class GetDeviceTypePacket(injector: HasAndroidInjector) : MedtrumPacket(injector) {
|
||||
|
||||
var deviceType: Int = 0
|
||||
var deviceSN: Long = 0
|
||||
|
||||
companion object {
|
||||
|
||||
private const val RESP_DEVICE_TYPE_START = 6
|
||||
private const val RESP_DEVICE_TYPE_END = RESP_DEVICE_TYPE_START + 1
|
||||
private const val RESP_DEVICE_SN_START = 7
|
||||
private const val RESP_DEVICE_SN_END = RESP_DEVICE_SN_START + 4
|
||||
}
|
||||
|
||||
init {
|
||||
opCode = GET_DEVICE_TYPE.code
|
||||
expectedMinRespLength = RESP_DEVICE_SN_END
|
||||
}
|
||||
|
||||
override fun handleResponse(data: ByteArray): Boolean {
|
||||
val success = super.handleResponse(data)
|
||||
if (success) {
|
||||
deviceType = data.copyOfRange(RESP_DEVICE_TYPE_START, RESP_DEVICE_TYPE_END).toInt()
|
||||
deviceSN = data.copyOfRange(RESP_DEVICE_SN_START, RESP_DEVICE_SN_END).toLong()
|
||||
}
|
||||
|
||||
return success
|
||||
}
|
||||
}
|
|
@ -0,0 +1,353 @@
|
|||
package info.nightscout.pump.medtrum.comm.packets
|
||||
|
||||
import dagger.android.HasAndroidInjector
|
||||
import info.nightscout.interfaces.pump.DetailedBolusInfoStorage
|
||||
import info.nightscout.interfaces.pump.PumpSync
|
||||
import info.nightscout.interfaces.pump.TemporaryBasalStorage
|
||||
import info.nightscout.pump.medtrum.MedtrumPump
|
||||
import info.nightscout.pump.medtrum.comm.enums.CommandType.GET_RECORD
|
||||
import info.nightscout.pump.medtrum.comm.enums.BasalType
|
||||
import info.nightscout.pump.medtrum.comm.enums.BolusType
|
||||
import info.nightscout.pump.medtrum.extension.toByteArray
|
||||
import info.nightscout.pump.medtrum.extension.toFloat
|
||||
import info.nightscout.pump.medtrum.extension.toInt
|
||||
import info.nightscout.pump.medtrum.extension.toLong
|
||||
import info.nightscout.pump.medtrum.util.MedtrumTimeUtil
|
||||
import info.nightscout.rx.logging.LTag
|
||||
import info.nightscout.shared.utils.DateUtil
|
||||
import info.nightscout.shared.utils.T
|
||||
import javax.inject.Inject
|
||||
|
||||
class GetRecordPacket(injector: HasAndroidInjector, private val recordIndex: Int) : MedtrumPacket(injector) {
|
||||
|
||||
@Inject lateinit var medtrumPump: MedtrumPump
|
||||
@Inject lateinit var pumpSync: PumpSync
|
||||
@Inject lateinit var temporaryBasalStorage: TemporaryBasalStorage
|
||||
@Inject lateinit var detailedBolusInfoStorage: DetailedBolusInfoStorage
|
||||
@Inject lateinit var dateUtil: DateUtil
|
||||
|
||||
companion object {
|
||||
|
||||
private const val RESP_RECORD_HEADER_START = 6
|
||||
private const val RESP_RECORD_HEADER_END = RESP_RECORD_HEADER_START + 1
|
||||
private const val RESP_RECORD_UNKNOWN_START = RESP_RECORD_HEADER_END
|
||||
private const val RESP_RECORD_UNKNOWN_END = RESP_RECORD_UNKNOWN_START + 1
|
||||
private const val RESP_RECORD_TYPE_START = RESP_RECORD_UNKNOWN_END
|
||||
private const val RESP_RECORD_TYPE_END = RESP_RECORD_TYPE_START + 1
|
||||
private const val RESP_RECORD_UNKNOWN1_START = RESP_RECORD_TYPE_END
|
||||
private const val RESP_RECORD_UNKNOWN1_END = RESP_RECORD_UNKNOWN1_START + 1
|
||||
private const val RESP_RECORD_SERIAL_START = RESP_RECORD_UNKNOWN1_END
|
||||
private const val RESP_RECORD_SERIAL_END = RESP_RECORD_SERIAL_START + 4
|
||||
private const val RESP_RECORD_PATCHID_START = RESP_RECORD_SERIAL_END
|
||||
private const val RESP_RECORD_PATCHID_END = RESP_RECORD_PATCHID_START + 2
|
||||
private const val RESP_RECORD_SEQUENCE_START = RESP_RECORD_PATCHID_END
|
||||
private const val RESP_RECORD_SEQUENCE_END = RESP_RECORD_SEQUENCE_START + 2
|
||||
private const val RESP_RECORD_DATA_START = RESP_RECORD_SEQUENCE_END
|
||||
|
||||
private const val VALID_HEADER = 170
|
||||
private const val BOLUS_RECORD = 1
|
||||
private const val BOLUS_RECORD_ALT = 65
|
||||
private const val BASAL_RECORD = 2
|
||||
private const val BASAL_RECORD_ALT = 66
|
||||
private const val ALARM_RECORD = 3
|
||||
private const val AUTO_RECORD = 4
|
||||
private const val TIME_SYNC_RECORD = 5
|
||||
private const val AUTO1_RECORD = 6
|
||||
private const val AUTO2_RECORD = 7
|
||||
private const val AUTO3_RECORD = 8
|
||||
private const val TDD_RECORD = 9
|
||||
|
||||
}
|
||||
|
||||
init {
|
||||
opCode = GET_RECORD.code
|
||||
expectedMinRespLength = RESP_RECORD_DATA_START
|
||||
}
|
||||
|
||||
override fun getRequest(): ByteArray {
|
||||
return byteArrayOf(opCode) + recordIndex.toByteArray(2) + medtrumPump.patchId.toByteArray(2)
|
||||
}
|
||||
|
||||
override fun handleResponse(data: ByteArray): Boolean {
|
||||
val success = super.handleResponse(data)
|
||||
if (success) {
|
||||
val recordHeader = data.copyOfRange(RESP_RECORD_HEADER_START, RESP_RECORD_HEADER_END).toInt()
|
||||
val recordUnknown = data.copyOfRange(RESP_RECORD_UNKNOWN_START, RESP_RECORD_UNKNOWN_END).toInt()
|
||||
val recordType = data.copyOfRange(RESP_RECORD_TYPE_START, RESP_RECORD_TYPE_END).toInt()
|
||||
val recordSerial = data.copyOfRange(RESP_RECORD_SERIAL_START, RESP_RECORD_SERIAL_END).toLong()
|
||||
val recordPatchId = data.copyOfRange(RESP_RECORD_PATCHID_START, RESP_RECORD_PATCHID_END).toInt()
|
||||
val recordSequence = data.copyOfRange(RESP_RECORD_SEQUENCE_START, RESP_RECORD_SEQUENCE_END).toInt()
|
||||
|
||||
aapsLogger.debug(
|
||||
LTag.PUMPCOMM,
|
||||
"GetRecordPacket HandleResponse: Record header: $recordHeader, unknown: $recordUnknown, type: $recordType, serial: $recordSerial, patchId: $recordPatchId, " + "sequence: $recordSequence"
|
||||
)
|
||||
|
||||
medtrumPump.syncedSequenceNumber = recordSequence // Assume sync upwards
|
||||
|
||||
if (recordHeader == VALID_HEADER) {
|
||||
when (recordType) {
|
||||
BOLUS_RECORD, BOLUS_RECORD_ALT -> {
|
||||
aapsLogger.debug(LTag.PUMPCOMM, "GetRecordPacket HandleResponse: BOLUS_RECORD")
|
||||
val typeAndWizard = data.copyOfRange(RESP_RECORD_DATA_START, RESP_RECORD_DATA_START + 1).toInt()
|
||||
val bolusCause = data.copyOfRange(RESP_RECORD_DATA_START + 1, RESP_RECORD_DATA_START + 2).toInt()
|
||||
val unknown = data.copyOfRange(RESP_RECORD_DATA_START + 2, RESP_RECORD_DATA_START + 4).toInt()
|
||||
val bolusStartTime = MedtrumTimeUtil().convertPumpTimeToSystemTimeMillis(data.copyOfRange(RESP_RECORD_DATA_START + 4, RESP_RECORD_DATA_START + 8).toLong())
|
||||
val bolusNormalAmount = data.copyOfRange(RESP_RECORD_DATA_START + 8, RESP_RECORD_DATA_START + 10).toInt() * 0.05
|
||||
val bolusNormalDelivered = data.copyOfRange(RESP_RECORD_DATA_START + 10, RESP_RECORD_DATA_START + 12).toInt() * 0.05
|
||||
val bolusExtendedAmount = data.copyOfRange(RESP_RECORD_DATA_START + 12, RESP_RECORD_DATA_START + 14).toInt() * 0.05
|
||||
val bolusExtendedDuration = data.copyOfRange(RESP_RECORD_DATA_START + 14, RESP_RECORD_DATA_START + 16).toLong() * 1000
|
||||
val bolusExtendedDelivered = data.copyOfRange(RESP_RECORD_DATA_START + 16, RESP_RECORD_DATA_START + 18).toInt() * 0.05
|
||||
val bolusCarb = data.copyOfRange(RESP_RECORD_DATA_START + 18, RESP_RECORD_DATA_START + 20).toInt()
|
||||
val bolusGlucose = data.copyOfRange(RESP_RECORD_DATA_START + 20, RESP_RECORD_DATA_START + 22).toInt()
|
||||
val bolusIOB = data.copyOfRange(RESP_RECORD_DATA_START + 22, RESP_RECORD_DATA_START + 24).toInt()
|
||||
val unkown1 = data.copyOfRange(RESP_RECORD_DATA_START + 24, RESP_RECORD_DATA_START + 26).toInt()
|
||||
val unkown2 = data.copyOfRange(RESP_RECORD_DATA_START + 26, RESP_RECORD_DATA_START + 28).toInt()
|
||||
val bolusType = enumValues<BolusType>()[typeAndWizard and 0x0F]
|
||||
val bolusWizard = (typeAndWizard and 0xF0) != 0
|
||||
aapsLogger.debug(
|
||||
LTag.PUMPCOMM,
|
||||
"GetRecordPacket HandleResponse: BOLUS_RECORD: typeAndWizard: $typeAndWizard, bolusCause: $bolusCause, unknown: $unknown, bolusStartTime: $bolusStartTime, " + "bolusNormalAmount: $bolusNormalAmount, bolusNormalDelivered: $bolusNormalDelivered, bolusExtendedAmount: $bolusExtendedAmount, bolusExtendedDuration: $bolusExtendedDuration, " + "bolusExtendedDelivered: $bolusExtendedDelivered, bolusCarb: $bolusCarb, bolusGlucose: $bolusGlucose, bolusIOB: $bolusIOB, unkown1: $unkown1, unkown2: $unkown2, " + "bolusType: $bolusType, bolusWizard: $bolusWizard"
|
||||
)
|
||||
|
||||
if (bolusType == BolusType.NORMAL) {
|
||||
val detailedBolusInfo = detailedBolusInfoStorage.findDetailedBolusInfo(bolusStartTime, bolusNormalDelivered)
|
||||
var newRecord = false
|
||||
if (detailedBolusInfo != null) {
|
||||
val syncOk = pumpSync.syncBolusWithTempId(
|
||||
timestamp = bolusStartTime,
|
||||
amount = bolusNormalDelivered,
|
||||
temporaryId = detailedBolusInfo.timestamp,
|
||||
type = detailedBolusInfo.bolusType,
|
||||
pumpId = bolusStartTime,
|
||||
pumpType = medtrumPump.pumpType(),
|
||||
pumpSerial = medtrumPump.pumpSN.toString(radix = 16)
|
||||
)
|
||||
if (syncOk == false) {
|
||||
aapsLogger.warn(LTag.PUMPCOMM, "GetRecordPacket HandleResponse: BOLUS_RECORD: Failed to sync bolus with tempId: ${detailedBolusInfo.timestamp}")
|
||||
// detailedInfo can be from another similar record. Reinsert
|
||||
detailedBolusInfoStorage.add(detailedBolusInfo)
|
||||
}
|
||||
} else {
|
||||
newRecord = pumpSync.syncBolusWithPumpId(
|
||||
timestamp = bolusStartTime,
|
||||
amount = bolusNormalDelivered,
|
||||
type = null,
|
||||
pumpId = bolusStartTime,
|
||||
pumpType = medtrumPump.pumpType(),
|
||||
pumpSerial = medtrumPump.pumpSN.toString(radix = 16)
|
||||
)
|
||||
}
|
||||
|
||||
aapsLogger.debug(
|
||||
LTag.PUMPCOMM,
|
||||
"from record: ${if (newRecord) "**NEW** " else ""}EVENT BOLUS ${dateUtil.dateAndTimeString(bolusStartTime)} ($bolusStartTime) Bolus: ${bolusNormalDelivered}U "
|
||||
)
|
||||
if (bolusStartTime > medtrumPump.lastBolusTime) {
|
||||
medtrumPump.lastBolusTime = bolusStartTime
|
||||
medtrumPump.lastBolusAmount = bolusNormalDelivered
|
||||
}
|
||||
} else if (bolusType == BolusType.EXTENDED) {
|
||||
val newRecord = pumpSync.syncExtendedBolusWithPumpId(
|
||||
timestamp = bolusStartTime,
|
||||
amount = bolusExtendedDelivered,
|
||||
duration = bolusExtendedDuration,
|
||||
isEmulatingTB = false,
|
||||
pumpId = bolusStartTime,
|
||||
pumpType = medtrumPump.pumpType(),
|
||||
pumpSerial = medtrumPump.pumpSN.toString(radix = 16)
|
||||
)
|
||||
aapsLogger.debug(
|
||||
LTag.PUMPCOMM,
|
||||
"from record: ${if (newRecord) "**NEW** " else ""}EVENT EXTENDED BOLUS ${dateUtil.dateAndTimeString(bolusStartTime)} ($bolusStartTime) Bolus: ${bolusNormalDelivered}U "
|
||||
)
|
||||
} else if (bolusType == BolusType.COMBI) {
|
||||
// Note, this should never happen, as we don't use combo bolus
|
||||
val detailedBolusInfo = detailedBolusInfoStorage.findDetailedBolusInfo(bolusStartTime, bolusNormalDelivered)
|
||||
val newRecord = pumpSync.syncBolusWithPumpId(
|
||||
timestamp = bolusStartTime,
|
||||
amount = bolusNormalDelivered,
|
||||
type = detailedBolusInfo?.bolusType,
|
||||
pumpId = bolusStartTime,
|
||||
pumpType = medtrumPump.pumpType(),
|
||||
pumpSerial = medtrumPump.pumpSN.toString(radix = 16)
|
||||
)
|
||||
pumpSync.syncExtendedBolusWithPumpId(
|
||||
timestamp = bolusStartTime,
|
||||
amount = bolusExtendedDelivered,
|
||||
duration = bolusExtendedDuration,
|
||||
isEmulatingTB = false,
|
||||
pumpId = bolusStartTime,
|
||||
pumpType = medtrumPump.pumpType(),
|
||||
pumpSerial = medtrumPump.pumpSN.toString(radix = 16)
|
||||
)
|
||||
aapsLogger.error(
|
||||
LTag.PUMPCOMM,
|
||||
"from record: ${if (newRecord) "**NEW** " else ""}EVENT COMBI BOLUS ${dateUtil.dateAndTimeString(bolusStartTime)} ($bolusStartTime) Bolus: ${bolusNormalDelivered}U Extended: ${bolusExtendedDelivered} THIS SHOULD NOT HAPPEN!!!"
|
||||
)
|
||||
if (!newRecord && detailedBolusInfo != null) {
|
||||
// detailedInfo can be from another similar record. Reinsert
|
||||
detailedBolusInfoStorage.add(detailedBolusInfo)
|
||||
}
|
||||
if (bolusStartTime > medtrumPump.lastBolusTime) {
|
||||
medtrumPump.lastBolusTime = bolusStartTime
|
||||
medtrumPump.lastBolusAmount = bolusNormalDelivered
|
||||
}
|
||||
} else {
|
||||
aapsLogger.error(LTag.PUMPCOMM, "GetRecordPacket HandleResponse: BOLUS_RECORD: Unknown bolus type: $bolusType")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
BASAL_RECORD, BASAL_RECORD_ALT -> {
|
||||
val medtrumTimeUtil = MedtrumTimeUtil()
|
||||
val basalStartTime = medtrumTimeUtil.convertPumpTimeToSystemTimeMillis(data.copyOfRange(RESP_RECORD_DATA_START, RESP_RECORD_DATA_START + 4).toLong())
|
||||
val basalEndTime = medtrumTimeUtil.convertPumpTimeToSystemTimeMillis(data.copyOfRange(RESP_RECORD_DATA_START + 4, RESP_RECORD_DATA_START + 8).toLong())
|
||||
val basalType = enumValues<BasalType>()[data.copyOfRange(RESP_RECORD_DATA_START + 8, RESP_RECORD_DATA_START + 9).toInt()]
|
||||
val basalEndReason = data.copyOfRange(RESP_RECORD_DATA_START + 9, RESP_RECORD_DATA_START + 10).toInt()
|
||||
val basalRate = data.copyOfRange(RESP_RECORD_DATA_START + 10, RESP_RECORD_DATA_START + 12).toInt() * 0.05
|
||||
val basalDelivered = data.copyOfRange(RESP_RECORD_DATA_START + 12, RESP_RECORD_DATA_START + 14).toInt() * 0.05
|
||||
val basalPercent = data.copyOfRange(RESP_RECORD_DATA_START + 14, RESP_RECORD_DATA_START + 16).toInt()
|
||||
|
||||
aapsLogger.debug(
|
||||
LTag.PUMPCOMM,
|
||||
"GetRecordPacket HandleResponse: BASAL_RECORD: Start: $basalStartTime, End: $basalEndTime, Type: $basalType, EndReason: $basalEndReason, Rate: $basalRate, Delivered: $basalDelivered, Percent: $basalPercent"
|
||||
)
|
||||
|
||||
when (basalType) {
|
||||
BasalType.STANDARD -> {
|
||||
aapsLogger.debug(LTag.PUMPCOMM, "GetRecordPacket HandleResponse: BASAL_RECORD: Standard basal")
|
||||
// If we are here it means the basal has ended
|
||||
}
|
||||
|
||||
BasalType.ABSOLUTE_TEMP, BasalType.RELATIVE_TEMP -> {
|
||||
aapsLogger.debug(LTag.PUMPCOMM, "GetRecordPacket HandleResponse: BASAL_RECORD: Absolute temp basal")
|
||||
var duration = (basalEndTime - basalStartTime)
|
||||
// Work around for pumpSync not accepting 0 duration.
|
||||
// sometimes we get 0 duration for very short basal because the pump only reports time in seconds
|
||||
if (duration < 250) duration = 250 // 250ms to make sure AAPS accepts it
|
||||
|
||||
val newRecord = pumpSync.syncTemporaryBasalWithPumpId(
|
||||
timestamp = basalStartTime,
|
||||
rate = if (basalType == BasalType.ABSOLUTE_TEMP) basalRate else basalPercent.toDouble(),
|
||||
duration = duration,
|
||||
isAbsolute = (basalType == BasalType.ABSOLUTE_TEMP),
|
||||
type = PumpSync.TemporaryBasalType.NORMAL,
|
||||
pumpId = basalStartTime,
|
||||
pumpType = medtrumPump.pumpType(),
|
||||
pumpSerial = medtrumPump.pumpSN.toString(radix = 16)
|
||||
)
|
||||
aapsLogger.debug(
|
||||
LTag.PUMPCOMM,
|
||||
"handleBasalStatusUpdate from record: ${if (newRecord) "**NEW** " else ""}EVENT TEMP_SYNC: ($basalType) ${dateUtil.dateAndTimeString(basalStartTime)} ($basalStartTime) " +
|
||||
"Rate: $basalRate Duration: ${duration}"
|
||||
)
|
||||
}
|
||||
|
||||
in BasalType.SUSPEND_LOW_GLUCOSE..BasalType.STOP -> {
|
||||
aapsLogger.debug(LTag.PUMPCOMM, "GetRecordPacket HandleResponse: BASAL_RECORD: Suspend basal")
|
||||
val duration = (basalEndTime - basalStartTime)
|
||||
val newRecord = pumpSync.syncTemporaryBasalWithPumpId(
|
||||
timestamp = basalEndTime,
|
||||
rate = 0.0,
|
||||
duration = duration,
|
||||
isAbsolute = true,
|
||||
type = PumpSync.TemporaryBasalType.PUMP_SUSPEND,
|
||||
pumpId = basalStartTime,
|
||||
pumpType = medtrumPump.pumpType(),
|
||||
pumpSerial = medtrumPump.pumpSN.toString(radix = 16)
|
||||
)
|
||||
aapsLogger.debug(
|
||||
LTag.PUMPCOMM,
|
||||
"handleBasalStatusUpdate from record: ${if (newRecord) "**NEW** " else ""}EVENT SUSPEND: ($basalType) ${dateUtil.dateAndTimeString(basalStartTime)} ($basalStartTime) " +
|
||||
"Rate: $basalRate Duration: ${duration}"
|
||||
)
|
||||
}
|
||||
|
||||
else -> {
|
||||
aapsLogger.error(LTag.PUMPCOMM, "GetRecordPacket HandleResponse: BASAL_RECORD: Unknown basal type: $basalType")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ALARM_RECORD -> {
|
||||
aapsLogger.debug(LTag.PUMPCOMM, "GetRecordPacket HandleResponse: ALARM_RECORD")
|
||||
}
|
||||
|
||||
AUTO_RECORD -> {
|
||||
aapsLogger.debug(LTag.PUMPCOMM, "GetRecordPacket HandleResponse: AUTO_RECORD")
|
||||
}
|
||||
|
||||
TIME_SYNC_RECORD -> {
|
||||
aapsLogger.debug(LTag.PUMPCOMM, "GetRecordPacket HandleResponse: TIME_SYNC_RECORD")
|
||||
}
|
||||
|
||||
AUTO1_RECORD -> {
|
||||
aapsLogger.debug(LTag.PUMPCOMM, "GetRecordPacket HandleResponse: AUTO1_RECORD")
|
||||
}
|
||||
|
||||
AUTO2_RECORD -> {
|
||||
aapsLogger.debug(LTag.PUMPCOMM, "GetRecordPacket HandleResponse: AUTO2_RECORD")
|
||||
}
|
||||
|
||||
AUTO3_RECORD -> {
|
||||
aapsLogger.debug(LTag.PUMPCOMM, "GetRecordPacket HandleResponse: AUTO3_RECORD")
|
||||
}
|
||||
|
||||
TDD_RECORD -> {
|
||||
aapsLogger.debug(LTag.PUMPCOMM, "GetRecordPacket HandleResponse: TDD_RECORD")
|
||||
val timestamp = MedtrumTimeUtil().convertPumpTimeToSystemTimeMillis(data.copyOfRange(RESP_RECORD_DATA_START, RESP_RECORD_DATA_START + 4).toLong())
|
||||
val timeZoneOffset = data.copyOfRange(RESP_RECORD_DATA_START + 4, RESP_RECORD_DATA_START + 6).toInt()
|
||||
val tddMins = data.copyOfRange(RESP_RECORD_DATA_START + 6, RESP_RECORD_DATA_START + 8).toInt()
|
||||
val glucoseRecordTime = data.copyOfRange(RESP_RECORD_DATA_START + 8, RESP_RECORD_DATA_START + 12).toLong()
|
||||
val tdd = data.copyOfRange(RESP_RECORD_DATA_START + 12, RESP_RECORD_DATA_START + 16).toFloat()
|
||||
val basalTdd = data.copyOfRange(RESP_RECORD_DATA_START + 16, RESP_RECORD_DATA_START + 20).toFloat()
|
||||
val glucose = data.copyOfRange(RESP_RECORD_DATA_START + 20, RESP_RECORD_DATA_START + 24).toFloat()
|
||||
val unknown = data.copyOfRange(RESP_RECORD_DATA_START + 24, RESP_RECORD_DATA_START + 28).toFloat()
|
||||
val meanSomething = data.copyOfRange(RESP_RECORD_DATA_START + 28, RESP_RECORD_DATA_START + 32).toFloat()
|
||||
val usedTdd = data.copyOfRange(RESP_RECORD_DATA_START + 32, RESP_RECORD_DATA_START + 36).toFloat()
|
||||
val usedIBasal = data.copyOfRange(RESP_RECORD_DATA_START + 36, RESP_RECORD_DATA_START + 40).toFloat()
|
||||
val usedSgBasal = data.copyOfRange(RESP_RECORD_DATA_START + 40, RESP_RECORD_DATA_START + 44).toFloat()
|
||||
val usedUMax = data.copyOfRange(RESP_RECORD_DATA_START + 44, RESP_RECORD_DATA_START + 48).toFloat()
|
||||
val newTdd = data.copyOfRange(RESP_RECORD_DATA_START + 48, RESP_RECORD_DATA_START + 52).toFloat()
|
||||
val newIBasal = data.copyOfRange(RESP_RECORD_DATA_START + 52, RESP_RECORD_DATA_START + 56).toFloat()
|
||||
val newSgBasal = data.copyOfRange(RESP_RECORD_DATA_START + 56, RESP_RECORD_DATA_START + 60).toFloat()
|
||||
val newUMax = data.copyOfRange(RESP_RECORD_DATA_START + 60, RESP_RECORD_DATA_START + 64).toFloat()
|
||||
|
||||
aapsLogger.debug(
|
||||
LTag.PUMPCOMM, "TDD_RECORD: timestamp: $timestamp, timeZoneOffset: $timeZoneOffset, tddMins: $tddMins, glucoseRecordTime: $glucoseRecordTime, tdd: " +
|
||||
"$tdd, basalTdd: $basalTdd, glucose: $glucose, unknown: $unknown, meanSomething: $meanSomething, usedTdd: $usedTdd, usedIBasal: $usedIBasal, usedSgBasal: " +
|
||||
"$usedSgBasal, usedUMax: $usedUMax, newTdd: $newTdd, newIBasal: $newIBasal, newSgBasal: $newSgBasal, newUMax: $newUMax"
|
||||
)
|
||||
|
||||
val newRecord = pumpSync.createOrUpdateTotalDailyDose(
|
||||
timestamp = timestamp,
|
||||
bolusAmount = (tdd - basalTdd).toDouble(),
|
||||
basalAmount = basalTdd.toDouble(),
|
||||
totalAmount = tdd.toDouble(),
|
||||
pumpId = timestamp,
|
||||
pumpType = medtrumPump.pumpType(),
|
||||
pumpSerial = medtrumPump.pumpSN.toString(radix = 16)
|
||||
)
|
||||
|
||||
aapsLogger.debug(
|
||||
LTag.PUMPCOMM,
|
||||
"handleBasalStatusUpdate from record: ${if (newRecord) "**NEW** " else ""}EVENT TDD: ${dateUtil.dateAndTimeString(timestamp)} ($timestamp) " +
|
||||
"TDD: $tdd, BasalTDD: $basalTdd, BolusTDD: ${tdd - basalTdd}"
|
||||
)
|
||||
|
||||
}
|
||||
|
||||
else -> {
|
||||
aapsLogger.debug(LTag.PUMPCOMM, "GetRecordPacket HandleResponse: Unknown record type: $recordType")
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
aapsLogger.error(LTag.PUMPCOMM, "GetRecordPacket HandleResponse: Invalid record header")
|
||||
}
|
||||
}
|
||||
|
||||
return success
|
||||
}
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
package info.nightscout.pump.medtrum.comm.packets
|
||||
|
||||
import dagger.android.HasAndroidInjector
|
||||
import info.nightscout.pump.medtrum.MedtrumPump
|
||||
import info.nightscout.pump.medtrum.comm.enums.CommandType.GET_TIME
|
||||
import info.nightscout.pump.medtrum.extension.toLong
|
||||
import info.nightscout.pump.medtrum.util.MedtrumTimeUtil
|
||||
import javax.inject.Inject
|
||||
|
||||
class GetTimePacket(injector: HasAndroidInjector) : MedtrumPacket(injector) {
|
||||
|
||||
@Inject lateinit var medtrumPump: MedtrumPump
|
||||
|
||||
companion object {
|
||||
|
||||
private const val RESP_TIME_START = 6
|
||||
private const val RESP_TIME_END = RESP_TIME_START + 4
|
||||
}
|
||||
|
||||
init {
|
||||
opCode = GET_TIME.code
|
||||
expectedMinRespLength = RESP_TIME_END
|
||||
}
|
||||
|
||||
override fun handleResponse(data: ByteArray): Boolean {
|
||||
val success = super.handleResponse(data)
|
||||
if (success) {
|
||||
val time = MedtrumTimeUtil().convertPumpTimeToSystemTimeMillis(data.copyOfRange(RESP_TIME_START, RESP_TIME_END).toLong())
|
||||
medtrumPump.lastTimeReceivedFromPump = time
|
||||
}
|
||||
|
||||
return success
|
||||
}
|
||||
}
|
|
@ -0,0 +1,79 @@
|
|||
package info.nightscout.pump.medtrum.comm.packets
|
||||
|
||||
import dagger.android.HasAndroidInjector
|
||||
import info.nightscout.pump.medtrum.extension.toInt
|
||||
import info.nightscout.rx.logging.AAPSLogger
|
||||
import info.nightscout.rx.logging.LTag
|
||||
import javax.inject.Inject
|
||||
|
||||
open class MedtrumPacket(protected var injector: HasAndroidInjector) {
|
||||
|
||||
@Inject lateinit var aapsLogger: AAPSLogger
|
||||
|
||||
var opCode: Byte = 0
|
||||
var failed = false
|
||||
var expectedMinRespLength = RESP_RESULT_END
|
||||
|
||||
companion object {
|
||||
|
||||
const val RESP_OPCODE_START = 1
|
||||
const val RESP_OPCODE_END = RESP_OPCODE_START + 1
|
||||
const val RESP_RESULT_START = 4
|
||||
const val RESP_RESULT_END = RESP_RESULT_START + 2
|
||||
|
||||
private const val RESP_WAITING = 16384
|
||||
}
|
||||
|
||||
init {
|
||||
// @Suppress("LeakingThis")
|
||||
injector.androidInjector().inject(this)
|
||||
}
|
||||
|
||||
open fun getRequest(): ByteArray {
|
||||
return byteArrayOf(opCode)
|
||||
}
|
||||
|
||||
/** handles a response from the Medtrum pump, returns true if command was successfull, returns false if command failed or waiting for response */
|
||||
open fun handleResponse(data: ByteArray): Boolean {
|
||||
// Check for broken packets
|
||||
if (RESP_RESULT_END > data.size) {
|
||||
failed = true
|
||||
aapsLogger.debug(LTag.PUMPCOMM, "handleResponse: Unexpected response length, expected: $expectedMinRespLength got: ${data.size}")
|
||||
return false
|
||||
}
|
||||
|
||||
val incomingOpCode: Byte = data.copyOfRange(RESP_OPCODE_START, RESP_OPCODE_END).first()
|
||||
val responseCode = data.copyOfRange(RESP_RESULT_START, RESP_RESULT_END).toInt()
|
||||
|
||||
return when {
|
||||
incomingOpCode != opCode -> {
|
||||
failed = true
|
||||
aapsLogger.error(LTag.PUMPCOMM, "handleResponse: Unexpected command, expected: $opCode got: $incomingOpCode")
|
||||
false
|
||||
}
|
||||
|
||||
responseCode == 0 -> {
|
||||
// Check if length is what is expected from this type of packet
|
||||
if (expectedMinRespLength > data.size) {
|
||||
failed = true
|
||||
aapsLogger.debug(LTag.PUMPCOMM, "handleResponse: Unexpected response length, expected: $expectedMinRespLength got: ${data.size}")
|
||||
return false
|
||||
}
|
||||
aapsLogger.debug(LTag.PUMPCOMM, "handleResponse: Happy command: $opCode response: $responseCode")
|
||||
true
|
||||
}
|
||||
|
||||
responseCode == RESP_WAITING -> {
|
||||
aapsLogger.debug(LTag.PUMPCOMM, "handleResponse: Waiting command: $opCode response: $responseCode")
|
||||
// Waiting do nothing
|
||||
false
|
||||
}
|
||||
|
||||
else -> {
|
||||
failed = true
|
||||
aapsLogger.warn(LTag.PUMPCOMM, "handleResponse: Error in command: $opCode response: $responseCode")
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,236 @@
|
|||
package info.nightscout.pump.medtrum.comm.packets
|
||||
|
||||
import dagger.android.HasAndroidInjector
|
||||
import info.nightscout.pump.medtrum.MedtrumPump
|
||||
import info.nightscout.pump.medtrum.comm.enums.AlarmState
|
||||
import info.nightscout.pump.medtrum.comm.enums.BasalType
|
||||
import info.nightscout.pump.medtrum.comm.enums.MedtrumPumpState
|
||||
import info.nightscout.pump.medtrum.extension.toInt
|
||||
import info.nightscout.pump.medtrum.extension.toLong
|
||||
import info.nightscout.pump.medtrum.util.MedtrumTimeUtil
|
||||
import info.nightscout.rx.logging.AAPSLogger
|
||||
import info.nightscout.rx.logging.LTag
|
||||
import javax.inject.Inject
|
||||
|
||||
class NotificationPacket(val injector: HasAndroidInjector) {
|
||||
|
||||
/**
|
||||
* This is a bit of a special packet, as it is not a command packet
|
||||
* but a notification packet. It is sent by the pump to the phone
|
||||
* when the pump has a notification to send.
|
||||
*
|
||||
* Notifications are sent regualary, regardless of the pump state.
|
||||
*
|
||||
* There can be multiple messages in one packet, this is noted by the fieldMask.
|
||||
*
|
||||
* Byte 1: State (Handle a state change directly? before analyzing further?)
|
||||
* Byte 2-3: FieldMask (BitMask which tells the fields present in the message)
|
||||
* Byte 4-end : status data
|
||||
*
|
||||
* When multiple fields are in the message, the data is concatenated.
|
||||
* This kind of message can also come as a response of SynchronizePacket,
|
||||
* and can be handled here by handleMaskedMessage() as well.
|
||||
*/
|
||||
|
||||
@Inject lateinit var aapsLogger: AAPSLogger
|
||||
@Inject lateinit var medtrumPump: MedtrumPump
|
||||
|
||||
companion object {
|
||||
|
||||
private const val NOTIF_STATE_START = 0
|
||||
private const val NOTIF_STATE_END = NOTIF_STATE_START + 1
|
||||
|
||||
private const val MASK_SUSPEND = 0x01
|
||||
private const val MASK_NORMAL_BOLUS = 0x02
|
||||
private const val MASK_EXTENDED_BOLUS = 0x04
|
||||
private const val MASK_BASAL = 0x08
|
||||
|
||||
private const val MASK_SETUP = 0x10
|
||||
private const val MASK_RESERVOIR = 0x20
|
||||
private const val MASK_START_TIME = 0x40
|
||||
private const val MASK_BATTERY = 0x80
|
||||
|
||||
private const val MASK_STORAGE = 0x100
|
||||
private const val MASK_ALARM = 0x200
|
||||
private const val MASK_AGE = 0x400
|
||||
private const val MASK_UNKNOWN_1 = 0x800
|
||||
|
||||
private const val MASK_UNUSED_CGM = 0x1000
|
||||
private const val MASK_UNUSED_COMMAND_CONFIRM = 0x2000
|
||||
private const val MASK_UNUSED_AUTO_STATUS = 0x4000
|
||||
private const val MASK_UNUSED_LEGACY = 0x8000
|
||||
}
|
||||
|
||||
init {
|
||||
injector.androidInjector().inject(this)
|
||||
}
|
||||
|
||||
fun handleNotification(notification: ByteArray) {
|
||||
val state = MedtrumPumpState.fromByte(notification[0])
|
||||
aapsLogger.debug(LTag.PUMPCOMM, "Notification state: $state, current state: ${medtrumPump.pumpState}")
|
||||
|
||||
if (state != medtrumPump.pumpState) {
|
||||
aapsLogger.debug(LTag.PUMPCOMM, "State changed from ${medtrumPump.pumpState} to $state")
|
||||
medtrumPump.pumpState = state
|
||||
}
|
||||
|
||||
if (notification.size > NOTIF_STATE_END) {
|
||||
handleMaskedMessage(notification.copyOfRange(NOTIF_STATE_END, notification.size))
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle a message with a field mask, can be used by other packets as well
|
||||
*/
|
||||
fun handleMaskedMessage(data: ByteArray) {
|
||||
val fieldMask = data.copyOfRange(0, 2).toInt()
|
||||
var offset = 2
|
||||
|
||||
aapsLogger.debug(LTag.PUMPCOMM, "Message field mask: $fieldMask")
|
||||
|
||||
if (fieldMask and MASK_SUSPEND != 0) {
|
||||
aapsLogger.debug(LTag.PUMPCOMM, "Suspend notification received")
|
||||
medtrumPump.suspendTime = MedtrumTimeUtil().convertPumpTimeToSystemTimeMillis(data.copyOfRange(offset, offset + 4).toLong())
|
||||
aapsLogger.debug(LTag.PUMPCOMM, "Suspend time: ${medtrumPump.suspendTime}")
|
||||
offset += 4
|
||||
}
|
||||
|
||||
if (fieldMask and MASK_NORMAL_BOLUS != 0) {
|
||||
aapsLogger.debug(LTag.PUMPCOMM, "Normal bolus notification received")
|
||||
var bolusData = data.copyOfRange(offset, offset + 1).toInt()
|
||||
var bolusType = bolusData and 0x7F
|
||||
val bolusCompleted: Boolean = ((bolusData shr 7) and 0x01) != 0
|
||||
var bolusDelivered = data.copyOfRange(offset + 1, offset + 3).toInt() * 0.05
|
||||
aapsLogger.debug(LTag.PUMPCOMM, "Bolus type: $bolusType, bolusData: $bolusData bolus completed: $bolusCompleted, bolus delivered: $bolusDelivered")
|
||||
medtrumPump.handleBolusStatusUpdate(bolusType, bolusCompleted, bolusDelivered)
|
||||
offset += 3
|
||||
}
|
||||
|
||||
if (fieldMask and MASK_EXTENDED_BOLUS != 0) {
|
||||
aapsLogger.error(LTag.PUMPCOMM, "Extended bolus notification received, extended bolus not supported!")
|
||||
// TODO Handle error and stop pump if this happens?
|
||||
offset += 3
|
||||
}
|
||||
|
||||
if (fieldMask and MASK_BASAL != 0) {
|
||||
aapsLogger.debug(LTag.PUMPCOMM, "Basal notification received")
|
||||
val basalType = enumValues<BasalType>()[data.copyOfRange(offset, offset + 1).toInt()]
|
||||
var basalSequence = data.copyOfRange(offset + 1, offset + 3).toInt()
|
||||
var basalPatchId = data.copyOfRange(offset + 3, offset + 5).toLong()
|
||||
var basalStartTime = MedtrumTimeUtil().convertPumpTimeToSystemTimeMillis(data.copyOfRange(offset + 5, offset + 9).toLong())
|
||||
var basalRateAndDelivery = data.copyOfRange(offset + 9, offset + 12).toInt()
|
||||
var basalRate = (basalRateAndDelivery and 0xFFF) * 0.05
|
||||
var basalDelivery = (basalRateAndDelivery shr 12) * 0.05
|
||||
aapsLogger.debug(
|
||||
LTag.PUMPCOMM,
|
||||
"Basal type: $basalType, basal sequence: $basalSequence, basal patch id: $basalPatchId, basal time: $basalStartTime, basal rate: $basalRate, basal delivery: $basalDelivery"
|
||||
)
|
||||
// Don't spam with basal updates here, only if the running basal rate has changed, or a new basal is set
|
||||
if (medtrumPump.lastBasalRate != basalRate || medtrumPump.lastBasalStartTime != basalStartTime) {
|
||||
medtrumPump.handleBasalStatusUpdate(basalType, basalRate, basalSequence, basalPatchId, basalStartTime)
|
||||
}
|
||||
offset += 12
|
||||
}
|
||||
|
||||
if (fieldMask and MASK_SETUP != 0) {
|
||||
aapsLogger.debug(LTag.PUMPCOMM, "Setup notification received")
|
||||
medtrumPump.primeProgress = data.copyOfRange(offset, offset + 1).toInt()
|
||||
aapsLogger.debug(LTag.PUMPCOMM, "Prime progress: ${medtrumPump.primeProgress}")
|
||||
offset += 1
|
||||
}
|
||||
|
||||
if (fieldMask and MASK_RESERVOIR != 0) {
|
||||
aapsLogger.debug(LTag.PUMPCOMM, "Reservoir notification received")
|
||||
medtrumPump.reservoir = data.copyOfRange(offset, offset + 2).toInt() * 0.05
|
||||
aapsLogger.debug(LTag.PUMPCOMM, "Reservoir: ${medtrumPump.reservoir}")
|
||||
offset += 2
|
||||
}
|
||||
|
||||
if (fieldMask and MASK_START_TIME != 0) {
|
||||
aapsLogger.debug(LTag.PUMPCOMM, "Start time notification received")
|
||||
val patchStartTime = MedtrumTimeUtil().convertPumpTimeToSystemTimeMillis(data.copyOfRange(offset, offset + 4).toLong())
|
||||
if (medtrumPump.patchStartTime != patchStartTime) {
|
||||
aapsLogger.debug(LTag.PUMPCOMM, "Patch start time changed from ${medtrumPump.patchStartTime} to $patchStartTime")
|
||||
medtrumPump.patchStartTime = patchStartTime
|
||||
}
|
||||
aapsLogger.debug(LTag.PUMPCOMM, "Patch start time: ${patchStartTime}")
|
||||
offset += 4
|
||||
}
|
||||
|
||||
if (fieldMask and MASK_BATTERY != 0) {
|
||||
aapsLogger.debug(LTag.PUMPCOMM, "Battery notification received")
|
||||
var parameter = data.copyOfRange(offset, offset + 3).toInt()
|
||||
// Precision for voltage A is a guess, voltage B is the important one, threshold: < 2.64
|
||||
medtrumPump.batteryVoltage_A = (parameter and 0xFFF) / 512.0
|
||||
medtrumPump.batteryVoltage_B = (parameter shr 12) / 512.0
|
||||
aapsLogger.debug(LTag.PUMPCOMM, "Battery voltage A: ${medtrumPump.batteryVoltage_A}, battery voltage B: ${medtrumPump.batteryVoltage_B}")
|
||||
offset += 3
|
||||
}
|
||||
|
||||
if (fieldMask and MASK_STORAGE != 0) {
|
||||
aapsLogger.debug(LTag.PUMPCOMM, "Storage notification received")
|
||||
val sequence = data.copyOfRange(offset, offset + 2).toInt()
|
||||
if (sequence > medtrumPump.currentSequenceNumber) {
|
||||
medtrumPump.currentSequenceNumber = sequence
|
||||
}
|
||||
val patchId = data.copyOfRange(offset + 2, offset + 4).toLong()
|
||||
if (patchId != medtrumPump.patchId) {
|
||||
aapsLogger.warn(LTag.PUMPCOMM, "handleMaskedMessage: We got wrong patch id!")
|
||||
}
|
||||
aapsLogger.debug(LTag.PUMPCOMM, "Last known sequence number: ${medtrumPump.currentSequenceNumber}, patch id: ${patchId}")
|
||||
offset += 4
|
||||
}
|
||||
|
||||
if (fieldMask and MASK_ALARM != 0) {
|
||||
val alarmFlags = data.copyOfRange(offset, offset + 2).toInt()
|
||||
val alarmParameter = data.copyOfRange(offset + 2, offset + 4).toInt()
|
||||
aapsLogger.debug(LTag.PUMPCOMM, "Alarm notification received, Alarm flags: $alarmFlags, alarm parameter: $alarmParameter")
|
||||
|
||||
// If no alarm, clear activeAlarm list
|
||||
if (alarmFlags == 0 && medtrumPump.activeAlarms.isNotEmpty()) {
|
||||
medtrumPump.clearAlarmState()
|
||||
} else if (alarmFlags != 0) {
|
||||
// Check each alarm bit
|
||||
for (i in 0..3) { // Only the first 3 flags are interesting for us, the rest we will get from the pump state
|
||||
val alarmState = AlarmState.values()[i]
|
||||
if ((alarmFlags shr i) and 1 != 0) {
|
||||
// If the alarm bit is set, add the corresponding alarm to activeAlarms
|
||||
medtrumPump.addAlarm(alarmState)
|
||||
} else if (medtrumPump.activeAlarms.contains(alarmState)) {
|
||||
// If the alarm bit is not set, and the corresponding alarm is in activeAlarms, remove it
|
||||
medtrumPump.removeAlarm(alarmState)
|
||||
}
|
||||
}
|
||||
}
|
||||
offset += 4
|
||||
}
|
||||
|
||||
if (fieldMask and MASK_AGE != 0) {
|
||||
aapsLogger.debug(LTag.PUMPCOMM, "Age notification received")
|
||||
medtrumPump.patchAge = data.copyOfRange(offset, offset + 4).toLong()
|
||||
aapsLogger.debug(LTag.PUMPCOMM, "Patch age: ${medtrumPump.patchAge}")
|
||||
offset += 4
|
||||
}
|
||||
|
||||
if (fieldMask and MASK_UNKNOWN_1 != 0) {
|
||||
aapsLogger.debug(LTag.PUMPCOMM, "Unknown 1 notification received, not handled!")
|
||||
}
|
||||
|
||||
if (fieldMask and MASK_UNUSED_CGM != 0) {
|
||||
aapsLogger.debug(LTag.PUMPCOMM, "Unused CGM notification received, not handled!")
|
||||
}
|
||||
|
||||
if (fieldMask and MASK_UNUSED_COMMAND_CONFIRM != 0) {
|
||||
// This one is a warning, as this happens we need to know about it, and maybe implement
|
||||
aapsLogger.warn(LTag.PUMPCOMM, "Unused command confirm notification received, not handled!")
|
||||
}
|
||||
|
||||
if (fieldMask and MASK_UNUSED_AUTO_STATUS != 0) {
|
||||
aapsLogger.debug(LTag.PUMPCOMM, "Unused auto status notification received, not handled!")
|
||||
}
|
||||
|
||||
if (fieldMask and MASK_UNUSED_LEGACY != 0) {
|
||||
aapsLogger.debug(LTag.PUMPCOMM, "Unused legacy notification received, not handled!")
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
package info.nightscout.pump.medtrum.comm.packets
|
||||
|
||||
import dagger.android.HasAndroidInjector
|
||||
import info.nightscout.pump.medtrum.comm.enums.CommandType.POLL_PATCH
|
||||
|
||||
class PollPatchPacket(injector: HasAndroidInjector) : MedtrumPacket(injector) {
|
||||
|
||||
init {
|
||||
opCode = POLL_PATCH.code
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
package info.nightscout.pump.medtrum.comm.packets
|
||||
|
||||
import dagger.android.HasAndroidInjector
|
||||
import info.nightscout.pump.medtrum.comm.enums.CommandType.PRIME
|
||||
|
||||
class PrimePacket(injector: HasAndroidInjector) : MedtrumPacket(injector) {
|
||||
|
||||
init {
|
||||
opCode = PRIME.code
|
||||
}
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
package info.nightscout.pump.medtrum.comm.packets
|
||||
|
||||
import dagger.android.HasAndroidInjector
|
||||
import info.nightscout.pump.medtrum.comm.enums.CommandType.READ_BOLUS_STATE
|
||||
|
||||
class ReadBolusStatePacket(injector: HasAndroidInjector) : MedtrumPacket(injector) {
|
||||
// UNUSED
|
||||
// Bolus sync is currently done by getting the records and syncing then with AAPS pumpSync there
|
||||
|
||||
var bolusData: ByteArray = byteArrayOf()
|
||||
|
||||
companion object {
|
||||
|
||||
private const val RESP_BOLUS_DATA_START = 6
|
||||
}
|
||||
|
||||
init {
|
||||
opCode = READ_BOLUS_STATE.code
|
||||
expectedMinRespLength = RESP_BOLUS_DATA_START + 1
|
||||
}
|
||||
|
||||
override fun handleResponse(data: ByteArray): Boolean {
|
||||
val success = super.handleResponse(data)
|
||||
if (success) {
|
||||
// UNUSED
|
||||
bolusData = data.copyOfRange(RESP_BOLUS_DATA_START, data.size)
|
||||
}
|
||||
|
||||
return success
|
||||
}
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
package info.nightscout.pump.medtrum.comm.packets
|
||||
|
||||
import dagger.android.HasAndroidInjector
|
||||
import info.nightscout.pump.medtrum.comm.enums.CommandType.RESUME_PUMP
|
||||
import info.nightscout.pump.medtrum.extension.toByteArray
|
||||
|
||||
class ResumePumpPacket(injector: HasAndroidInjector) : MedtrumPacket(injector) {
|
||||
|
||||
init {
|
||||
opCode = RESUME_PUMP.code
|
||||
}
|
||||
|
||||
override fun getRequest(): ByteArray {
|
||||
return byteArrayOf(opCode)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,57 @@
|
|||
package info.nightscout.pump.medtrum.comm.packets
|
||||
|
||||
import dagger.android.HasAndroidInjector
|
||||
import info.nightscout.pump.medtrum.MedtrumPump
|
||||
import info.nightscout.pump.medtrum.comm.enums.CommandType.SET_BASAL_PROFILE
|
||||
import info.nightscout.pump.medtrum.comm.enums.BasalType
|
||||
import info.nightscout.pump.medtrum.extension.toInt
|
||||
import info.nightscout.pump.medtrum.extension.toLong
|
||||
import info.nightscout.pump.medtrum.util.MedtrumTimeUtil
|
||||
import javax.inject.Inject
|
||||
|
||||
class SetBasalProfilePacket(injector: HasAndroidInjector, private val basalProfile: ByteArray) : MedtrumPacket(injector) {
|
||||
|
||||
@Inject lateinit var medtrumPump: MedtrumPump
|
||||
|
||||
companion object {
|
||||
|
||||
private const val RESP_BASAL_TYPE_START = 6
|
||||
private const val RESP_BASAL_TYPE_END = RESP_BASAL_TYPE_START + 1
|
||||
private const val RESP_BASAL_VALUE_START = 7
|
||||
private const val RESP_BASAL_VALUE_END = RESP_BASAL_VALUE_START + 2
|
||||
private const val RESP_BASAL_SEQUENCE_START = 9
|
||||
private const val RESP_BASAL_SEQUENCE_END = RESP_BASAL_SEQUENCE_START + 2
|
||||
private const val RESP_BASAL_PATCH_ID_START = 11
|
||||
private const val RESP_BASAL_PATCH_ID_END = RESP_BASAL_PATCH_ID_START + 2
|
||||
private const val RESP_BASAL_START_TIME_START = 13
|
||||
private const val RESP_BASAL_START_TIME_END = RESP_BASAL_START_TIME_START + 4
|
||||
}
|
||||
|
||||
init {
|
||||
opCode = SET_BASAL_PROFILE.code
|
||||
expectedMinRespLength = RESP_BASAL_START_TIME_END
|
||||
|
||||
}
|
||||
|
||||
override fun getRequest(): ByteArray {
|
||||
val basalType: Byte = 1 // Fixed to normal basal
|
||||
return byteArrayOf(opCode) + basalType + basalProfile
|
||||
}
|
||||
|
||||
override fun handleResponse(data: ByteArray): Boolean {
|
||||
val success = super.handleResponse(data)
|
||||
if (success) {
|
||||
val medtrumTimeUtil = MedtrumTimeUtil()
|
||||
val basalType = enumValues<BasalType>()[data.copyOfRange(RESP_BASAL_TYPE_START, RESP_BASAL_TYPE_END).toInt()]
|
||||
val basalValue = data.copyOfRange(RESP_BASAL_VALUE_START, RESP_BASAL_VALUE_END).toInt() * 0.05
|
||||
val basalSequence = data.copyOfRange(RESP_BASAL_SEQUENCE_START, RESP_BASAL_SEQUENCE_END).toInt()
|
||||
val basalPatchId = data.copyOfRange(RESP_BASAL_PATCH_ID_START, RESP_BASAL_PATCH_ID_END).toLong()
|
||||
val basalStartTime = medtrumTimeUtil.convertPumpTimeToSystemTimeMillis(data.copyOfRange(RESP_BASAL_START_TIME_START, RESP_BASAL_START_TIME_END).toLong())
|
||||
|
||||
// Update the actual basal profile
|
||||
medtrumPump.actualBasalProfile = basalProfile
|
||||
medtrumPump.handleBasalStatusUpdate(basalType, basalValue, basalSequence, basalPatchId, basalStartTime)
|
||||
}
|
||||
return success
|
||||
}
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
package info.nightscout.pump.medtrum.comm.packets
|
||||
|
||||
import dagger.android.HasAndroidInjector
|
||||
import info.nightscout.pump.medtrum.comm.enums.CommandType.SET_BOLUS_MOTOR
|
||||
|
||||
class SetBolusMotorPacket(injector: HasAndroidInjector) : MedtrumPacket(injector) {
|
||||
|
||||
// UNUSED in our driver
|
||||
|
||||
init {
|
||||
opCode = SET_BOLUS_MOTOR.code
|
||||
}
|
||||
|
||||
override fun getRequest(): ByteArray {
|
||||
return byteArrayOf(opCode) + 0.toByte()
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue