HR strap battery + low-charge voice/beep alerts at 10% and 5%

- BleHrService reads the standard Battery service (0x180F/0x2A19) 2.5s after
  the HR subscribe and every 60s; writes 'bat' into ble_hr_data.json.
- HrReading gains battery: Option<u8> (serde alias 'bat').
- gps.js: the HR poll captures reading.battery; _checkBatteryAlert speaks
  (speechSynthesis ru-RU) and beeps once at 10% and 5% (beep is the
  guaranteed cue where TTS is absent), resetting above 15%.
- Workout screen shows the strap charge in its status line.
This commit is contained in:
4aiman 2026-10-17 00:58:31 +03:00
commit 62434d6155
5 changed files with 95 additions and 4 deletions

View file

@ -31,8 +31,18 @@ project-hr-sensor.
`gps_sessions.total_kcal`). `recalculateSession` для workout - no-op (точек нет, возвращает null),
так что "Пересчитать всё" не затирает HR-ккал.
## Осталось (отдельным коммитом)
Заряд ремня ЧСС (0x180F/0x2A19) + голос/писк на 10% и 5%.
## Заряд ремня ЧСС + голос/писк на 10% и 5% (сделано)
- Kotlin `BleHrService`: читает 0x180F/0x2A19 (readBattery) через 2.5с после подписки и раз в
60с; `lastBattery` пишется в `ble_hr_data.json` как `"bat":N`. onCharacteristicRead (две
перегрузки под API 33+/старый).
- Rust `HrReading`: поле `battery: Option<u8>` (alias "bat").
- JS `gps.js`: поллинг ловит `reading.battery` -> `GPS.recording.currentBattery` +
`GPS._checkBatteryAlert`: на 10% и 5% ОДИН раз - голос (`speechSynthesis` ru-RU) + писк
(Web Audio, гарантированный сигнал, т.к. TTS на de-Googled ROM может не быть). Сброс флагов
при заряде > 15% (перезарядили/заменили).
- Экран зарядки показывает "заряд N%" в статусе.
- Заметка: аудио в WebView может требовать user-gesture; старт записи - это жест, должно
играть. Проверить на устройстве.
## Проверка
Синтаксис JS ок. На телефоне: выбрать "Зарядка", Старт (без браслета покажет "Подключите