Downloads iFit workouts and uploads them to Strava.
You can install ifit-strava like any other python script, e.g. using pip
directly, Nixpkgs (see the provided shell.nix), or conda.
The primary dependency is stravalib and currently a patched version is
required to support the 'Virtual Run' activity type (see stravalib PR#199). If
you don't want to bother building that you could change the activity type to
just a plain run (see the _strava_upload
function). tcxparser is also
needed.
ifit-strava takes a YAML config file, by default config/config.yaml
. See
(example_config/config.yaml for an example. The
configuration options are explained below:
strava
auth_port
andredirect_uri
: the port to run the authorisation webserver on and the URL on which it is exposed externally (see Authentication below)client_id
andclient_secret
: Strava authorisation credentialsgear_id
: The ID of the 'gear' (i.e. shoes) you want the uploaded activities to be marked as using. Optional.
skip
: Optional list of bad/unwanted iFit workout IDs to skip uploading
Note: authentication with iFit currently works in a hacky way by using a
saved cookies.txt
file. Unfortunately this will need to be kept up to date
(although the cookies last about a month before expiry). The intention is to
improve this at some point. See the Authentication section for details.
To obtain the gear ID, I just inspect the HTML on the gear section of your Strava profile. There is likely a better way.
There are three main commands that ifit_strava.py
exposes:
- download: downloads workouts from iFit
- auth: authenticates with Strava
- upload: uploads downloaded workouts to Strava
You can run these all together or a subset, e.g.:
./ifit_strava.py download auth upload
ifit-strava is designed to be idempotent, so you can run it multiple times and if nothing has changed it will do nothing. I personally run the above command on a cron every 15 minutes, so any workouts I do are automatically uploaded within 15 mins.
Use -v
for verbose logging and --help
to see other options.
As explained above, authentication with iFit currently works in a hacky way by
using a saved cookies.txt
file.
The easiest way to get one is to log in to the iFit website in a browser and
save it, e.g. using the cookies.txt extension for Chrome, to
config/cookies.txt
(use the --cookies-file
option to the download
command
to specify a different file).
Unfortunately this will need to be kept up to date manually (although the cookies last about a month before expiry). The intention is to improve this at some point, e.g. by using a proper iFit API with a username/password, if one exists. Suggestions welcome!
Strava authentication is a little complicated and is explained more fully in the Strava docs and by stravalib. Firstly, one must register an application to obtain credentials (you should register your own application). To actually use the API, one needs to obtain an access token from the client credentials for a given scope of (e.g. read/write activity). This access token must then be periodically renewed.
In order to validate the client and confirm the user wants the application to access the given scope, Strava 'calls back' on a URI which is configured for the application. This means you need to run an externally visible webserver for initial authentication. Once you have an access token it can be saved and renewed, so you only need this the first time.
ifit-strava contains a simple implementation of this using Flask. You should run
it (at least until you obtain an access token) on a host with an externally
visible IP (or perhaps port-forward/reverse-proxy to it) and configure the port
the server should run on and the corresponding external URL in the config
(described above). Then, when you run the auth
command for the first time,
ifit-strava will obtain and log an authorisation URL from stravalib which you
should paste into your browser. When you visit this URL (on strava.com) it will
ask you to confirm the application's access to the required scope, and then call
you back on the URL provided with a (short-lived) access token, an expiry time
and a refresh token that can be used to get a new access token. ifit-strava
saves these tokens in config/token.yaml
and will automatically refresh your
access token when next invoked if it has expired. You should keep these tokens
safe (as you should your client credentials) so be careful checking these into
git. I use git-crypt to make this easy.
- Find a way to obtain iFit credentials from username/password via a proper API
- Find a better way to obtain the list of workouts, rather than parsing HTML
- Strava interactions occasionally fail with an auth error - possibly because the token expires during operations (should probably renew if the token has almost expired).
- Some hardcoded values should probably be exposed as options
- Better way to obtain gear ID
- Get stravalib PR#199 merged
- Upstream tcxparser Nix expression