GPS: safe on-device recovery, net-kcal model, poll/watchPosition dedup
- native_root(): pick app root by presence of gps_live/gps_points files. app_data_dir() is the root directly on this Tauri; the old .parent().parent() read the wrong dir, so background (screen-off) points were never imported. - recoverFromFiles: match file->session by id/date, plus session id stamped into the native file name (gps_points_<ms>_s<id>.jsonl) for exact binding (gps_set_session_id -> Kotlin bindSessionIfPending). Proximity dedup +-2.5s, recalc with noDelete (never runs the destructive glitch/>24h filter that once wiped real rides), delete already-imported files. Progress bar UI. - bike kcal is NET (daily balance already books BMR*activityLevel): pedaling = max(physics power/efficiency, MET-net by speed), coasting (power<=0, the bike would roll unpowered) = basal only. Elevation via cumulative hysteresis. recomputeAllStats + "recompute elevation/kcal" menu refresh stored tracks without touching points. - live recording: the native file is the DB source of truth; watchPosition only drives the live marker, so a fix is not stored twice with two timestamps. - track list pagination, SAF local-file picker, tile regions from router.
This commit is contained in:
parent
84a2b786ca
commit
56c2ff4ec7
12 changed files with 854 additions and 190 deletions
|
|
@ -23,7 +23,7 @@
|
|||
|------|-------|------------|
|
||||
| `js/main.js` | ~5800 | Экраны, навигация, модалки, графики, нутриенты, HR UI, компас (EMA + gimbal lock), ландшафт (3 режима), дороги |
|
||||
| `js/db.js` | ~1500 | SQLite через Tauri IPC. Миграции, CRUD, 41 поле добавок, water_pct, reserves, sync |
|
||||
| `js/gps.js` | ~1400 | GPS запись, физика ккал (power model), altitude filter, BLE HR polling, dead reckoning. Импорт нативных точек: JS-поллинг (экран-gated) + ПОЛНЫЙ до-импорт по множеству ts на «Стоп»/recoverSession (без потерь при экране-офф), отбор по точности (minAccuracyM), bearing_deg |
|
||||
| `js/gps.js` | ~1600 | GPS запись, ккал (нетто-модель + MET-нетто floor, накат=базовый), altitude filter + гистерезис высоты, BLE HR polling, dead reckoning. Источник истины БД при живой записи — нативный файл (`_processIncomingPoint(p, fromNative)`: watchPosition только рисует, поллинг пишет). `recoverFromFiles` — восстановление точек с устройства (матч по id/дате + `_s<id>` в имени, дедуп ±2.5с, `recalculateSession(noDelete)`, чистка импортированных файлов). `recomputeAllStats` — пересчёт статы всех треков без изменения точек. Отбор по точности (minAccuracyM), bearing_deg |
|
||||
| `js/sync.js` | ~300 | Синхронизация между устройствами (LAN, PHP сервер на роутере) |
|
||||
| `js/tilecache.js` | 178 | Оффлайн кэш тайлов карты (IndexedDB) |
|
||||
| `js/bmr.js` | ~70 | BMR (Mifflin-St Jeor), РСП из БД (33 нутриента), полураспад |
|
||||
|
|
@ -38,7 +38,7 @@
|
|||
|
||||
| Файл | Строк | Назначение |
|
||||
|------|-------|------------|
|
||||
| `src/lib.rs` | ~700 | Миграции v1, IPC команды, seed import, update check, tile import, road map rebuild |
|
||||
| `src/lib.rs` | ~750 | Миграции v1, IPC команды, seed import, update check, tile import, road map rebuild. `native_root()` — выбор корня приложения по наличию `gps_live_points.jsonl`/`gps_points_*` (на этом Tauri `app_data_dir()` = корень напрямую; старый `.parent().parent()` читал мимо, отсюда потеря фоновых точек) |
|
||||
| `src/ble.rs` | ~470 | BLE HR: btleplug (desktop), file IPC (Android), FitPro + Standard HR |
|
||||
| `src/main.rs` | 5 | Точка входа |
|
||||
| `Cargo.toml` | — | tauri, tauri-plugin-sql, rusqlite, serde, btleplug, tokio, uuid |
|
||||
|
|
@ -49,7 +49,7 @@
|
|||
| Файл | Строк | Назначение |
|
||||
|------|-------|------------|
|
||||
| `MainActivity.kt` | ~300 | FileObserver IPC, seed DB, safe insets, SAF, BLE commands, OTA check |
|
||||
| `GpsRecorderService.kt` | ~500 | Foreground service GPS, WakeLock, JSONL (один файл на сессию до Стоп, идемпотентный onStartCommand при START_STICKY-перезапуске ОС), 50Hz акселерометр/гироскоп, dead reckoning, raw sensor files |
|
||||
| `GpsRecorderService.kt` | ~530 | Foreground service GPS, WakeLock, JSONL (один файл на сессию до Стоп, идемпотентный onStartCommand при START_STICKY-перезапуске ОС; `bindSessionIfPending()` дописывает id сессии в имя файла `_s<id>` по `gps_session.txt`), 50Hz акселерометр/гироскоп, dead reckoning, raw sensor files |
|
||||
| `BleHrService.kt` | ~340 | Foreground service BLE HR, FitPro protocol, GATT queue, scan/connect |
|
||||
| `generated/*.kt` | ~1100 | Tauri-сгенерированные: WebView, IPC, permissions |
|
||||
|
||||
|
|
@ -146,7 +146,11 @@
|
|||
| `import_seed_products` | Импорт продуктов из seed DB, прогресс-события |
|
||||
| `get_safe_insets` | Отступы Android status/nav bar |
|
||||
| `gps_service_command` | start/stop GPS + BLE команды (ble_scan/connect/disconnect) |
|
||||
| `gps_service_read_points` | Чтение JSONL файла точек |
|
||||
| `gps_service_read_points` | Чтение активного JSONL файла точек (через `native_root`) |
|
||||
| `gps_set_session_id` | Передать id сессии сервису (пишет `gps_session.txt` → сервис дописывает `_s<id>` в имя файла) |
|
||||
| `list_points_files` / `read_points_file` / `delete_points_file` | Список/чтение/удаление нативных `gps_points_*` (восстановление + чистка) |
|
||||
| `get_points_filename` | Имя активного файла точек (по указателю `gps_live_points.jsonl`) |
|
||||
| `debug_native_paths` | Диагностика путей нативных файлов |
|
||||
| `save_file` | SAF диалог сохранения (GPX экспорт) |
|
||||
| `get_app_info` | Версия, git hash, дата сборки |
|
||||
| `get_update_info` | Проверка OTA обновления (BUILD_NUMBER с VPS) |
|
||||
|
|
@ -165,15 +169,21 @@
|
|||
|
||||
## Формула ккал (GPS)
|
||||
|
||||
### Велосипед — физическая модель
|
||||
### Велосипед — НЕТТО-модель (суточный баланс = intake − BMR*activityLevel − activity, поэтому активность считается СВЕРХ покоя)
|
||||
```
|
||||
Power = v * (m*g*sin(gradient) + Crr*m*g*cos(gradient) + 0.5*CdA*rho*v^2)
|
||||
m = rider_kg + bike_kg
|
||||
m = rider_kg + bike_kg; gradient из СГЛАЖЕННОЙ высоты
|
||||
Crr = 0.004 (асфальт) / 0.006 (смешанный) / 0.008 (грунт)
|
||||
CdA = 0.6, rho = 1.225, efficiency = 0.25
|
||||
|
||||
Power > 0: педалирование → kcal = power*dt / (0.25 * 4184)
|
||||
Power <= 0: каботаж → kcal = базальный метаболизм
|
||||
Педалирование (power>0): kcal = max(физика, MET-нетто), физика = power*dt/(0.25*4184)
|
||||
MET по скорости: <16км/ч=6.0, <19=6.8, <22=8.0, <25=10.0, <28=12.0, иначе 14.0
|
||||
MET-нетто = (dt/60)*((MET-1)*3.5*weight)/200 (−1 MET покоя, он уже в BMR)
|
||||
Floor только при v≥5км/ч (ниже — дрожание GPS, не езда)
|
||||
Накат / freewheel (power≤0, «велик катился бы сам»): kcal = базальный метаболизм
|
||||
(детектор кручу/накат по IMU-каденсу проверен на 50Hz — сигнал слишком слаб, не используется; хук cadence_rpm — под BLE-датчик шатуна)
|
||||
|
||||
Набор высоты: кумулятивный гистерезис (elevRef, порог 1м) — на плотных треках per-point разница <1м даёт 0
|
||||
```
|
||||
|
||||
### Ходьба/бег — MET-таблица
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue