Strap usage tracking: accrue real HR-delivering time + battery steps natively

The strap's battery % is coarse/laggy (reads 100% for >24h), so to judge real
battery life we accumulate the time it actually delivered HR plus every battery
step into strap_uptime.json in the foreground service (persistent across
sessions). ble_read_strap_uptime / ble_reset_strap_uptime expose and reset it;
Settings shows hours-since-charge + steps with a Charged reset button.
This commit is contained in:
4aiman 2026-10-20 23:49:17 +03:00
commit abc4e3cef0
6 changed files with 174 additions and 4 deletions

View file

@ -0,0 +1,33 @@
# Сессия 2026-10-20 (доб.) - наработка ремня ЧСС + разделение склейки (UI)
## Наработка ремня (считаем ресурс батареи сами)
Проблема: ремень >24ч пишет 100%, непонятно шагами по 25% или как. Нужно самим считать
"300 часов". Заряд (0x2A19) грубый/запаздывает - поэтому копим ВРЕМЯ реальной отдачи ЧСС.
- Kotlin BleHrService: `accrueUptime`/`writeUptimeFile` - на каждый замер ЧСС копят время
(только промежутки <10с, т.е. без разрывов) и шаги заряда в `strap_uptime.json`
(персистентно, НЕ чистится per-session; flush ~20с и принудительно при обрыве/disconnect).
- Rust: `ble_read_strap_uptime` (чтение), `ble_reset_strap_uptime` (сброс при зарядке).
Зарегистрированы в lib.rs.
- JS: в настройках (Пульсометр) строка "Ремень ЧСС: наработка" - заряд, Hч Mм с последней
зарядки, шаги заряда, кнопка "Заряжен" (сброс через appConfirm).
Счётчик считает С МОМЕНТА установки/сброса; прошедшие сутки задним числом не восстановить.
## Авто-реконнект ремня (из прошлого лога этой даты)
Отдельный коммит ранее: переподключение только УЖЕ установленного соединения (connectedOnce),
до 3 попыток, не долбится в отсутствующий/не запущенный вручную ремень.
## Разделение склейки (по образцу merge, из UI)
Пользователь склеил 3 велопоездки в одну (session 1792506450721) и пожалел; склейка растянула
время и перекрыла воркауты между кусками. Все точки хранят `orig_session_id` -> разъединяемо.
- db.js `unmergeGpsSession(sessionId)`: по distinct `orig_session_id` пересоздаёт исходные
сессии (id = исходные), ретегает точки (orig_session_id=NULL, seq=NULL), выставляет каждой
дату/start/end из её точек. `countMergedOrigins` - сколько исходных склеено (>1 = склейка).
- main.js: кнопка "Разделить склейку (N)" в деталях трека (после "Разрезать"), видна только
для склейки; по тапу - unmerge + пересчёт каждой (computeStats+finishGpsSession, MET-оценка;
точную по физике - кнопкой "Пересчитать" в каждой) + возврат к списку.
## Проверка
Синтаксис JS ок (db/gps/main/tilecache). Rust/Kotlin - в сборке. Собираем в одну сборку с
реконнектом; ставим после Стопа ночной записи (переустановка её прерывает, данные в бэкапе
`scratchpad/night_hr_log_backup.jsonl`). На устройстве: наработка растёт и показывается в
настройках; "Разделить склейку" даёт 3 трека; реконнект переживает снятие ремня на 10-20с.