VEU.WathBody/1-docs/4-modules/m12-watch-channel
virus-home d4867acefd m12-watch-channel (итерация 5): live-пульс с Fenix 6X — errata ОВ-3: companion-канал Connect IQ нереализуем на fenix 6X (CIQ ≤4.1.7, Communications в полях данных с API 5.0), транспорт = штатная трансляция «Broadcast Heart Rate» (BLE Heart Rate Service, односторонний, без GCM/ANT-железа) за интерфейсом WatchTransport — мультичасовая инфраструктура (указание владельца: любые часы со стандартной трансляцией, CIQ 5+/ANT+ — будущие реализации); таймер отдыха на часах автономный (Ф-2.4 errata, настройка поля, умолчание Rest.DefaultSec); ядро: HrBleClient (скан 0x180D→indications 0x2A37, оба поколения GATT-колбэков, батарея 0x180F опц., автопереподключение 1/5/30 с) + HrPacketParser + HrSampleStore + фасад WatchChannel (статусы/avgHr/freshHr/series, в БД не пишет) + WatchFormat + DeviceScanner; UI: статус-строка и блок пульса 44sp+зона+Canvas-линия последнего подхода на «Тренировке», finishWorkout(avgHr)→sync avg_hr, «Взять с часов» (≤30 с) на «Допуске», блок «Часы» (скан 15 с/выбор/забыть/инструкция) в «Настройках», 5 BLE-разрешений; unit 89/89 (m12 +26), APK 57,3 МБ; errata НД: requirements Ф-2.4/Ф-3.2/ОВ-реестр№3, tech-req 3п.3+7п.1, architecture 1.1/1.2/3/1.4; BLE на устройстве — приёмка владельца 2026-10-19 14:08:54 +05:00
..
api_specs m12-watch-channel (итерация 5): live-пульс с Fenix 6X — errata ОВ-3: companion-канал Connect IQ нереализуем на fenix 6X (CIQ ≤4.1.7, Communications в полях данных с API 5.0), транспорт = штатная трансляция «Broadcast Heart Rate» (BLE Heart Rate Service, односторонний, без GCM/ANT-железа) за интерфейсом WatchTransport — мультичасовая инфраструктура (указание владельца: любые часы со стандартной трансляцией, CIQ 5+/ANT+ — будущие реализации); таймер отдыха на часах автономный (Ф-2.4 errata, настройка поля, умолчание Rest.DefaultSec); ядро: HrBleClient (скан 0x180D→indications 0x2A37, оба поколения GATT-колбэков, батарея 0x180F опц., автопереподключение 1/5/30 с) + HrPacketParser + HrSampleStore + фасад WatchChannel (статусы/avgHr/freshHr/series, в БД не пишет) + WatchFormat + DeviceScanner; UI: статус-строка и блок пульса 44sp+зона+Canvas-линия последнего подхода на «Тренировке», finishWorkout(avgHr)→sync avg_hr, «Взять с часов» (≤30 с) на «Допуске», блок «Часы» (скан 15 с/выбор/забыть/инструкция) в «Настройках», 5 BLE-разрешений; unit 89/89 (m12 +26), APK 57,3 МБ; errata НД: requirements Ф-2.4/Ф-3.2/ОВ-реестр№3, tech-req 3п.3+7п.1, architecture 1.1/1.2/3/1.4; BLE на устройстве — приёмка владельца 2026-10-19 14:08:54 +05:00
SKILL.md m12-watch-channel (итерация 5): live-пульс с Fenix 6X — errata ОВ-3: companion-канал Connect IQ нереализуем на fenix 6X (CIQ ≤4.1.7, Communications в полях данных с API 5.0), транспорт = штатная трансляция «Broadcast Heart Rate» (BLE Heart Rate Service, односторонний, без GCM/ANT-железа) за интерфейсом WatchTransport — мультичасовая инфраструктура (указание владельца: любые часы со стандартной трансляцией, CIQ 5+/ANT+ — будущие реализации); таймер отдыха на часах автономный (Ф-2.4 errata, настройка поля, умолчание Rest.DefaultSec); ядро: HrBleClient (скан 0x180D→indications 0x2A37, оба поколения GATT-колбэков, батарея 0x180F опц., автопереподключение 1/5/30 с) + HrPacketParser + HrSampleStore + фасад WatchChannel (статусы/avgHr/freshHr/series, в БД не пишет) + WatchFormat + DeviceScanner; UI: статус-строка и блок пульса 44sp+зона+Canvas-линия последнего подхода на «Тренировке», finishWorkout(avgHr)→sync avg_hr, «Взять с часов» (≤30 с) на «Допуске», блок «Часы» (скан 15 с/выбор/забыть/инструкция) в «Настройках», 5 BLE-разрешений; unit 89/89 (m12 +26), APK 57,3 МБ; errata НД: requirements Ф-2.4/Ф-3.2/ОВ-реестр№3, tech-req 3п.3+7п.1, architecture 1.1/1.2/3/1.4; BLE на устройстве — приёмка владельца 2026-10-19 14:08:54 +05:00
module_reqs.md m12-watch-channel (итерация 5): live-пульс с Fenix 6X — errata ОВ-3: companion-канал Connect IQ нереализуем на fenix 6X (CIQ ≤4.1.7, Communications в полях данных с API 5.0), транспорт = штатная трансляция «Broadcast Heart Rate» (BLE Heart Rate Service, односторонний, без GCM/ANT-железа) за интерфейсом WatchTransport — мультичасовая инфраструктура (указание владельца: любые часы со стандартной трансляцией, CIQ 5+/ANT+ — будущие реализации); таймер отдыха на часах автономный (Ф-2.4 errata, настройка поля, умолчание Rest.DefaultSec); ядро: HrBleClient (скан 0x180D→indications 0x2A37, оба поколения GATT-колбэков, батарея 0x180F опц., автопереподключение 1/5/30 с) + HrPacketParser + HrSampleStore + фасад WatchChannel (статусы/avgHr/freshHr/series, в БД не пишет) + WatchFormat + DeviceScanner; UI: статус-строка и блок пульса 44sp+зона+Canvas-линия последнего подхода на «Тренировке», finishWorkout(avgHr)→sync avg_hr, «Взять с часов» (≤30 с) на «Допуске», блок «Часы» (скан 15 с/выбор/забыть/инструкция) в «Настройках», 5 BLE-разрешений; unit 89/89 (m12 +26), APK 57,3 МБ; errata НД: requirements Ф-2.4/Ф-3.2/ОВ-реестр№3, tech-req 3п.3+7п.1, architecture 1.1/1.2/3/1.4; BLE на устройстве — приёмка владельца 2026-10-19 14:08:54 +05:00
readme.md m12-watch-channel (итерация 5): live-пульс с Fenix 6X — errata ОВ-3: companion-канал Connect IQ нереализуем на fenix 6X (CIQ ≤4.1.7, Communications в полях данных с API 5.0), транспорт = штатная трансляция «Broadcast Heart Rate» (BLE Heart Rate Service, односторонний, без GCM/ANT-железа) за интерфейсом WatchTransport — мультичасовая инфраструктура (указание владельца: любые часы со стандартной трансляцией, CIQ 5+/ANT+ — будущие реализации); таймер отдыха на часах автономный (Ф-2.4 errata, настройка поля, умолчание Rest.DefaultSec); ядро: HrBleClient (скан 0x180D→indications 0x2A37, оба поколения GATT-колбэков, батарея 0x180F опц., автопереподключение 1/5/30 с) + HrPacketParser + HrSampleStore + фасад WatchChannel (статусы/avgHr/freshHr/series, в БД не пишет) + WatchFormat + DeviceScanner; UI: статус-строка и блок пульса 44sp+зона+Canvas-линия последнего подхода на «Тренировке», finishWorkout(avgHr)→sync avg_hr, «Взять с часов» (≤30 с) на «Допуске», блок «Часы» (скан 15 с/выбор/забыть/инструкция) в «Настройках», 5 BLE-разрешений; unit 89/89 (m12 +26), APK 57,3 МБ; errata НД: requirements Ф-2.4/Ф-3.2/ОВ-реестр№3, tech-req 3п.3+7п.1, architecture 1.1/1.2/3/1.4; BLE на устройстве — приёмка владельца 2026-10-19 14:08:54 +05:00

