3.2 KiB
Спецификация 01: FitParser — канонический факт workout-facts/1
Источники: tech-req 2.3, Ф-8.2, Ф-13.4. SDK — Garmin.FIT.Sdk
(NuGet 21.218.0), namespace Dynastream.Fit, событийный
Decode.MesgEvent.
1. Сигнатура
public sealed record FitFacts(
string FactsJson, // workout-facts/1, разд. 2
DateTime StartedAt, // session start (UTC)
int? AvgHr, // среднее records.hr (округление AwayFromZero)
int? HrRecoveryS, // разд. 3
string FitFileId, // file_idmesg.time_created (UTC ISO) + серийник
string Device); // device_infomesg (продукт/версия) или ""
Parse(string path) — файл читается один раз (потоково,
tech-req 5); Decode.CheckIntegrity перед разбором; кривой файл →
FitException (обрабатывает ImportService — spec 04).
2. Схема JSON
{"schema": "workout-facts/1",
"session": {"type": "strength_training", "start": "2026-10-18T18:00:00Z",
"duration_s": 3600},
"laps": [{"index": 0, "start": "...", "duration_s": 120}],
"records": [{"t_offset_s": 0, "hr": 95}],
"sets": [{"index": 0, "reps": 12, "weight_kg": 100.0}],
"fit_file_id": "...", "device": "..."}
| Сообщение | Что берём |
|---|---|
FileIdMesg |
TimeCreated (UTC) + SerialNumber → fit_file_id ("{serial}-{yyyyMMddTHHmmssZ}"); оба пусты → имя файла |
SessionMesg |
Sport/SubSport (строкой), StartTime, TotalTimerTime → duration_s (сек, округление) |
LapMesg |
index по порядку, StartTime, TotalTimerTime |
RecordMesg |
Timestamp → t_offset_s (от session start), HeartRate (есть и > 0) |
SetMesg |
index по порядку, NumReps, Weight (кг; 0xFFFF/0 — нет) |
DeviceInfoMesg |
последний (свежий) Product/GarminProduct → device (строкой) |
- Session нет →
FitException(файл не активность). sets/laps/recordsпустые → пустые массивы (не null).- Тип сессии — как есть строкой (
strength_training,cardio, …); фильтра по типу импорт не делает (решает сопоставление).
3. hr_recovery_s (Ф-13.4)
Конец последнего Lap (start + duration) → первый Record строго
после него с hr < 90 (порог Safety.RestingHrSitting — конфиг,
Р3-А): hr_recovery_s = t_offset(record) − конец последнего lap в offset. Нет записей после последнего Lap или не опустился → null.
4. Тест-фикстуры
Генерируются в тестах энкодером SDK (Encode, Mesg-объекты в
прямом порядке FileId → DeviceInfo → Record* → Lap* → Set* → Session):
полная активность (3 рекорда до/1 после Lap с hr < 90, Set с
reps/weight), активность без Set, битый файл (усечённый байтовый
массив).