Skip to content

OpenVitals 2.1.0

github-actions[bot] edited this page Nov 9, 2026 · 1 revision

Released 2026-07-13.

This release is about the activities the app was throwing away. A treadmill run, a trainer ride, a strength session — anything recorded without GPS — was refused at the door as a broken file. It was not broken. It had no route, and the app had quietly decided those were the same thing.

Added

  • Import a whole folder of FIT files. Pick the folder; every FIT file inside it is imported, including the ones in the sub-folders where a watch buries them (GARMIN/ACTIVITY, and the like). A file that will not read fails on its own and the rest of the folder carries on. The files are opened one at a time as the import reaches them, so a folder holding a year of rides costs no more memory than the single largest ride in it.
  • TCX files. The format Strava and Garmin actually export an indoor activity as. The app could not open one at all, which is why a user reporting "GPX route must contain at least 2 timestamped location points" was so often holding a TCX: it is XML, so it fell through to the GPX reader, which found no track and blamed the file.
  • The elevation profile of an activity — where you climbed, not just how much. Health Connect has no elevation series (it stores one total for the session, so it can tell you that you climbed 240 m and never where), so the profile is drawn from the altitudes on the route itself.
  • A speed graph for an activity whose device recorded no speed — which is most watches. It is rebuilt from the splits, which knew each segment's distance and duration all along. It is drawn as a step, one flat run per split, because that is the resolution those numbers really have; a smooth curve would claim a precision they do not.

Fixed

  • Indoor activities could not be imported. Two separate faults, and every routeless FIT file hit the first one. A FIT file records total calories and has no active-calorie field, so the app filled the blank with an estimate — and stood that estimate next to the number the file had actually measured. A treadmill run arrived as 226 estimated active calories against its own recorded 208 total, Health Connect refuses a record whose total is below its active, and the import died. A guess was allowed to contradict a measurement. Now it is estimate both or estimate neither: a file that measured nothing still gets a full estimate, and a file that measured something is not second-guessed.
  • An indoor bike ride imported as a run. The app worked out what an activity was by mashing the sport, the name and the file name into one string and looking for words in it — testing "run" before "cycling". So Indoor_CyclingiSmoothRun.fit was read as a run, because the exporter's name is in the file name, and the file's own sport (which said cycling, and knew) was outvoted by it. A 27 km ride was saved as a run, with a runner's calorie estimate to match. The file's sport is now asked first, and on its own.
  • A stationary bike had nowhere to go. It is now an activity type of its own, so a trainer ride is no longer saved as an outdoor one. FIT names the indoor variants (treadmill, trainer, indoor rowing, strength) in a field the app had never read; it reads it now.
  • A GPX with no locations in it was refused. Real exporters write indoor sessions as GPX track points that carry a time, a heart rate and no coordinates at all — 1,931 of them for a strength session, in one of the files this was fixed against. The session was in the file the whole time: the timestamps give the start, the end and the duration, and the extensions give the heart rate. What such a file genuinely lacks is distance and calories, and those are not invented.
  • A GPX with a heart rate in it lost the heart rate, and imported as a bare line on a map.

A file with no locations and no timestamps is still refused, which is what keeps a corrupt download from arriving as a blank activity.

The app keeps the same package name and signing certificate, so this installs as a normal update.

Distribution flow:

  • Codeberg release with signed APK and signed Android App Bundle assets.
  • Direct Google Play production upload from the approved Woodpecker deployment.

Generated from docs/releases/2.1.0.md. Edit it there; changes made here are overwritten.

Home

Features

How-to

App

Reference

Engineering

Proposals

Releases

Project

Clone this wiki locally