Merge pull request #3082 from swissalpine/garmin-sgv-json
Add iob, cob, tbr to GARMIN sgv.json endpoint
This commit is contained in:
commit
3cdf73ce46
5 changed files with 69 additions and 12 deletions
|
@ -327,6 +327,14 @@ class GarminPlugin @Inject constructor(
|
|||
GlucoseUnit.MGDL -> jo.addProperty("units_hint", "mgdl")
|
||||
GlucoseUnit.MMOL -> jo.addProperty("units_hint", "mmol")
|
||||
}
|
||||
jo.addProperty("iob", loopHub.insulinOnboard + loopHub.insulinBasalOnboard)
|
||||
loopHub.temporaryBasal.also {
|
||||
if (!it.isNaN()) {
|
||||
val temporaryBasalRateInPercent = (it * 100.0).toInt()
|
||||
jo.addProperty("tbr", temporaryBasalRateInPercent)
|
||||
}
|
||||
}
|
||||
jo.addProperty("cob", loopHub.carbsOnboard)
|
||||
}
|
||||
joa.add(jo)
|
||||
}
|
||||
|
|
|
@ -20,6 +20,12 @@ interface LoopHub {
|
|||
/** Returns the remaining bolus insulin on board. */
|
||||
val insulinOnboard: Double
|
||||
|
||||
/** Returns the basal insulin on board. */
|
||||
val insulinBasalOnboard: Double
|
||||
|
||||
/** Returns the remaining carbs on board. */
|
||||
val carbsOnboard: Double?
|
||||
|
||||
/** Returns true if the pump is connected. */
|
||||
val isConnected: Boolean
|
||||
|
||||
|
@ -48,4 +54,4 @@ interface LoopHub {
|
|||
avgHeartRate: Int,
|
||||
device: String?
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,6 +13,7 @@ import app.aaps.core.interfaces.profile.ProfileFunction
|
|||
import app.aaps.core.interfaces.pump.DetailedBolusInfo
|
||||
import app.aaps.core.interfaces.queue.CommandQueue
|
||||
import app.aaps.core.interfaces.sharedPreferences.SP
|
||||
import app.aaps.core.main.graph.OverviewData
|
||||
import app.aaps.database.ValueWrapper
|
||||
import app.aaps.database.entities.EffectiveProfileSwitch
|
||||
import app.aaps.database.entities.GlucoseValue
|
||||
|
@ -42,6 +43,7 @@ class LoopHubImpl @Inject constructor(
|
|||
private val repo: AppRepository,
|
||||
private val userEntryLogger: UserEntryLogger,
|
||||
private val sp: SP,
|
||||
private val overviewData: OverviewData,
|
||||
) : LoopHub {
|
||||
|
||||
@VisibleForTesting
|
||||
|
@ -64,6 +66,14 @@ class LoopHubImpl @Inject constructor(
|
|||
override val insulinOnboard: Double
|
||||
get() = iobCobCalculator.calculateIobFromBolus().iob
|
||||
|
||||
/** Returns the remaining bolus and basal insulin on board. */
|
||||
override val insulinBasalOnboard :Double
|
||||
get() = iobCobCalculator.calculateIobFromTempBasalsIncludingConvertedExtended().basaliob
|
||||
|
||||
/** Returns the remaining carbs on board. */
|
||||
override val carbsOnboard: Double?
|
||||
get() = overviewData.cobInfo(iobCobCalculator).displayCob
|
||||
|
||||
/** Returns true if the pump is connected. */
|
||||
override val isConnected: Boolean get() = !loop.isDisconnected
|
||||
|
||||
|
@ -142,4 +152,4 @@ class LoopHubImpl @Inject constructor(
|
|||
)
|
||||
repo.runTransaction(InsertOrUpdateHeartRateTransaction(hr)).blockingAwait()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -57,6 +57,10 @@ class GarminPluginTest: TestBase() {
|
|||
@AfterEach
|
||||
fun verifyNoFurtherInteractions() {
|
||||
verify(loopHub, atMost(2)).currentProfileName
|
||||
verify(loopHub, atMost(3)).insulinOnboard
|
||||
verify(loopHub, atMost(3)).insulinBasalOnboard
|
||||
verify(loopHub, atMost(3)).temporaryBasal
|
||||
verify(loopHub, atMost(3)).carbsOnboard
|
||||
verifyNoMoreInteractions(loopHub)
|
||||
}
|
||||
|
||||
|
@ -221,14 +225,18 @@ class GarminPluginTest: TestBase() {
|
|||
}
|
||||
|
||||
@Test
|
||||
fun onSgv_NoDelta() {
|
||||
fun onSgv_NoDelta() {
|
||||
whenever(loopHub.glucoseUnit).thenReturn(GlucoseUnit.MMOL)
|
||||
whenever(loopHub.insulinOnboard).thenReturn(2.7)
|
||||
whenever(loopHub.insulinBasalOnboard).thenReturn(2.5)
|
||||
whenever(loopHub.temporaryBasal).thenReturn(0.8)
|
||||
whenever(loopHub.carbsOnboard).thenReturn(10.7)
|
||||
whenever(loopHub.getGlucoseValues(any(), eq(false))).thenReturn(
|
||||
listOf(createGlucoseValue(
|
||||
clock.instant().minusSeconds(100L), 99.3)))
|
||||
assertEquals(
|
||||
"""[{"_id":"-900000","device":"RANDOM","deviceString":"1969-12-31T23:58:30Z","sysTime":"1969-12-31T23:58:30Z","unfiltered":90.0,"date":-90000,"sgv":99,"direction":"Flat","noise":4.5,"units_hint":"mmol"}]""",
|
||||
gp.onSgv(mock(), createUri(mapOf()), null))
|
||||
"""[{"_id":"-900000","device":"RANDOM","deviceString":"1969-12-31T23:58:30Z","sysTime":"1969-12-31T23:58:30Z","unfiltered":90.0,"date":-90000,"sgv":99,"direction":"Flat","noise":4.5,"units_hint":"mmol","iob":5.2,"tbr":80,"cob":10.7}]""",
|
||||
gp.onSgv(mock(), createUri(mapOf()), null))
|
||||
verify(loopHub).getGlucoseValues(clock.instant().minusSeconds(25L * 300L), false)
|
||||
verify(loopHub).glucoseUnit
|
||||
}
|
||||
|
@ -236,26 +244,31 @@ class GarminPluginTest: TestBase() {
|
|||
@Test
|
||||
fun onSgv() {
|
||||
whenever(loopHub.glucoseUnit).thenReturn(GlucoseUnit.MMOL)
|
||||
whenever(loopHub.insulinOnboard).thenReturn(2.7)
|
||||
whenever(loopHub.insulinBasalOnboard).thenReturn(2.5)
|
||||
whenever(loopHub.temporaryBasal).thenReturn(0.8)
|
||||
whenever(loopHub.carbsOnboard).thenReturn(10.7)
|
||||
whenever(loopHub.getGlucoseValues(any(), eq(false))).thenAnswer { i ->
|
||||
val from = i.getArgument<Instant>(0)
|
||||
fromClosedRange(from.toEpochMilli(), clock.instant().toEpochMilli(), 300_000L)
|
||||
.map(Instant::ofEpochMilli)
|
||||
.mapIndexed { idx, ts -> createGlucoseValue(ts, 100.0+(10 * idx)) }.reversed()}
|
||||
assertEquals(
|
||||
"""[{"_id":"100000","device":"RANDOM","deviceString":"1970-01-01T00:00:10Z","sysTime":"1970-01-01T00:00:10Z","unfiltered":90.0,"date":10000,"sgv":120,"delta":10,"direction":"Flat","noise":4.5,"units_hint":"mmol"}]""",
|
||||
"""[{"_id":"100000","device":"RANDOM","deviceString":"1970-01-01T00:00:10Z","sysTime":"1970-01-01T00:00:10Z","unfiltered":90.0,"date":10000,"sgv":120,"delta":10,"direction":"Flat","noise":4.5,"units_hint":"mmol","iob":5.2,"tbr":80,"cob":10.7}]""",
|
||||
gp.onSgv(mock(), createUri(mapOf("count" to "1")), null))
|
||||
verify(loopHub).getGlucoseValues(
|
||||
clock.instant().minusSeconds(600L), false)
|
||||
|
||||
|
||||
assertEquals(
|
||||
"""[{"_id":"100000","device":"RANDOM","deviceString":"1970-01-01T00:00:10Z","sysTime":"1970-01-01T00:00:10Z","unfiltered":90.0,"date":10000,"sgv":130,"delta":10,"direction":"Flat","noise":4.5,"units_hint":"mmol"},""" +
|
||||
"""{"_id":"-2900000","device":"RANDOM","deviceString":"1969-12-31T23:55:10Z","sysTime":"1969-12-31T23:55:10Z","unfiltered":90.0,"date":-290000,"sgv":120,"delta":10,"direction":"Flat","noise":4.5}]""",
|
||||
"""[{"_id":"100000","device":"RANDOM","deviceString":"1970-01-01T00:00:10Z","sysTime":"1970-01-01T00:00:10Z","unfiltered":90.0,"date":10000,"sgv":130,"delta":10,"direction":"Flat","noise":4.5,"units_hint":"mmol","iob":5.2,"tbr":80,"cob":10.7},""" +
|
||||
"""{"_id":"-2900000","device":"RANDOM","deviceString":"1969-12-31T23:55:10Z","sysTime":"1969-12-31T23:55:10Z","unfiltered":90.0,"date":-290000,"sgv":120,"delta":10,"direction":"Flat","noise":4.5}]""",
|
||||
gp.onSgv(mock(), createUri(mapOf("count" to "2")), null))
|
||||
verify(loopHub).getGlucoseValues(
|
||||
clock.instant().minusSeconds(900L), false)
|
||||
|
||||
assertEquals(
|
||||
"""[{"date":10000,"sgv":130,"delta":10,"direction":"Flat","noise":4.5,"units_hint":"mmol"},""" +
|
||||
"""[{"date":10000,"sgv":130,"delta":10,"direction":"Flat","noise":4.5,"units_hint":"mmol","iob":5.2,"tbr":80,"cob":10.7},""" +
|
||||
"""{"date":-290000,"sgv":120,"delta":10,"direction":"Flat","noise":4.5}]""",
|
||||
gp.onSgv(mock(), createUri(mapOf("count" to "2", "brief_mode" to "true")), null))
|
||||
verify(loopHub, times(2)).getGlucoseValues(
|
||||
|
|
|
@ -5,6 +5,7 @@ import app.aaps.core.interfaces.aps.Loop
|
|||
import app.aaps.core.interfaces.constraints.Constraint
|
||||
import app.aaps.core.interfaces.constraints.ConstraintsChecker
|
||||
import app.aaps.core.interfaces.db.GlucoseUnit
|
||||
import app.aaps.core.interfaces.iob.CobInfo
|
||||
import app.aaps.core.interfaces.iob.IobCobCalculator
|
||||
import app.aaps.core.interfaces.iob.IobTotal
|
||||
import app.aaps.core.interfaces.logging.UserEntryLogger
|
||||
|
@ -13,6 +14,7 @@ import app.aaps.core.interfaces.profile.ProfileFunction
|
|||
import app.aaps.core.interfaces.pump.DetailedBolusInfo
|
||||
import app.aaps.core.interfaces.queue.CommandQueue
|
||||
import app.aaps.core.interfaces.sharedPreferences.SP
|
||||
import app.aaps.core.main.graph.OverviewData
|
||||
import app.aaps.database.ValueWrapper
|
||||
import app.aaps.database.entities.EffectiveProfileSwitch
|
||||
import app.aaps.database.entities.GlucoseValue
|
||||
|
@ -54,6 +56,7 @@ class LoopHubTest: TestBase() {
|
|||
@Mock lateinit var repo: AppRepository
|
||||
@Mock lateinit var userEntryLogger: UserEntryLogger
|
||||
@Mock lateinit var sp: SP
|
||||
@Mock lateinit var overviewData: OverviewData
|
||||
|
||||
private lateinit var loopHub: LoopHubImpl
|
||||
private val clock = Clock.fixed(Instant.ofEpochMilli(10_000), ZoneId.of("UTC"))
|
||||
|
@ -62,7 +65,7 @@ class LoopHubTest: TestBase() {
|
|||
fun setup() {
|
||||
loopHub = LoopHubImpl(
|
||||
aapsLogger, commandQueue, constraints, iobCobCalculator, loop,
|
||||
profileFunction, repo, userEntryLogger, sp
|
||||
profileFunction, repo, userEntryLogger, sp, overviewData
|
||||
)
|
||||
loopHub.clock = clock
|
||||
}
|
||||
|
@ -76,9 +79,10 @@ class LoopHubTest: TestBase() {
|
|||
verifyNoMoreInteractions(profileFunction)
|
||||
verifyNoMoreInteractions(repo)
|
||||
verifyNoMoreInteractions(userEntryLogger)
|
||||
verifyNoMoreInteractions(overviewData)
|
||||
}
|
||||
|
||||
@Test
|
||||
@Test
|
||||
fun testCurrentProfile() {
|
||||
val profile = mock(Profile::class.java)
|
||||
`when`(profileFunction.getProfile()).thenReturn(profile)
|
||||
|
@ -109,6 +113,22 @@ class LoopHubTest: TestBase() {
|
|||
verify(iobCobCalculator, times(1)).calculateIobFromBolus()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testBasalOnBoard() {
|
||||
val iobBasal = IobTotal(time = 0).apply { basaliob = 23.9 }
|
||||
`when`(iobCobCalculator.calculateIobFromTempBasalsIncludingConvertedExtended()).thenReturn(iobBasal)
|
||||
assertEquals(23.9, loopHub.insulinBasalOnboard, 1e-10)
|
||||
verify(iobCobCalculator, times(1)).calculateIobFromTempBasalsIncludingConvertedExtended()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testCarbsOnBoard() {
|
||||
val cobInfo = CobInfo(0, 12.0, 0.0)
|
||||
`when`(overviewData.cobInfo(iobCobCalculator)).thenReturn(cobInfo)
|
||||
assertEquals(12.0, loopHub.carbsOnboard)
|
||||
verify(overviewData, times(1)).cobInfo(iobCobCalculator)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testIsConnected() {
|
||||
`when`(loop.isDisconnected).thenReturn(false)
|
||||
|
@ -247,4 +267,4 @@ class LoopHubTest: TestBase() {
|
|||
samplingStart, samplingEnd, 101, "Test Device")
|
||||
verify(repo).runTransaction(InsertOrUpdateHeartRateTransaction(hr))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue