feat(train): setting up and keeping the Polar Loop (ADR 0030, D34–D36)

On Android, the Loop through Polar's BLE SDK 8.3.0 (from JitPack, asked
for Polar's group alone, its files pinned by SHA-256 in Gradle's
verification metadata): LoopBridge.kt over app.halkyon.train/loop, the
first-time use's figures mapped and checked in LoopSetup.kt, tested on
the JVM. PolarLoop per person remembers the band in loop.json, connects
while the app is open, sets its clock at each connection, keeps what it
tells (battery, charging, firmware), offers a changed profile and sends
it only when asked (D35: first-time use writes a new user identifier
each time), and lets the band go by a factory reset after asking. The
setup sheet finds Loops nearest first and asks only for what the
profile lacks; Polar's defaults (60, 220 less the age, a VO2max from
Polar's fitness tables) go to the band alone.

Polar's SDK is not free software (D36, correcting D32): the app's AGPL
gains a section 7 permission for linking it, LICENSE.md names it, and
its licence and bundled notices join the licence list on Android.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
This commit is contained in:
Tizian 「ティツィアーン」 2026-10-28 18:58:02 +01:00
commit cd72cf6ccc
Signed by: raisondetredev
GPG key ID: 07F6FCF405488B64

View file

@ -188,5 +188,37 @@
"profileSleepGoal": "Schlafziel",
"profileSave": "Speichern",
"profileSaved": "Gespeichert",
"profileInvalid": "Prüfe die markierten Angaben."
"profileInvalid": "Prüfe die markierten Angaben.",
"profileNeeded": "Braucht dein Band",
"loopTitle": "Polar Loop",
"loopHint": "Dein Band: Einrichtung, Akku und Uhrzeit",
"loopNone": "Train richtet einen Polar Loop ein und betreut ihn selbst, ohne Polar Flow und ohne Polar-Konto. Ein Band, das mit Polar Flow verbunden war, braucht zuerst einen Werksreset.",
"loopSetUp": "Loop einrichten",
"loopSetUpAgain": "Neu einrichten",
"loopLetGo": "Band freigeben",
"loopLetGoTitle": "Band freigeben?",
"loopLetGoText": "Das Band wird auf Werkseinstellungen zurückgesetzt, und was es hält und noch nicht bei Train angekommen ist, geht verloren. Danach kannst du es mit einem anderen Handy oder mit Polar Flow koppeln.",
"loopLetGoConfirm": "Band zurücksetzen",
"loopConnected": "Verbunden",
"loopLastSeen": "Zuletzt gesehen {when}",
"loopNotInReach": "Nicht in Reichweite",
"loopBattery": "Akku {level} %",
"loopCharging": "Akku {level} %, lädt",
"loopFirmware": "Firmware {version}",
"loopProfileChanged": "Dein Körper hat sich geändert, seit das Band eingerichtet wurde",
"loopProfileChangedHint": "Senden richtet das Band mit deinen jetzigen Angaben neu ein.",
"loopSend": "Ans Band senden",
"loopSent": "Ans Band gesendet.",
"loopFailed": "Das Band hat nicht geantwortet. Halte es nah und versuch es noch mal.",
"loopSearching": "Suche Loops in der Nähe",
"loopSearchingHint": "Halte das Band nah; tipp darauf, um es zu wecken.",
"loopRefused": "Ohne Geräte in der Nähe kann Train dein Band nicht suchen. Erlaube sie in den Android-Einstellungen.",
"loopUnnamed": "Polar Loop",
"loopSettingUp": "Richte das Band ein …",
"loopSettingUpHint": "Android fragt dich vielleicht, ob du es koppeln willst.",
"loopSetUpDone": "Das Band ist eingerichtet.",
"loopFormTitle": "Für dein Band",
"loopFormIntro": "Dein Band braucht diese Angaben. Sie bleiben in „Dein Körper“, mit deinem Schlüssel versiegelt. Für einen Ruhe- oder Maximalpuls oder eine VO2max, die du nicht angegeben hast, nimmt das Band Polars Standardwerte, und „Dein Körper“ bleibt, wie er ist.",
"loopFormSave": "Band einrichten"
}