Giter Club home page Giter Club logo

garmin-workouts's Introduction

Garmin Connect Workouts Tools

CI codecov

Command line tools for managing Garmin Connect workouts.

Features:

  • Target power is set according to Your current FTP.
  • All workouts under Your control stored as JSON files.
  • Easy to understand workout format, see examples below.
  • Workout parts like warm-up or cool-down are reusable.
  • Schedule saved workouts
  • The most important parameters (TSS, IF, NP) embedded in workout description field.

Installation

Requirements:

  • Python 3.x (doc)

Clone this repo:

git clone https://github.com/mkuthan/garmin-workouts.git

Use the venv command to create a virtual copy of the entire Python installation.:

cd garmin-workouts
python3 -m venv venv

Set your shell to use the venv paths for Python by activating the virtual environment:

source venv/bin/activate

Install dependencies:

pip3 install -r requirements.txt

Usage

First call to Garmin Connect takes some time to authenticate user. Once user is authenticated cookie jar is created with session cookies for further calls. It is required due to strict request limits for Garmin SSO service.

Authentication

Define Garmin connect account credentials as GARMIN_USERNAME and GARMIN_PASSWORD environment variables:

export GARMIN_USERNAME=username
export GARMIN_PASSWORD=password

Alternatively use -u and -p command line arguments:

python -m garminworkouts -u [USERNAME] -p [PASSWORD]

Import Workouts

Import workouts into Garmin Connect from definitions in YAML files. If the workout already exists it will be updated:

python -m garminworkouts import --ftp [YOUR_FTP] 'sample_workouts/*.yaml'

Sample workout definition:

name: "Boring as hell but simple workout"

steps:
  - { power: 50, duration: "10:00" }
  - { power: 70, duration: "20:00" }
  - { duration: "5:00" }
  - { power: 70, duration: "20:00" }
  - { power: 50 }
  • Target power is defined as percent of FTP (provided as mandatory command line parameter). If the target power is not specified "No target" will be used for the workout step.
  • Target power may be defined as absolute value like: "150W", it could be useful in FTP ramp tests.
  • Duration is defined as HH:MM:SS (or MM:SS, or SS) format. If the duration is not specified "Lap Button Press" will be used to move into next workout step.

Reusing workout definitions:

name: "Boring as hell but simple workout"

steps:
  - !include inc/warmup.yaml
  - { power: 70, duration: "20:00" }
  - { duration: "5:00" }
  - { power: 70, duration: "20:00" }
  - !include inc/cooldown.yaml
  • !include is a custom YAML directive for including another file as a part of the workout.

Reusing workout steps:

name: "Boring as hell but simple workout"

steps:
  - !include inc/warmup.yaml
  - &INTERVAL { power: 70, duration: "20:00" }
  - { duration: "5:00" }
  - *INTERVAL
  - !include inc/cooldown.yaml
  • Thanks to YAML aliases, workout steps can be easily reused once defined.

Sample Over-Under workout:

name: "OverUnder 3x9"

steps:
  - !include inc/warmup.yaml
  - &INTERVAL
    - &UNDER { power: 95, duration: "2:00" }
    - &OVER { power: 105, duration: "1:00" }
    - *UNDER
    - *OVER
    - *UNDER
    - *OVER
    - { power: 50, duration: "3:00" }
  - *INTERVAL
  - *INTERVAL
  - !include inc/cooldown.yaml
  • All nested sections are mapped as repeated steps in Garmin Connect. First repeat for warmup, second repeat for main interval (repeated 3 times) and the last one for cool down.

To import your workout from an xlsx file, construct a table in Excel that looks like this (making sure that all Excel cells are set to text and not to date or any other format):

Start End Duration
43 85 3:00
85 15:00
85 43 2:00

If your "start" and "end" power for a step differ, a ramp of 10 seconds steps will be created by default for the chosen duration. If more than 50 total steps are to be uploaded ramp's steps will get longer so that the total number of steps is under Garmin maximum value of 50. TIPS Do not use your TACX without the power cable as your Garmin will have a hard time controlling the trainer while changing from one step to the next. Turn off the tones in your Garmin. If you wish to give your values in W instead of % of your FTP:

Start End Duration
80W 160W 3:00
160W 15:00
160W 80W 2:00

You can then import as with the yaml files:

python -m garminworkouts import --ftp [YOUR_FTP] my.workout.xlsx

