Skip to content

Commit 4cadcf5

Browse files
committed
HealthStatsDialog: show per-weekday typical step totals
Surfaces the seven <weekday>_steps typical totals computed by computeAllWeekdayTypicalSteps in the Health Debug Stats dialog so the values pushed to the watch can be sanity-checked from the phone. Each row sums the 96 15-min bins of that weekday's payload (matching the firmware's prv_cur_step_avg sum semantics), or shows "--" for weekdays below the 2-day minimum-history threshold. New decodeTypicalStepTotal helper in HealthStatsSync encapsulates the wire-format knowledge; HealthDebugStats gains a weekdayTypicalSteps field; Health.getHealthDebugStats and FakeLibPebble.getHealthDebugStats populate it; the iOS healthDebugStatsToJson includes it.
1 parent 0c843a6 commit 4cadcf5

6 files changed

Lines changed: 71 additions & 4 deletions

File tree

libpebble3/src/commonMain/kotlin/io/rebble/libpebblecommon/connection/FakeLibPebble.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -379,7 +379,8 @@ class FakeLibPebble : LibPebble {
379379
todaySteps = 0L,
380380
lastNightSleepHours = null,
381381
latestDataTimestamp = null,
382-
daysOfData = 0
382+
daysOfData = 0,
383+
weekdayTypicalSteps = emptyMap(),
383384
)
384385
}
385386