readme.md

m12-watch-channel — план работ (d-dev)

Модуль: WatchChannel — приём live-пульса с Fenix 6X по штатной трансляции BLE (Heart Rate Service), статус связи/заряд, подача в «Тренировку»/«Допуск», avg_hr при финише. Транспорт-обоснование и errata ОВ-3/Ф-2.4 — module_reqs.md разд. 1.1/5. Алгоритм: std1\_rules\d\d-dev.md. Зависимости: m09 (WorkoutCore/finishWorkout(avgHr), DataStore — DONE), m10 (экраны «Тренировка»/«Допуск»/«Настройки», ZoneCalculator — DONE), m11 (DONE; независимо). Часы: Fenix 6X (якорь, владелец, 2026-10-19).

Шаг Что делаем Статус
0 Модульные документы: module_reqs.md / readme.md / SKILL.md ✅ 2026-10-19
1 Список единиц (BLE-клиент/буфер/фасад/UI×3/разрешения/тесты) ✅ 2026-10-19
1.3 Пользователь! утверждение списка (+ решения по транспорту и errata Ф-2.4) ✅ 2026-10-19 (+ указание: инфраструктура мультичасовых сборок)
2 Спецификации: api_specs (BLE-клиент/буфер/фасад, UI×3, payload — без изменений контракта) ✅ 2026-10-19 (01-transport+BLE, 02-store, 03-facade, 04-UI)
2.4 Пользователь! утверждение спецификаций ✅ 2026-10-19
3 Реализация + тесты + сборка ✅ 2026-10-19
3.4 Пользователь! утверждение реализации (закрытие модуля) ✅ 2026-10-19
4 Завершение: план, примечания, волна errata НД ✅ 2026-10-19

