A fitness balance app with calories calculator (consumed+burnt), extensive mapping/routing capabilities route for your walks and bike rides
Find a file
4aiman 542bb5c376 rec screen: rename wind button 'Ветер в лицо' -> 'Ветер'
Shorter label on the recording screen; docs (README, PROJECT_MAP) updated to match.
2026-09-09 17:04:04 +03:00
docs Map: dark-map toggle (invert tiles only), no repacking 2026-09-09 13:33:05 +03:00
frontend rec screen: rename wind button 'Ветер в лицо' -> 'Ветер' 2026-09-09 17:04:04 +03:00
src GPS point ordering + GPX export + chart zoom fixes 2026-05-16 21:21:13 +03:00
src-tauri BRouter: download segments from own mirror (LAN->WAN->upstream) 2026-09-09 11:48:50 +03:00
tools/brouter-web brouter-web: broaden dark theme (sidebar tabs, inputs, dropdowns, elevation chart text/footer) 2026-09-09 16:51:58 +03:00
.gitignore Chestny Znak scanner: DataMatrix -> National Catalog КБЖУ prefill 2026-08-27 03:27:15 +03:00
data.js GPS point ordering + GPX export + chart zoom fixes 2026-05-16 21:21:13 +03:00
IMPLEMENTATION_PLAN.md POI overlay on maps: circular contrasting icons + category filter (offline) 2026-09-09 16:51:58 +03:00
index.html GPS point ordering + GPX export + chart zoom fixes 2026-05-16 21:21:13 +03:00
LICENSE-brouter BRouter: analysis + embed the offline routing engine (Stage 1) 2026-09-09 00:56:13 +03:00
package-lock.json GPS point ordering + GPX export + chart zoom fixes 2026-05-16 21:21:13 +03:00
package.json Initial commit: BalDav health tracker 2026-05-13 10:21:24 +03:00
PROJECT_MAP.md rec screen: rename wind button 'Ветер в лицо' -> 'Ветер' 2026-09-09 17:04:04 +03:00
README.md rec screen: rename wind button 'Ветер в лицо' -> 'Ветер' 2026-09-09 17:04:04 +03:00

BalDav

Персональный трекер здоровья и физической активности.

Возможности

  • Дневник питания — ~13000 продуктов с меткой источника (Магнит, 5ка, ИОН, KDV, Гриднев, свои). Поиск порядко-независимый (слова в любом порядке). Каталог чистится от неиспользованного импорта без метки (health-diet и пр.) кнопкой в настройках — съеденные и в рецептах сохраняются. 37 нутриентов (витамины, минералы, omega-3/6, вода, клетчатка). Рецепты с термообработкой. Формулы порций (4*30, 300+50).
  • GPS трекинг — запись маршрутов на велосипеде/пешком в фоне (foreground service, точки пишутся при выключенном экране; один файл на сессию с id сессии в имени gps_points_<ms>_s<id>.jsonl для однозначной привязки, переживает START_STICKY-перезапуск ОС; полный до-импорт нативных точек по timestamp при финализации — без потерь, даже если экран был выключен всю запись, а при пробуждении экрана точки видимо нарастают на карте по мере импорта). При живой записи нативный файл — источник истины для БД, watchPosition только рисует маркер (без дублей одного фикса с разными ts). Восстановление точек из файлов на устройстве — матч файла к сессии по id/дате, дозаполнение разрывов с дедупом по близости ±2.5с, безопасный пересчёт без удаления точек, чистка уже импортированных файлов. Оффлайн карты (Leaflet + IndexedDB кэш). Импорт GPX/FTB (FitoTrack). Экспорт GPX. Фильтр altitude outlier'ов и GPS-залипаний. Отбор точек по точности (жёсткий порог по настройке «Мин. точность» — рубит грубые сотовые фиксы ~800м, оставляет слабый но точный GPS; где сигнала нет — честный разрыв). Направление (bearing) каждой точки пишется в БД. Вращение карты по компасу (leaflet-rotate, EMA-сглаживание, gimbal lock компенсация) и course-up по GPS-курсу (в ландшафте карта доворачивается вместе с экраном — курс к физическому верху). Ландшафтный режим (CSS rotation + панель справа, 3 режима: off/auto/lock). Dead reckoning при потере GPS (гироскоп + акселерометр). Placeholder до GPS (пиксельарт). Карта проезженных дорог (дедупликация 2м, вело/пешие). Настраиваемый цвет линии трека (чтобы отличать от цветных дорог). Навигационный маркер позиции с треугольником-направленцем (по компасу или GPS-курсу); порядок слоёв тайлы<дороги<маршрут<трек<маркер. Импорт тайлов по регионам (SQLite, роутер LAN).
  • BLE пульсометр — подключение к FitPro браслетам и стандартным HR датчикам (0x180D). ЧСС, SpO2, давление в реальном времени при записи трека.
  • Расчёт ккал — велосипед: НЕТТО-модель (суточный баланс уже учитывает BMR, поэтому активность считается сверх покоя). Кручение = max(физика мощности из gradient+Crr+CdA / КПД, эмпирический MET-нетто по скорости); накат (freewheel, power≤0 — «велик катился бы сам») = только базовый обмен. Crr на грунтах уточняется по вибрации акселерометра (до 0.020 на траве/колее). Ходьба с велосипедом в горку (только односкоростной) отделяется автоматически по скорости ниже каденса 30 об/мин и не засчитывается как езда. MET-таблица для ходьбы/бега и тренировок (приседания 6.0, скакалка 12.3, растяжки 2.3, бассейн 8.0). Набор высоты — кумулятивный гистерезис (устойчив на плотных треках, где per-point разница <1м); абсолютная точность набора ограничена сырым GPS-альтиметром (порядка десятков процентов, без модели рельефа не разрешается). Известное ограничение: max(физика, MET) не складывает накладные расходы, поэтому подъёмы по ккал слегка недосчитываются. Пункт меню «Пересчитать высоту/калории» пересчитывает статистику всех треков без изменения точек. Профили велосипедов. BMR по Mifflin-St Jeor с коэффициентом активности.
  • Дистанция на разрывах GPS — на «слепых» участках (интервал между фиксами > gapThresholdSec) путь считается по скорости (speed×dt, с ограничением по макс. скорости), а не прямой хордой — иначе разрывы занижают/искажают длину. Телепорт-скачки без временного разрыва отбрасываются. Расчёт зависит только от времени и скорости, поэтому live-счётчик, «Стоп» и пересчёт дают одинаковую длину. Порог gapThresholdSec настраивается; при изменении и пересчёте применяется сразу.
  • Тренировки — приседания (подходы x повторения), скакалка, растяжки, бассейн (дистанция). Автоматический расчёт ккал по MET и весу.
  • Нутриенты — 37 микронутриентов (витамины, минералы, жирные кислоты, женьшень, ресвератрол, CoQ10). Нормы РСП/АУП (РФ/ЕС/США). Фармакокинетика — запасы в организме по полураспаду.
  • Трекинг жидкости — water_pct в продуктах, прогресс-бар, настраиваемая норма.
  • Графики — скорость, высота, ЧСС тренировки с зумом и pan. Тренд веса. Донат макронутриентов. Баланс ккал (приход/расход).
  • OTA обновления — проверка BUILD_NUMBER на роутере (LAN) или VPS, скачивание через браузер.
  • Ручные маршруты — рисование трека на карте тапами, elevation из прошлых треков или open-meteo API.
  • Сохранённые маршруты — импорт GPX-маршрутов, нарисованных заранее (например, в конструкторе Яндекс.Карт: формат <rtept>), выбор активного, наложение цветной линией поверх карты во время записи И на экране просмотра прошлого трека — для визуальной навигации. Управление на отдельной странице (импорт/переименование/цвет/удаление, один активный за раз), переключение линии кнопкой-тогглом. Цвета «проезженных дорог» настраиваются раздельно для вело/пеших/бега.
  • Высоты маршрута (рельеф до поездки) — экран предпросмотра маршрута (тап по названию): профиль высоты (крутые участки красным), длина/набор/сброс/макс. уклон, тап по точке — высота и уклон, разворот карты на весь экран. Топографическая обводка линии с тогглом уклон/высота: уклон дискретными полосами по 1% (зелёный→жёлтый→красный→коричневый→чёрный, ≥10% чёрный) или гипсометрия по высоте (зелёный→жёлтый→коричневый). Обводка и тоггл доступны и в оверлее на карте записанного трека и во время записи; маршрут рисуется ПОД треком. Высоты (<ele> из GPX или онлайн) тянутся по цепочке: GPXZ (Copernicus GLO-30, точнее для уклонов; ключ в GPS-настройках, хранится только на устройстве) → open-elevation → open-meteo → OpenTopoData (без ключа). Калории пересчитываются по сглаженным точкам; для уклона высоты сглаживаются (гасит вертикальный шум SRTM).
  • Редактор маршрутов — создание («Новый маршрут») и правка сохранённого маршрута прямо в приложении: тап по карте — добавить точку в конец, тап по линии — вставить точку в это место, тащить точку — двигать, тап по точке — удалить. Высоты подтягиваются онлайн после отрисовки (из предпросмотра).
  • Де-джиттер трека — сглаживание дрожащего GPS-трека методом Савицкого-Голея (настраиваемое окно/число итераций, живое превью на карте детали трека). Хранится обратимо: оригинал и сглаженный вариант лежат раздельно, калории пересчитываются по сглаженным точкам, откат к оригиналу в один тап. Точность каждого фикса (accuracy_m) пишется в БД: при пересчёте трека точки хуже порога «Макс. погрешность GPS» исключаются из расчёта и линии (обратимо — точки в БД остаются; поднять порог = вернуть). Работает во всех пересчётах (кнопка «Пересчитать», «Пересчитать всё», после де-джиттера); импорт/старьё без точности и dead-reckoning заполнения не трогает.
  • POI на карте — точки интереса (кафе, магазины, вода, туалеты, банки/ATM, остановки, укрытия, смотровые и т.д.) круглыми контрастными значками (эмодзи в кружке, читаемо на светлой и тёмной карте). Кнопка 📍 с панелью-фильтром категорий; рендер по видимой области от зума 13. Данные оффлайн (data/pois.json, ~100 км вокруг город, 5662 объекта из OSM/Overpass). На картах записи, деталей трека и дорог.
  • Тёмная карта — тумблер ☾ на экранах записи, деталей трека и дорог: инвертирует ТОЛЬКО слой тайлов (invert + hue-rotate 180° + brightness, трек/маршрут/дороги остаются цветными), выбор запоминается. Работает одинаково на офлайн-тайлах и онлайне, без ключей/квот/перепаковки.
  • Метки ветра — кнопка «Ветер» на экране записи: тап открывает интервал встречного ветра, тап закрывает. Метки хранятся с треком (wind_marks) как эталон для проверки оценки ветра по треку; на расчёт калорий/мощности не влияют. Голосовые метки — на будущее.
  • Экспорт/импорт — свои продукты, рецепты и добавки одним файлом (JSON).
  • Вес, сон, добавки — логирование с историей.