This will generate a yaml file with the name my.workout.xlsx. The name of the workout will be "my.workout".

Export Workouts

Export all workouts from Garmin Connect into local directory as FIT files. This is the easiest way to synchronize all workouts with Garmin device:

python -m garminworkouts export /mnt/GARMIN/NewFiles

List Workouts

Print summary for all workouts (workout identifier, workout name and description):

$ python -m garminworkouts list
188952654 VO2MAX 5x4           FTP 214, TSS 80, NP 205, IF 0.96
188952362 TEMPO 3x15           FTP 214, TSS 68, NP 172, IF 0.81
188952359 SS 3x12              FTP 214, TSS 65, NP 178, IF 0.83
188952356 VO2MAX 5x3           FTP 214, TSS 63, NP 202, IF 0.95
188952357 OU 3x9               FTP 214, TSS 62, NP 188, IF 0.88
188952354 SS 4x9               FTP 214, TSS 65, NP 178, IF 0.83
188952350 TEMPO 3x10           FTP 214, TSS 49, NP 169, IF 0.79
188952351 TEMPO 3x12           FTP 214, TSS 57, NP 171, IF 0.80
188952349 OU 3x6               FTP 214, TSS 47, NP 181, IF 0.85
188952348 SS 6x6               FTP 214, TSS 65, NP 178, IF 0.83
127739603 FTP RAMP             FTP 214, TSS 62, NP 230, IF 1.08

Get Workout

Print full workout definition (as JSON):

$ python -m garminworkouts get --id [WORKOUT_ID]
{"workoutId": 188952654, "ownerId": 2043461, "workoutName": "VO2MAX 5x4", "description": "FTP 214, TSS 80, NP 205, IF 0.96", "updatedDate": "2020-02-11T14:37:56.0", ...

Delete Workout

Permanently delete workout from Garmin Connect:

python -m garminworkouts delete --id [WORKOUT_ID]

Schedule Workouts

Schedule preexisting workouts using the workout number (e.g. "https://connect.garmin.com/modern/workout/234567894") The workout number is the last digits of the URL here: 234567894 Note: the date format is as follows : 2021-12-31

python -m garminworkouts schedule -d [DATE] -w [WORKOUT_ID]

garmin-workouts's People

Contributors

darkzbaron avatar dependabot[bot] avatar github-actions[bot] avatar j-fuentes avatar jorgeboucas avatar mkuthan avatar naglis avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

garmin-workouts's Issues

unable to login: Too Many Requests for url

Hello

I'm not able to login to garmin.
Too Many Requests for url: https://sso.garmin.com/sso/signin

login via firefox works very well.

btw, nice project!

INFO:garminworkouts.garmin.garminclient:Authenticate user [email protected]'
Traceback (most recent call last):
  File "/usr/lib/python3.6/runpy.py", line 193, in _run_module_as_main
    "__main__", mod_spec)
  File "/usr/lib/python3.6/runpy.py", line 85, in _run_code
    exec(code, run_globals)
  File ".../src/garmin-workouts/garminworkouts/__main__.py", line 110, in <module>
    main()
  File ".../src/garmin-workouts/garminworkouts/__main__.py", line 106, in main
    args.func(args)
  File ".../src/garmin-workouts/garminworkouts/__main__.py", line 50, in command_list
    with _garmin_client(args) as connection:
  File ".../src/garmin-workouts/garminworkouts/garmin/garminclient.py", line 29, in __enter__
    self._connect()
  File ".../src/garmin-workouts/garminworkouts/garmin/garminclient.py", line 103, in _connect
    self._authenticate()
  File ".../src/garmin-workouts/garminworkouts/garmin/garminclient.py", line 129, in _authenticate
    auth_response.raise_for_status()
  File ".../.local/share/virtualenvs/garmin-workouts-VBtzPHpF/lib/python3.6/site-packages/requests/models.py", line 940, in raise_for_status
    raise HTTPError(http_error_msg, response=self)
requests.exceptions.HTTPError: 429 Client Error: Too Many Requests for url: https://sso.garmin.com/sso/signin?service=https%3A%2F%2Fconnect.garmin.com%2Fmodern```

Scheduling

Hi there, any plan for scheduling existing workouts?

Add support for Strenght workout

At first I was confused what the FTP was, then I realized it's for cycling.

Would be awesome to use some of the code you already have to be able to declare strength workouts !

HTTPError - Garmin api problem?

