Hevy to Garmin Connect – Automatic Strength Workout Sync via Home Assistant
TL;DR: A Python script that automatically syncs your strength training workouts from Hevy to Garmin Connect, running as a scheduled job every 30 minutes from Home Assistant using PyScript + shell_command.
GitHub: github.com/amasolov/hevy2garmin
The Problem
I use Hevy to track my strength workouts (exercises, sets, reps, weights) and a Garmin watch for everything else. Garmin Connect is my single dashboard for all fitness data, but there’s no native integration between the two. I wanted my Hevy workouts to show up in Garmin Connect automatically — as proper strength training activities with exercise names, sets, reps, and weights — without any manual effort.
The Solution
hevy2garmin fetches workouts from the official Hevy API, converts them into Garmin FIT files (the native binary format Garmin uses), and uploads them to Garmin Connect. It runs from Home Assistant on a 30-minute schedule, so my workouts appear in Garmin shortly after I finish them.
How It Works
-
Fetches recent workouts from Hevy (last 7 days by default) via the official Hevy API v1
-
Skips workouts that were already synced (tracked in a state file — no duplicates)
-
Auto-maps Hevy exercise names to Garmin FIT exercise categories using keyword heuristics (e.g., “Barbell Bench Press” → bench_press, “Romanian Deadlift” → deadlift)
-
Builds valid FIT files with a custom binary encoder — each set appears in Garmin with the correct exercise name, reps, weight, and duration
-
Uploads the FIT files to Garmin Connect via OAuth (using the
garthlibrary)
Key Features
-
Custom FIT builder — no external FIT SDK needed; generates proper strength training activities that Garmin displays correctly
-
Smart exercise mapping — automatically maps Hevy exercises to Garmin categories using keyword heuristics. Unknown exercises are logged for manual review
-
Multi-user support — configure multiple users in
users.json, each synced independently -
Garmin MFA support — a helper script creates an OAuth session locally (where you can enter MFA), then the sync script reuses it with token auto-refresh
-
Duplicate prevention — state file per user ensures workouts are never synced twice
-
Retry logic — handles transient API errors and Garmin rate limits gracefully
Home Assistant Integration
The HA integration uses PyScript (available via HACS) to trigger a shell_command on a cron schedule. The sync runs in the background with nohup to avoid the 60-second shell_command timeout.
Full Setup Guide
Step 1: Install PyScript
Install PyScript via HACS:
-
Open HACS in your Home Assistant UI
-
Go to Integrations → click the + button → search for PyScript → install it
-
Restart Home Assistant
-
Go to Settings → Devices & Services → Add Integration → search for PyScript → add it
Alternatively, add pyscript: to your configuration.yaml manually.
Step 2: Clone the project to your Home Assistant
SSH into your Home Assistant host and clone the repo into the config directory:
cd /config/scripts
git clone https://github.com/amasolov/hevy2garmin.git
cd hevy2garmin
Note: If you’re using Home Assistant OS (supervised), you can SSH in via the SSH & Web Terminal add-on. The config directory is typically
/config/or/homeassistant/depending on your setup.
Step 3: Create a Python virtual environment and install dependencies
cd /config/scripts/hevy2garmin
python3 -m venv .venv
.venv/bin/pip install --upgrade pip
.venv/bin/pip install -r requirements.txt
This installs garth (Garmin OAuth library) and requests.
Step 4: Get your Hevy API key
-
Go to hevy.com/settings (requires Hevy Pro)
-
Under the Developer section, generate or copy your API key
Step 5: Configure users
cd /config/scripts/hevy2garmin
cp users.json.example users.json
Edit users.json with your details:
[
{
"id": "myname",
"hevy_api_key": "YOUR_HEVY_API_KEY",
"garmin_email": "[email protected]",
"garmin_password": "your_garmin_password"
}
]
You can add multiple users to the array if needed.
Step 6: Set up the exercise mapping
cp exercise_mapping.json.example exercise_mapping.json
This seeds 30+ common exercises. New exercises are auto-mapped on each sync run. Anything that can’t be auto-mapped gets logged to unmapped_exercises.json for you to review.
Step 7: Handle Garmin MFA / CAPTCHA (if applicable)
If your Garmin account has MFA enabled, or Garmin blocks login with a CAPTCHA on your server, you need to create an OAuth session locally (on your laptop/desktop where you can complete MFA):
# On your local machine (not on HA):
git clone https://github.com/amasolov/hevy2garmin.git
cd hevy2garmin
pip install -r requirements.txt
python garmin_login.py [email protected] your_garmin_password ./garth_session_myname
This will prompt for your MFA code interactively. Then copy the session to your HA host:
scp -r ./garth_session_myname your-ha-host:/config/scripts/hevy2garmin/
And update users.json to point to it:
{
"id": "myname",
"hevy_api_key": "YOUR_HEVY_API_KEY",
"garmin_email": "[email protected]",
"garmin_password": "your_garmin_password",
"garth_session_path": "/config/scripts/hevy2garmin/garth_session_myname"
}
MFA is only needed once. The sync script uses garth.resume() with OAuth refresh tokens, and running every 30 minutes keeps the tokens fresh.
Step 8: Test the sync manually
Before setting up automation, verify everything works:
cd /config/scripts/hevy2garmin
.venv/bin/python run_sync.py
Check the output for any errors. If successful, you should see your recent Hevy workouts uploaded to Garmin Connect.
Step 9: Add the shell command to Home Assistant
Add this to your configuration.yaml (or an included file):
shell_command:
hevy_garmin_sync: >-
nohup /config/scripts/hevy2garmin/.venv/bin/python
/config/scripts/hevy2garmin/run_sync.py
>> /config/scripts/hevy2garmin/sync.log 2>&1 &
The
nohup ... &runs the sync in the background so it isn’t killed by the 60-second shell_command timeout.
Step 10: Add the PyScript scheduled job
Copy the PyScript trigger file:
cp /config/scripts/hevy2garmin/homeassistant/pyscript/hevy_garmin_sync.py /config/pyscript/hevy_garmin_sync.py
This file contains:
@time_trigger("cron(*/30 * * * *)")
def hevy_garmin_scheduled_sync():
service.call("shell_command", "hevy_garmin_sync", blocking=False)
Reload PyScript (Developer Tools → Services → call pyscript.reload) or restart Home Assistant.
Step 11: Verify it’s running
-
Sync logs:
tail -f /config/scripts/hevy2garmin/sync.log -
HA logs: Developer Tools → Logs (look for PyScript or shell_command entries)
-
Garmin Connect: Check that your workouts appear as strength training activities with correct exercises, sets, reps, and weights
Updating
To update to the latest version:
cd /config/scripts/hevy2garmin
git pull
.venv/bin/pip install -r requirements.txt
Your users.json, exercise_mapping.json, and state files are gitignored, so they won’t be overwritten.
Requirements
-
Hevy Pro (for the official API key)
-
Garmin Connect account
-
Home Assistant with PyScript (or just run it standalone via cron — HA is optional)
-
Python 3 with
garthandrequests
License
MIT — free to use, modify, and contribute.
If you’re a Hevy user with a Garmin watch, give it a try and let me know how it works for you! Happy to answer any questions or take feature requests on GitHub.