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.
3.5 KiB
Сессия 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 компиляция - в сборке. На телефоне: старт воркаута "зарядка (пульс)", экран гаснет на ночь, утром стоп -> сэмплы должны быть сплошные (из нативного лога), включая сон. Живую проверку делает пользователь ночью.