Workout HR: log samples natively so recording survives screen-off

The JS 2s poll that stored workout HR samples is frozen by Android when the
screen is off, so a sleep-long recording kept only the on-screen stretches
(the strap and live display were fine — the persist path was the gap). The
foreground service now appends every reading to ble_hr_log.jsonl; ble_read_hr_log
exposes it; on stop the workout rebuilds its samples from that log (falling back
to the poll array). ble_clear_hr truncates the log at start.
This commit is contained in:
4aiman 2026-10-20 23:09:50 +03:00
commit ee47af4479
6 changed files with 98 additions and 5 deletions

View file

@ -0,0 +1,36 @@
# Сессия 2026-10-20 - нативный лог ЧСС (запись воркаута переживает гаснущий экран)
## Причина (из разбора 21ч-прогона эксперимента)
Сессия-воркаут 1792436740262 (19.10 22:05 -> 20.10 17:27) в сохранёнке имела дырки 11.6ч,
НО пользователь видел живые цифры засыпая/просыпаясь/весь день. Проверка: шаг внутри
покрытия ровно 2.0с (это JS-поллинг), границы дыр = сон/утро/обед (экран гас). Вывод: ремень
и дисплей работали; молчал ПЕРСИСТ - историю сэмплов воркаута писал JS setInterval(2с),
который Android замораживает в фоне/при гаснущем экране. Нативная часть клала только ТЕКУЩЕЕ
значение (ble_hr_data.json, overwrite), истории не было.
## Сделано
Нативный лог истории ЧСС (как GPS-точки пишутся foreground-сервисом):
- Kotlin BleHrService: поле `logFile` = `ble_hr_log.jsonl`; в `writeData` каждая строка с
`"hr":` дописывается (appendText) в лог. Пишет сам foreground-сервис -> переживает
гаснущий экран.
- Rust ble.rs: команда `ble_read_hr_log` (читает лог), `ble_clear_hr` теперь чистит и лог.
Зарегистрировано в lib.rs invoke_handler.
- JS gps.js: `GPS._readHrLogSamples()` - парсит лог в [[relSec,bpm]] относительно startTime
(фильтр hr>0, rel>=0, дедуп по секунде, сортировка). На остановке воркаута сэмплы берутся
из лога, если он полнее JS-массива (fallback на JS-массив, если лог пуст). Чтение - ДО
`_stopHrMonitor` (который чистит лог). Лог чистится при старте воркаута (ble_clear_hr, 1453).
## Не делал (осознанно, по риску разовой ночной записи)
Авто-реконнект ремня при обрыве BLE - НЕ добавлял сейчас. Причина дыр была в заморозке JS,
а не в обрыве BLE (днём была длинная непрерывная связь). Ночью пользователь запишет сон -
это проверит, рвётся ли BLE на самом деле. Если нативный лог покажет обрыв среди ночи -
тогда добавим реконнект. Иначе он не нужен.
## Также отложено
Разделение склеенного велотрека 1792506450721 (3 поездки по orig_session_id: 17:27-17:57,
18:00-18:32, 18:44-18:49) - одобрено, но отложено ради срочного ночного фикса.
## Проверка
Синтаксис JS ок. Rust/Kotlin компиляция - в сборке. На телефоне: старт воркаута "зарядка
(пульс)", экран гаснет на ночь, утром стоп -> сэмплы должны быть сплошные (из нативного лога),
включая сон. Живую проверку делает пользователь ночью.