Стек

  • Frontend: чистый JavaScript, HTML, CSS. Без React/Vue/bundler.
  • Backend: Rust (Tauri 2) — SQLite, IPC, seed import, BLE (btleplug на десктопе).
  • Android: Kotlin — foreground GPS service, BLE HR service, WakeLock, SAF.
  • Библиотеки: Leaflet 1.9.4 (карты), leaflet-rotate (компас), Chart.js (графики), Hammer.js (жесты), JSZip.

Сборка

# Зависимости: Rust, Node.js, Android SDK + NDK
./build.sh -d android       # debug APK
./build.sh android          # release APK
./build.sh -i android -d    # debug + установка на устройство
./build.sh -u android       # release + upload на роутер (LAN) и VPS (OTA)
./build.sh -d -i -u android # debug + install + upload

Версия и трассируемость сборки

Чтобы по розданному APK однозначно находить, где регресс/косяк:

  • versionName 0.1.NNN — монотонный BUILD_NUMBER (инкремент на каждой сборке в build.sh), первичный уникальный идентификатор билда. Виден в Настройках и в свойствах пакета Android.
  • git-хэш коммита исходников зашивается в бинарник при компиляции (src-tauri/build.rs → GIT_HASH) и показывается в Настройках: v0.1.NNN (<hash>) <дата>. Хэш всегда свежий (build.rs перезапускается при смене коммита через cargo:rerun-if-changed), с суффиксом -dirty, если отслеживаемый код (frontend/, src-tauri/src/) не закоммичен.
  • Хэш = HEAD на момент компиляции. build.sh бампает версию, но НЕ коммитит, поэтому в dev-сборке хэш = последний коммит, а код может быть впереди (тогда -dirty). Для раздачи: закоммить код перед release-сборкой — тогда хэш чистый и APK точно соответствует коммиту.

Решение о точном встроенном хэше принято на коммите b4fdc824144 (ветка master, 2026-08-16).

Структура

Подробно: PROJECT_MAP.md

frontend/
  js/main.js          — UI, навигация, модалки, компас, ландшафт (~5500 строк)
  js/db.js            — БД, миграции, CRUD (~1500)
  js/gps.js           — GPS, физика ккал, BLE HR polling (~1200)
  js/bmr.js           — BMR формула, РСП, полураспад нутриентов
  js/sync.js          — синхронизация между устройствами (LAN)
  js/tilecache.js     — оффлайн тайлы (IndexedDB)
  css/styles.css      — стили, тёмная тема, ландшафтный режим
  img/gps-placeholder.png — пиксельарт заглушка до GPS
  data/products_seed.db — 13480 продуктов
src-tauri/
  src/lib.rs          — Rust бэкенд, seed import
  src/ble.rs          — BLE HR (btleplug десктоп, file IPC Android)
  gen/android/        — Kotlin: MainActivity, GpsRecorderService, BleHrService
tools/
  5ka_scraper.user.js — Tampermonkey скрейпер 5ка
  magnit_scraper.user.js — Tampermonkey скрейпер Магнит
  ion_scraper.user.js — Tampermonkey скрейпер ИОН
smart/
  protocol.js         — FitPro BLE протокол (reverse-engineered)
  hr-reader.js        — Node.js прототип чтения ЧСС

Данные продуктов

Каталог (seed) очищен от импорта без метки источника (health-diet, ашан, фастфуд) — остаются источники с плашкой:

Источник Продуктов Витамины/минералы
Магнит (SSR парсинг) 7690 нет
5ка (API скрейпер) 3354 нет
ИОН (web.ion.ru) 1079 да
KDV (SSR парсинг) 667 нет
Гриднев (PDF) 217 да
Свои (manual) — по вводу
Всего (seed) ~13000

На устройстве такая же чистка — кнопка «Очистить продукты без магазина» в настройках (удаляет только неиспользованные без метки; съеденные/в рецептах остаются).