Статусы: ⬜ не начат · 🔄 в работе · ✅ готов.

Список единиц (шаг 1)

# Единица Что делает
1 WatchTransport + HrBleClient транспорт-интерфейс (события/статусы, мультичасовая инфраструктура — решение 6) + BLE-реализация: скан по UUID 0x180D, подключение, indications 0x2A37, разбор пакета (8/16 бит, Energy/RR пропуск), автопереподключение, Battery Service (0x180F) при наличии
2 HrSampleStore чистый буфер в памяти: сэмплы (bpm, t_offset_s), текущее/среднее/серия «последний подход», устаревание >10 с
3 WatchChannel (фасад) StateFlow статуса (не выбраны/скан/связь/потеря/BT-выкл/нет разрешения 🛡 текстом) + пульс + заряд + серия; активен при открытых экранах «Тренировка»/«Допуск»
4 UI «Тренировка» статус-строка часов (зелёный/красный/серый + текст, заряд), крупный пульс с окраской по зонам Танака, линия последнего подхода (Canvas), прочерки при отсутствии; finishWorkout(avgHr=среднее)
5 UI «Допуск» кнопка «взять с часов» при свежем сэмпле ≤30 с → поле «Пульс сидя» (Ф-13.2)
6 UI «Настройки» блок «Часы»: скан/список/выбор (Watch.HrDeviceAddress), статус, сброс, инструкция «включите Broadcast Heart Rate»
7 Разрешения BLUETOOTH_SCAN(neverForLocation)+BLUETOOTH_CONNECT (12+, runtime), ACCESS_FINE_LOCATION+BLUETOOTH/BLUETOOTH_ADMIN (8–11); отказ — статус, не блок
8 WorkoutCore.finishWorkout(avgHr) подстановка среднего из канала при финише (цепочка m09 готова: workout.avg_hr → sync avg_hr)
9 unit-тесты парсер 0x2A37 (байтовые фикстуры), буфер (среднее/серия/устаревание), фасад на фейках (переходы статусов)

Решения на гейт 1.3 (для владельца)

  1. Транспорт live-пульса — рекомендуем (а): штатная трансляция «Broadcast Heart Rate» Fenix 6X, приём по BLE (стандартный Heart Rate Service; работает на любом Android, Garmin Connect Mobile не нужен; трансляция ANT++BLE на Pro-линии fenix 6 — прошивка июня 2020). Альтернативы: (б) ANT+-плагин Garmin — нужен ANT-транспорт в телефоне (Samsung до S20 или USB-стик), в v1 не реализуем (кандидат v2); (в) CIQ companion SDK — живой пульс не даёт: поле данных на fenix 6X без Communications (CIQ ≤ 4.1.7 < 5.0), CIQ-приложение не работает во время штатной активности.
  2. Errata Ф-2.4 / ОВ-3 — таймер отдыха на часах автономный (длительность — настройка поля в Garmin Connect, умолчание Rest.DefaultSec); с телефона в v1 не передаётся (канал односторонний). Пакет правок НД — module_reqs разд. 5, вносится после утверждения.
  3. Заряд часов — из Battery Service, если трансляция его exposing; иначе прочерк (Ф-3.1 «если передаётся» допускает).
  4. Хранение live-пульса — только в памяти: буфер линии последнего подхода + среднее в workout.avg_hr при финише; сэмплы в LocalDb/sync не пишутся (история пульса — из .fit m07/m08), схема БД и sync-контракт не меняются.
  5. Жизненный цикл канала — активен при открытых экранах «Тренировка»/«Допуск» (foreground-сервис — кандидат v2); среднее считается за время работы канала (ограничение фиксируется в readme приёмки).
  6. Мультичасовая инфраструктура (указание владельца при утверждении гейта 1.3, 2026-10-19) — транспорт скрывается за интерфейсом WatchTransport (BLE-реализация — первая; CIQ 5+/ANT+ — реализациями того же интерфейса, без правок фасада/UI/БД); в коде только стандартные профили GATT, без Garmin/fenix-специфики — любые часы со стандартной BLE-трансляцией пульса работают без изменений; платформо- специфичные тексты подсказок — расширяемый справочник (v1 — Garmin). Требование наследуется m13: мультитаргет- сборка по моделям/разрешениям (vision 1.1, Ф-2.8).