libpebble3/src/commonMain/kotlin/io/rebble/libpebblecommon/health/Health.kt

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ import io.rebble.libpebblecommon.datalogging.HealthDataProcessor
1919
import io.rebble.libpebblecommon.di.LibPebbleCoroutineScope
2020
import io.rebble.libpebblecommon.services.DailySleep
2121
import io.rebble.libpebblecommon.services.calculateHealthAverages
22+
import io.rebble.libpebblecommon.services.computeAllWeekdayTypicalSteps
23+
import io.rebble.libpebblecommon.services.decodeTypicalStepTotal
2224
import io.rebble.libpebblecommon.services.groupSleepSessions
2325
import io.rebble.libpebblecommon.services.fetchAndGroupDailySleep
2426
import io.rebble.libpebblecommon.services.updateHealthStatsInDatabase
@@ -94,6 +96,9 @@ class Health(
9496
val lastNightSleepHours =
9597
if (lastNightSleepSeconds > 0) lastNightSleepSeconds / 3600f else null
9698

99+
val weekdayTypicalSteps = computeAllWeekdayTypicalSteps(healthDao, today, timeZone)
100+
.mapValues { (_, payload) -> decodeTypicalStepTotal(payload) }
101+
97102
return HealthDebugStats(
98103
totalSteps30Days = averages.totalSteps,
99104
averageStepsPerDay = averages.averageStepsPerDay,
@@ -102,7 +107,8 @@ class Health(
102107
todaySteps = todaySteps,
103108
lastNightSleepHours = lastNightSleepHours,
104109
latestDataTimestamp = latestTimestamp,
105-
daysOfData = daysOfData
110+
daysOfData = daysOfData,
111+
weekdayTypicalSteps = weekdayTypicalSteps,
106112
)
107113
}
108114

libpebble3/src/commonMain/kotlin/io/rebble/libpebblecommon/health/HealthRecords.kt

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,10 @@ class RawOverlayRecord : StructMappable() {
7777

7878
/**
7979
* Debug statistics for health data, used for diagnostics and testing.
80+
*
81+
* [weekdayTypicalSteps] carries the per-weekday typical-step totals computed for the
82+
* `<weekday>_steps` BlobDB rows; absent keys are weekdays where the user has insufficient
83+
* same-weekday history (we don't write a row for them, so the watch shows no comparison).
8084
*/
8185
data class HealthDebugStats(
8286
val totalSteps30Days: Long,
@@ -86,5 +90,6 @@ data class HealthDebugStats(
8690
val todaySteps: Long,
8791
val lastNightSleepHours: Float?,
8892
val latestDataTimestamp: Long?,
89-
val daysOfData: Int
93+
val daysOfData: Int,
94+
val weekdayTypicalSteps: Map<kotlinx.datetime.DayOfWeek, Int> = emptyMap(),
9095
)

libpebble3/src/commonMain/kotlin/io/rebble/libpebblecommon/services/HealthStatsSync.kt

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -247,6 +247,29 @@ internal fun buildWeekdayTypicalsFromData(
247247
* Returns one entry per weekday that has at least [MIN_DAYS_FOR_TYPICAL] distinct matching days
248248
* in the queried window. Empty map when there's no data or no weekday clears the threshold.
249249
*/
250+
/**
251+
* Sums the 96 little-endian UShort step counts in a typical-step payload, skipping the
252+
* UNKNOWN sentinel — i.e., "total typical steps for the day represented by this payload."
253+
*
254+
* Used by the debug stats dialog to surface the per-weekday typical totals; mirrors the
255+
* watch firmware's [`prv_cur_step_avg`](activity_insights.c:1143) which sums the same
256+
* array.
257+
*/
258+
internal fun decodeTypicalStepTotal(payload: ByteArray): Int {
259+
require(payload.size == TYPICAL_STEP_BINS * UShort.SIZE_BYTES) {
260+
"typical-step payload must be ${TYPICAL_STEP_BINS * UShort.SIZE_BYTES} bytes, got ${payload.size}"
261+
}
262+
var total = 0
263+
for (slot in 0 until TYPICAL_STEP_BINS) {
264+
val byteOffset = slot * 2
265+
val lo = payload[byteOffset].toInt() and 0xFF
266+
val hi = payload[byteOffset + 1].toInt() and 0xFF
267+
val v = (hi shl 8) or lo
268+
if (v != UNKNOWN_TYPICAL_STEPS.toInt()) total += v
269+
}
270+
return total
271+
}
272+
250273
internal suspend fun computeAllWeekdayTypicalSteps(
251274
healthDao: HealthDao,
252275
today: LocalDate,

pebble/src/commonMain/kotlin/coredevices/pebble/ui/HealthStatsDialog.kt

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ import io.rebble.libpebblecommon.connection.LibPebble
3535
import io.rebble.libpebblecommon.health.HealthDebugStats
3636
import kotlinx.coroutines.delay
3737
import kotlinx.coroutines.launch
38+
import kotlinx.datetime.DayOfWeek
3839
import kotlin.time.Duration.Companion.seconds
3940

4041
private val logger = Logger.withTag("HealthStatsDialog")
@@ -171,6 +172,35 @@ fun HealthStatsDialog(libPebble: LibPebble, onDismissRequest: () -> Unit) {
171172
color = MaterialTheme.colorScheme.onSurfaceVariant,
172173
)
173174
}
175+
176+
Spacer(Modifier.height(4.dp))
177+
178+
Text(
179+
"Typical steps by weekday",
180+
style = MaterialTheme.typography.bodyMedium,
181+
)
182+
for (wd in DayOfWeek.entries) {
183+
val total = s.weekdayTypicalSteps[wd]
184+
Row(
185+
modifier = Modifier.fillMaxWidth(),
186+
horizontalArrangement = Arrangement.SpaceBetween
187+
) {
188+
Text(
189+
wd.name.lowercase().replaceFirstChar { it.uppercase() },
190+
style = MaterialTheme.typography.bodySmall,
191+
color = MaterialTheme.colorScheme.onSurfaceVariant,
192+
)
193+
Text(
194+
total?.toString() ?: "--",
195+
style = MaterialTheme.typography.bodySmall,
196+
color = if (total != null) {
197+
MaterialTheme.colorScheme.onSurface
198+
} else {
199+
MaterialTheme.colorScheme.onSurfaceVariant
200+
},
201+
)
202+
}
203+
}
174204
}
175205
} else {
176206
Text(

pebble/src/iosMain/kotlin/coredevices/pebble/actions/watch/HealthStats.kt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,5 +8,7 @@ import io.rebble.libpebblecommon.health.HealthDebugStats
88
fun healthDebugStatsToJson(stats: HealthDebugStats): String {
99
val lastNight = stats.lastNightSleepHours?.toString() ?: "null"
1010
val latestTs = stats.latestDataTimestamp?.toString() ?: "null"
11-
return """{"totalSteps30Days":${stats.totalSteps30Days},"averageStepsPerDay":${stats.averageStepsPerDay},"totalSleepSeconds30Days":${stats.totalSleepSeconds30Days},"averageSleepSecondsPerDay":${stats.averageSleepSecondsPerDay},"todaySteps":${stats.todaySteps},"lastNightSleepHours":$lastNight,"latestDataTimestamp":$latestTs,"daysOfData":${stats.daysOfData}}"""
11+
val typicalSteps = stats.weekdayTypicalSteps.entries
12+
.joinToString(prefix = "{", postfix = "}") { (wd, total) -> "\"$wd\":$total" }
13+
return """{"totalSteps30Days":${stats.totalSteps30Days},"averageStepsPerDay":${stats.averageStepsPerDay},"totalSleepSeconds30Days":${stats.totalSleepSeconds30Days},"averageSleepSecondsPerDay":${stats.averageSleepSecondsPerDay},"todaySteps":${stats.todaySteps},"lastNightSleepHours":$lastNight,"latestDataTimestamp":$latestTs,"daysOfData":${stats.daysOfData},"weekdayTypicalSteps":$typicalSteps}"""
1214
}

0 commit comments

Comments
 (0)