{"id":15673945,"url":"https://github.com/michael-simons/garmin-babel","last_synced_at":"2025-07-21T16:32:28.901Z","repository":{"id":139303907,"uuid":"571757259","full_name":"michael-simons/garmin-babel","owner":"michael-simons","description":"Tooling for the archive created by Garmin datamanagement.","archived":false,"fork":false,"pushed_at":"2025-07-14T07:26:03.000Z","size":3370,"stargazers_count":21,"open_issues_count":0,"forks_count":1,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-07-14T10:00:01.320Z","etag":null,"topics":["garmin"],"latest_commit_sha":null,"homepage":"","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/michael-simons.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2022-11-28T20:26:30.000Z","updated_at":"2025-07-14T07:26:05.000Z","dependencies_parsed_at":"2023-11-09T12:57:30.478Z","dependency_job_id":"36dbf1dd-15c7-4d9f-a03f-1c27ae230f5d","html_url":"https://github.com/michael-simons/garmin-babel","commit_stats":{"total_commits":142,"total_committers":2,"mean_commits":71.0,"dds":"0.37323943661971826","last_synced_commit":"4ea372d94e49add06eac3580edda4827b36f4987"},"previous_names":[],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/michael-simons/garmin-babel","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/michael-simons%2Fgarmin-babel","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/michael-simons%2Fgarmin-babel/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/michael-simons%2Fgarmin-babel/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/michael-simons%2Fgarmin-babel/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/michael-simons","download_url":"https://codeload.github.com/michael-simons/garmin-babel/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/michael-simons%2Fgarmin-babel/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":266334170,"owners_count":23912906,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-07-21T11:47:31.412Z","response_time":64,"last_error":null,"robots_txt_status":null,"robots_txt_updated_at":null,"robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["garmin"],"created_at":"2024-10-03T15:43:09.354Z","updated_at":"2025-07-21T16:32:28.883Z","avatar_url":"https://github.com/michael-simons.png","language":"Java","funding_links":[],"categories":[],"sub_categories":[],"readme":"# garmin-babel\n\nA Java program to massage Garmin data exported via [Garmin GDPR management](https://www.garmin.com/de-DE/account/datamanagement)\ninto usable CSV files for further processing.\n\n⚠️ This program is not in any way, shape or form associated, supported or sponsored by Garmin. \nIt's a personal project suiting my needs. It may or may not be helpful to other people.\n\n## Installation\n\nFor copy\u0026pasting the examples further down, you need to either build this tool yourself or pick one of the pre-build artifacts fitting your operating system and architecture.\n\n### Pre-build artifacts\n\nI have a limited, untested set of packages for various operating systems on the [release page](https://github.com/michael-simons/garmin-babel/releases).\nThey come either as plain Java distribution requiring a locally installed JDK, with batteries included (that is, with a JDK for a specific operating system and architecture) or as a native distribution not requiring a JDK at all. You can use them as follows (the example is based on the plain Java distribution):\n\n```bash\nmkdir -p target\ncd target\ncurl -LO https://github.com/michael-simons/garmin-babel/releases/download/early-access/garmin-babel-1.0.0-SNAPSHOT.zip\nunzip garmin-babel-1.0.0-SNAPSHOT.zip \u0026\u0026 mv garmin-babel-1.0.0-SNAPSHOT garmin-babel\ncd - \n./target/garmin-babel/bin/garmin-babel --version\n```\n\nℹ️ All archives with _native_ in their name can be run standalone, without a Java virtual machine. The ones with an operating system in their name are custom JVM bundles and OS specific. In case your operating system is not in the list, grab the one named `garmin-babel-x.y.z.zip`. That one requires [OpenJDK](https://adoptium.net/de/) or any other Java 17 installed.\n\n### Building the tool yourself\n\nYou need Java 24 or higher installed to build the program. Build should be quite fast, there are no tests ;)\n\n```bash\n./mvnw clean package -no-transfer-progress\nunzip -q target/artifacts/garmin-babel-*.zip -d target/garmin-babel\n./target/garmin-babel/bin/garmin-babel --version\n```\n\nIf you want to build a native binary for an architecture and operating system for which no binaries are available, you need to install [GraalVM](https://www.graalvm.org), including native-image and run the following:\n\n```bash\n./mvnw clean package -Dnative -pl app\nmkdir -p target/garmin-babel/bin \u0026\u0026 mv ./app/target/garmin-babel target/garmin-babel/bin\n./target/garmin-babel/bin/garmin-babel --version\n```\n## Usage\n\n### Activities\n\nThe `dump-activities` command requires a username (your Garmin username), as recorded in the archive:\n\n#### Dump all\n\nThe following will export all activities into a csv file.\n\n```bash\n./target/garmin-babel/bin/garmin-babel \\\n   ~/tmp/Garmin_Archive \\\n   dump-activities \\\n   --user-name=michael.simons \\\n   target/demo/activities.csv\n```\n\n#### Filtering\n\n##### Filter by date and type\n\nThe date filters are generally available, the types are only for the activities\n\n```bash\n./target/garmin-babel/bin/garmin-babel \\\n  --start-date=2022-01-01 --end-date=2022-02-01 ~/tmp/Garmin_Archive \\\n  dump-activities \\\n  --user-name=michael.simons \\\n  --sport-type=CYCLING,SWIMMING\n```\n\n##### Combining filters\n\nGet all runs longer than 15km prior to second half of 2022, displace speed as pace, use MySQL format\n\n```bash\n./target/garmin-babel/bin/garmin-babel \\\n  --csv-format=MySQL --speed-to-pace --end-date=2022-07-01 ~/tmp/Garmin_Archive \\\n  dump-activities \\\n  --user-name=michael.simons \\\n  --sport-type=RUNNING \\\n  --min-distance=15 \\\n  target/demo/long-runs.csv\n```\n\nGet all cycling activities longer than 75km prior to second half of 2022, prepared for loading into MySQL\n\n```bash\n./target/garmin-babel/bin/garmin-babel \\\n  --csv-format=MySQL --end-date=2022-07-01 ~/tmp/Garmin_Archive \\\n  dump-activities \\\n  --user-name=michael.simons \\\n  --sport-type=CYCLING \\\n  --activity-type=road_biking,gravel_cycling,cycling,mountain_biking,virtual_ride,indoor_cycling \\\n  --min-distance 75 \\\n  target/demo/long-rides.csv\n```\n\n#### Change units\n\n```bash\n./target/garmin-babel/bin/garmin-babel \\\n  --start-date=2022-01-01 --end-date=2022-01-10 --unit-distance=metre --speed-to-pace \\\n  ~/tmp/Garmin_Archive \\\n  dump-activities \\\n  --user-name=michael.simons \\\n  --sport-type=RUNNING\n```\n\n#### Downloading activities\n\n⚠️ There is no guarantee whatsoever that this feature keeps working. It's basically doing the same what a user would manually click the download link on Garmin Connect. I added a bit of jitter when downloading things to not hammer the service like bot would do, but use this feature of the tool on your own risk!\n\nWhile all activities are actually contained in the GDPR archive dump I didn't find any indicator which file belongs to which activity. This is sad, as I wanted to have them for my personal archive, at least some of them (Yes, I can go through the devices or the Garmin Connect page, but you know ;)).\n\nDo download things you have to log in to [Garmin Connect](https://connect.garmin.com). Once done, open your Browsers developer tools and find the cookie jar. Find a cookie named `JWT_FGP` and copy its value.\n\nExport it in your shell like this:\n\n```bash\nexport GARMIN_JWT=jwt_token_from_your_cookie_store_for_garmin\n```\n\nThen in the _network_ tab of your Browsers developer tools (name might be different), clear all requests (or leave them, if you really want to search to the ton of requests the UI does). Then go to [activities](https://connect.garmin.com/modern/activities) for example and look in the requests tab for a request to `activities`. Look for something that says `HEADER` and in those headers look for `Authorization: Bearer ` and copy that (very long) very long header and export it, too.\n\n```bash\nexport GARMIN_BACKEND_TOKEN=long_gibberish_token_from_one_of_the_requests\n```\n\n\u003e [!TIP]\n\u003e There's a script in the `bin` folder that automates this process. \n\u003e The script emulates a browser flow and does all the things for you, but there's absolutely no guarantee that it will keep on working when Garmin chances Connect-\n\u003e In a regular shell you would use it like `source retrieve_garmin_tokens.sh \u003cusername\u003e \u003cpassword\u003e`.\n\u003e The script requires `cURL` and `jq`.\n\nThen, the `--download` option can be used like this:\n\n```bash\n./target/garmin-babel/bin/garmin-babel \\\n  --csv-format=MySQL --speed-to-pace --end-date=2022-07-01 ~/tmp/Garmin_Archive \\\n  dump-activities \\\n  --user-name=michael.simons \\\n  --sport-type=RUNNING \\\n  --min-distance=15 \\\n  --download=fit \\\n  target/demo/long-runs.csv\n```\n\n#### Fun with SQL\n\nFor aggregating I recommend importing the CSV data into a proper database.\n[DuckDB](https://duckdb.org) is a pretty good choice for online analytics, even in memory.\nHere are two examples that I found useful:\n\n##### Getting the 10 fastest long runs\n\n```bash\n./target/garmin-babel/bin/garmin-babel ~/tmp/Garmin_Archive dump-activities --user-name=michael.simons |\nduckdb -s \"\n  WITH\n   runs AS (\n     SELECT name, 3600.0/avg_speed AS pace, distance\n     FROM read_csv_auto('/dev/stdin')\n     WHERE sport_type = 'RUNNING'\n       AND distance \u003e 20\n   ),\n   paced_runs AS (\n     SELECT name, distance, cast(floor(pace/60) AS int) || ':' || cast(floor(pace%60) AS int) AS pace FROM runs\n   )\n  SELECT dense_rank() OVER (ORDER BY pace ASC) AS rnk, name, distance, pace\n  FROM paced_runs\n  QUALIFY rnk \u003c= 10\n\"\n```\n\n##### What gear did I use the most\n\nNote: If you have more than one item used per activity, the following want work:\n\n```bash\n./target/garmin-babel/bin/garmin-babel ~/tmp/Garmin_Archive dump-activities --user-name=michael.simons |\nduckdb -s \" \n  WITH\n    cycle_activities AS (\n      SELECT *\n      FROM read_csv_auto('/dev/stdin')\n      WHERE (sport_type = 'CYCLING' OR activity_type in ('road_biking', 'gravel_cycling', 'cycling', 'mountain_biking', 'virtual_ride', 'indoor_cycling'))\n        AND gear IS NOT NULL AND gear \u003c\u003e ''\n    ),\n    totals AS (\n      SELECT sum(moving_duration) AS duration, sum(distance) AS distance, gear\n      FROM cycle_activities\n      GROUP by gear\n    )\n  SELECT gear,\n         cast(floor(distance) AS integer) AS distance,\n         cast(floor(duration/3600) AS integer) || ':' || cast(floor(duration%3600/60) AS integer) || ':' || cast(floor(duration%3600%60) as integer) AS duration\n  FROM totals\n  ORDER BY totals.duration DESC\n\"\n```\n\n##### Distribution of mileages\n\n```bash\n./target/garmin-babel/bin/garmin-babel ~/tmp/Garmin_Archive dump-activities --user-name=michael.simons |\nduckdb -s \"\n  WITH \n    cycle_activities AS (\n      SELECT distance\n      FROM read_csv_auto('/dev/stdin')\n      WHERE (sport_type = 'CYCLING' OR activity_type in ('road_biking', 'gravel_cycling', 'cycling', 'mountain_biking', 'virtual_ride', 'indoor_cycling'))\n        AND gear IS NOT NULL AND gear \u003c\u003e ''\n    ),\n    distances AS (\n      SELECT CASE\n        WHEN distance \u003e= 300 THEN '1. More than 300km'\n        WHEN distance \u003e= 200 THEN '2. More than 200km'\n        WHEN distance \u003e= 100 THEN '3. More than 100km'\n        WHEN distance \u003e=  75 THEN '4. More than 75'\n        ELSE '5. Between 0 and 75' END AS value\n      FROM cycle_activities\n    )\n  SELECT substr(value, 4) || ': ' || count(*) || ' times' AS times FROM distances\n  GROUP BY value\n  ORDER BY value ASC\n\"\n```\n\n##### Working with spatial data\n\nSpatial you say? DuckDb has you covered: [PostGEESE? Introducing The DuckDB Spatial Extension](https://duckdb.org/2023/04/28/spatial.html).\n\nLet's create a proper database first, with an actual table holding the activities:\n\n```bash\n./target/garmin-babel/bin/garmin-babel ~/tmp/Garmin_Archive dump-activities --user-name=michael.simons |\nduckdb -s \"\n  INSTALL spatial;\n  LOAD spatial;\n  CREATE TABLE IF NOT EXISTS activities (\n     garmin_id BIGINT, name VARCHAR(256), started_on TIMESTAMP, activity_type VARCHAR(32), sport_type VARCHAR(32), distance NUMERIC, elevation_gain NUMERIC, avg_speed NUMERIC, max_speed NUMERIC, duration NUMERIC, elapsed_duration NUMERIC, moving_duration NUMERIC, v_o_2_max NUMERIC, start_longitude DECIMAL(12,8), start_latitude DECIMAL(12,8), end_longitude DECIMAL(12,8), end_latitude DECIMAL(12,8), gear VARCHAR(256),\n     PRIMARY KEY(garmin_id)\n  );\n  INSERT INTO activities SELECT * FROM read_csv_auto('/dev/stdin');\n  ALTER table activities ADD COLUMN track GEOMETRY;\n\" target/activities.db\n```\n\nNow download some data (follow the instructions for downloading above):\n\n```bash\n./target/garmin-babel/bin/garmin-babel ~/tmp/Garmin_Archive dump-activities --user-name=michael.simons \\\n  --sport-type=CYCLING \\\n  --activity-type=road_biking,gravel_cycling,cycling,mountain_biking,virtual_ride,indoor_cycling \\\n  --min-distance 75 \\\n  --download=gpx \\\n  target/activities/long-rides.csv\n./target/garmin-babel/bin/garmin-babel ~/tmp/Garmin_Archive dump-activities --user-name=michael.simons \\\n  --sport-type=RUNNING \\\n  --min-distance=15 \\\n  --download=gpx \\\n  target/activities/long-runs.csv\n```\n\nAs the downloads are not one big shape file containing all tracks as features, we must query all GPX files manually.\nLet's create a SQL script todo this, ofc with DuckDB CLI:\n\n```bash\nduckdb --noheader -list -s \"\nSELECT 'UPDATE activities ' ||\n       'SET track = (' ||\n       'SELECT ST_FlipCoordinates(geom) FROM st_read(''target/activities/' || garmin_id  || '.gpx'', layer=''tracks'')' ||\n       ') WHERE garmin_id = '|| garmin_id || ';'\nFROM activities\nWHERE (sport_type = 'RUNNING' AND distance \u003e= 15)\n  OR (sport_type = 'CYCLING' AND distance \u003e= 75 AND activity_type IN ('road_biking','gravel_cycling','cycling','mountain_biking','virtual_ride','indoor_cycling'));\n\" target/activities.db \u003e target/load_tracks.sql\nduckdb -s \"INSTALL spatial; LOAD spatial;\" -s \".read target/load_tracks.sql\" target/activities.db\n```\n\n\u003e [!WARNING]\n\u003e For whatever reason the coordinates had been in the wrong order when I read from the GPX file without applying `ST_FlipCoordinates` with DuckDB 0.8. This might maybe no longer necessary in 1.0.\n\nNow let's answer the question, through which German communities did I ran and ride the most?\nGermany offers a lot of spatial data for free, for example the [Verwaltungsgebiete](https://gdz.bkg.bund.de/index.php/default/digitale-geodaten/verwaltungsgebiete.html).\nLet's grab them:\n\n```bash\nrm -rf target/verwaltungsgebiete \u0026\u0026 mkdir -p target/verwaltungsgebiete \u0026\u0026 \\\ncurl https://daten.gdz.bkg.bund.de/produkte/vg/vg250_ebenen_0101/aktuell/vg250_01-01.utm32s.shape.ebenen.zip | \\\nbsdtar xvf - --strip-components=1 -C target/verwaltungsgebiete\n```\nI picked the 1:250000 in the UTM32s (EPSG:25832) reference system (see [Georeferenzierungen](https://gdz.bkg.bund.de/index.php/default/georeferenzierungen/)) which is close enough to WGS84.\nThe following query demonstrates the spatial extension of DuckDB by transforming UTM32s into WGS-84 and then computing a join based on the intersection of two geometries:\n\n```bash\nduckdb -s \".mode markdown\" -s \"\n  LOAD spatial;\n  WITH gemeinden AS (\n    SELECT gen AS gemeinde,         \n           ST_transform(geom), 'EPSG:25832', 'EPSG:4326') geom\n    FROM st_read('./target/verwaltungsgebiete/vg250_ebenen_0101/VG250_GEM.shp')\n  ),\n  intersections AS (\n    SELECT gemeinde, \n           round(sum(St_length(ST_transform(St_Intersection(track, geom), 'EPSG:4326', 'EPSG:25832'))) / 1000) as km\n    FROM activities JOIN gemeinden g ON St_Intersects(track, geom)\n    WHERE track IS NOT NULL\n    GROUP BY gemeinde\n  )\n  SELECT dense_rank() OVER (ORDER BY km DESC) as rnk, \n         gemeinde, \n         km\n  FROM intersections\n  QUALIFY rnk \u003c= 10\n  ORDER BY rnk, gemeinde;\n\" target/activities.db\n```\n\nThis is probably dated soon, but I like the result very much: My top 10 communities by kilometers ran or cycled in them:\n\n| rnk |     gemeinde     |   km   |\n|-----|------------------|--------|\n| 1   | Aachen           | 2800.0 |\n| 2   | Stolberg (Rhld.) | 1093.0 |\n| 3   | Simmerath        | 803.0  |\n| 4   | Jülich           | 349.0  |\n| 5   | Hürtgenwald      | 314.0  |\n| 6   | Eschweiler       | 278.0  |\n| 7   | Würselen         | 237.0  |\n| 8   | Düren            | 224.0  |\n| 9   | Monschau         | 211.0  |\n| 10  | Aldenhoven       | 193.0  |\n\nYou might ask why transforming back to _ETRS89 / UTM zone 32N_ by `ST_transform(St_Intersection(track, geom), 'EPSG:4326', 'EPSG:25832')` before calling `St_length`? Because the latter computes the length in units of the reference system and WGS-84 doesn't use meters.\n\nYou can also export spatial data, creating new feature files.\nHere I use the GeoJSON driver:\n\n```sql\nCOPY(\n    WITH gemeinden AS (\n        SELECT gen AS gemeinde,\n               ST_transform(ST_GeomFromWKB(wkb_geometry), 'EPSG:25832', 'EPSG:4326') geom\n        FROM st_read('./target/verwaltungsgebiete/vg250_ebenen_0101/VG250_GEM.shp')\n        WHERE gemeinde = 'Aachen'\n      )\n    SELECT St_AsWKB(St_FlipCoordinates(St_Intersection(track, geom))),\n           strftime(started_on, '%x') AS done_on,\n           sport_type,\n           distance::double AS distance\n    FROM activities JOIN gemeinden g ON St_Intersects(track, geom)\n    WHERE track IS NOT NULL\n)\nTO 'docs/example/rides_and_runs_in_aachen.geojson'\n WITH (FORMAT GDAL, DRIVER 'GeoJSON');\n```\n\nThe result can be viewed on [GeoJSON.io](http://geojson.io/#id=github:michael-simons/garmin-babel/blob/main/docs/example/rides_and_runs_in_aachen.geojson\u0026map=10.88/50.7477/6.0948):\n\n![image](docs/example/rides_and_runs_in_aachen.jpg)\n\n### Gear\n\nExporting all your gear:\n\n```bash\n./target/garmin-babel/bin/garmin-babel ~/tmp/Garmin_Archive \\\n  dump-gear \\\n  --user-name=michael.simons\n```\n\n### Fitness data \n\n#### All fitness data\n\nYou can use the bash script [`bin/export_fitness_metrics.sh`](./bin/export_fitness_metrics.sh) to export a broad range of your fitness data stored in the Garmin Archive, including daily resting heart rate, weights, fitness age, VO2Max etc.\nUse it like this:\n\n```\n./bin/export_fitness_metrics.sh ~/tmp/Garmin_Archive \u003e fitness_data.csv\n```\n\nThe script exports the following fields:\n\n|    column_name     | column_type  | null |\n|--------------------|--------------|------|\n| ref_date           | DATE         | NO   |\n| chronological_age  | BIGINT       | YES  |\n| biological_age     | DECIMAL(5,2) | YES  |\n| weight             | DECIMAL(5,2) | YES  |\n| body_fat           | DECIMAL(5,2) | YES  |\n| resting_heart_rate | BIGINT       | YES  |\n| vo2max_biometric   | DECIMAL(5,2) | YES  |\n| vo2max_running     | DECIMAL(5,2) | YES  |\n| vo2max_cycling     | DECIMAL(5,2) | YES  |\n| avg_stress_level   | BIGINT       | YES  |\n| min_heart_rate     | BIGINT       | YES  |\n| max_heart_rate     | BIGINT       | YES  |\n| body_water         | DECIMAL(5,2) | YES  |\n| bone_mass          | DECIMAL(5,2) | YES  |\n| muscle_mass        | DECIMAL(5,2) | YES  |\n| lowest_spo2_value  | BIGINT       | YES  |\n\n#### Weights\n\nThe original `garmin-babel` has a dedicated option for exporting the weights alone.\nUse this if you don't want DuckDB.\n\n##### Exporting\n\nThe following will export weights prior to a given date, in kg, to a file name `weights.csv`, formatted for MySQL:\n\n```bash\n./target/garmin-babel/bin/garmin-babel \\\n  --csv-format=mysql --unit-weight=kilogram --end-date=2022-07-01 ~/tmp/Garmin_Archive \\\n  dump-weights \\\n  target/demo/weights.csv\n```\n\n##### Loading\n\nAs it is possible to store multiple weight measurements per day, you need to filter that file afterward.\nHere, I do this by a unique constraint in MySQL while loading:\n\n```sql\nCREATE TABLE IF NOT EXISTS weights_in(measured_on date, value DECIMAL(6,3), unique(measured_on));\nLOAD DATA LOCAL INFILE 'target/demo/weights.csv'\nINTO TABLE weights_in\nIGNORE 1 LINES\n(@measured_on, value)\nSET measured_on = date(str_to_date(@measured_on, '%Y-%m-%dT%H:%i:%sZ'))\n;\n```\n\n## Other tooling for (Garmin) FIT files\n\n* The official Garmin FIT SDK: https://developer.garmin.com/fit/overview/, the exports of `FIT CSV Tool` are a great fit for DuckDB analytics; the tool works well as GraalVM native image, too (`native-image -jar FitCSVTool.jar` gives you a nice standalone executable)\n* Rusty, but fit: https://github.com/meistermeier/rusty-but-fit Gerrits tool (and library) for parsing FIT data\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmichael-simons%2Fgarmin-babel","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmichael-simons%2Fgarmin-babel","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmichael-simons%2Fgarmin-babel/lists"}