baldav/docs/session-logs/2026-10-17_hr-workout-mode.md
4aiman f7ba059628 HR: auto-connect at recording start if a strap is paired; HR on/off toggle replaces the wind button
Earlier I over-corrected: 'don't scan when the strap is absent' became
'never auto-connect'. Restore conditional auto: at recording start (ride or
workout) connect the paired strap and poll; absent strap is safe now
(BleHrService scans briefly and stops - no drain). No paired strap -> HR off.

- gps.js: GPS.setHrOn(on) - connect+poll / disconnect+stop; start auto-ons it.
- Record screen: the inconvenient 'Ветер' button is gone; in its place an
  HR on/off toggle (square, heart+pulse icon; grey off, red on) -> setHrOn.

(Also corrected a stale assumption: the phone DOES have Google services.)
2026-10-17 01:45:02 +03:00

6.1 KiB
Raw Blame History

Сессия 2026-10-17 - HR-датчик Coospo H808S: чтение + режим "Зарядка" без GPS

Датчик прочитан с ПК (без спаривания)

F7:72:74:A4:FB:07 (808S 0026275), стандарт 0x180D/0x2A37. tools/ble_probe.py подключается без pair(), живой пульс ~1/сек (+ RR). tools/hr_log.py - фоновый логгер (epoch,bpm в файл, авто-переподключение). Адаптер ПК - hci1 (один). Подробности в памяти project-hr-sensor.

Режим "Зарядка" (workout) - запись без GPS, только пульс + нагрузка

Нужен был режим трекинга без геолокации (домашняя зарядка): меряет пульс и ккал, GPS не включает и не пишет.

  • frontend/js/gps.js:
    • GPS.hrKcalNet(samples, profile) - нетто-ккал по пульсу (Keytel gross минус BMR/мин, как и остальная активность). samples = relSec,bpm.
    • startRecording(type, wkg, profile) - ветка workout: НЕ запускает нативный GPS-сервис, watchPosition, поллинг точек. Создаёт сессию (activity_type="workout"), запускает HR-опрос.
    • HR-опрос (_startHrMonitor) при workout пушит [relSec,bpm] в GPS.recording.hrSamples.
    • stopRecording ветка workout: считает ккал (Keytel), avg/max пульс, сохраняет hr_samples (JSON) + finishGpsSession(dist=0, kcal).
  • frontend/js/db.js: миграция gps_sessions.hr_samples TEXT; setSessionHrSamples.
  • frontend/js/main.js:
    • выпадашка записи: "Зарядка (пульс)".
    • renderWorkoutInline - экран записи без карты: крупный пульс, таймер, живые ккал, средний/макс, кнопка "Подключить пульсометр" (с проверкой BT), Стоп -> деталь.
    • renderWorkoutDetail - деталь без карты: график пульса (цвет по HR-зонам), время, нагрузка (ккал), средний/макс, удалить.
  • frontend/css/styles.css: .workout-screen и пр.

Ккал зарядки идёт в дневной баланс автоматически (getDailyActivityTotals суммирует gps_sessions.total_kcal). recalculateSession для workout - no-op (точек нет, возвращает null), так что "Пересчитать всё" не затирает HR-ккал.

Заряд ремня ЧСС + голос/писк на 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; старт записи - это жест, должно играть. Проверить на устройстве.

Правка после теста: авто-ЧСС на старте + тоггл ВКЛ/ВЫКЛ вместо "Ветер"

Я перестарался: по просьбе "не искать, если браслета нет" убрал автоконнект ВООБЩЕ. Нужно было оставить авто с проверкой наличия. Исправлено:

  • GPS.setHrOn(on) (gps.js): ON - проверяет BT (off -> запрос включения), коннектит привязанный датчик, запускает поллинг; OFF - стоп поллинг + disconnect. Безопасно: BleHrService при отсутствии браслета коротко сканит и stopSelf (драйна нет).
  • Старт записи (и GPS, и зарядки): если датчик привязан - авто setHrOn(true). Так "надел датчик -> начал -> подключился сам", без ручного коннекта каждый раз. Нет привязанного - ЧСС off.
  • Экран записи: кнопка "Ветер" убрана (неудобна), на её месте тоггл ЧСС (квадрат с сердечком+линией пульса; серый = выкл, красный = вкл), дёргает GPS.setHrOn.
  • Ручная кнопка "Подключить" в настройках остаётся.

Факт-чек (я ошибся ранее): на телефоне Google-сервисы ЕСТЬ (com.google.android.gms, Play Store) - значит системный диалог включения гео через Play Services доступен. Авто-вкл BT/гео по запросу (попап + 2 настройки "не спрашивать") - отдельная задача, теперь подтверждено выполнимо.

Проверка

Синтаксис JS ок. На телефоне: выбрать "Зарядка", Старт (без браслета покажет "Подключите пульсометр"), подключить датчик -> пульс крупно + ккал растут; Стоп -> деталь с графиком. Нужен BT на телефоне + привязанный датчик. (Сейчас BT на телефоне выключен.)