VEU.WathBody/1-docs/4-modules/m12-watch-channel/module_reqs.md

201 lines
16 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Требования к модулю: m12-watch-channel
> Модуль — **WatchChannel** телефона `Phone.WatchBody` (архитектура
> разд. 1.2): приём live-пульса с часов Fenix 6X по штатной трансляции
> BLE (Heart Rate Service), статус связи, заряд (если передаётся),
> подача в экран «Тренировка» (m10), «Допуск» и запись среднего
> пульса тренировки (`avg_hr`, цепочка m09). Самодостаточная копия
> требований (d-dev-6). Источники: Ф-3.1–Ф-3.3 (статусная строка,
> пульс, таймер), Ф-13.2 (пульс сидя «с часов, если связаны»),
> Ф-2.4 (вибрация отдыха — errata, см. разд. 1.1), ОВ-3 (tech-req
> 3 п. 3, прототип 7 п. 1), ui-ux разд. 2.
## 1. Назначение и границы
Live-пульс на телефоне во время тренировки: часы Fenix 6X транслируют
пульс штатной функцией «Broadcast Heart Rate», телефон принимает и
показывает; отсутствие связи ничего не ломает (🛡 Ф-2.4, Ф-3.2 —
деградация молча, прочерки).
### 1.1. Транспорт: обоснование (errata ОВ-3)
ОВ-3 (tech-req 3 п. 3) предполагал companion-канал Connect IQ
Communications. Исследование 2026-10-19 показало, что на якорных
часах он нереализуем для живого пульса:
1. **Поля данных не имеют `Toybox.Communications` до API 5.0.0**,
а Fenix 6X навсегда остался на CIQ API ≤ 4.1.7 — поле данных
«Силовая» (Ф-2, m13) не может ни передавать, ни принимать.
2. **CIQ-приложение** (Communications доступен) не может работать
одновременно со штатной активностью «Силовая» — живой пульс
во время тренировки из приложения не транслировать; companion
SDK (`com.garmin.connectiq:ciq-companion-app-sdk`) для v1
неприменим.
3. **Штатная трансляция «Broadcast Heart Rate»** на fenix 6 серии
с прошивки июня 2020 идёт одновременно по ANT+ и BLE
(стандартный Heart Rate Service 0x180D; подтверждено на
Pro-линии — 6/6S/6X Pro; у базовой «шестёрки» 2022 г. сообщали
только ANT+). BLE-приём работает на любом Android без Garmin
Connect Mobile и без ANT-железа; канал односторонний
(часы → телефон).
4. Следствие для **Ф-2.4** (вибрация конца отдыха «по таймеру,
переданному с телефона»): передать секунды отдыха на часы
в v1 нечем — таймер отдыха на часах делает m13 **автономно**
(длительность — настройка поля данных в Garmin Connect Mobile,
умолчание = `Rest.DefaultSec` телефона). Таймер телефона (Ф-3.3)
работает независимо, как сейчас. Errata НД — разд. 5.
Критерий прототипа ОВ-3 (tech-req 7 п. 1 «пульс и таймер доходят
при экране часов активным») исполняется в части «пульс доходит»
(проверка на устройстве владельца); часть про таймер переносится
в m13 как автономная вибрация (errata 7 п. 1).
**В границах модуля:**
- **транспорт-интерфейс** `WatchTransport` + первая реализация —
**BLE-клиент** `HrBleClient` (требование владельца при утверждении
гейта 1.3, 2026-10-19: инфраструктура должна поддерживать и другие
умные часы): скан по UUID Heart Rate Service
(0x180D), подключение, подписка на изменения характеристики
Measurement (0x2A37, indications), разбор пакета (флаги: разрядность
8/16 бит, поля Energy/RR пропускаются), автопереподключение при
потере, чтение Battery Service (0x180F) при его наличии — иначе
заряд не показывается (Ф-3.1 «если передаётся»); интерфейс —
для unit-тестов на фейках и для будущих транспортов (CIQ 5+,
ANT+) без правок фасада и UI; только стандартные профили GATT,
платформо-специфичных UUID/имён/логики в коде нет — любые часы,
транслирующие стандартный Heart Rate Service, работают без
изменений кода; платформо-специчное — только тексты подсказок
включения трансляции в «Настройках» (расширяемый справочник
по производителям, v1 — Garmin);
- **буфер пульса** `HrSampleStore` (чистый, в памяти): сэмплы
(bpm, `t_offset_s` от старта тренировки), текущее значение,
среднее за тренировку, серия «последний подход» (сэмплы от
последнего записанного подхода до текущего момента — Ф-3.2
«линия за последний подход»), устаревание (> 10 с без сэмплов —
«нет данных», прочерк);
- **фасад** `WatchChannel`: состояние канала — `StateFlow` со
статусом (не выбраны / скан / связь есть / потеряна / Bluetooth
выключен / нет разрешения 🛡 текстом), текущим пульсом, зарядом,
серией последнего подхода и средним; жизненный цикл: канал активен,
пока открыты экраны «Тренировка» или «Допуск» (v1 — без
foreground-сервиса; пульс считается за время открытого экрана —
ограничение решения 5 гейта 1.3);
- **выбор устройства**: в «Настройках» блок «Часы» — скан, список
найденных пульс-датчиков (имя + адрес), выбор сохраняется
(`Watch.HrDeviceAddress` в DataStore); не задано — статус «часы
не выбраны», канал не сканирует; сброс выбора;
- **экран «Тренировка»** (интеграция m10, замена заглушек
WorkoutScreen: статус-строка): связь часов — зелёный/красный/
серый, дублируется текстом («часы: связь есть (заряд 80 %)» /
«часы: нет связи» / «часы: не выбраны»); пульс — крупное текущее
значение, окраска по зонам Танака (`ZoneCalculator` m10, границы
из `Hr.MaxBpm`), под значением — линия последнего подхода
(Canvas, серия буфера); при отсутствии/устаревании — прочерк,
голос и ручной ввод работают (Ф-1.1, Ф-3.2);
- **финиш тренировки**: `WorkoutCore.finishWorkout(avgHr = среднее
буфера)` — готовая цепочка m09 (`workout.avg_hr` → sync);
канал сам в БД не пишет;
- **экран «Допуск»** (Ф-13.2): если канал активен и есть свежий
сэмпл (≤ 30 с) — кнопка «взять с часов» подставляет пульс сидя
в поле допуска; иначе — ручной ввод пикером (как в m10);
- **разрешения Bluetooth**: Android 12+ — `BLUETOOTH_SCAN`
(neverForLocation) + `BLUETOOTH_CONNECT` (runtime); Android
8–11 — `ACCESS_FINE_LOCATION` (runtime) + `BLUETOOTH`/
`BLUETOOTH_ADMIN` (манифест); отказ в разрешении — статус
«нет разрешения», экран не блокируется (🛡);
- unit-тесты (pure JVM): разбор 0x2A37 (фикстуры байтов: 8/16 бит,
с полями Energy/RR), буфер (среднее, серия последнего подхода,
устаревание), статусные переходы фасада на фейках клиента.
**Вне границ модуля:** m13 поле данных (Monkey C — отображение,
зоны, автономный таймер отдыха с настройкой длительности;
мультитаргет-сборка по моделям — там же), дополнительные
реализации `WatchTransport` — ANT+-приём (плагин Garmin, нужен
ANT-транспорт в телефоне) и CIQ companion (часы с CIQ 5+) —
кандидаты v2 по мере появления устройств, foreground-фон пульса
при погашенном экране (v2),
запись live-сэмплов в LocalDb/sync (история пульса — из .fit,
m07/m08), пульсограмма всей тренировки на телефоне (Ф-5 —
карточка факт из .fit на сервере m08), wake-слова, смена устройства
голосом.
## 2. Решения интерфейса (ui-ux разд. 2, tech-req 6)
- Статусная строка часов не конкурирует с пульсом: статус — мелкой
строкой сверху, пульс — крупным значением (≥ 40 sp) в зоне пульса;
- статус и доступность связи дублируются текстом (🛡 цвет — только
дублирование, не единственный носитель);
- линия последнего подхода — без сеток и подписей, минимум чернил;
значение пульса — цифрой всегда;
- «взять с часов» на допуске — вторичная кнопка рядом с полем
«Пульс сидя», после нажатия значение видно в поле (правка
пикером сохраняется);
- блок «Часы» в «Настройках» — по образцу блока «Распознавание
речи» (m11): статус, действие, инструкция текстом («включите
Broadcast Heart Rate на часах»).
## 3. Инварианты (🛡 — нарушать запрещено)
1. **Офлайн-first**: приём пульса — локальный BLE, сеть и облако
не используются; сервер не участвует (БЦ-3, Ф-1.1).
2. **Деградация молча** (Ф-2.4, Ф-3.2): отсутствие часов, потери
связи, отказ разрешения, выключенный Bluetooth — только прочерки
и статус; тренировка, голос, ручной ввод и sync не блокируются.
3. **Канал не пишет в БД**: единственная точка записи —
`WorkoutCore.finishWorkout(avgHr)` (единственный писатель
LocalDb — инвариант m09); live-сэмплы никуда не сохраняются.
4. **Часы не зависят от телефона** (Ф-2.4 «не зависимость»):
телефон ничего не «требует» от часов; трансляцию включает сам
атлет на часах (инструкция в «Настройках»).
5. **Тайны**: BLE-адрес устройства хранится только в DataStore
телефона; в лог/журнал команд адреса не пишутся (З-6).
6. **Платформо-независимость канала** (указание владельца
2026-10-19): любые часы, транслирующие стандартный Heart Rate
Service, работают без изменений кода; Garmin/fenix-специфика
в коде запрещена; новые транспорты подключаются реализацией
`WatchTransport` без правок фасада, UI и БД; то же требование
наследуется m13 — мультитаргет-сборка поля данных по моделям
(vision 1.1, Ф-2.8).
## 4. Критерии приёмки модуля
1. `assembleDebug` собирается; unit-тесты (все, включая m09–m11)
зелёные.
2. Приёмка на устройстве владельца (Fenix 6X, см. инструкцию
в readme): включить «Broadcast Heart Rate» → «Настройки → Часы»
→ скан → выбрать часы → экран «Тренировка»: статус «связь есть»,
пульс обновляется ≈1 Гц при активном экране часов, линия
последнего подхода рисуется; финиш → `avg_hr` в записи
(История на телефоне, карточка в консоли m08 после sync);
«Допуск» → «взять с часов» подставляет пульс.
3. Отрицательные исходы: часы не выбраны / трансляция выключена /
Bluetooth выключен / отказ разрешения — прочерки и статус
текстом, приложение работает (ручной смок владельца).
4. Прототип ОВ-3 (tech-req 7 п. 1) — в части «пульс доходит при
экране часов активным»: подтверждается пунктом 2; фиксируется
в журнале приёмки владельца; часть «таймер» — errata, m13.
## 5. Errata НД (по утверждению гейта 1.3, решение 2; ВНЕСЕНА 2026-10-19)
- requirements **Ф-2.4**: «вибрация — конец таймера отдыха,
переданного с телефона» → «вибрация — конец автономного таймера
отдыха поля; длительность — настройка поля в Garmin Connect
(умолчание `Rest.DefaultSec`); передача с телефона — v2
(кандидат при смене часов на CIQ 5+)»;
- requirements **Ф-3.2**: источник пульса — «штатная трансляция
пульса часов (BLE Heart Rate Service; ОВ-3 закрыт: companion-
канал Connect IQ на fenix 6X недоступен для полей данных)»;
- tech-requirements **3 п. 3 (ОВ-3)**: описание канала фактически =
односторонняя штатная трансляция «Broadcast Heart Rate»
(BLE/ANT+), Garmin Connect Mobile для пульса не нужен;
- tech-requirements **7 п. 1**: критерий прототипа — «пульс
доходит на телефон при активном экране часов» (таймер —
автономный, проверяется в m13);
- architecture **1.1/1.2/3** (телефон↔часы): канал = BLE-приём
штатной трансляции, односторонний.
Волна правок НД вносится после «утверждаю» по гейту 1.3 одним
пакетом (без подъёма версий документов — errata в телах разделов,
версии поднимутся на ближайшем ревью).