I've got this connection error when using the tool as usual:

requests.exceptions.HTTPError: 402 Client Error: Payment Required for url: https://connect.garmin.com/modern/proxy/workout-service/workouts?start=0&limit=100

Traceback (most recent call last):
File "C:/Users/Fabian/Documents/Git/garmin_workouts/garminworkouts/run_script_dbg.py", line 117, in
command_import(args)
File "C:/Users/Fabian/Documents/Git/garmin_workouts/garminworkouts/run_script_dbg.py", line 21, in command_import
existing_workouts_by_name = {Workout.extract_workout_name(w): w for w in connection.list_workouts()}
File "C:/Users/Fabian/Documents/Git/garmin_workouts/garminworkouts/run_script_dbg.py", line 21, in
existing_workouts_by_name = {Workout.extract_workout_name(w): w for w in connection.list_workouts()}
File "C:\Users\Fabian\Documents\Git\garmin_workouts\garminworkouts\garmin\garminclient.py", line 44, in list_workouts
response.raise_for_status()
File "C:\Users\Fabian\Documents\Git\garmin_workouts\py_env\lib\site-packages\requests\models.py", line 940, in raise_for_status
raise HTTPError(http_error_msg, response=self)

Is it possible that the Garmin api has changed? Has anyone encountered this problem already?

AttributeError: 'Namespace' object has no attribute 'func'

When running the command line with Python 3.11.6 on my Mac.

(venv) garmin-workouts % python3 -m garminworkouts
Traceback (most recent call last):
  File "<frozen runpy>", line 198, in _run_module_as_main
  File "<frozen runpy>", line 88, in _run_code
  File "***/garminworkouts/__main__.py", line 140, in <module>
    main()
  File "***/garminworkouts/__main__.py", line 136, in main
    args.func(args)
    ^^^^^^^^^
AttributeError: 'Namespace' object has no attribute 'func'

auth failing

(venv) laptop:~/garmin-workouts% python -m garminworkouts -u USERNAME -p PASSWORD import --ftp FTP SST.short.xlsx
INFO:garminworkouts.garmin.garminclient:Authenticate user 'USERNAME'
Traceback (most recent call last):
  File "/Library/Developer/CommandLineTools/Library/Frameworks/Python3.framework/Versions/3.8/lib/python3.8/runpy.py", line 193, in _run_module_as_main
    return _run_code(code, main_globals, None,
  File "/Library/Developer/CommandLineTools/Library/Frameworks/Python3.framework/Versions/3.8/lib/python3.8/runpy.py", line 86, in _run_code
    exec(code, run_globals)
  File "/Users/jboucas/garmin-workouts/garminworkouts/__main__.py", line 112, in <module>
    main()
  File "/Users/jboucas/garmin-workouts/garminworkouts/__main__.py", line 108, in main
    args.func(args)
  File "/Users/jboucas/garmin-workouts/garminworkouts/__main__.py", line 22, in command_import
    with _garmin_client(args) as connection:
  File "/Users/jboucas/garmin-workouts/garminworkouts/garmin/garminclient.py", line 29, in __enter__
    self._connect()
  File "/Users/jboucas/garmin-workouts/garminworkouts/garmin/garminclient.py", line 103, in _connect
    self._authenticate()
  File "/Users/jboucas/garmin-workouts/garminworkouts/garmin/garminclient.py", line 128, in _authenticate
    auth_response.raise_for_status()
  File "/Users/jboucas/garmin-workouts/venv/lib/python3.8/site-packages/requests/models.py", line 940, in raise_for_status
    raise HTTPError(http_error_msg, response=self)
requests.exceptions.HTTPError: 403 Client Error: Forbidden for url: https://sso.garmin.com/sso/signin?service=https%3A%2F%2Fconnect.garmin.com%2Fmodern

HTTPError: 403 Client Error: Forbidden for url: https://connect.garmin.com/proxy/workout-service/workouts?start=0&limit=100

Hello,
When i'm trying to use your work to send workouts on my garmin account, i'm getting this error :
requests.exceptions.HTTPError: 403 Client Error: Forbidden for url: https://connect.garmin.com/proxy/workout-service/workouts?start=0&limit=100
I suppose that this is garmin website which is denying me the access,
Do I need an API key for their Workouts API or the issue may be caused by something else ?
(I'm using a Python 3.11.6 virtual environment with the last releases of the requirements)
Thx for your help

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.