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">
|
<dictionary name="project-dictionary">
|
||||||
<words>
|
<words>
|
||||||
<w>aaps</w>
|
<w>aaps</w>
|
||||||
|
<w>aapsclient</w>
|
||||||
<w>abcdef</w>
|
<w>abcdef</w>
|
||||||
<w>accu</w>
|
<w>accu</w>
|
||||||
<w>acked</w>
|
<w>acked</w>
|
||||||
|
@ -18,11 +19,13 @@
|
||||||
<w>bage</w>
|
<w>bage</w>
|
||||||
<w>basaliob</w>
|
<w>basaliob</w>
|
||||||
<w>basals</w>
|
<w>basals</w>
|
||||||
|
<w>batt</w>
|
||||||
<w>bgcheck</w>
|
<w>bgcheck</w>
|
||||||
<w>bgsource</w>
|
<w>bgsource</w>
|
||||||
<w>boluscalc</w>
|
<w>boluscalc</w>
|
||||||
<w>bolusing</w>
|
<w>bolusing</w>
|
||||||
<w>boluswizard</w>
|
<w>boluswizard</w>
|
||||||
|
<w>boyda</w>
|
||||||
<w>carb</w>
|
<w>carb</w>
|
||||||
<w>carbratio</w>
|
<w>carbratio</w>
|
||||||
<w>carbs</w>
|
<w>carbs</w>
|
||||||
|
@ -67,6 +70,7 @@
|
||||||
<w>humalog</w>
|
<w>humalog</w>
|
||||||
<w>iage</w>
|
<w>iage</w>
|
||||||
<w>infinivocgm</w>
|
<w>infinivocgm</w>
|
||||||
|
<w>instantiator</w>
|
||||||
<w>insulet</w>
|
<w>insulet</w>
|
||||||
<w>intelligo</w>
|
<w>intelligo</w>
|
||||||
<w>iobtotal</w>
|
<w>iobtotal</w>
|
||||||
|
@ -78,6 +82,7 @@
|
||||||
<w>lyumjev</w>
|
<w>lyumjev</w>
|
||||||
<w>mdtp</w>
|
<w>mdtp</w>
|
||||||
<w>medtronic</w>
|
<w>medtronic</w>
|
||||||
|
<w>medtrum</w>
|
||||||
<w>mgdl</w>
|
<w>mgdl</w>
|
||||||
<w>miao</w>
|
<w>miao</w>
|
||||||
<w>misformatted</w>
|
<w>misformatted</w>
|
||||||
|
@ -99,6 +104,7 @@
|
||||||
<w>oref</w>
|
<w>oref</w>
|
||||||
<w>otpauth</w>
|
<w>otpauth</w>
|
||||||
<w>passcode</w>
|
<w>passcode</w>
|
||||||
|
<w>pbage</w>
|
||||||
<w>pdus</w>
|
<w>pdus</w>
|
||||||
<w>philoul</w>
|
<w>philoul</w>
|
||||||
<w>poctech</w>
|
<w>poctech</w>
|
||||||
|
@ -108,6 +114,7 @@
|
||||||
<w>pumpcontrol</w>
|
<w>pumpcontrol</w>
|
||||||
<w>pumpdrivers</w>
|
<w>pumpdrivers</w>
|
||||||
<w>quickwizard</w>
|
<w>quickwizard</w>
|
||||||
|
<w>rawbg</w>
|
||||||
<w>readstatus</w>
|
<w>readstatus</w>
|
||||||
<w>realduration</w>
|
<w>realduration</w>
|
||||||
<w>refresheventsfromnightscout</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'
|
namespace 'info.nightscout.shared.impl'
|
||||||
defaultConfig {
|
defaultConfig {
|
||||||
minSdkVersion 23 // for wear
|
minSdkVersion 25 // for wear
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -16,7 +16,7 @@ android {
|
||||||
|
|
||||||
namespace 'info.nightscout.shared'
|
namespace 'info.nightscout.shared'
|
||||||
defaultConfig {
|
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
|
package info.nightscout.rx.events
|
||||||
|
|
||||||
import info.nightscout.rx.events.Event
|
|
||||||
|
|
||||||
class EventRefreshButtonState (val newState : Boolean): Event()
|
class EventRefreshButtonState (val newState : Boolean): Event()
|
|
@ -96,9 +96,9 @@ class DateUtil @Inject constructor(private val context: Context) {
|
||||||
return calendar.timeInMillis
|
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 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
|
var retVal = 0
|
||||||
if (m.find()) {
|
if (m.find()) {
|
||||||
retVal = SafeParse.stringToInt(m.group(1)) * 60 * 60 + SafeParse.stringToInt(m.group(2)) * 60
|
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)
|
minutes = rh.gs(R.string.shortminute)
|
||||||
}
|
}
|
||||||
var result = ""
|
var result = ""
|
||||||
if (diff[TimeUnit.DAYS]!! > 0) result += diff[TimeUnit.DAYS].toString() + days
|
if (diff.getOrDefault(TimeUnit.DAYS, -1) > 0) result += diff[TimeUnit.DAYS].toString() + days
|
||||||
if (diff[TimeUnit.HOURS]!! > 0) result += diff[TimeUnit.HOURS].toString() + hours
|
if (diff.getOrDefault(TimeUnit.HOURS, -1) > 0) result += diff[TimeUnit.HOURS].toString() + hours
|
||||||
if (diff[TimeUnit.DAYS] == 0L) result += diff[TimeUnit.MINUTES].toString() + minutes
|
if (diff[TimeUnit.DAYS] == 0L) result += diff[TimeUnit.MINUTES].toString() + minutes
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
@ -368,6 +368,7 @@ class DateUtil @Inject constructor(private val context: Context) {
|
||||||
if (t > 28) {
|
if (t > 28) {
|
||||||
unit = rh.gs(R.string.unit_week)
|
unit = rh.gs(R.string.unit_week)
|
||||||
t /= 7
|
t /= 7
|
||||||
|
@Suppress("KotlinConstantConditions")
|
||||||
if (t != 1L) unit = rh.gs(R.string.unit_weeks)
|
if (t != 1L) unit = rh.gs(R.string.unit_weeks)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -406,8 +407,8 @@ class DateUtil @Inject constructor(private val context: Context) {
|
||||||
} else {
|
} else {
|
||||||
thisDf = DecimalFormat("#", dfs)
|
thisDf = DecimalFormat("#", dfs)
|
||||||
}
|
}
|
||||||
thisDf!!.maximumFractionDigits = digits
|
thisDf?.maximumFractionDigits = digits
|
||||||
return thisDf.format(x)
|
return thisDf?.format(x) ?: ""
|
||||||
}
|
}
|
||||||
|
|
||||||
fun formatHHMM(timeAsSeconds: Int): String {
|
fun formatHHMM(timeAsSeconds: Int): String {
|
||||||
|
@ -432,9 +433,9 @@ class DateUtil @Inject constructor(private val context: Context) {
|
||||||
fun timeStampToUtcDateMillis(timestamp: Long): Long {
|
fun timeStampToUtcDateMillis(timestamp: Long): Long {
|
||||||
val current = Calendar.getInstance().apply { timeInMillis = timestamp }
|
val current = Calendar.getInstance().apply { timeInMillis = timestamp }
|
||||||
return Calendar.getInstance().apply {
|
return Calendar.getInstance().apply {
|
||||||
set(Calendar.YEAR, current.get(Calendar.YEAR))
|
set(Calendar.YEAR, current[Calendar.YEAR])
|
||||||
set(Calendar.MONTH, current.get(Calendar.MONTH))
|
set(Calendar.MONTH, current[Calendar.MONTH])
|
||||||
set(Calendar.DAY_OF_MONTH, current.get(Calendar.DAY_OF_MONTH))
|
set(Calendar.DAY_OF_MONTH, current[Calendar.DAY_OF_MONTH])
|
||||||
}.timeInMillis
|
}.timeInMillis
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -442,9 +443,9 @@ class DateUtil @Inject constructor(private val context: Context) {
|
||||||
val selected = Calendar.getInstance().apply { timeInMillis = dateUtcMillis }
|
val selected = Calendar.getInstance().apply { timeInMillis = dateUtcMillis }
|
||||||
return Calendar.getInstance().apply {
|
return Calendar.getInstance().apply {
|
||||||
timeInMillis = timestamp
|
timeInMillis = timestamp
|
||||||
set(Calendar.YEAR, selected.get(Calendar.YEAR))
|
set(Calendar.YEAR, selected[Calendar.YEAR])
|
||||||
set(Calendar.MONTH, selected.get(Calendar.MONTH))
|
set(Calendar.MONTH, selected[Calendar.MONTH])
|
||||||
set(Calendar.DAY_OF_MONTH, selected.get(Calendar.DAY_OF_MONTH))
|
set(Calendar.DAY_OF_MONTH, selected[Calendar.DAY_OF_MONTH])
|
||||||
}.timeInMillis
|
}.timeInMillis
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -110,7 +110,7 @@ android {
|
||||||
defaultConfig {
|
defaultConfig {
|
||||||
multiDexEnabled true
|
multiDexEnabled true
|
||||||
versionCode 1500
|
versionCode 1500
|
||||||
version "3.2.0-dev-j"
|
version "3.2.0-dev-k"
|
||||||
buildConfigField "String", "VERSION", '"' + version + '"'
|
buildConfigField "String", "VERSION", '"' + version + '"'
|
||||||
buildConfigField "String", "BUILDVERSION", '"' + generateGitBuild() + '-' + generateDate() + '"'
|
buildConfigField "String", "BUILDVERSION", '"' + generateGitBuild() + '-' + generateDate() + '"'
|
||||||
buildConfigField "String", "REMOTE", '"' + generateGitRemote() + '"'
|
buildConfigField "String", "REMOTE", '"' + generateGitRemote() + '"'
|
||||||
|
@ -213,6 +213,7 @@ dependencies {
|
||||||
implementation project(':pump:danar')
|
implementation project(':pump:danar')
|
||||||
implementation project(':pump:diaconn')
|
implementation project(':pump:diaconn')
|
||||||
implementation project(':pump:eopatch')
|
implementation project(':pump:eopatch')
|
||||||
|
implementation project(':pump:medtrum')
|
||||||
implementation project(':insight')
|
implementation project(':insight')
|
||||||
implementation project(':pump:medtronic')
|
implementation project(':pump:medtronic')
|
||||||
implementation project(':pump:pump-common')
|
implementation project(':pump:pump-common')
|
||||||
|
|
|
@ -469,7 +469,7 @@ class MainActivity : DaggerAppCompatActivityWithResult() {
|
||||||
* Check for existing PasswordReset file and
|
* Check for existing PasswordReset file and
|
||||||
* reset password to SN of active pump if file exists
|
* 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")
|
val passwordReset = File(fileListProvider.ensureExtraDirExists(), "PasswordReset")
|
||||||
if (passwordReset.exists()) {
|
if (passwordReset.exists()) {
|
||||||
val sn = activePlugin.activePump.serialNumber()
|
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.combo.ComboPlugin
|
||||||
import info.nightscout.pump.combov2.ComboV2Plugin
|
import info.nightscout.pump.combov2.ComboV2Plugin
|
||||||
import info.nightscout.pump.diaconn.DiaconnG8Plugin
|
import info.nightscout.pump.diaconn.DiaconnG8Plugin
|
||||||
|
import info.nightscout.pump.medtrum.MedtrumPlugin
|
||||||
import info.nightscout.pump.virtual.VirtualPumpPlugin
|
import info.nightscout.pump.virtual.VirtualPumpPlugin
|
||||||
import info.nightscout.rx.bus.RxBus
|
import info.nightscout.rx.bus.RxBus
|
||||||
import info.nightscout.rx.events.EventPreferenceChange
|
import info.nightscout.rx.events.EventPreferenceChange
|
||||||
|
@ -122,6 +123,7 @@ class MyPreferenceFragment : PreferenceFragmentCompat(), OnSharedPreferenceChang
|
||||||
@Inject lateinit var wearPlugin: WearPlugin
|
@Inject lateinit var wearPlugin: WearPlugin
|
||||||
@Inject lateinit var maintenancePlugin: MaintenancePlugin
|
@Inject lateinit var maintenancePlugin: MaintenancePlugin
|
||||||
@Inject lateinit var eopatchPumpPlugin: EopatchPumpPlugin
|
@Inject lateinit var eopatchPumpPlugin: EopatchPumpPlugin
|
||||||
|
@Inject lateinit var medtrumPlugin: MedtrumPlugin
|
||||||
|
|
||||||
@Inject lateinit var passwordCheck: PasswordCheck
|
@Inject lateinit var passwordCheck: PasswordCheck
|
||||||
@Inject lateinit var nsSettingStatus: NSSettingsStatus
|
@Inject lateinit var nsSettingStatus: NSSettingsStatus
|
||||||
|
@ -212,6 +214,7 @@ class MyPreferenceFragment : PreferenceFragmentCompat(), OnSharedPreferenceChang
|
||||||
addPreferencesFromResourceIfEnabled(medtronicPumpPlugin, rootKey, config.PUMPDRIVERS)
|
addPreferencesFromResourceIfEnabled(medtronicPumpPlugin, rootKey, config.PUMPDRIVERS)
|
||||||
addPreferencesFromResourceIfEnabled(diaconnG8Plugin, rootKey, config.PUMPDRIVERS)
|
addPreferencesFromResourceIfEnabled(diaconnG8Plugin, rootKey, config.PUMPDRIVERS)
|
||||||
addPreferencesFromResourceIfEnabled(eopatchPumpPlugin, rootKey, config.PUMPDRIVERS)
|
addPreferencesFromResourceIfEnabled(eopatchPumpPlugin, rootKey, config.PUMPDRIVERS)
|
||||||
|
addPreferencesFromResourceIfEnabled(medtrumPlugin, rootKey, config.PUMPDRIVERS)
|
||||||
addPreferencesFromResource(R.xml.pref_pump, rootKey, config.PUMPDRIVERS)
|
addPreferencesFromResource(R.xml.pref_pump, rootKey, config.PUMPDRIVERS)
|
||||||
addPreferencesFromResourceIfEnabled(virtualPumpPlugin, rootKey)
|
addPreferencesFromResourceIfEnabled(virtualPumpPlugin, rootKey)
|
||||||
addPreferencesFromResourceIfEnabled(insulinOrefFreePeakPlugin, 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.DanaHistoryModule
|
||||||
import info.nightscout.pump.dana.di.DanaModule
|
import info.nightscout.pump.dana.di.DanaModule
|
||||||
import info.nightscout.pump.danars.di.DanaRSModule
|
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.diaconn.di.DiaconnG8Module
|
||||||
import info.nightscout.pump.virtual.di.VirtualPumpModule
|
import info.nightscout.pump.virtual.di.VirtualPumpModule
|
||||||
import info.nightscout.rx.di.RxModule
|
import info.nightscout.rx.di.RxModule
|
||||||
|
@ -87,6 +88,7 @@ import javax.inject.Singleton
|
||||||
OmnipodErosModule::class,
|
OmnipodErosModule::class,
|
||||||
PumpCommonModule::class,
|
PumpCommonModule::class,
|
||||||
RileyLinkModule::class,
|
RileyLinkModule::class,
|
||||||
|
MedtrumModule::class,
|
||||||
VirtualPumpModule::class
|
VirtualPumpModule::class
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
|
|
@ -46,6 +46,7 @@ import info.nightscout.plugins.sync.tidepool.TidepoolPlugin
|
||||||
import info.nightscout.plugins.sync.xdrip.XdripPlugin
|
import info.nightscout.plugins.sync.xdrip.XdripPlugin
|
||||||
import info.nightscout.pump.combo.ComboPlugin
|
import info.nightscout.pump.combo.ComboPlugin
|
||||||
import info.nightscout.pump.combov2.ComboV2Plugin
|
import info.nightscout.pump.combov2.ComboV2Plugin
|
||||||
|
import info.nightscout.pump.medtrum.MedtrumPlugin
|
||||||
import info.nightscout.pump.diaconn.DiaconnG8Plugin
|
import info.nightscout.pump.diaconn.DiaconnG8Plugin
|
||||||
import info.nightscout.pump.virtual.VirtualPumpPlugin
|
import info.nightscout.pump.virtual.VirtualPumpPlugin
|
||||||
import info.nightscout.sensitivity.SensitivityAAPSPlugin
|
import info.nightscout.sensitivity.SensitivityAAPSPlugin
|
||||||
|
@ -209,6 +210,12 @@ abstract class PluginsListModule {
|
||||||
@IntKey(156)
|
@IntKey(156)
|
||||||
abstract fun bindEopatchPumpPlugin(plugin: EopatchPumpPlugin): PluginBase
|
abstract fun bindEopatchPumpPlugin(plugin: EopatchPumpPlugin): PluginBase
|
||||||
|
|
||||||
|
@Binds
|
||||||
|
@PumpDriver
|
||||||
|
@IntoMap
|
||||||
|
@IntKey(160)
|
||||||
|
abstract fun bindMedtrumPlugin(plugin: MedtrumPlugin): PluginBase
|
||||||
|
|
||||||
@Binds
|
@Binds
|
||||||
@AllConfigs
|
@AllConfigs
|
||||||
@IntoMap
|
@IntoMap
|
||||||
|
|
|
@ -59,7 +59,7 @@ buildscript {
|
||||||
dependencies {
|
dependencies {
|
||||||
classpath 'com.android.tools.build:gradle:8.1.0'
|
classpath 'com.android.tools.build:gradle:8.1.0'
|
||||||
classpath 'com.google.gms:google-services:4.3.15'
|
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
|
// NOTE: Do not place your application dependencies here; they belong
|
||||||
// in the individual module build.gradle files
|
// in the individual module build.gradle files
|
||||||
|
@ -75,7 +75,7 @@ buildscript {
|
||||||
plugins {
|
plugins {
|
||||||
// Test Gradle build, keep disabled under normal circumstances
|
// Test Gradle build, keep disabled under normal circumstances
|
||||||
// id "com.osacky.doctor" version "0.8.1"
|
// 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
|
// Aggregates and/or logs Jacoco test coverage to the Gradle build log
|
||||||
id 'org.barfuin.gradle.jacocolog' version '3.1.0'
|
id 'org.barfuin.gradle.jacocolog' version '3.1.0'
|
||||||
id 'org.jetbrains.kotlin.android' version "$kotlin_version" apply false
|
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 IDENTIFICATION_NOT_SET = 77
|
||||||
const val PERMISSION_BT = 78
|
const val PERMISSION_BT = 78
|
||||||
const val EOELOW_PATCH_ALERTS = 79
|
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 COMBO_UNKNOWN_TBR = 81
|
||||||
const val BLUETOOTH_NOT_ENABLED = 82
|
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
|
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) {
|
enum class ManufacturerType(val description: String) {
|
||||||
AAPS("AAPS"),
|
AAPS("AAPS"),
|
||||||
|
Medtrum("Medtrum"),
|
||||||
Medtronic("Medtronic"),
|
Medtronic("Medtronic"),
|
||||||
Sooil("SOOIL"),
|
Sooil("SOOIL"),
|
||||||
Tandem("Tandem"),
|
Tandem("Tandem"),
|
||||||
|
|
|
@ -26,6 +26,7 @@ enum class PumpCapability {
|
||||||
YpsomedCapabilities(arrayOf(Bolus, ExtendedBolus, TempBasal, BasalProfileSet, Refill, ReplaceBattery, TDD, ManualTDDLoad)), // BasalRates (separately grouped)
|
YpsomedCapabilities(arrayOf(Bolus, ExtendedBolus, TempBasal, BasalProfileSet, Refill, ReplaceBattery, TDD, ManualTDDLoad)), // BasalRates (separately grouped)
|
||||||
DiaconnCapabilities(arrayOf(Bolus, ExtendedBolus, TempBasal, BasalProfileSet, Refill, ReplaceBattery, TDD, ManualTDDLoad)), //
|
DiaconnCapabilities(arrayOf(Bolus, ExtendedBolus, TempBasal, BasalProfileSet, Refill, ReplaceBattery, TDD, ManualTDDLoad)), //
|
||||||
EopatchCapabilities(arrayOf(Bolus, ExtendedBolus, TempBasal, BasalProfileSet, BasalRate30min)),
|
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_Duration15minAllowed,
|
||||||
BasalRate_Duration30minAllowed,
|
BasalRate_Duration30minAllowed,
|
||||||
BasalRate_Duration15and30minAllowed(arrayOf(BasalRate_Duration15minAllowed, BasalRate_Duration30minAllowed)),
|
BasalRate_Duration15and30minAllowed(arrayOf(BasalRate_Duration15minAllowed, BasalRate_Duration30minAllowed)),
|
||||||
|
|
|
@ -391,7 +391,29 @@ enum class PumpType {
|
||||||
isPatchPump = true,
|
isPatchPump = true,
|
||||||
maxReservoirReading = 50,
|
maxReservoirReading = 50,
|
||||||
source = Source.EOPatch2
|
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
|
val description: String
|
||||||
var manufacturer: ManufacturerType? = null
|
var manufacturer: ManufacturerType? = null
|
||||||
|
@ -458,6 +480,7 @@ enum class PumpType {
|
||||||
OmnipodEros,
|
OmnipodEros,
|
||||||
OmnipodDash,
|
OmnipodDash,
|
||||||
EOPatch2,
|
EOPatch2,
|
||||||
|
Medtrum,
|
||||||
MDI,
|
MDI,
|
||||||
VirtualPump,
|
VirtualPump,
|
||||||
Unknown
|
Unknown
|
||||||
|
|
|
@ -23,11 +23,14 @@ abstract class Command(
|
||||||
BASAL_PROFILE,
|
BASAL_PROFILE,
|
||||||
READSTATUS,
|
READSTATUS,
|
||||||
LOAD_HISTORY, // TDDs and so far only Dana specific
|
LOAD_HISTORY, // TDDs and so far only Dana specific
|
||||||
LOAD_EVENTS, // so far only Dana specific
|
LOAD_EVENTS,
|
||||||
LOAD_TDD,
|
LOAD_TDD,
|
||||||
SET_USER_SETTINGS, // so far only Dana specific,
|
SET_USER_SETTINGS, // so far only Dana specific,
|
||||||
START_PUMP,
|
START_PUMP,
|
||||||
STOP_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
|
INSIGHT_SET_TBR_OVER_ALARM, // insight only
|
||||||
CUSTOM_COMMAND
|
CUSTOM_COMMAND
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,6 +31,9 @@ interface CommandQueue {
|
||||||
fun setUserOptions(callback: Callback?): Boolean
|
fun setUserOptions(callback: Callback?): Boolean
|
||||||
fun loadTDDs(callback: Callback?): Boolean
|
fun loadTDDs(callback: Callback?): Boolean
|
||||||
fun loadEvents(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 customCommand(customCommand: CustomCommand, callback: Callback?): Boolean
|
||||||
fun isCustomCommandRunning(customCommandType: Class<out CustomCommand>): Boolean
|
fun isCustomCommandRunning(customCommandType: Class<out CustomCommand>): Boolean
|
||||||
fun isCustomCommandInQueue(customCommandType: Class<out CustomCommand>): Boolean
|
fun isCustomCommandInQueue(customCommandType: Class<out CustomCommand>): Boolean
|
||||||
|
|
|
@ -21,22 +21,23 @@ interface DataSyncSelector {
|
||||||
|
|
||||||
val value: Any
|
val value: Any
|
||||||
val id: Long
|
val id: Long
|
||||||
|
var confirmed: Boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
data class PairTemporaryTarget(override val value: TemporaryTarget, 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) : 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) : 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) : 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) : 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) : 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) : 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) : 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) : 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) : 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) : 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) : 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) : 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) : DataPair
|
data class PairDeviceStatus(override val value: DeviceStatus, override val id: Long, override var confirmed: Boolean = false) : DataPair
|
||||||
|
|
||||||
fun queueSize(): Long
|
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.USER -> PumpType.USER
|
||||||
InterfaceIDs.PumpType.DIACONN_G8 -> PumpType.DIACONN_G8
|
InterfaceIDs.PumpType.DIACONN_G8 -> PumpType.DIACONN_G8
|
||||||
InterfaceIDs.PumpType.EOPATCH2 -> PumpType.EOFLOW_EOPATCH2
|
InterfaceIDs.PumpType.EOPATCH2 -> PumpType.EOFLOW_EOPATCH2
|
||||||
|
InterfaceIDs.PumpType.MEDTRUM -> PumpType.MEDTRUM_NANO
|
||||||
|
InterfaceIDs.PumpType.MEDTRUM_UNTESTED -> PumpType.MEDTRUM_UNTESTED
|
||||||
InterfaceIDs.PumpType.CACHE -> PumpType.CACHE
|
InterfaceIDs.PumpType.CACHE -> PumpType.CACHE
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -117,5 +119,7 @@ fun PumpType.toDbPumpType(): InterfaceIDs.PumpType =
|
||||||
PumpType.USER -> InterfaceIDs.PumpType.USER
|
PumpType.USER -> InterfaceIDs.PumpType.USER
|
||||||
PumpType.DIACONN_G8 -> InterfaceIDs.PumpType.DIACONN_G8
|
PumpType.DIACONN_G8 -> InterfaceIDs.PumpType.DIACONN_G8
|
||||||
PumpType.EOFLOW_EOPATCH2 -> InterfaceIDs.PumpType.EOPATCH2
|
PumpType.EOFLOW_EOPATCH2 -> InterfaceIDs.PumpType.EOPATCH2
|
||||||
|
PumpType.MEDTRUM_NANO -> InterfaceIDs.PumpType.MEDTRUM
|
||||||
|
PumpType.MEDTRUM_UNTESTED -> InterfaceIDs.PumpType.MEDTRUM_UNTESTED
|
||||||
PumpType.CACHE -> InterfaceIDs.PumpType.CACHE
|
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="carbs_g">CARBS %1$d g</string>
|
||||||
<string name="extended_bolus_u_min">EXTENDED BOLUS %1$.2f U %2$d min</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="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_history">LOAD HISTORY %1$d</string>
|
||||||
<string name="load_tdds">LOAD TDDs</string>
|
<string name="load_tdds">LOAD TDDs</string>
|
||||||
<string name="set_profile">SET PROFILE</string>
|
<string name="set_profile">SET PROFILE</string>
|
||||||
|
|
|
@ -21,7 +21,7 @@ dependencies {
|
||||||
implementation project(':app-wear-shared:shared')
|
implementation project(':app-wear-shared:shared')
|
||||||
|
|
||||||
//Firebase
|
//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-analytics-ktx"
|
||||||
api "com.google.firebase:firebase-crashlytics-ktx"
|
api "com.google.firebase:firebase-crashlytics-ktx"
|
||||||
// StatsActivity not in use now
|
// StatsActivity not in use now
|
||||||
|
|
|
@ -71,6 +71,10 @@ files:
|
||||||
translation: /pump/danars/src/main/res/values-%android_code%/strings.xml
|
translation: /pump/danars/src/main/res/values-%android_code%/strings.xml
|
||||||
- source: /pump/medtronic/src/main/res/values/strings.xml
|
- source: /pump/medtronic/src/main/res/values/strings.xml
|
||||||
translation: /pump/medtronic/src/main/res/values-%android_code%/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
|
- source: /pump/omnipod-common/src/main/res/values/strings.xml
|
||||||
translation: /pump/omnipod-common/src/main/res/values-%android_code%/strings.xml
|
translation: /pump/omnipod-common/src/main/res/values-%android_code%/strings.xml
|
||||||
- source: /pump/omnipod-dash/src/main/res/values/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.Index
|
||||||
import androidx.room.PrimaryKey
|
import androidx.room.PrimaryKey
|
||||||
import info.nightscout.database.entities.embedments.InterfaceIDs
|
import info.nightscout.database.entities.embedments.InterfaceIDs
|
||||||
|
import info.nightscout.database.entities.interfaces.DBEntry
|
||||||
import info.nightscout.database.entities.interfaces.DBEntryWithTime
|
import info.nightscout.database.entities.interfaces.DBEntryWithTime
|
||||||
import java.util.TimeZone
|
import java.util.TimeZone
|
||||||
|
|
||||||
|
@ -17,7 +18,7 @@ import java.util.TimeZone
|
||||||
])
|
])
|
||||||
data class DeviceStatus(
|
data class DeviceStatus(
|
||||||
@PrimaryKey(autoGenerate = true)
|
@PrimaryKey(autoGenerate = true)
|
||||||
var id: Long = 0,
|
override var id: Long = 0,
|
||||||
@Embedded
|
@Embedded
|
||||||
var interfaceIDs_backing: InterfaceIDs? = null,
|
var interfaceIDs_backing: InterfaceIDs? = null,
|
||||||
override var timestamp: Long,
|
override var timestamp: Long,
|
||||||
|
@ -31,7 +32,7 @@ data class DeviceStatus(
|
||||||
var isCharging: Boolean?,
|
var isCharging: Boolean?,
|
||||||
var configuration: String? = null
|
var configuration: String? = null
|
||||||
|
|
||||||
) : DBEntryWithTime {
|
) : DBEntry, DBEntryWithTime {
|
||||||
|
|
||||||
var interfaceIDs: InterfaceIDs
|
var interfaceIDs: InterfaceIDs
|
||||||
get() {
|
get() {
|
||||||
|
|
|
@ -43,6 +43,8 @@ data class InterfaceIDs(
|
||||||
MDI,
|
MDI,
|
||||||
DIACONN_G8,
|
DIACONN_G8,
|
||||||
EOPATCH2,
|
EOPATCH2,
|
||||||
|
MEDTRUM,
|
||||||
|
MEDTRUM_UNTESTED,
|
||||||
USER,
|
USER,
|
||||||
CACHE;
|
CACHE;
|
||||||
|
|
||||||
|
|
|
@ -254,6 +254,7 @@ import kotlin.math.roundToInt
|
||||||
|
|
||||||
fun insert(word: UserEntry) {
|
fun insert(word: UserEntry) {
|
||||||
database.userEntryDao.insert(word)
|
database.userEntryDao.insert(word)
|
||||||
|
changeSubject.onNext(mutableListOf(word)) // Not TraceableDao
|
||||||
}
|
}
|
||||||
|
|
||||||
// PROFILE SWITCH
|
// PROFILE SWITCH
|
||||||
|
@ -712,8 +713,10 @@ import kotlin.math.roundToInt
|
||||||
database.bolusCalculatorResultDao.getLastId()
|
database.bolusCalculatorResultDao.getLastId()
|
||||||
|
|
||||||
// DEVICE STATUS
|
// DEVICE STATUS
|
||||||
fun insert(deviceStatus: DeviceStatus): Long =
|
fun insert(deviceStatus: DeviceStatus) {
|
||||||
database.deviceStatusDao.insert(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".
|
* 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)
|
database.deviceStatusDao.getNextModifiedOrNewAfter(id)
|
||||||
.subscribeOn(Schedulers.io())
|
.subscribeOn(Schedulers.io())
|
||||||
|
|
||||||
fun getModifiedDeviceStatusDataFromId(lastId: Long): Single<List<DeviceStatus>> =
|
|
||||||
database.deviceStatusDao.getModifiedFrom(lastId)
|
|
||||||
.subscribeOn(Schedulers.io())
|
|
||||||
|
|
||||||
fun getLastDeviceStatusId(): Long? =
|
fun getLastDeviceStatusId(): Long? =
|
||||||
database.deviceStatusDao.getLastId()
|
database.deviceStatusDao.getLastId()
|
||||||
|
|
||||||
|
|
|
@ -3,6 +3,7 @@ package info.nightscout.implementation.db
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import info.nightscout.database.entities.Bolus
|
import info.nightscout.database.entities.Bolus
|
||||||
import info.nightscout.database.entities.Carbs
|
import info.nightscout.database.entities.Carbs
|
||||||
|
import info.nightscout.database.entities.DeviceStatus
|
||||||
import info.nightscout.database.entities.EffectiveProfileSwitch
|
import info.nightscout.database.entities.EffectiveProfileSwitch
|
||||||
import info.nightscout.database.entities.ExtendedBolus
|
import info.nightscout.database.entities.ExtendedBolus
|
||||||
import info.nightscout.database.entities.Food
|
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.database.impl.AppRepository
|
||||||
import info.nightscout.interfaces.ui.UiInteraction
|
import info.nightscout.interfaces.ui.UiInteraction
|
||||||
import info.nightscout.rx.bus.RxBus
|
import info.nightscout.rx.bus.RxBus
|
||||||
|
import info.nightscout.rx.events.EventDeviceStatusChange
|
||||||
import info.nightscout.rx.events.EventEffectiveProfileSwitchChanged
|
import info.nightscout.rx.events.EventEffectiveProfileSwitchChanged
|
||||||
import info.nightscout.rx.events.EventExtendedBolusChange
|
import info.nightscout.rx.events.EventExtendedBolusChange
|
||||||
import info.nightscout.rx.events.EventFoodDatabaseChanged
|
import info.nightscout.rx.events.EventFoodDatabaseChanged
|
||||||
|
@ -109,5 +111,9 @@ class CompatDBHelper @Inject constructor(
|
||||||
aapsLogger.debug(LTag.DATABASE, "Firing EventOfflineChange $oe")
|
aapsLogger.debug(LTag.DATABASE, "Firing EventOfflineChange $oe")
|
||||||
rxBus.send(EventOfflineChange())
|
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.CommandBolus
|
||||||
import info.nightscout.implementation.queue.commands.CommandCancelExtendedBolus
|
import info.nightscout.implementation.queue.commands.CommandCancelExtendedBolus
|
||||||
import info.nightscout.implementation.queue.commands.CommandCancelTempBasal
|
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.CommandCustomCommand
|
||||||
|
import info.nightscout.implementation.queue.commands.CommandDeactivate
|
||||||
import info.nightscout.implementation.queue.commands.CommandExtendedBolus
|
import info.nightscout.implementation.queue.commands.CommandExtendedBolus
|
||||||
import info.nightscout.implementation.queue.commands.CommandInsightSetTBROverNotification
|
import info.nightscout.implementation.queue.commands.CommandInsightSetTBROverNotification
|
||||||
import info.nightscout.implementation.queue.commands.CommandLoadEvents
|
import info.nightscout.implementation.queue.commands.CommandLoadEvents
|
||||||
import info.nightscout.implementation.queue.commands.CommandLoadHistory
|
import info.nightscout.implementation.queue.commands.CommandLoadHistory
|
||||||
import info.nightscout.implementation.queue.commands.CommandLoadTDDs
|
import info.nightscout.implementation.queue.commands.CommandLoadTDDs
|
||||||
|
import info.nightscout.implementation.queue.commands.CommandUpdateTime
|
||||||
|
|
||||||
@Module
|
@Module
|
||||||
@Suppress("unused")
|
@Suppress("unused")
|
||||||
|
@ -32,6 +35,9 @@ abstract class CommandQueueModule {
|
||||||
@ContributesAndroidInjector abstract fun commandExtendedBolusInjector(): CommandExtendedBolus
|
@ContributesAndroidInjector abstract fun commandExtendedBolusInjector(): CommandExtendedBolus
|
||||||
@ContributesAndroidInjector abstract fun commandInsightSetTBROverNotificationInjector(): CommandInsightSetTBROverNotification
|
@ContributesAndroidInjector abstract fun commandInsightSetTBROverNotificationInjector(): CommandInsightSetTBROverNotification
|
||||||
@ContributesAndroidInjector abstract fun commandLoadEventsInjector(): CommandLoadEvents
|
@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 commandLoadHistoryInjector(): CommandLoadHistory
|
||||||
@ContributesAndroidInjector abstract fun commandLoadTDDsInjector(): CommandLoadTDDs
|
@ContributesAndroidInjector abstract fun commandLoadTDDsInjector(): CommandLoadTDDs
|
||||||
@ContributesAndroidInjector abstract fun commandReadStatusInjector(): CommandReadStatus
|
@ContributesAndroidInjector abstract fun commandReadStatusInjector(): CommandReadStatus
|
||||||
|
|
|
@ -1,11 +1,15 @@
|
||||||
package info.nightscout.implementation.pump
|
package info.nightscout.implementation.pump
|
||||||
|
|
||||||
import com.google.gson.Gson
|
import com.google.gson.Gson
|
||||||
|
import com.google.gson.reflect.TypeToken
|
||||||
import info.nightscout.androidaps.annotations.OpenForTesting
|
import info.nightscout.androidaps.annotations.OpenForTesting
|
||||||
|
import info.nightscout.implementation.R
|
||||||
import info.nightscout.interfaces.pump.DetailedBolusInfo
|
import info.nightscout.interfaces.pump.DetailedBolusInfo
|
||||||
import info.nightscout.interfaces.pump.DetailedBolusInfoStorage
|
import info.nightscout.interfaces.pump.DetailedBolusInfoStorage
|
||||||
import info.nightscout.rx.logging.AAPSLogger
|
import info.nightscout.rx.logging.AAPSLogger
|
||||||
|
import info.nightscout.shared.sharedPreferences.SP
|
||||||
import info.nightscout.rx.logging.LTag
|
import info.nightscout.rx.logging.LTag
|
||||||
|
import info.nightscout.shared.interfaces.ResourceHelper
|
||||||
import info.nightscout.shared.utils.T
|
import info.nightscout.shared.utils.T
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
import javax.inject.Singleton
|
import javax.inject.Singleton
|
||||||
|
@ -14,10 +18,12 @@ import kotlin.math.abs
|
||||||
@OpenForTesting
|
@OpenForTesting
|
||||||
@Singleton
|
@Singleton
|
||||||
class DetailedBolusInfoStorageImpl @Inject constructor(
|
class DetailedBolusInfoStorageImpl @Inject constructor(
|
||||||
val aapsLogger: AAPSLogger
|
val aapsLogger: AAPSLogger,
|
||||||
|
val sp: SP,
|
||||||
|
val rh: ResourceHelper
|
||||||
) : DetailedBolusInfoStorage {
|
) : DetailedBolusInfoStorage {
|
||||||
|
|
||||||
val store = ArrayList<DetailedBolusInfo>()
|
val store = loadStore()
|
||||||
|
|
||||||
fun DetailedBolusInfo.toJsonString(): String = Gson().toJson(this)
|
fun DetailedBolusInfo.toJsonString(): String = Gson().toJson(this)
|
||||||
|
|
||||||
|
@ -25,6 +31,7 @@ class DetailedBolusInfoStorageImpl @Inject constructor(
|
||||||
override fun add(detailedBolusInfo: DetailedBolusInfo) {
|
override fun add(detailedBolusInfo: DetailedBolusInfo) {
|
||||||
aapsLogger.debug("Stored bolus info: ${detailedBolusInfo.toJsonString()}")
|
aapsLogger.debug("Stored bolus info: ${detailedBolusInfo.toJsonString()}")
|
||||||
store.add(detailedBolusInfo)
|
store.add(detailedBolusInfo)
|
||||||
|
saveStore()
|
||||||
}
|
}
|
||||||
|
|
||||||
@Synchronized
|
@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) {
|
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]}")
|
aapsLogger.debug(LTag.PUMP, "Using & removing bolus info for time $bolusTime: ${store[i]}")
|
||||||
store.removeAt(i)
|
store.removeAt(i)
|
||||||
|
saveStore()
|
||||||
return d
|
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) {
|
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]}")
|
aapsLogger.debug(LTag.PUMP, "Using TIME-ONLY & removing bolus info for time $bolusTime: ${store[i]}")
|
||||||
store.removeAt(i)
|
store.removeAt(i)
|
||||||
|
saveStore()
|
||||||
return d
|
return d
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -61,4 +70,24 @@ class DetailedBolusInfoStorageImpl @Inject constructor(
|
||||||
aapsLogger.debug(LTag.PUMP, "Bolus info not found for time $bolusTime")
|
aapsLogger.debug(LTag.PUMP, "Bolus info not found for time $bolusTime")
|
||||||
return null
|
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.CommandBolus
|
||||||
import info.nightscout.implementation.queue.commands.CommandCancelExtendedBolus
|
import info.nightscout.implementation.queue.commands.CommandCancelExtendedBolus
|
||||||
import info.nightscout.implementation.queue.commands.CommandCancelTempBasal
|
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.CommandCustomCommand
|
||||||
|
import info.nightscout.implementation.queue.commands.CommandDeactivate
|
||||||
import info.nightscout.implementation.queue.commands.CommandExtendedBolus
|
import info.nightscout.implementation.queue.commands.CommandExtendedBolus
|
||||||
import info.nightscout.implementation.queue.commands.CommandInsightSetTBROverNotification
|
import info.nightscout.implementation.queue.commands.CommandInsightSetTBROverNotification
|
||||||
import info.nightscout.implementation.queue.commands.CommandLoadEvents
|
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.CommandStopPump
|
||||||
import info.nightscout.implementation.queue.commands.CommandTempBasalAbsolute
|
import info.nightscout.implementation.queue.commands.CommandTempBasalAbsolute
|
||||||
import info.nightscout.implementation.queue.commands.CommandTempBasalPercent
|
import info.nightscout.implementation.queue.commands.CommandTempBasalPercent
|
||||||
|
import info.nightscout.implementation.queue.commands.CommandUpdateTime
|
||||||
import info.nightscout.interfaces.AndroidPermission
|
import info.nightscout.interfaces.AndroidPermission
|
||||||
import info.nightscout.interfaces.Config
|
import info.nightscout.interfaces.Config
|
||||||
import info.nightscout.interfaces.constraints.Constraint
|
import info.nightscout.interfaces.constraints.Constraint
|
||||||
|
@ -535,6 +538,46 @@ class CommandQueueImplementation @Inject constructor(
|
||||||
return true
|
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 {
|
override fun customCommand(customCommand: CustomCommand, callback: Callback?): Boolean {
|
||||||
if (isCustomCommandInQueue(customCommand.javaClass)) {
|
if (isCustomCommandInQueue(customCommand.javaClass)) {
|
||||||
callback?.result(executingNowError())?.run()
|
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.plugin.ActivePlugin
|
||||||
import info.nightscout.interfaces.pump.Dana
|
import info.nightscout.interfaces.pump.Dana
|
||||||
import info.nightscout.interfaces.pump.Diaconn
|
import info.nightscout.interfaces.pump.Diaconn
|
||||||
|
import info.nightscout.interfaces.pump.Medtrum
|
||||||
import info.nightscout.interfaces.pump.PumpEnactResult
|
import info.nightscout.interfaces.pump.PumpEnactResult
|
||||||
import info.nightscout.interfaces.queue.Callback
|
import info.nightscout.interfaces.queue.Callback
|
||||||
import info.nightscout.interfaces.queue.Command
|
import info.nightscout.interfaces.queue.Command
|
||||||
|
@ -32,6 +33,13 @@ class CommandLoadEvents(
|
||||||
aapsLogger.debug(LTag.PUMPQUEUE, "Result success: ${r.success} enacted: ${r.enacted}")
|
aapsLogger.debug(LTag.PUMPQUEUE, "Result success: ${r.success} enacted: ${r.enacted}")
|
||||||
callback?.result(r)?.run()
|
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)
|
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.plugin.ActivePlugin
|
||||||
import info.nightscout.interfaces.pump.Dana
|
import info.nightscout.interfaces.pump.Dana
|
||||||
import info.nightscout.interfaces.pump.Diaconn
|
import info.nightscout.interfaces.pump.Diaconn
|
||||||
|
import info.nightscout.interfaces.pump.Medtrum
|
||||||
import info.nightscout.interfaces.pump.PumpEnactResult
|
import info.nightscout.interfaces.pump.PumpEnactResult
|
||||||
import info.nightscout.interfaces.queue.Callback
|
import info.nightscout.interfaces.queue.Callback
|
||||||
import info.nightscout.interfaces.queue.Command
|
import info.nightscout.interfaces.queue.Command
|
||||||
|
@ -30,6 +31,12 @@ class CommandSetUserSettings(
|
||||||
aapsLogger.debug(LTag.PUMPQUEUE, "Result success: ${r.success} enacted: ${r.enacted}")
|
aapsLogger.debug(LTag.PUMPQUEUE, "Result success: ${r.success} enacted: ${r.enacted}")
|
||||||
callback?.result(r)?.run()
|
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)
|
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"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<resources>
|
<resources>
|
||||||
|
<string name="key_bolus_storage" translatable="false">key_bolus_storage</string>
|
||||||
<string name="bg_label">BG</string>
|
<string name="bg_label">BG</string>
|
||||||
|
|
||||||
<string name="executing_right_now">Command is executed right now</string>
|
<string name="executing_right_now">Command is executed right now</string>
|
||||||
|
|
|
@ -1,14 +1,22 @@
|
||||||
package info.nightscout.implementation.pump
|
package info.nightscout.implementation.pump
|
||||||
|
|
||||||
import info.nightscout.androidaps.TestBase
|
import info.nightscout.androidaps.TestBase
|
||||||
|
import info.nightscout.implementation.R
|
||||||
import info.nightscout.interfaces.pump.DetailedBolusInfo
|
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.assertEquals
|
||||||
import org.junit.Assert.assertNull
|
import org.junit.Assert.assertNull
|
||||||
import org.junit.jupiter.api.BeforeEach
|
import org.junit.jupiter.api.BeforeEach
|
||||||
import org.junit.jupiter.api.Test
|
import org.junit.jupiter.api.Test
|
||||||
|
import org.mockito.Mock
|
||||||
|
import org.mockito.Mockito
|
||||||
|
|
||||||
class DetailedBolusInfoStorageTest : TestBase() {
|
class DetailedBolusInfoStorageTest : TestBase() {
|
||||||
|
|
||||||
|
@Mock lateinit var sp: SP
|
||||||
|
@Mock lateinit var rh: ResourceHelper
|
||||||
|
|
||||||
private val info1 = DetailedBolusInfo()
|
private val info1 = DetailedBolusInfo()
|
||||||
private val info2 = DetailedBolusInfo()
|
private val info2 = DetailedBolusInfo()
|
||||||
private val info3 = DetailedBolusInfo()
|
private val info3 = DetailedBolusInfo()
|
||||||
|
@ -26,7 +34,8 @@ class DetailedBolusInfoStorageTest : TestBase() {
|
||||||
|
|
||||||
@BeforeEach
|
@BeforeEach
|
||||||
fun prepare() {
|
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() {
|
private fun setUp() {
|
||||||
|
|
|
@ -238,6 +238,19 @@ class CommandQueueImplementationTest : TestBaseWithProfile() {
|
||||||
// add loadEvents
|
// add loadEvents
|
||||||
commandQueue.loadEvents(null)
|
commandQueue.loadEvents(null)
|
||||||
Assertions.assertEquals(4, commandQueue.size())
|
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.clear()
|
||||||
commandQueue.tempBasalAbsolute(0.0, 30, true, validProfile, PumpSync.TemporaryBasalType.NORMAL, null)
|
commandQueue.tempBasalAbsolute(0.0, 30, true, validProfile, PumpSync.TemporaryBasalType.NORMAL, null)
|
||||||
commandQueue.pickup()
|
commandQueue.pickup()
|
||||||
|
@ -354,6 +367,54 @@ class CommandQueueImplementationTest : TestBaseWithProfile() {
|
||||||
Assertions.assertEquals(1, commandQueue.size())
|
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
|
@Test
|
||||||
fun isLoadTDDsCommandInQueue() {
|
fun isLoadTDDsCommandInQueue() {
|
||||||
// given
|
// given
|
||||||
|
|
|
@ -35,6 +35,7 @@ import info.nightscout.interfaces.plugin.ActivePlugin
|
||||||
import info.nightscout.interfaces.plugin.PluginBase
|
import info.nightscout.interfaces.plugin.PluginBase
|
||||||
import info.nightscout.interfaces.plugin.PluginType
|
import info.nightscout.interfaces.plugin.PluginType
|
||||||
import info.nightscout.interfaces.profile.ProfileFunction
|
import info.nightscout.interfaces.profile.ProfileFunction
|
||||||
|
import info.nightscout.interfaces.pump.Medtrum
|
||||||
import info.nightscout.interfaces.pump.OmnipodDash
|
import info.nightscout.interfaces.pump.OmnipodDash
|
||||||
import info.nightscout.interfaces.pump.OmnipodEros
|
import info.nightscout.interfaces.pump.OmnipodEros
|
||||||
import info.nightscout.interfaces.queue.CommandQueue
|
import info.nightscout.interfaces.queue.CommandQueue
|
||||||
|
@ -319,23 +320,24 @@ class SWDefinition @Inject constructor(
|
||||||
.text(R.string.readstatus)
|
.text(R.string.readstatus)
|
||||||
.action { commandQueue.readStatus(rh.gs(info.nightscout.core.ui.R.string.clicked_connect_to_pump), null) }
|
.action { commandQueue.readStatus(rh.gs(info.nightscout.core.ui.R.string.clicked_connect_to_pump), null) }
|
||||||
.visibility {
|
.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
|
// 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)
|
.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() }
|
.validator { isPumpInitialized() }
|
||||||
|
|
||||||
private fun isPumpInitialized(): Boolean {
|
private fun isPumpInitialized(): Boolean {
|
||||||
val activePump = activePlugin.activePump
|
val activePump = activePlugin.activePump
|
||||||
|
|
||||||
// For Omnipod, activating a Pod can be done after setup through the Omnipod fragment
|
// For Omnipod and Medtrum, activating a Pod/Patch can be done after setup through the pump fragment
|
||||||
// For the Eros model, consider the pump initialized when a RL has been configured successfully
|
// For the Eros, consider the pump initialized when a RL has been configured successfully
|
||||||
// For Dash model, consider the pump setup without any extra conditions
|
// For all others, consider the pump setup without any extra conditions
|
||||||
return activePump.isInitialized()
|
return activePump.isInitialized()
|
||||||
|| (activePump is OmnipodEros && activePump.isRileyLinkReady())
|
|| (activePump is OmnipodEros && activePump.isRileyLinkReady())
|
||||||
|| activePump is OmnipodDash
|
|| activePump is OmnipodDash
|
||||||
|
|| activePump is Medtrum
|
||||||
}
|
}
|
||||||
|
|
||||||
private val screenAps
|
private val screenAps
|
||||||
|
|
|
@ -6,6 +6,7 @@ import info.nightscout.shared.utils.DateUtil
|
||||||
import java.net.DatagramPacket
|
import java.net.DatagramPacket
|
||||||
import java.net.DatagramSocket
|
import java.net.DatagramSocket
|
||||||
import java.net.InetAddress
|
import java.net.InetAddress
|
||||||
|
import java.security.SecureRandom
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
import javax.inject.Singleton
|
import javax.inject.Singleton
|
||||||
|
|
||||||
|
@ -195,6 +196,6 @@ class SntpClient @Inject constructor(
|
||||||
buffer[offset++] = (fraction shr 16).toByte()
|
buffer[offset++] = (fraction shr 16).toByte()
|
||||||
buffer[offset++] = (fraction shr 8).toByte()
|
buffer[offset++] = (fraction shr 8).toByte()
|
||||||
// low order bits should be random data
|
// 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() {
|
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_dark_theme, "dark") -> MODE_NIGHT_YES
|
||||||
sp.getString(R.string.value_light_theme, "light") -> MODE_NIGHT_NO
|
sp.getString(R.string.value_light_theme, "light") -> MODE_NIGHT_NO
|
||||||
else -> MODE_NIGHT_FOLLOW_SYSTEM
|
else -> MODE_NIGHT_FOLLOW_SYSTEM
|
||||||
}
|
}
|
||||||
|
} catch (ignored: Exception) {
|
||||||
|
MODE_NIGHT_FOLLOW_SYSTEM
|
||||||
|
}
|
||||||
AppCompatDelegate.setDefaultNightMode(mode)
|
AppCompatDelegate.setDefaultNightMode(mode)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -22,7 +22,7 @@ import info.nightscout.shared.sharedPreferences.SP
|
||||||
import info.nightscout.shared.utils.T
|
import info.nightscout.shared.utils.T
|
||||||
import io.reactivex.rxjava3.disposables.CompositeDisposable
|
import io.reactivex.rxjava3.disposables.CompositeDisposable
|
||||||
import io.reactivex.rxjava3.kotlin.plusAssign
|
import io.reactivex.rxjava3.kotlin.plusAssign
|
||||||
import java.lang.Math.random
|
import java.security.SecureRandom
|
||||||
import java.util.Calendar
|
import java.util.Calendar
|
||||||
import java.util.GregorianCalendar
|
import java.util.GregorianCalendar
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
@ -100,7 +100,7 @@ class RandomBgPlugin @Inject constructor(
|
||||||
|
|
||||||
val cal = GregorianCalendar()
|
val cal = GregorianCalendar()
|
||||||
val currentMinute = cal[Calendar.MINUTE] + (cal[Calendar.HOUR_OF_DAY] % 2) * 60
|
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.MILLISECOND] = 0
|
||||||
cal[Calendar.SECOND] = 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.NSSettingsStatus
|
||||||
import info.nightscout.interfaces.nsclient.ProcessedDeviceStatusData
|
import info.nightscout.interfaces.nsclient.ProcessedDeviceStatusData
|
||||||
import info.nightscout.interfaces.nsclient.StoreDataForDb
|
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.interfaces.sync.DataSyncSelectorXdrip
|
||||||
import info.nightscout.plugins.sync.nsShared.NSClientFragment
|
import info.nightscout.plugins.sync.nsShared.NSClientFragment
|
||||||
import info.nightscout.plugins.sync.nsShared.StoreDataForDbImpl
|
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.NSSettingsStatusImpl
|
||||||
import info.nightscout.plugins.sync.nsclient.data.ProcessedDeviceStatusDataImpl
|
import info.nightscout.plugins.sync.nsclient.data.ProcessedDeviceStatusDataImpl
|
||||||
import info.nightscout.plugins.sync.nsclient.services.NSClientService
|
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.NSClientAddUpdateWorker
|
||||||
import info.nightscout.plugins.sync.nsclient.workers.NSClientMbgWorker
|
import info.nightscout.plugins.sync.nsclient.workers.NSClientMbgWorker
|
||||||
import info.nightscout.plugins.sync.nsclient.workers.NSClientUpdateRemoveAckWorker
|
import info.nightscout.plugins.sync.nsclient.workers.NSClientUpdateRemoveAckWorker
|
||||||
import info.nightscout.plugins.sync.nsclientV3.DataSyncSelectorV3Impl
|
import info.nightscout.plugins.sync.nsclientV3.workers.DataSyncWorker
|
||||||
import info.nightscout.plugins.sync.nsclientV3.workers.*
|
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.tidepool.TidepoolFragment
|
||||||
import info.nightscout.plugins.sync.xdrip.DataSyncSelectorXdripImpl
|
import info.nightscout.plugins.sync.xdrip.DataSyncSelectorXdripImpl
|
||||||
import info.nightscout.plugins.sync.xdrip.XdripFragment
|
import info.nightscout.plugins.sync.xdrip.XdripFragment
|
||||||
|
@ -75,8 +78,6 @@ abstract class SyncModule {
|
||||||
|
|
||||||
@Binds fun bindProcessedDeviceStatusData(processedDeviceStatusDataImpl: ProcessedDeviceStatusDataImpl): ProcessedDeviceStatusData
|
@Binds fun bindProcessedDeviceStatusData(processedDeviceStatusDataImpl: ProcessedDeviceStatusDataImpl): ProcessedDeviceStatusData
|
||||||
@Binds fun bindNSSettingsStatus(nsSettingsStatusImpl: NSSettingsStatusImpl): NSSettingsStatus
|
@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 bindDataSyncSelectorXdripInterface(dataSyncSelectorXdripImpl: DataSyncSelectorXdripImpl): DataSyncSelectorXdrip
|
||||||
@Binds fun bindStoreDataForDb(storeDataForDbImpl: StoreDataForDbImpl): StoreDataForDb
|
@Binds fun bindStoreDataForDb(storeDataForDbImpl: StoreDataForDbImpl): StoreDataForDb
|
||||||
@Binds fun bindXDripBroadcastInterface(xDripBroadcastImpl: XdripPlugin): XDripBroadcast
|
@Binds fun bindXDripBroadcastInterface(xDripBroadcastImpl: XdripPlugin): XDripBroadcast
|
||||||
|
|
|
@ -123,7 +123,7 @@ class NSClientFragment : DaggerFragment(), MenuProvider, PluginFragment {
|
||||||
nsClientPlugin?.listLog?.let {
|
nsClientPlugin?.listLog?.let {
|
||||||
synchronized(it) {
|
synchronized(it) {
|
||||||
it.clear()
|
it.clear()
|
||||||
_binding?.recyclerview?.swapAdapter(RecyclerViewAdapter(it), true)
|
updateLog()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
true
|
true
|
||||||
|
@ -211,6 +211,7 @@ class NSClientFragment : DaggerFragment(), MenuProvider, PluginFragment {
|
||||||
.subscribe({ updateStatus() }, fabricPrivacy::logException)
|
.subscribe({ updateStatus() }, fabricPrivacy::logException)
|
||||||
updateStatus()
|
updateStatus()
|
||||||
updateQueue()
|
updateQueue()
|
||||||
|
updateLog()
|
||||||
}
|
}
|
||||||
|
|
||||||
@Synchronized
|
@Synchronized
|
||||||
|
@ -231,6 +232,9 @@ class NSClientFragment : DaggerFragment(), MenuProvider, PluginFragment {
|
||||||
binding.status.text = nsClientPlugin?.status
|
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>() {
|
private inner class RecyclerViewAdapter(private var logList: List<EventNSClientNewLog>) : RecyclerView.Adapter<RecyclerViewAdapter.NsClientLogViewHolder>() {
|
||||||
|
|
||||||
override fun onCreateViewHolder(viewGroup: ViewGroup, viewType: Int): 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.Intent
|
||||||
import android.content.ServiceConnection
|
import android.content.ServiceConnection
|
||||||
import android.os.IBinder
|
import android.os.IBinder
|
||||||
import android.provider.ContactsContract
|
|
||||||
import androidx.preference.PreferenceFragmentCompat
|
import androidx.preference.PreferenceFragmentCompat
|
||||||
import androidx.preference.PreferenceScreen
|
import androidx.preference.PreferenceScreen
|
||||||
import androidx.preference.SwitchPreference
|
import androidx.preference.SwitchPreference
|
||||||
|
@ -24,7 +23,6 @@ import info.nightscout.interfaces.profile.Profile
|
||||||
import info.nightscout.interfaces.profile.ProfileFunction
|
import info.nightscout.interfaces.profile.ProfileFunction
|
||||||
import info.nightscout.interfaces.source.DoingOwnUploadSource
|
import info.nightscout.interfaces.source.DoingOwnUploadSource
|
||||||
import info.nightscout.interfaces.sync.DataSyncSelector
|
import info.nightscout.interfaces.sync.DataSyncSelector
|
||||||
import info.nightscout.interfaces.sync.DataSyncSelectorV1
|
|
||||||
import info.nightscout.interfaces.sync.NsClient
|
import info.nightscout.interfaces.sync.NsClient
|
||||||
import info.nightscout.interfaces.sync.Sync
|
import info.nightscout.interfaces.sync.Sync
|
||||||
import info.nightscout.plugins.sync.R
|
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.NSAlarm
|
||||||
import info.nightscout.interfaces.nsclient.NSSettingsStatus
|
import info.nightscout.interfaces.nsclient.NSSettingsStatus
|
||||||
import info.nightscout.interfaces.nsclient.StoreDataForDb
|
import info.nightscout.interfaces.nsclient.StoreDataForDb
|
||||||
import info.nightscout.interfaces.sync.DataSyncSelectorV1
|
|
||||||
import info.nightscout.interfaces.ui.UiInteraction
|
import info.nightscout.interfaces.ui.UiInteraction
|
||||||
import info.nightscout.interfaces.utils.JsonHelper.safeGetString
|
import info.nightscout.interfaces.utils.JsonHelper.safeGetString
|
||||||
import info.nightscout.interfaces.utils.JsonHelper.safeGetStringAllowNull
|
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.EventConnectivityOptionChanged
|
||||||
import info.nightscout.plugins.sync.nsShared.events.EventNSClientStatus
|
import info.nightscout.plugins.sync.nsShared.events.EventNSClientStatus
|
||||||
import info.nightscout.plugins.sync.nsShared.events.EventNSClientUpdateGuiStatus
|
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.NSClientPlugin
|
||||||
import info.nightscout.plugins.sync.nsclient.acks.NSAddAck
|
import info.nightscout.plugins.sync.nsclient.acks.NSAddAck
|
||||||
import info.nightscout.plugins.sync.nsclient.acks.NSAuthAck
|
import info.nightscout.plugins.sync.nsclient.acks.NSAuthAck
|
||||||
|
@ -179,6 +179,18 @@ import javax.inject.Inject
|
||||||
.toObservable(EventNewHistoryData::class.java)
|
.toObservable(EventNewHistoryData::class.java)
|
||||||
.observeOn(aapsSchedulers.io)
|
.observeOn(aapsSchedulers.io)
|
||||||
.subscribe({ resend("NEW_DATA") }, fabricPrivacy::logException)
|
.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() {
|
override fun onDestroy() {
|
||||||
|
@ -541,6 +553,7 @@ import javax.inject.Inject
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
rxBus.send(EventNSClientNewLog("◄ LAST", dateUtil.dateAndTimeString(latestDateInReceivedData)))
|
rxBus.send(EventNSClientNewLog("◄ LAST", dateUtil.dateAndTimeString(latestDateInReceivedData)))
|
||||||
|
resend("LAST")
|
||||||
} catch (e: JSONException) {
|
} catch (e: JSONException) {
|
||||||
aapsLogger.error("Unhandled exception", e)
|
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 {
|
try {
|
||||||
if (_id == null) return
|
if (_id == null) return
|
||||||
if (!isConnected || !hasWriteAuth) return
|
if (!isConnected || !hasWriteAuth) return
|
||||||
|
@ -595,10 +608,10 @@ import javax.inject.Inject
|
||||||
if (!isConnected || !hasWriteAuth) return@runBlocking
|
if (!isConnected || !hasWriteAuth) return@runBlocking
|
||||||
scope.async {
|
scope.async {
|
||||||
if (socket?.connected() != true) return@async
|
if (socket?.connected() != true) return@async
|
||||||
if (lastAckTime > System.currentTimeMillis() - 10 * 1000L) {
|
// if (lastAckTime > System.currentTimeMillis() - 10 * 1000L) {
|
||||||
aapsLogger.debug(LTag.NSCLIENT, "Skipping resend by lastAckTime: " + (System.currentTimeMillis() - lastAckTime) / 1000L + " sec")
|
// aapsLogger.debug(LTag.NSCLIENT, "Skipping resend by lastAckTime: " + (System.currentTimeMillis() - lastAckTime) / 1000L + " sec")
|
||||||
return@async
|
// return@async
|
||||||
}
|
// }
|
||||||
rxBus.send(EventNSClientNewLog("● QUEUE", "Resend started: $reason"))
|
rxBus.send(EventNSClientNewLog("● QUEUE", "Resend started: $reason"))
|
||||||
dataSyncSelectorV1.doUpload()
|
dataSyncSelectorV1.doUpload()
|
||||||
rxBus.send(EventNSClientNewLog("● QUEUE", "Resend ended: $reason"))
|
rxBus.send(EventNSClientNewLog("● QUEUE", "Resend ended: $reason"))
|
||||||
|
|
|
@ -4,6 +4,7 @@ import android.content.Context
|
||||||
import android.os.SystemClock
|
import android.os.SystemClock
|
||||||
import androidx.work.WorkerParameters
|
import androidx.work.WorkerParameters
|
||||||
import androidx.work.workDataOf
|
import androidx.work.workDataOf
|
||||||
|
import info.nightscout.core.utils.notify
|
||||||
import info.nightscout.core.utils.receivers.DataWorkerStorage
|
import info.nightscout.core.utils.receivers.DataWorkerStorage
|
||||||
import info.nightscout.core.utils.worker.LoggingWorker
|
import info.nightscout.core.utils.worker.LoggingWorker
|
||||||
import info.nightscout.database.impl.AppRepository
|
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.PairTemporaryBasal
|
||||||
import info.nightscout.interfaces.sync.DataSyncSelector.PairTemporaryTarget
|
import info.nightscout.interfaces.sync.DataSyncSelector.PairTemporaryTarget
|
||||||
import info.nightscout.interfaces.sync.DataSyncSelector.PairTherapyEvent
|
import info.nightscout.interfaces.sync.DataSyncSelector.PairTherapyEvent
|
||||||
import info.nightscout.interfaces.sync.DataSyncSelectorV1
|
|
||||||
import info.nightscout.plugins.sync.R
|
import info.nightscout.plugins.sync.R
|
||||||
import info.nightscout.plugins.sync.nsclient.acks.NSAddAck
|
import info.nightscout.plugins.sync.nsclient.acks.NSAddAck
|
||||||
import info.nightscout.rx.AapsSchedulers
|
import info.nightscout.rx.AapsSchedulers
|
||||||
|
@ -40,7 +40,6 @@ class NSClientAddAckWorker(
|
||||||
@Inject lateinit var dataWorkerStorage: DataWorkerStorage
|
@Inject lateinit var dataWorkerStorage: DataWorkerStorage
|
||||||
@Inject lateinit var repository: AppRepository
|
@Inject lateinit var repository: AppRepository
|
||||||
@Inject lateinit var rxBus: RxBus
|
@Inject lateinit var rxBus: RxBus
|
||||||
@Inject lateinit var dataSyncSelectorV1: DataSyncSelectorV1
|
|
||||||
@Inject lateinit var aapsSchedulers: AapsSchedulers
|
@Inject lateinit var aapsSchedulers: AapsSchedulers
|
||||||
@Inject lateinit var sp: SP
|
@Inject lateinit var sp: SP
|
||||||
@Inject lateinit var storeDataForDb: StoreDataForDb
|
@Inject lateinit var storeDataForDb: StoreDataForDb
|
||||||
|
@ -60,152 +59,128 @@ class NSClientAddAckWorker(
|
||||||
is PairTemporaryTarget -> {
|
is PairTemporaryTarget -> {
|
||||||
val pair = ack.originalObject
|
val pair = ack.originalObject
|
||||||
pair.value.interfaceIDs.nightscoutId = ack.id
|
pair.value.interfaceIDs.nightscoutId = ack.id
|
||||||
|
pair.confirmed = true
|
||||||
storeDataForDb.nsIdTemporaryTargets.add(pair.value)
|
storeDataForDb.nsIdTemporaryTargets.add(pair.value)
|
||||||
dataSyncSelectorV1.confirmLastTempTargetsIdIfGreater(pair.id)
|
|
||||||
storeDataForDb.scheduleNsIdUpdate()
|
storeDataForDb.scheduleNsIdUpdate()
|
||||||
rxBus.send(EventNSClientNewLog("◄ DBADD", "Acked TemporaryTarget " + pair.value.interfaceIDs.nightscoutId))
|
rxBus.send(EventNSClientNewLog("◄ DBADD", "Acked TemporaryTarget " + pair.value.interfaceIDs.nightscoutId))
|
||||||
// Send new if waiting
|
|
||||||
dataSyncSelectorV1.processChangedTempTargets()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
is PairGlucoseValue -> {
|
is PairGlucoseValue -> {
|
||||||
val pair = ack.originalObject
|
val pair = ack.originalObject
|
||||||
pair.value.interfaceIDs.nightscoutId = ack.id
|
pair.value.interfaceIDs.nightscoutId = ack.id
|
||||||
|
pair.confirmed = true
|
||||||
storeDataForDb.nsIdGlucoseValues.add(pair.value)
|
storeDataForDb.nsIdGlucoseValues.add(pair.value)
|
||||||
dataSyncSelectorV1.confirmLastGlucoseValueIdIfGreater(pair.id)
|
|
||||||
storeDataForDb.scheduleNsIdUpdate()
|
storeDataForDb.scheduleNsIdUpdate()
|
||||||
rxBus.send(EventNSClientNewLog("◄ DBADD", "Acked GlucoseValue " + pair.value.interfaceIDs.nightscoutId))
|
rxBus.send(EventNSClientNewLog("◄ DBADD", "Acked GlucoseValue " + pair.value.interfaceIDs.nightscoutId))
|
||||||
// Send new if waiting
|
|
||||||
dataSyncSelectorV1.processChangedGlucoseValues()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
is PairFood -> {
|
is PairFood -> {
|
||||||
val pair = ack.originalObject
|
val pair = ack.originalObject
|
||||||
pair.value.interfaceIDs.nightscoutId = ack.id
|
pair.value.interfaceIDs.nightscoutId = ack.id
|
||||||
|
pair.confirmed = true
|
||||||
storeDataForDb.nsIdFoods.add(pair.value)
|
storeDataForDb.nsIdFoods.add(pair.value)
|
||||||
dataSyncSelectorV1.confirmLastFoodIdIfGreater(pair.id)
|
|
||||||
storeDataForDb.scheduleNsIdUpdate()
|
storeDataForDb.scheduleNsIdUpdate()
|
||||||
rxBus.send(EventNSClientNewLog("◄ DBADD", "Acked Food " + pair.value.interfaceIDs.nightscoutId))
|
rxBus.send(EventNSClientNewLog("◄ DBADD", "Acked Food " + pair.value.interfaceIDs.nightscoutId))
|
||||||
// Send new if waiting
|
// Send new if waiting
|
||||||
dataSyncSelectorV1.processChangedFoods()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
is PairTherapyEvent -> {
|
is PairTherapyEvent -> {
|
||||||
val pair = ack.originalObject
|
val pair = ack.originalObject
|
||||||
pair.value.interfaceIDs.nightscoutId = ack.id
|
pair.value.interfaceIDs.nightscoutId = ack.id
|
||||||
|
pair.confirmed = true
|
||||||
storeDataForDb.nsIdTherapyEvents.add(pair.value)
|
storeDataForDb.nsIdTherapyEvents.add(pair.value)
|
||||||
dataSyncSelectorV1.confirmLastTherapyEventIdIfGreater(pair.id)
|
|
||||||
storeDataForDb.scheduleNsIdUpdate()
|
storeDataForDb.scheduleNsIdUpdate()
|
||||||
rxBus.send(EventNSClientNewLog("◄ DBADD", "Acked TherapyEvent " + pair.value.interfaceIDs.nightscoutId))
|
rxBus.send(EventNSClientNewLog("◄ DBADD", "Acked TherapyEvent " + pair.value.interfaceIDs.nightscoutId))
|
||||||
// Send new if waiting
|
|
||||||
dataSyncSelectorV1.processChangedTherapyEvents()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
is PairBolus -> {
|
is PairBolus -> {
|
||||||
val pair = ack.originalObject
|
val pair = ack.originalObject
|
||||||
pair.value.interfaceIDs.nightscoutId = ack.id
|
pair.value.interfaceIDs.nightscoutId = ack.id
|
||||||
|
pair.confirmed = true
|
||||||
storeDataForDb.nsIdBoluses.add(pair.value)
|
storeDataForDb.nsIdBoluses.add(pair.value)
|
||||||
dataSyncSelectorV1.confirmLastBolusIdIfGreater(pair.id)
|
|
||||||
storeDataForDb.scheduleNsIdUpdate()
|
storeDataForDb.scheduleNsIdUpdate()
|
||||||
rxBus.send(EventNSClientNewLog("◄ DBADD", "Acked Bolus " + pair.value.interfaceIDs.nightscoutId))
|
rxBus.send(EventNSClientNewLog("◄ DBADD", "Acked Bolus " + pair.value.interfaceIDs.nightscoutId))
|
||||||
// Send new if waiting
|
|
||||||
dataSyncSelectorV1.processChangedBoluses()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
is PairCarbs -> {
|
is PairCarbs -> {
|
||||||
val pair = ack.originalObject
|
val pair = ack.originalObject
|
||||||
pair.value.interfaceIDs.nightscoutId = ack.id
|
pair.value.interfaceIDs.nightscoutId = ack.id
|
||||||
|
pair.confirmed = true
|
||||||
storeDataForDb.nsIdCarbs.add(pair.value)
|
storeDataForDb.nsIdCarbs.add(pair.value)
|
||||||
dataSyncSelectorV1.confirmLastCarbsIdIfGreater(pair.id)
|
|
||||||
storeDataForDb.scheduleNsIdUpdate()
|
storeDataForDb.scheduleNsIdUpdate()
|
||||||
rxBus.send(EventNSClientNewLog("◄ DBADD", "Acked Carbs " + pair.value.interfaceIDs.nightscoutId))
|
rxBus.send(EventNSClientNewLog("◄ DBADD", "Acked Carbs " + pair.value.interfaceIDs.nightscoutId))
|
||||||
// Send new if waiting
|
|
||||||
dataSyncSelectorV1.processChangedCarbs()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
is PairBolusCalculatorResult -> {
|
is PairBolusCalculatorResult -> {
|
||||||
val pair = ack.originalObject
|
val pair = ack.originalObject
|
||||||
pair.value.interfaceIDs.nightscoutId = ack.id
|
pair.value.interfaceIDs.nightscoutId = ack.id
|
||||||
storeDataForDb.nsIdBolusCalculatorResults.add(pair.value)
|
storeDataForDb.nsIdBolusCalculatorResults.add(pair.value)
|
||||||
dataSyncSelectorV1.confirmLastBolusCalculatorResultsIdIfGreater(pair.id)
|
|
||||||
storeDataForDb.scheduleNsIdUpdate()
|
storeDataForDb.scheduleNsIdUpdate()
|
||||||
rxBus.send(EventNSClientNewLog("◄ DBADD", "Acked BolusCalculatorResult " + pair.value.interfaceIDs.nightscoutId))
|
rxBus.send(EventNSClientNewLog("◄ DBADD", "Acked BolusCalculatorResult " + pair.value.interfaceIDs.nightscoutId))
|
||||||
// Send new if waiting
|
|
||||||
dataSyncSelectorV1.processChangedBolusCalculatorResults()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
is PairTemporaryBasal -> {
|
is PairTemporaryBasal -> {
|
||||||
val pair = ack.originalObject
|
val pair = ack.originalObject
|
||||||
pair.value.interfaceIDs.nightscoutId = ack.id
|
pair.value.interfaceIDs.nightscoutId = ack.id
|
||||||
|
pair.confirmed = true
|
||||||
storeDataForDb.nsIdTemporaryBasals.add(pair.value)
|
storeDataForDb.nsIdTemporaryBasals.add(pair.value)
|
||||||
dataSyncSelectorV1.confirmLastTemporaryBasalIdIfGreater(pair.id)
|
|
||||||
storeDataForDb.scheduleNsIdUpdate()
|
storeDataForDb.scheduleNsIdUpdate()
|
||||||
rxBus.send(EventNSClientNewLog("◄ DBADD", "Acked TemporaryBasal " + pair.value.interfaceIDs.nightscoutId))
|
rxBus.send(EventNSClientNewLog("◄ DBADD", "Acked TemporaryBasal " + pair.value.interfaceIDs.nightscoutId))
|
||||||
// Send new if waiting
|
|
||||||
dataSyncSelectorV1.processChangedTemporaryBasals()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
is PairExtendedBolus -> {
|
is PairExtendedBolus -> {
|
||||||
val pair = ack.originalObject
|
val pair = ack.originalObject
|
||||||
pair.value.interfaceIDs.nightscoutId = ack.id
|
pair.value.interfaceIDs.nightscoutId = ack.id
|
||||||
|
pair.confirmed = true
|
||||||
storeDataForDb.nsIdExtendedBoluses.add(pair.value)
|
storeDataForDb.nsIdExtendedBoluses.add(pair.value)
|
||||||
dataSyncSelectorV1.confirmLastExtendedBolusIdIfGreater(pair.id)
|
|
||||||
storeDataForDb.scheduleNsIdUpdate()
|
storeDataForDb.scheduleNsIdUpdate()
|
||||||
rxBus.send(EventNSClientNewLog("◄ DBADD", "Acked ExtendedBolus " + pair.value.interfaceIDs.nightscoutId))
|
rxBus.send(EventNSClientNewLog("◄ DBADD", "Acked ExtendedBolus " + pair.value.interfaceIDs.nightscoutId))
|
||||||
// Send new if waiting
|
|
||||||
dataSyncSelectorV1.processChangedExtendedBoluses()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
is PairProfileSwitch -> {
|
is PairProfileSwitch -> {
|
||||||
val pair = ack.originalObject
|
val pair = ack.originalObject
|
||||||
pair.value.interfaceIDs.nightscoutId = ack.id
|
pair.value.interfaceIDs.nightscoutId = ack.id
|
||||||
|
pair.confirmed = true
|
||||||
storeDataForDb.nsIdProfileSwitches.add(pair.value)
|
storeDataForDb.nsIdProfileSwitches.add(pair.value)
|
||||||
dataSyncSelectorV1.confirmLastProfileSwitchIdIfGreater(pair.id)
|
|
||||||
storeDataForDb.scheduleNsIdUpdate()
|
storeDataForDb.scheduleNsIdUpdate()
|
||||||
rxBus.send(EventNSClientNewLog("◄ DBADD", "Acked ProfileSwitch " + pair.value.interfaceIDs.nightscoutId))
|
rxBus.send(EventNSClientNewLog("◄ DBADD", "Acked ProfileSwitch " + pair.value.interfaceIDs.nightscoutId))
|
||||||
// Send new if waiting
|
|
||||||
dataSyncSelectorV1.processChangedProfileSwitches()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
is PairEffectiveProfileSwitch -> {
|
is PairEffectiveProfileSwitch -> {
|
||||||
val pair = ack.originalObject
|
val pair = ack.originalObject
|
||||||
pair.value.interfaceIDs.nightscoutId = ack.id
|
pair.value.interfaceIDs.nightscoutId = ack.id
|
||||||
|
pair.confirmed = true
|
||||||
storeDataForDb.nsIdEffectiveProfileSwitches.add(pair.value)
|
storeDataForDb.nsIdEffectiveProfileSwitches.add(pair.value)
|
||||||
dataSyncSelectorV1.confirmLastEffectiveProfileSwitchIdIfGreater(pair.id)
|
|
||||||
storeDataForDb.scheduleNsIdUpdate()
|
storeDataForDb.scheduleNsIdUpdate()
|
||||||
rxBus.send(EventNSClientNewLog("◄ DBADD", "Acked EffectiveProfileSwitch " + pair.value.interfaceIDs.nightscoutId))
|
rxBus.send(EventNSClientNewLog("◄ DBADD", "Acked EffectiveProfileSwitch " + pair.value.interfaceIDs.nightscoutId))
|
||||||
// Send new if waiting
|
|
||||||
dataSyncSelectorV1.processChangedEffectiveProfileSwitches()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
is DataSyncSelector.PairDeviceStatus -> {
|
is DataSyncSelector.PairDeviceStatus -> {
|
||||||
val pair = ack.originalObject
|
val pair = ack.originalObject
|
||||||
pair.value.interfaceIDs.nightscoutId = ack.id
|
pair.value.interfaceIDs.nightscoutId = ack.id
|
||||||
|
pair.confirmed = true
|
||||||
storeDataForDb.nsIdDeviceStatuses.add(pair.value)
|
storeDataForDb.nsIdDeviceStatuses.add(pair.value)
|
||||||
dataSyncSelectorV1.confirmLastDeviceStatusIdIfGreater(pair.value.id)
|
|
||||||
storeDataForDb.scheduleNsIdUpdate()
|
storeDataForDb.scheduleNsIdUpdate()
|
||||||
rxBus.send(EventNSClientNewLog("◄ DBADD", "Acked DeviceStatus " + pair.value.interfaceIDs.nightscoutId))
|
rxBus.send(EventNSClientNewLog("◄ DBADD", "Acked DeviceStatus " + pair.value.interfaceIDs.nightscoutId))
|
||||||
// Send new if waiting
|
|
||||||
dataSyncSelectorV1.processChangedDeviceStatuses()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
is PairProfileStore -> {
|
is PairProfileStore -> {
|
||||||
dataSyncSelectorV1.confirmLastProfileStore(ack.originalObject.id)
|
val pair = ack.originalObject
|
||||||
|
pair.confirmed = true
|
||||||
rxBus.send(EventNSClientNewLog("◄ DBADD", "Acked ProfileStore " + ack.id))
|
rxBus.send(EventNSClientNewLog("◄ DBADD", "Acked ProfileStore " + ack.id))
|
||||||
}
|
}
|
||||||
|
|
||||||
is PairOfflineEvent -> {
|
is PairOfflineEvent -> {
|
||||||
val pair = ack.originalObject
|
val pair = ack.originalObject
|
||||||
pair.value.interfaceIDs.nightscoutId = ack.id
|
pair.value.interfaceIDs.nightscoutId = ack.id
|
||||||
|
pair.confirmed = true
|
||||||
storeDataForDb.nsIdOfflineEvents.add(pair.value)
|
storeDataForDb.nsIdOfflineEvents.add(pair.value)
|
||||||
dataSyncSelectorV1.confirmLastOfflineEventIdIfGreater(pair.id)
|
|
||||||
storeDataForDb.scheduleNsIdUpdate()
|
storeDataForDb.scheduleNsIdUpdate()
|
||||||
rxBus.send(EventNSClientNewLog("◄ DBADD", "Acked OfflineEvent " + pair.value.interfaceIDs.nightscoutId))
|
rxBus.send(EventNSClientNewLog("◄ DBADD", "Acked OfflineEvent " + pair.value.interfaceIDs.nightscoutId))
|
||||||
// Send new if waiting
|
|
||||||
dataSyncSelectorV1.processChangedOfflineEvents()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
ack.originalObject?.let { synchronized(it) { it.notify() } }
|
||||||
return ret
|
return ret
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -3,6 +3,7 @@ package info.nightscout.plugins.sync.nsclient.workers
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import androidx.work.WorkerParameters
|
import androidx.work.WorkerParameters
|
||||||
import androidx.work.workDataOf
|
import androidx.work.workDataOf
|
||||||
|
import info.nightscout.core.utils.notify
|
||||||
import info.nightscout.core.utils.receivers.DataWorkerStorage
|
import info.nightscout.core.utils.receivers.DataWorkerStorage
|
||||||
import info.nightscout.core.utils.worker.LoggingWorker
|
import info.nightscout.core.utils.worker.LoggingWorker
|
||||||
import info.nightscout.database.impl.AppRepository
|
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.PairTemporaryBasal
|
||||||
import info.nightscout.interfaces.sync.DataSyncSelector.PairTemporaryTarget
|
import info.nightscout.interfaces.sync.DataSyncSelector.PairTemporaryTarget
|
||||||
import info.nightscout.interfaces.sync.DataSyncSelector.PairTherapyEvent
|
import info.nightscout.interfaces.sync.DataSyncSelector.PairTherapyEvent
|
||||||
import info.nightscout.interfaces.sync.DataSyncSelectorV1
|
|
||||||
import info.nightscout.plugins.sync.nsclient.acks.NSUpdateAck
|
import info.nightscout.plugins.sync.nsclient.acks.NSUpdateAck
|
||||||
import info.nightscout.rx.AapsSchedulers
|
import info.nightscout.rx.AapsSchedulers
|
||||||
import info.nightscout.rx.bus.RxBus
|
import info.nightscout.rx.bus.RxBus
|
||||||
|
@ -34,7 +34,6 @@ class NSClientUpdateRemoveAckWorker(
|
||||||
@Inject lateinit var dataWorkerStorage: DataWorkerStorage
|
@Inject lateinit var dataWorkerStorage: DataWorkerStorage
|
||||||
@Inject lateinit var repository: AppRepository
|
@Inject lateinit var repository: AppRepository
|
||||||
@Inject lateinit var rxBus: RxBus
|
@Inject lateinit var rxBus: RxBus
|
||||||
@Inject lateinit var dataSyncSelectorV1: DataSyncSelectorV1
|
|
||||||
@Inject lateinit var aapsSchedulers: AapsSchedulers
|
@Inject lateinit var aapsSchedulers: AapsSchedulers
|
||||||
|
|
||||||
override suspend fun doWorkAndLog(): Result {
|
override suspend fun doWorkAndLog(): Result {
|
||||||
|
@ -47,112 +46,89 @@ class NSClientUpdateRemoveAckWorker(
|
||||||
when (ack.originalObject) {
|
when (ack.originalObject) {
|
||||||
is PairTemporaryTarget -> {
|
is PairTemporaryTarget -> {
|
||||||
val pair = ack.originalObject
|
val pair = ack.originalObject
|
||||||
dataSyncSelectorV1.confirmLastTempTargetsIdIfGreater(pair.id)
|
pair.confirmed = true
|
||||||
rxBus.send(EventNSClientNewLog("◄ DBUPDATE", "Acked TemporaryTarget" + ack._id))
|
rxBus.send(EventNSClientNewLog("◄ DBUPDATE", "Acked TemporaryTarget" + ack._id))
|
||||||
// Send new if waiting
|
|
||||||
dataSyncSelectorV1.processChangedTempTargets()
|
|
||||||
ret = Result.success(workDataOf("ProcessedData" to pair.toString()))
|
ret = Result.success(workDataOf("ProcessedData" to pair.toString()))
|
||||||
}
|
}
|
||||||
|
|
||||||
is PairGlucoseValue -> {
|
is PairGlucoseValue -> {
|
||||||
val pair = ack.originalObject
|
val pair = ack.originalObject
|
||||||
dataSyncSelectorV1.confirmLastGlucoseValueIdIfGreater(pair.id)
|
pair.confirmed = true
|
||||||
rxBus.send(EventNSClientNewLog("◄ DBUPDATE", "Acked GlucoseValue " + ack._id))
|
rxBus.send(EventNSClientNewLog("◄ DBUPDATE", "Acked GlucoseValue " + ack._id))
|
||||||
// Send new if waiting
|
|
||||||
dataSyncSelectorV1.processChangedGlucoseValues()
|
|
||||||
ret = Result.success(workDataOf("ProcessedData" to pair.toString()))
|
ret = Result.success(workDataOf("ProcessedData" to pair.toString()))
|
||||||
}
|
}
|
||||||
|
|
||||||
is PairFood -> {
|
is PairFood -> {
|
||||||
val pair = ack.originalObject
|
val pair = ack.originalObject
|
||||||
dataSyncSelectorV1.confirmLastFoodIdIfGreater(pair.id)
|
pair.confirmed = true
|
||||||
rxBus.send(EventNSClientNewLog("◄ DBUPDATE", "Acked Food " + ack._id))
|
rxBus.send(EventNSClientNewLog("◄ DBUPDATE", "Acked Food " + ack._id))
|
||||||
// Send new if waiting
|
|
||||||
dataSyncSelectorV1.processChangedFoods()
|
|
||||||
ret = Result.success(workDataOf("ProcessedData" to pair.toString()))
|
ret = Result.success(workDataOf("ProcessedData" to pair.toString()))
|
||||||
}
|
}
|
||||||
|
|
||||||
is PairTherapyEvent -> {
|
is PairTherapyEvent -> {
|
||||||
val pair = ack.originalObject
|
val pair = ack.originalObject
|
||||||
dataSyncSelectorV1.confirmLastTherapyEventIdIfGreater(pair.id)
|
pair.confirmed = true
|
||||||
rxBus.send(EventNSClientNewLog("◄ DBUPDATE", "Acked TherapyEvent " + ack._id))
|
rxBus.send(EventNSClientNewLog("◄ DBUPDATE", "Acked TherapyEvent " + ack._id))
|
||||||
// Send new if waiting
|
|
||||||
dataSyncSelectorV1.processChangedTherapyEvents()
|
|
||||||
ret = Result.success(workDataOf("ProcessedData" to pair.toString()))
|
ret = Result.success(workDataOf("ProcessedData" to pair.toString()))
|
||||||
}
|
}
|
||||||
|
|
||||||
is PairBolus -> {
|
is PairBolus -> {
|
||||||
val pair = ack.originalObject
|
val pair = ack.originalObject
|
||||||
dataSyncSelectorV1.confirmLastBolusIdIfGreater(pair.id)
|
pair.confirmed = true
|
||||||
rxBus.send(EventNSClientNewLog("◄ DBUPDATE", "Acked Bolus " + ack._id))
|
rxBus.send(EventNSClientNewLog("◄ DBUPDATE", "Acked Bolus " + ack._id))
|
||||||
// Send new if waiting
|
|
||||||
dataSyncSelectorV1.processChangedBoluses()
|
|
||||||
ret = Result.success(workDataOf("ProcessedData" to pair.toString()))
|
ret = Result.success(workDataOf("ProcessedData" to pair.toString()))
|
||||||
}
|
}
|
||||||
|
|
||||||
is PairCarbs -> {
|
is PairCarbs -> {
|
||||||
val pair = ack.originalObject
|
val pair = ack.originalObject
|
||||||
dataSyncSelectorV1.confirmLastCarbsIdIfGreater(pair.id)
|
pair.confirmed = true
|
||||||
rxBus.send(EventNSClientNewLog("◄ DBUPDATE", "Acked Carbs " + ack._id))
|
rxBus.send(EventNSClientNewLog("◄ DBUPDATE", "Acked Carbs " + ack._id))
|
||||||
// Send new if waiting
|
|
||||||
dataSyncSelectorV1.processChangedCarbs()
|
|
||||||
ret = Result.success(workDataOf("ProcessedData" to pair.toString()))
|
ret = Result.success(workDataOf("ProcessedData" to pair.toString()))
|
||||||
}
|
}
|
||||||
|
|
||||||
is PairBolusCalculatorResult -> {
|
is PairBolusCalculatorResult -> {
|
||||||
val pair = ack.originalObject
|
val pair = ack.originalObject
|
||||||
dataSyncSelectorV1.confirmLastBolusCalculatorResultsIdIfGreater(pair.id)
|
pair.confirmed = true
|
||||||
rxBus.send(EventNSClientNewLog("◄ DBUPDATE", "Acked BolusCalculatorResult " + ack._id))
|
rxBus.send(EventNSClientNewLog("◄ DBUPDATE", "Acked BolusCalculatorResult " + ack._id))
|
||||||
// Send new if waiting
|
|
||||||
dataSyncSelectorV1.processChangedBolusCalculatorResults()
|
|
||||||
ret = Result.success(workDataOf("ProcessedData" to pair.toString()))
|
ret = Result.success(workDataOf("ProcessedData" to pair.toString()))
|
||||||
}
|
}
|
||||||
|
|
||||||
is PairTemporaryBasal -> {
|
is PairTemporaryBasal -> {
|
||||||
val pair = ack.originalObject
|
val pair = ack.originalObject
|
||||||
dataSyncSelectorV1.confirmLastTemporaryBasalIdIfGreater(pair.id)
|
pair.confirmed = true
|
||||||
rxBus.send(EventNSClientNewLog("◄ DBUPDATE", "Acked TemporaryBasal " + ack._id))
|
rxBus.send(EventNSClientNewLog("◄ DBUPDATE", "Acked TemporaryBasal " + ack._id))
|
||||||
// Send new if waiting
|
|
||||||
dataSyncSelectorV1.processChangedTemporaryBasals()
|
|
||||||
ret = Result.success(workDataOf("ProcessedData" to pair.toString()))
|
ret = Result.success(workDataOf("ProcessedData" to pair.toString()))
|
||||||
}
|
}
|
||||||
|
|
||||||
is PairExtendedBolus -> {
|
is PairExtendedBolus -> {
|
||||||
val pair = ack.originalObject
|
val pair = ack.originalObject
|
||||||
dataSyncSelectorV1.confirmLastExtendedBolusIdIfGreater(pair.id)
|
pair.confirmed = true
|
||||||
rxBus.send(EventNSClientNewLog("◄ DBUPDATE", "Acked ExtendedBolus " + ack._id))
|
rxBus.send(EventNSClientNewLog("◄ DBUPDATE", "Acked ExtendedBolus " + ack._id))
|
||||||
// Send new if waiting
|
|
||||||
dataSyncSelectorV1.processChangedExtendedBoluses()
|
|
||||||
ret = Result.success(workDataOf("ProcessedData" to pair.toString()))
|
ret = Result.success(workDataOf("ProcessedData" to pair.toString()))
|
||||||
}
|
}
|
||||||
|
|
||||||
is PairProfileSwitch -> {
|
is PairProfileSwitch -> {
|
||||||
val pair = ack.originalObject
|
val pair = ack.originalObject
|
||||||
dataSyncSelectorV1.confirmLastProfileSwitchIdIfGreater(pair.id)
|
pair.confirmed = true
|
||||||
rxBus.send(EventNSClientNewLog("◄ DBUPDATE", "Acked ProfileSwitch " + ack._id))
|
rxBus.send(EventNSClientNewLog("◄ DBUPDATE", "Acked ProfileSwitch " + ack._id))
|
||||||
// Send new if waiting
|
|
||||||
dataSyncSelectorV1.processChangedProfileSwitches()
|
|
||||||
ret = Result.success(workDataOf("ProcessedData" to pair.toString()))
|
ret = Result.success(workDataOf("ProcessedData" to pair.toString()))
|
||||||
}
|
}
|
||||||
|
|
||||||
is PairEffectiveProfileSwitch -> {
|
is PairEffectiveProfileSwitch -> {
|
||||||
val pair = ack.originalObject
|
val pair = ack.originalObject
|
||||||
dataSyncSelectorV1.confirmLastEffectiveProfileSwitchIdIfGreater(pair.id)
|
pair.confirmed = true
|
||||||
rxBus.send(EventNSClientNewLog("◄ DBUPDATE", "Acked EffectiveProfileSwitch " + ack._id))
|
rxBus.send(EventNSClientNewLog("◄ DBUPDATE", "Acked EffectiveProfileSwitch " + ack._id))
|
||||||
// Send new if waiting
|
|
||||||
dataSyncSelectorV1.processChangedEffectiveProfileSwitches()
|
|
||||||
ret = Result.success(workDataOf("ProcessedData" to pair.toString()))
|
ret = Result.success(workDataOf("ProcessedData" to pair.toString()))
|
||||||
}
|
}
|
||||||
|
|
||||||
is PairOfflineEvent -> {
|
is PairOfflineEvent -> {
|
||||||
val pair = ack.originalObject
|
val pair = ack.originalObject
|
||||||
dataSyncSelectorV1.confirmLastOfflineEventIdIfGreater(pair.id)
|
pair.confirmed = true
|
||||||
rxBus.send(EventNSClientNewLog("◄ DBUPDATE", "Acked OfflineEvent" + ack._id))
|
rxBus.send(EventNSClientNewLog("◄ DBUPDATE", "Acked OfflineEvent" + ack._id))
|
||||||
// Send new if waiting
|
|
||||||
dataSyncSelectorV1.processChangedOfflineEvents()
|
|
||||||
ret = Result.success(workDataOf("ProcessedData" to pair.toString()))
|
ret = Result.success(workDataOf("ProcessedData" to pair.toString()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
ack.originalObject?.let { synchronized(it) { it.notify() } }
|
||||||
return ret
|
return ret
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -7,7 +7,6 @@ import info.nightscout.interfaces.nsclient.StoreDataForDb
|
||||||
import info.nightscout.interfaces.plugin.ActivePlugin
|
import info.nightscout.interfaces.plugin.ActivePlugin
|
||||||
import info.nightscout.interfaces.profile.ProfileFunction
|
import info.nightscout.interfaces.profile.ProfileFunction
|
||||||
import info.nightscout.interfaces.sync.DataSyncSelector
|
import info.nightscout.interfaces.sync.DataSyncSelector
|
||||||
import info.nightscout.interfaces.sync.DataSyncSelectorV3
|
|
||||||
import info.nightscout.interfaces.utils.JsonHelper
|
import info.nightscout.interfaces.utils.JsonHelper
|
||||||
import info.nightscout.plugins.sync.R
|
import info.nightscout.plugins.sync.R
|
||||||
import info.nightscout.plugins.sync.nsShared.events.EventNSClientUpdateGuiQueue
|
import info.nightscout.plugins.sync.nsShared.events.EventNSClientUpdateGuiQueue
|
||||||
|
@ -22,7 +21,7 @@ import javax.inject.Singleton
|
||||||
|
|
||||||
@OpenForTesting
|
@OpenForTesting
|
||||||
@Singleton
|
@Singleton
|
||||||
class DataSyncSelectorV3Impl @Inject constructor(
|
class DataSyncSelectorV3 @Inject constructor(
|
||||||
private val sp: SP,
|
private val sp: SP,
|
||||||
private val aapsLogger: AAPSLogger,
|
private val aapsLogger: AAPSLogger,
|
||||||
private val dateUtil: DateUtil,
|
private val dateUtil: DateUtil,
|
||||||
|
@ -32,7 +31,7 @@ class DataSyncSelectorV3Impl @Inject constructor(
|
||||||
private val rxBus: RxBus,
|
private val rxBus: RxBus,
|
||||||
private val storeDataForDb: StoreDataForDb,
|
private val storeDataForDb: StoreDataForDb,
|
||||||
private val config: Config
|
private val config: Config
|
||||||
) : DataSyncSelectorV3 {
|
) : DataSyncSelector {
|
||||||
|
|
||||||
class QueueCounter(
|
class QueueCounter(
|
||||||
var bolusesRemaining: Long = -1L,
|
var bolusesRemaining: Long = -1L,
|
||||||
|
@ -127,14 +126,14 @@ class DataSyncSelectorV3Impl @Inject constructor(
|
||||||
else sp.remove(R.string.key_ns_device_status_last_synced_id)
|
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)) {
|
if (lastSynced > sp.getLong(R.string.key_ns_bolus_last_synced_id, 0)) {
|
||||||
//aapsLogger.debug(LTag.NSCLIENT, "Setting Bolus data sync from $lastSynced")
|
//aapsLogger.debug(LTag.NSCLIENT, "Setting Bolus data sync from $lastSynced")
|
||||||
sp.putLong(R.string.key_ns_bolus_last_synced_id, lastSynced)
|
sp.putLong(R.string.key_ns_bolus_last_synced_id, lastSynced)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun processChangedBoluses() {
|
private suspend fun processChangedBoluses() {
|
||||||
var cont = true
|
var cont = true
|
||||||
while (cont) {
|
while (cont) {
|
||||||
if (isPaused) return
|
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)) {
|
if (lastSynced > sp.getLong(R.string.key_ns_carbs_last_synced_id, 0)) {
|
||||||
//aapsLogger.debug(LTag.NSCLIENT, "Setting Carbs data sync from $lastSynced")
|
//aapsLogger.debug(LTag.NSCLIENT, "Setting Carbs data sync from $lastSynced")
|
||||||
sp.putLong(R.string.key_ns_carbs_last_synced_id, lastSynced)
|
sp.putLong(R.string.key_ns_carbs_last_synced_id, lastSynced)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun processChangedCarbs() {
|
private suspend fun processChangedCarbs() {
|
||||||
var cont = true
|
var cont = true
|
||||||
while (cont) {
|
while (cont) {
|
||||||
if (isPaused) return
|
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)) {
|
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")
|
//aapsLogger.debug(LTag.NSCLIENT, "Setting BolusCalculatorResult data sync from $lastSynced")
|
||||||
sp.putLong(R.string.key_ns_bolus_calculator_result_last_synced_id, lastSynced)
|
sp.putLong(R.string.key_ns_bolus_calculator_result_last_synced_id, lastSynced)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun processChangedBolusCalculatorResults() {
|
private suspend fun processChangedBolusCalculatorResults() {
|
||||||
var cont = true
|
var cont = true
|
||||||
while (cont) {
|
while (cont) {
|
||||||
if (isPaused) return
|
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)) {
|
if (lastSynced > sp.getLong(R.string.key_ns_temporary_target_last_synced_id, 0)) {
|
||||||
//aapsLogger.debug(LTag.NSCLIENT, "Setting TemporaryTarget data sync from $lastSynced")
|
//aapsLogger.debug(LTag.NSCLIENT, "Setting TemporaryTarget data sync from $lastSynced")
|
||||||
sp.putLong(R.string.key_ns_temporary_target_last_synced_id, lastSynced)
|
sp.putLong(R.string.key_ns_temporary_target_last_synced_id, lastSynced)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun processChangedTempTargets() {
|
private suspend fun processChangedTempTargets() {
|
||||||
var cont = true
|
var cont = true
|
||||||
while (cont) {
|
while (cont) {
|
||||||
if (isPaused) return
|
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)) {
|
if (lastSynced > sp.getLong(R.string.key_ns_food_last_synced_id, 0)) {
|
||||||
//aapsLogger.debug(LTag.NSCLIENT, "Setting Food data sync from $lastSynced")
|
//aapsLogger.debug(LTag.NSCLIENT, "Setting Food data sync from $lastSynced")
|
||||||
sp.putLong(R.string.key_ns_food_last_synced_id, lastSynced)
|
sp.putLong(R.string.key_ns_food_last_synced_id, lastSynced)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun processChangedFoods() {
|
private suspend fun processChangedFoods() {
|
||||||
var cont = true
|
var cont = true
|
||||||
while (cont) {
|
while (cont) {
|
||||||
if (isPaused) return
|
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)) {
|
if (lastSynced > sp.getLong(R.string.key_ns_glucose_value_last_synced_id, 0)) {
|
||||||
//aapsLogger.debug(LTag.NSCLIENT, "Setting GlucoseValue data sync from $lastSynced")
|
//aapsLogger.debug(LTag.NSCLIENT, "Setting GlucoseValue data sync from $lastSynced")
|
||||||
sp.putLong(R.string.key_ns_glucose_value_last_synced_id, lastSynced)
|
sp.putLong(R.string.key_ns_glucose_value_last_synced_id, lastSynced)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun processChangedGlucoseValues() {
|
private suspend fun processChangedGlucoseValues() {
|
||||||
var cont = true
|
var cont = true
|
||||||
while (cont) {
|
while (cont) {
|
||||||
if (isPaused) return
|
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)) {
|
if (lastSynced > sp.getLong(R.string.key_ns_therapy_event_last_synced_id, 0)) {
|
||||||
//aapsLogger.debug(LTag.NSCLIENT, "Setting TherapyEvents data sync from $lastSynced")
|
//aapsLogger.debug(LTag.NSCLIENT, "Setting TherapyEvents data sync from $lastSynced")
|
||||||
sp.putLong(R.string.key_ns_therapy_event_last_synced_id, lastSynced)
|
sp.putLong(R.string.key_ns_therapy_event_last_synced_id, lastSynced)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun processChangedTherapyEvents() {
|
private suspend fun processChangedTherapyEvents() {
|
||||||
var cont = true
|
var cont = true
|
||||||
while (cont) {
|
while (cont) {
|
||||||
if (isPaused) return
|
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)) {
|
if (lastSynced > sp.getLong(R.string.key_ns_device_status_last_synced_id, 0)) {
|
||||||
//aapsLogger.debug(LTag.NSCLIENT, "Setting DeviceStatus data sync from $lastSynced")
|
//aapsLogger.debug(LTag.NSCLIENT, "Setting DeviceStatus data sync from $lastSynced")
|
||||||
sp.putLong(R.string.key_ns_device_status_last_synced_id, 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
|
if (isPaused) return
|
||||||
val lastDbId = appRepository.getLastDeviceStatusId() ?: 0L
|
val lastDbId = appRepository.getLastDeviceStatusId() ?: 0L
|
||||||
var startId = sp.getLong(R.string.key_ns_device_status_last_synced_id, 0)
|
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())
|
rxBus.send(EventNSClientUpdateGuiQueue())
|
||||||
appRepository.getNextSyncElementDeviceStatus(startId).blockingGet()?.let { deviceStatus ->
|
appRepository.getNextSyncElementDeviceStatus(startId).blockingGet()?.let { deviceStatus ->
|
||||||
//aapsLogger.info(LTag.NSCLIENT, "Loading DeviceStatus data Start: $startId $deviceStatus")
|
//aapsLogger.info(LTag.NSCLIENT, "Loading DeviceStatus data Start: $startId $deviceStatus")
|
||||||
// without nsId = create new
|
cont = activePlugin.activeNsClient?.nsAdd("devicestatus", DataSyncSelector.PairDeviceStatus(deviceStatus, lastDbId), "$startId/$lastDbId") ?: false
|
||||||
if (deviceStatus.interfaceIDs.nightscoutId == null) {
|
if (cont) confirmLastDeviceStatusIdIfGreater(deviceStatus.id)
|
||||||
if (activePlugin.activeNsClient?.nsAdd("devicestatus", DataSyncSelector.PairDeviceStatus(deviceStatus, lastDbId), "$startId/$lastDbId") == true)
|
|
||||||
confirmLastDeviceStatusIdIfGreater(lastDbId)
|
|
||||||
}
|
|
||||||
// with nsId = ignore
|
// 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)) {
|
if (lastSynced > sp.getLong(R.string.key_ns_temporary_basal_last_synced_id, 0)) {
|
||||||
//aapsLogger.debug(LTag.NSCLIENT, "Setting TemporaryBasal data sync from $lastSynced")
|
//aapsLogger.debug(LTag.NSCLIENT, "Setting TemporaryBasal data sync from $lastSynced")
|
||||||
sp.putLong(R.string.key_ns_temporary_basal_last_synced_id, lastSynced)
|
sp.putLong(R.string.key_ns_temporary_basal_last_synced_id, lastSynced)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun processChangedTemporaryBasals() {
|
private suspend fun processChangedTemporaryBasals() {
|
||||||
var cont = true
|
var cont = true
|
||||||
while (cont) {
|
while (cont) {
|
||||||
if (isPaused) return
|
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)) {
|
if (lastSynced > sp.getLong(R.string.key_ns_extended_bolus_last_synced_id, 0)) {
|
||||||
//aapsLogger.debug(LTag.NSCLIENT, "Setting ExtendedBolus data sync from $lastSynced")
|
//aapsLogger.debug(LTag.NSCLIENT, "Setting ExtendedBolus data sync from $lastSynced")
|
||||||
sp.putLong(R.string.key_ns_extended_bolus_last_synced_id, lastSynced)
|
sp.putLong(R.string.key_ns_extended_bolus_last_synced_id, lastSynced)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun processChangedExtendedBoluses() {
|
private suspend fun processChangedExtendedBoluses() {
|
||||||
var cont = true
|
var cont = true
|
||||||
while (cont) {
|
while (cont) {
|
||||||
if (isPaused) return
|
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)) {
|
if (lastSynced > sp.getLong(R.string.key_ns_profile_switch_last_synced_id, 0)) {
|
||||||
//aapsLogger.debug(LTag.NSCLIENT, "Setting ProfileSwitch data sync from $lastSynced")
|
//aapsLogger.debug(LTag.NSCLIENT, "Setting ProfileSwitch data sync from $lastSynced")
|
||||||
sp.putLong(R.string.key_ns_profile_switch_last_synced_id, lastSynced)
|
sp.putLong(R.string.key_ns_profile_switch_last_synced_id, lastSynced)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun processChangedProfileSwitches() {
|
private suspend fun processChangedProfileSwitches() {
|
||||||
var cont = true
|
var cont = true
|
||||||
while (cont) {
|
while (cont) {
|
||||||
if (isPaused) return
|
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)) {
|
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")
|
//aapsLogger.debug(LTag.NSCLIENT, "Setting EffectiveProfileSwitch data sync from $lastSynced")
|
||||||
sp.putLong(R.string.key_ns_effective_profile_switch_last_synced_id, lastSynced)
|
sp.putLong(R.string.key_ns_effective_profile_switch_last_synced_id, lastSynced)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun processChangedEffectiveProfileSwitches() {
|
private suspend fun processChangedEffectiveProfileSwitches() {
|
||||||
var cont = true
|
var cont = true
|
||||||
while (cont) {
|
while (cont) {
|
||||||
if (isPaused) return
|
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)) {
|
if (lastSynced > sp.getLong(R.string.key_ns_offline_event_last_synced_id, 0)) {
|
||||||
//aapsLogger.debug(LTag.NSCLIENT, "Setting OfflineEvent data sync from $lastSynced")
|
//aapsLogger.debug(LTag.NSCLIENT, "Setting OfflineEvent data sync from $lastSynced")
|
||||||
sp.putLong(R.string.key_ns_offline_event_last_synced_id, lastSynced)
|
sp.putLong(R.string.key_ns_offline_event_last_synced_id, lastSynced)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun processChangedOfflineEvents() {
|
private suspend fun processChangedOfflineEvents() {
|
||||||
var cont = true
|
var cont = true
|
||||||
while (cont) {
|
while (cont) {
|
||||||
if (isPaused) return
|
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)
|
sp.putLong(R.string.key_ns_profile_store_last_synced_timestamp, lastSynced)
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun processChangedProfileStore() {
|
private suspend fun processChangedProfileStore() {
|
||||||
if (isPaused) return
|
if (isPaused) return
|
||||||
val lastSync = sp.getLong(R.string.key_ns_profile_store_last_synced_timestamp, 0)
|
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)
|
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.profile.Profile
|
||||||
import info.nightscout.interfaces.source.NSClientSource
|
import info.nightscout.interfaces.source.NSClientSource
|
||||||
import info.nightscout.interfaces.sync.DataSyncSelector
|
import info.nightscout.interfaces.sync.DataSyncSelector
|
||||||
import info.nightscout.interfaces.sync.DataSyncSelectorV3
|
|
||||||
import info.nightscout.interfaces.sync.NsClient
|
import info.nightscout.interfaces.sync.NsClient
|
||||||
import info.nightscout.interfaces.sync.Sync
|
import info.nightscout.interfaces.sync.Sync
|
||||||
import info.nightscout.interfaces.ui.UiInteraction
|
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.AapsSchedulers
|
||||||
import info.nightscout.rx.bus.RxBus
|
import info.nightscout.rx.bus.RxBus
|
||||||
import info.nightscout.rx.events.EventAppExit
|
import info.nightscout.rx.events.EventAppExit
|
||||||
|
import info.nightscout.rx.events.EventDeviceStatusChange
|
||||||
import info.nightscout.rx.events.EventDismissNotification
|
import info.nightscout.rx.events.EventDismissNotification
|
||||||
import info.nightscout.rx.events.EventNSClientNewLog
|
import info.nightscout.rx.events.EventNSClientNewLog
|
||||||
import info.nightscout.rx.events.EventNewHistoryData
|
import info.nightscout.rx.events.EventNewHistoryData
|
||||||
|
import info.nightscout.rx.events.EventOfflineChange
|
||||||
import info.nightscout.rx.events.EventPreferenceChange
|
import info.nightscout.rx.events.EventPreferenceChange
|
||||||
import info.nightscout.rx.events.EventSWSyncStatus
|
import info.nightscout.rx.events.EventSWSyncStatus
|
||||||
|
import info.nightscout.rx.events.EventTherapyEventChange
|
||||||
import info.nightscout.rx.logging.AAPSLogger
|
import info.nightscout.rx.logging.AAPSLogger
|
||||||
import info.nightscout.rx.logging.LTag
|
import info.nightscout.rx.logging.LTag
|
||||||
import info.nightscout.sdk.NSAndroidClientImpl
|
import info.nightscout.sdk.NSAndroidClientImpl
|
||||||
|
@ -224,6 +226,18 @@ class NSClientV3Plugin @Inject constructor(
|
||||||
.toObservable(EventNewHistoryData::class.java)
|
.toObservable(EventNewHistoryData::class.java)
|
||||||
.observeOn(aapsSchedulers.io)
|
.observeOn(aapsSchedulers.io)
|
||||||
.subscribe({ executeUpload("NEW_DATA", forceNew = false) }, fabricPrivacy::logException)
|
.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 {
|
runLoop = Runnable {
|
||||||
var refreshInterval = T.mins(5).msecs()
|
var refreshInterval = T.mins(5).msecs()
|
||||||
|
|
|
@ -5,7 +5,7 @@ import androidx.work.WorkerParameters
|
||||||
import info.nightscout.androidaps.annotations.OpenForTesting
|
import info.nightscout.androidaps.annotations.OpenForTesting
|
||||||
import info.nightscout.core.utils.worker.LoggingWorker
|
import info.nightscout.core.utils.worker.LoggingWorker
|
||||||
import info.nightscout.interfaces.plugin.ActivePlugin
|
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.plugins.sync.nsclientV3.NSClientV3Plugin
|
||||||
import info.nightscout.rx.bus.RxBus
|
import info.nightscout.rx.bus.RxBus
|
||||||
import info.nightscout.rx.events.EventNSClientNewLog
|
import info.nightscout.rx.events.EventNSClientNewLog
|
||||||
|
|
|
@ -45,7 +45,7 @@ internal class NSClientV3PluginTest : TestBaseWithProfile() {
|
||||||
|
|
||||||
@Mock lateinit var receiverDelegate: ReceiverDelegate
|
@Mock lateinit var receiverDelegate: ReceiverDelegate
|
||||||
@Mock lateinit var uiInteraction: UiInteraction
|
@Mock lateinit var uiInteraction: UiInteraction
|
||||||
@Mock lateinit var dataSyncSelectorV3: DataSyncSelectorV3Impl
|
@Mock lateinit var dataSyncSelectorV3: DataSyncSelectorV3
|
||||||
@Mock lateinit var nsAndroidClient: NSAndroidClient
|
@Mock lateinit var nsAndroidClient: NSAndroidClient
|
||||||
@Mock lateinit var uel: UserEntryLogger
|
@Mock lateinit var uel: UserEntryLogger
|
||||||
@Mock lateinit var nsClientSource: NSClientSource
|
@Mock lateinit var nsClientSource: NSClientSource
|
||||||
|
|
|
@ -8,7 +8,7 @@ import info.nightscout.androidaps.TestBase
|
||||||
import info.nightscout.core.utils.fabric.FabricPrivacy
|
import info.nightscout.core.utils.fabric.FabricPrivacy
|
||||||
import info.nightscout.interfaces.plugin.ActivePlugin
|
import info.nightscout.interfaces.plugin.ActivePlugin
|
||||||
import info.nightscout.interfaces.sync.NsClient
|
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.plugins.sync.nsclientV3.NSClientV3Plugin
|
||||||
import info.nightscout.rx.bus.RxBus
|
import info.nightscout.rx.bus.RxBus
|
||||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||||
|
@ -24,7 +24,7 @@ import org.mockito.Mockito.`when`
|
||||||
internal class DataSyncWorkerTest : TestBase() {
|
internal class DataSyncWorkerTest : TestBase() {
|
||||||
|
|
||||||
@Mock lateinit var fabricPrivacy: FabricPrivacy
|
@Mock lateinit var fabricPrivacy: FabricPrivacy
|
||||||
@Mock lateinit var dataSyncSelectorV3: DataSyncSelectorV3Impl
|
@Mock lateinit var dataSyncSelectorV3: DataSyncSelectorV3
|
||||||
@Mock lateinit var activePlugin: ActivePlugin
|
@Mock lateinit var activePlugin: ActivePlugin
|
||||||
@Mock lateinit var nsClient: NsClient
|
@Mock lateinit var nsClient: NsClient
|
||||||
@Mock lateinit var rxBus: RxBus
|
@Mock lateinit var rxBus: RxBus
|
||||||
|
|
|
@ -17,11 +17,11 @@ import info.nightscout.interfaces.Config
|
||||||
import info.nightscout.interfaces.nsclient.StoreDataForDb
|
import info.nightscout.interfaces.nsclient.StoreDataForDb
|
||||||
import info.nightscout.interfaces.receivers.ReceiverStatusStore
|
import info.nightscout.interfaces.receivers.ReceiverStatusStore
|
||||||
import info.nightscout.interfaces.source.NSClientSource
|
import info.nightscout.interfaces.source.NSClientSource
|
||||||
import info.nightscout.interfaces.sync.DataSyncSelectorV3
|
|
||||||
import info.nightscout.interfaces.ui.UiInteraction
|
import info.nightscout.interfaces.ui.UiInteraction
|
||||||
import info.nightscout.plugins.sync.nsShared.NsIncomingDataProcessor
|
import info.nightscout.plugins.sync.nsShared.NsIncomingDataProcessor
|
||||||
import info.nightscout.plugins.sync.nsclient.ReceiverDelegate
|
import info.nightscout.plugins.sync.nsclient.ReceiverDelegate
|
||||||
import info.nightscout.plugins.sync.nsclient.data.NSDeviceStatusHandler
|
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.NSClientV3Plugin
|
||||||
import info.nightscout.plugins.sync.nsclientV3.extensions.toNSSvgV3
|
import info.nightscout.plugins.sync.nsclientV3.extensions.toNSSvgV3
|
||||||
import info.nightscout.rx.bus.RxBus
|
import info.nightscout.rx.bus.RxBus
|
||||||
|
|
|
@ -1102,7 +1102,17 @@ class ComboV2Plugin @Inject constructor (
|
||||||
reportFinishedBolus(R.string.combov2_bolus_delivery_failed, pumpEnactResult, succeeded = false)
|
reportFinishedBolus(R.string.combov2_bolus_delivery_failed, pumpEnactResult, succeeded = false)
|
||||||
} finally {
|
} finally {
|
||||||
// The delivery was enacted if even a partial amount was infused.
|
// 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
|
bolusJob = null
|
||||||
bolusProgressJob.cancelAndJoin()
|
bolusProgressJob.cancelAndJoin()
|
||||||
}
|
}
|
||||||
|
@ -2216,7 +2226,7 @@ class ComboV2Plugin @Inject constructor (
|
||||||
// only shows up in the Combo fragment.
|
// only shows up in the Combo fragment.
|
||||||
if (newState == DriverState.Suspended) {
|
if (newState == DriverState.Suspended) {
|
||||||
uiInteraction.addNotification(
|
uiInteraction.addNotification(
|
||||||
Notification.COMBO_PUMP_SUSPENDED,
|
Notification.PUMP_SUSPENDED,
|
||||||
text = rh.gs(R.string.combov2_pump_is_suspended),
|
text = rh.gs(R.string.combov2_pump_is_suspended),
|
||||||
level = Notification.NORMAL
|
level = Notification.NORMAL
|
||||||
)
|
)
|
||||||
|
|
|
@ -171,6 +171,7 @@ public class SerialIOThread extends Thread {
|
||||||
aapsLogger.error(LTag.PUMPBTCOMM, "Reply not received " + message.getMessageName());
|
aapsLogger.error(LTag.PUMPBTCOMM, "Reply not received " + message.getMessageName());
|
||||||
if (message.getCommand() == 0xF0F1) {
|
if (message.getCommand() == 0xF0F1) {
|
||||||
danaPump.setNewPump(false);
|
danaPump.setNewPump(false);
|
||||||
|
danaPump.reset();
|
||||||
aapsLogger.debug(LTag.PUMPBTCOMM, "Old firmware detected");
|
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