Skip to content

feat(huawei): store workout cadence, altitude and power from Band 10 runs - #113

Open
vuongvm812 wants to merge 1 commit into
mainfrom
run-metrics-band10
Open

vuongvm812 wants to merge 1 commit into
mainfrom
run-metrics-band10

Conversation

@vuongvm812

Copy link
Copy Markdown
Owner

Summary

  • Part of a stack: run-metrics-garmin (bottom) adds the charts; this PR (top) supplies Huawei Band 10 data. They render from the same new kinds once both merge. Not to be merged on its own.
  • Adds DeviceMetricKind entries CADENCE("cadence"), POWER_W("power_w"), ALTITUDE_M("altitude_m") (Kotlin only, no migration). Swift is untouched: it has no Huawei ingest, and the Garmin PR adds the Swift entries.
  • Carries per-sample step rate / cadence, altitude and power from the band's 17/0A workout pages into deviceMetricSample through the existing insert. Absent, sentinel (0xFF / 0xFFFF / raw -1) and 0 values are not stored; samples outside the workout are dropped.
  • Gadgetbridge import reads STEP_RATE, CADENCE, ALTITUDE, CYCLING_POWER when the columns exist.
  • One always-on strap-log line per synced or imported workout with the usable sample counts for HR / cadence / altitude / power.

Changes

Area Change
data/WhoopRepository.kt three new kinds appended after SKIN_TEMP_C
ingest/HuaweiWatchIngest.kt workoutSeries() extracts the rows and counts; fold stores them with source huawei-17-0a (or gadgetbridge)
data/HuaweiHistoryIngest.kt store(..., log) logs workoutLine per workout
ingest/Gadgetbridge{Importer,Mapping}.kt extra columns (guarded by the existing column helper) and a log hook, wired in DataSourcesScreen
ATTRIBUTION.md, Tools/parity_*.json facts-only attribution; platform_specific dispositions ("Huawei ingest exists only on Android")
tests HuaweiWorkoutSeriesTest, extended GadgetbridgeImporterTest, kind-list pin

Decisions, from Gadgetbridge's HuaweiWorkoutGbParser.buildActivityPoint: cadence is steps/min, taken from the step rate (field 2) for walking (types 2, 13) and otherwise from the inner-block cadence (bit 0), each falling back to the other. Altitude is stored in tenths of a metre (raw / 10). The step rate is read as an unsigned byte (& 0xFF), with raw -1 meaning absent. Power is raw watts.

How to Test

  1. cd android && ./gradlew testFullDebugUnitTest (create app/build/roomSchemaOracle if Gradle complains).
  2. python3 Tools/parity_ledger.py --base origin/main, doc_comment_lint.py, i18n_audit.py --ci origin/main.
  3. On a device: sync a Band 10 workout (or import a Gadgetbridge export) and look for Huawei: workout <ts> type=N usable samples hr=.. cadence=.. altitude=.. power=.. in the strap log.

Verification

  • Android unit suite: 7303 tests; the only failures are the known main ones (HuaweiSyncedEngineTest, RecoveryDriversTest x2).
  • Parity ledger clean. parity_ratchet.py still prints "base authority cannot be reproduced with the current derivation", which comes from main's base, not this change.
  • Tools unittest: 4 test_check_source_references failures from macOS /var vs /private/var paths, unrelated.
  • Not tested on hardware: decoding is untested on a real Huawei Band 10 (and no Garmin file for the sibling PR). The Gadgetbridge export at hand has all these columns at 0, so only a synthetic fixture was exercised.

Known Limitations / Follow-ups

  • A 0 count in the log can mean the band or sport does not provide the series; the line states what was decoded, not what the band supports.
  • Altitude of exactly 0.0 m is skipped with the other zeros, although sea level is a real altitude.
  • GPS-file altitude (GpsPoint.altitudeM) is still not stored.
  • The Gadgetbridge columns' signedness is inferred from its & 0xFF use; both readings map to the same value.
  • A restore of an Android .noopbak on Apple relies on Swift tolerating unknown kinds (as for skin_temp_c).
  • Reviews: code-review skill and Codex (Codex found nothing and could not run tests).

…runs

Carry per-sample step rate / cadence, altitude and power from the 17/0A
workout data pages (and the Gadgetbridge HUAWEI_WORKOUT_DATA_SAMPLE
columns) into deviceMetricSample as the new CADENCE, ALTITUDE_M and
POWER_W kinds. Absent, sentinel and zero values are not stored. One
always-on strap-log line per workout reports the usable sample counts.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant