{"id":18391764,"url":"https://github.com/mkuthan/garmin-workouts","last_synced_at":"2025-04-07T03:33:45.628Z","repository":{"id":45472813,"uuid":"237306408","full_name":"mkuthan/garmin-workouts","owner":"mkuthan","description":"Command line tool for managing Garmin workouts.","archived":false,"fork":false,"pushed_at":"2024-02-26T07:39:20.000Z","size":147,"stargazers_count":58,"open_issues_count":4,"forks_count":12,"subscribers_count":5,"default_branch":"main","last_synced_at":"2024-02-26T08:44:35.621Z","etag":null,"topics":["cycling","garmin","python","workout"],"latest_commit_sha":null,"homepage":"","language":"Python","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/mkuthan.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","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}},"created_at":"2020-01-30T21:10:19.000Z","updated_at":"2024-04-15T09:45:07.468Z","dependencies_parsed_at":"2024-02-26T08:48:37.647Z","dependency_job_id":null,"html_url":"https://github.com/mkuthan/garmin-workouts","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mkuthan%2Fgarmin-workouts","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mkuthan%2Fgarmin-workouts/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mkuthan%2Fgarmin-workouts/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mkuthan%2Fgarmin-workouts/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/mkuthan","download_url":"https://codeload.github.com/mkuthan/garmin-workouts/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247589451,"owners_count":20963018,"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","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":["cycling","garmin","python","workout"],"created_at":"2024-11-06T01:53:12.402Z","updated_at":"2025-04-07T03:33:45.359Z","avatar_url":"https://github.com/mkuthan.png","language":"Python","funding_links":[],"categories":["Miscellaneous"],"sub_categories":["Older resources"],"readme":"# Garmin Connect Workouts Tools\n\n[![CI](https://github.com/mkuthan/garmin-workouts/actions/workflows/ci.yml/badge.svg)](https://github.com/mkuthan/garmin-workouts/actions/workflows/ci.yml)\n[![codecov](https://codecov.io/gh/mkuthan/garmin-workouts/branch/master/graph/badge.svg?token=ZC7VITLNHF)](https://codecov.io/gh/mkuthan/garmin-workouts)\n\nCommand line tools for managing Garmin Connect workouts.\n\nFeatures:\n\n* Target power is set according to Your current FTP.\n* All workouts under Your control stored as JSON files.\n* Easy to understand workout format, see examples below.\n* Workout parts like warm-up or cool-down are reusable.\n* Schedule saved workouts\n* The most important parameters (TSS, IF, NP) embedded in workout description field.\n\n## Installation\n\nRequirements:\n\n* Python 3.x ([doc](https://www.python.org/downloads/))\n\nClone this repo:\n\n```shell\ngit clone https://github.com/mkuthan/garmin-workouts.git\n```\n\nUse the venv command to create a virtual copy of the entire Python installation.:\n\n```shell\ncd garmin-workouts\npython3 -m venv venv\n```\n\nSet your shell to use the venv paths for Python by activating the virtual environment:\n\n```shell\nsource venv/bin/activate\n```\n\nInstall dependencies:\n\n```shell\npip3 install -r requirements.txt\n```\n\n## Usage\n\nFirst call to Garmin Connect takes some time to authenticate user.\nOnce user is authenticated [cookie jar](https://docs.python.org/3/library/http.cookiejar.html) is created with session\ncookies for further calls.\nIt is required due to strict request limits for Garmin [SSO](https://en.wikipedia.org/wiki/Single_sign-on) service.\n\n### Authentication\n\nDefine Garmin connect account credentials as `GARMIN_USERNAME` and `GARMIN_PASSWORD` environment variables:\n\n```shell\nexport GARMIN_USERNAME=username\nexport GARMIN_PASSWORD=password\n```\n\nAlternatively use `-u` and `-p` command line arguments:\n\n```shell\npython -m garminworkouts -u [USERNAME] -p [PASSWORD]\n```\n\n### Import Workouts\n\nImport workouts into Garmin Connect from definitions in [YAML](https://yaml.org) files.\nIf the workout already exists it will be updated:\n\n```shell\npython -m garminworkouts import --ftp [YOUR_FTP] 'sample_workouts/*.yaml'\n```\n\nSample workout definition:\n\n```yaml\nname: \"Boring as hell but simple workout\"\n\nsteps:\n  - { power: 50, duration: \"10:00\" }\n  - { power: 70, duration: \"20:00\" }\n  - { duration: \"5:00\" }\n  - { power: 70, duration: \"20:00\" }\n  - { power: 50 }\n```\n\n* Target power is defined as percent of FTP (provided as mandatory command line parameter).\nIf the target power is not specified \"No target\" will be used for the workout step.\n* Target power may be defined as absolute value like: \"150W\", it could be useful in FTP ramp tests.\n* Duration is defined as HH:MM:SS (or MM:SS, or SS) format.\nIf the duration is not specified \"Lap Button Press\" will be used to move into next workout step.\n\nReusing workout definitions:\n\n```yaml\nname: \"Boring as hell but simple workout\"\n\nsteps:\n  - !include inc/warmup.yaml\n  - { power: 70, duration: \"20:00\" }\n  - { duration: \"5:00\" }\n  - { power: 70, duration: \"20:00\" }\n  - !include inc/cooldown.yaml\n```\n\n* `!include` is a custom YAML directive for including another file as a part of the workout.\n\nReusing workout steps:\n\n```yaml\nname: \"Boring as hell but simple workout\"\n\nsteps:\n  - !include inc/warmup.yaml\n  - \u0026INTERVAL { power: 70, duration: \"20:00\" }\n  - { duration: \"5:00\" }\n  - *INTERVAL\n  - !include inc/cooldown.yaml\n```\n\n* Thanks to YAML aliases, workout steps can be easily reused once defined.\n\nSample Over-Under workout:\n\n```yaml\nname: \"OverUnder 3x9\"\n\nsteps:\n  - !include inc/warmup.yaml\n  - \u0026INTERVAL\n    - \u0026UNDER { power: 95, duration: \"2:00\" }\n    - \u0026OVER { power: 105, duration: \"1:00\" }\n    - *UNDER\n    - *OVER\n    - *UNDER\n    - *OVER\n    - { power: 50, duration: \"3:00\" }\n  - *INTERVAL\n  - *INTERVAL\n  - !include inc/cooldown.yaml\n```\n\n* All nested sections are mapped as repeated steps in Garmin Connect.\nFirst repeat for warmup, second repeat for main interval (repeated 3 times) and the last one for cool down.\n\nTo import your workout from an `xlsx` file, construct a table in Excel that looks like this (making sure that all Excel\ncells are set to text and not to date or any other format):\n\n| Start | End | Duration |\n|-------|-----|----------|\n| 43    | 85  | 3:00     |\n| 85    |     | 15:00    |\n| 85    | 43  | 2:00     |\n\nIf your \"start\" and \"end\" power for a step differ, a ramp of 10 seconds steps will be created by default for the chosen\nduration. If more than 50 total steps are to be uploaded ramp's steps will get longer so that the total number of steps\nis under Garmin maximum value of 50. **TIPS** *Do not use your TACX without the power cable as your Garmin will have a\nhard time controlling the trainer while changing from one step to the next. Turn off the tones in your Garmin.* If you\nwish to give your values in W instead of % of your FTP:\n\n| Start | End  | Duration |\n|-------|------|----------|\n| 80W   | 160W | 3:00     |\n| 160W  |      | 15:00    |\n| 160W  | 80W  | 2:00     |\n\nYou can then import as with the `yaml` files:\n\n```shell\npython -m garminworkouts import --ftp [YOUR_FTP] my.workout.xlsx\n```\n\nThis will generate a `yaml` file with the name `my.workout.xlsx`. The name of the workout will be \"my.workout\".\n\n### Export Workouts\n\nExport all workouts from Garmin Connect into local directory as FIT files.\nThis is the easiest way to synchronize all workouts with Garmin device:\n\n```shell\npython -m garminworkouts export /mnt/GARMIN/NewFiles\n```\n\n### List Workouts\n\nPrint summary for all workouts (workout identifier, workout name and description):\n\n```shell\n$ python -m garminworkouts list\n188952654 VO2MAX 5x4           FTP 214, TSS 80, NP 205, IF 0.96\n188952362 TEMPO 3x15           FTP 214, TSS 68, NP 172, IF 0.81\n188952359 SS 3x12              FTP 214, TSS 65, NP 178, IF 0.83\n188952356 VO2MAX 5x3           FTP 214, TSS 63, NP 202, IF 0.95\n188952357 OU 3x9               FTP 214, TSS 62, NP 188, IF 0.88\n188952354 SS 4x9               FTP 214, TSS 65, NP 178, IF 0.83\n188952350 TEMPO 3x10           FTP 214, TSS 49, NP 169, IF 0.79\n188952351 TEMPO 3x12           FTP 214, TSS 57, NP 171, IF 0.80\n188952349 OU 3x6               FTP 214, TSS 47, NP 181, IF 0.85\n188952348 SS 6x6               FTP 214, TSS 65, NP 178, IF 0.83\n127739603 FTP RAMP             FTP 214, TSS 62, NP 230, IF 1.08\n```\n\n### Get Workout\n\nPrint full workout definition (as JSON):\n\n```shell\n$ python -m garminworkouts get --id [WORKOUT_ID]\n{\"workoutId\": 188952654, \"ownerId\": 2043461, \"workoutName\": \"VO2MAX 5x4\", \"description\": \"FTP 214, TSS 80, NP 205, IF 0.96\", \"updatedDate\": \"2020-02-11T14:37:56.0\", ...\n```\n\n### Delete Workout\n\nPermanently delete workout from Garmin Connect:\n\n```shell\npython -m garminworkouts delete --id [WORKOUT_ID]\n```\n\n### Schedule  Workouts\n\nSchedule preexisting workouts using the workout number (e.g. \"\u003chttps://connect.garmin.com/modern/workout/234567894\u003e\")\nThe workout number is the last digits of the URL here: 234567894\nNote: the date format is as follows : 2021-12-31\n\n```shell\npython -m garminworkouts schedule -d [DATE] -w [WORKOUT_ID]\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmkuthan%2Fgarmin-workouts","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmkuthan%2Fgarmin-workouts","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmkuthan%2Fgarmin-workouts/lists"}