Примечания по ходу работ

  1. Волна errata НД внесена (2026-10-19, после «утверждаю» гейта 1.3): requirements Ф-2.4/Ф-3.2 + реестр открытых вопросов № 3, tech-req 3 п. 3 (ОВ-3) + 7 п. 1, architecture 1.1/1.2/3/1.4 — транспорт = штатная BLE-трансляция «Broadcast Heart Rate», канал односторонний, таймер отдыха на часах автономный, WatchTransport-интерфейс (мультичасовая инфраструктура). Версии документов не поднимались (ближайшее ревью).

  2. Исследование канала (2026-10-19, веб): fenix 6X — CIQ API max 4.1.7 (Communications в полях данных — с API 5.0.0, только foreground); BLE HR-броадкаст fenix 6 серии — firmware 2020 (DCRainmaker, проверено на 6 Pro — Pro-линия 6X); Android companion SDK жив (com.garmin.connectiq:ciq-companion-app-sdk, Maven Central) — для v1 неприменим (см. решение 1).

  3. Инструкция включения трансляции (для приёмки, по руководству Garmin): на часах — виджет пульса → удержание MENU → «Heart Rate Options» → «Broadcast During Activity» = Вкл (или разовый «Broadcast Heart Rate» перед тренировкой).

  4. BLE-адрес часов при «Broadcast Heart Rate» виден как обычный пульс-датчик; в зале возможны чужие HRM — выбор устройства в «Настройках» обязателен (не авто-first-found).

  5. Состав реализации (app/src/main/java/com/watchbody/phone/watch/, 7 файлов): WatchTransport.kt (интерфейс + TransportEvent/Status

    • ReconnectPolicy 1/5/30 c + BleProfiles — только стандартные UUID), HrPacketParser.kt (0x2A37, 8/16 бит, Energy/RR пропуск, диапазон 30–250), HrSampleStore.kt, HrBleClient.kt (скан по 0x180D → connectGatt → indications 0x2A37; оба поколения GATT-колбэков — 33+ и <33; батарея 0x180F опционально; приёмник ACTION_STATE_CHANGED; автопереподключение), WatchChannel.kt (фасад: StateFlow статусов, bind/unbind/dispose, avgHr/ freshHr/series/clearSamples, тикер устаревания 2 с), WatchFormat.kt (тексты/зоны/подписи — чистые), WatchPermissions.kt (+ AndroidChannelEnvironment), DeviceScanner.kt (скан 15 с для «Настроек»). Интеграция: AppSettings.watchHrDeviceAddress (DataStore), контейнер (watchChannel + deviceScanner), WorkoutScreen (статус-строка m12, строка NO_PERMISSION+«Разрешить», HrBlock 44 sp с зоной и Canvas-линией, finish→avgHr+clear, bind/ unbind/ребинд при возврате разрешения), AdmissionScreen («Взять с часов» + подпись причины), SettingsScreen (блок «Часы»: скан/ список/тап-выбор/«Забыть»/инструкция), манифест — 5 разрешений (SCAN neverForLocation, CONNECT, BLUETOOTH/ADMIN ≤30, ACCESS_FINE_LOCATION).
  6. Сборка/тесты: BUILD SUCCESSFUL; unit 89/89 (m12 +26: парсер 7, буфер 6, фасад 9 — включая ReconnectPolicy, формат 4); APK 57,3 МБ (рост на ~0 — доминируют JNI Vosk из m11).

  7. Уточнения по ходу (спеки не меняют наблюдаемое поведение): NO_PERMISSION вычисляет фасад, в TransportStatus не входит (спека 01 ставила его в транспорт); добавлен WatchChannel.dispose() — полная остановка для тестов (в проде канал живёт с контейнером).

  8. Не проверено в среде (нет телефона/часов в контуре агента): живой BLE-приём с Fenix 6X, батарея через Battery Service, реальный скан, runtime-разрешения — критерии 2–4 приёмки на стороне владельца; логика покрыта фейками и байтовыми фикстурами.