Convert 80/20 Endurance .FIT workouts to intervals.icu structured workouts
Project description
eticu: 80/20 Endurance to Intervals.icu
eticu is a Python CLI pipeline that scrapes the free 80/20 Endurance workout library, parses and converts the .FIT files into fully structured Intervals.icu workouts, and idempotently uploads them to your Intervals.icu workout library.
It serves as a more robust, metric-first Python reimplementation of the 8020-intervals-icu TypeScript project, completely fixing target loss issues during imports, nested repeat structures, and adding idempotent uploading.
Scope Note: Brick (
BR*) workouts do not exist as.FITfiles in the library and are therefore also out of scope.
Installation & Setup
This project uses uv for dependency management.
-
Clone the repository:
git clone <repo-url> cd 8020-fetcher
-
Environment Variables: Copy
.env.exampleto.envand set your Intervals.icu credentials:INTERVALS_API_KEY=your_intervals_api_key INTERVALS_ATHLETE_ID=your_intervals_athlete_id
You can find these in your Intervals.icu settings.
Usage
To run the full pipeline (scrape → download → upload):
uv run eticu all
Options:
--dry-run: Do everything except network writes to Intervals.icu.--cycling-power: Emit Power targets (instead of Heart Rate) for Ride workouts. (Run and Swim always remain HR).--cache-dir <dir>: Directory to cache downloaded.FITfiles (defaults to8020_cache).
To convert and view a single downloaded .FIT file locally:
uv run eticu convert 8020_cache/bike/CCI1.FIT
To upload a training plan from a CSV file (e.g. plans/olympic_distance_level_0.csv):
uv run eticu upload-plan plans/olympic_distance_level_0.csv --name "Olympic Level 0"
Exercise names in the CSV's should be same as the 80/20 FIT files.
Options:
--pool-length: Pool length in meters (e.g., 25 or 50) for swim workouts.--dry-run: Parse the CSV and list the plan without uploading.
Critical Prerequisites
For the generated workouts to be accurate, you must configure your Intervals.icu settings to match the 80/20 Endurance methodology.
1. The 7-Zone Prerequisite
80/20 uses a 7-level zone system with two crossover zones: 1, 2, X, 3, Y, 4, 5.
Intervals.icu supports 7 zones (Z1 to Z7). eticu maps them sequentially.
You MUST update your Intervals.icu HR zones (and Power zones, if using --cycling-power) to match the numbers from the 80/20 zone calculator.
| 80/20 Zone | Intervals.icu Zone |
|---|---|
| Zone 1 | Z1 |
| Zone 2 | Z2 |
| Zone X | Z3 |
| Zone 3 | Z4 |
| Zone Y | Z5 |
| Zone 4 | Z6 |
| Zone 5 | Z7 |
Note: Because of crossover Zone X, 80/20's "Zone 3" maps to Intervals "Z4".
2. The --cycling-power Option & ERG Mode
By default, 80/20 workouts use Heart Rate targets. However, platforms like Zwift in ERG mode ignore HR targets; they require Power (%FTP).
If you ride on Zwift/TrainerRoad, pass the --cycling-power flag. This converts all Ride workouts to use Power zones.
- Prerequisite: For this to work, you MUST have your FTP and 7-level Power zones correctly configured in your Intervals.icu settings. If you don't, power targets will be meaningless.
Core Behaviors
- Metric Units: All outputs are metric. Run and Ride distances are rounded to the nearest
0.1 km. Swims are strictly handled inmeters(mtrin Intervals.icu to distinguish from minutes). - Pool Lengths: Only
25mand50mswim workouts are fetched and processed.25yfiles are skipped. - Folder Layout: Workouts are uploaded into three flat folders (created automatically if they don't exist):
80/20 - Run80/20 - Bike80/20 - Swim
- Idempotency: The upload is completely idempotent. It matches workouts by exact name within the folder and skips identical workouts, preventing duplication if the script is run multiple times.
Credits & License
This project was heavily inspired by the GPL-3.0 licensed njg4ne/8020-intervals-icu project, expanding its capabilities into a fully-typed Python package with deeper FIT file introspection.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file eticu-0.2.1.tar.gz.
File metadata
- Download URL: eticu-0.2.1.tar.gz
- Upload date:
- Size: 64.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
87a96086d74e9266e1cc92039e69331a6d4f3a6a93fe7283510fc90624dec23f
|
|
| MD5 |
38ef4706d864e08d009731c0444d9900
|
|
| BLAKE2b-256 |
19e963b9bfc4a9c2a7362fc94f37a77e262e47bf7bb2287f6d760a4428dd0a02
|
Provenance
The following attestation bundles were made for eticu-0.2.1.tar.gz:
Publisher:
publish.yml on melihakay/8020-Fetcher
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
eticu-0.2.1.tar.gz -
Subject digest:
87a96086d74e9266e1cc92039e69331a6d4f3a6a93fe7283510fc90624dec23f - Sigstore transparency entry: 2084491875
- Sigstore integration time:
-
Permalink:
melihakay/8020-Fetcher@24eff653c359e75ebd26d20c7a7a02791e6dd233 -
Branch / Tag:
refs/heads/master - Owner: https://github.com/melihakay
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@24eff653c359e75ebd26d20c7a7a02791e6dd233 -
Trigger Event:
push
-
Statement type:
File details
Details for the file eticu-0.2.1-py3-none-any.whl.
File metadata
- Download URL: eticu-0.2.1-py3-none-any.whl
- Upload date:
- Size: 20.3 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
610a6fa15547a78af44e1647622c045314e0f4c6cfc960748127a5f22c6d2be6
|
|
| MD5 |
3b3f93cd3c351b28ab35142f5e3c6da5
|
|
| BLAKE2b-256 |
a625a4086fd413bf5f4b19e5e3538dcd930068938dcfb66d8504821a5c568aaa
|
Provenance
The following attestation bundles were made for eticu-0.2.1-py3-none-any.whl:
Publisher:
publish.yml on melihakay/8020-Fetcher
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
eticu-0.2.1-py3-none-any.whl -
Subject digest:
610a6fa15547a78af44e1647622c045314e0f4c6cfc960748127a5f22c6d2be6 - Sigstore transparency entry: 2084491901
- Sigstore integration time:
-
Permalink:
melihakay/8020-Fetcher@24eff653c359e75ebd26d20c7a7a02791e6dd233 -
Branch / Tag:
refs/heads/master - Owner: https://github.com/melihakay
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@24eff653c359e75ebd26d20c7a7a02791e6dd233 -
Trigger Event:
push
-
Statement type: