Install
openclaw skills install garmin-connect-thebyteioIntegrate with Garmin Connect to fetch and analyze deep fitness metrics including sleep, body battery, resting heart rate, stress, and training status. Use this skill for enhanced training insights, recovery-aware nudges, and daily health summaries.
openclaw skills install garmin-connect-thebyteioDeep fitness metrics from Garmin Connect for enhanced training insights and recovery-aware nudges.
Strava: Social, activities, segments, ride tracking
Garmin: Physiological metrics, recovery, sleep, training load
Combined = Smart nudges that respect recovery status!
pip3 install garminconnect --break-system-packages
# Or using a virtual environment (recommended):
# python3 -m venv ./venv
# source ./venv/bin/activate
# pip install garminconnect
Create a new "Login" item in your 1Password vault (e.g., "Personal") with the following details:
Garmin Connect (or a custom name you prefer)If you use a custom title or a different vault, set the GARMIN_1P_ITEM_NAME and GARMIN_1P_VAULT environment variables before running the scripts.
Example:
export GARMIN_1P_ITEM_NAME="My Garmin Login"
export GARMIN_1P_VAULT="MyFamilyVault"
Ensure your OP_SERVICE_ACCOUNT_TOKEN is set up for 1Password CLI authentication:
export OP_SERVICE_ACCOUNT_TOKEN=$(cat ~/.config/op/service-account-token)
./scripts/garmin-login.sh
./scripts/get-stats.sh
Returns:
./scripts/get-sleep.sh [days_back]
Returns sleep duration, quality, stages for last N days.
./scripts/check-recovery.sh
Returns whether Brian is recovered enough for hard training.
Enhanced decision logic:
Before nudging for a hard workout:
Example:
{
"body_battery": {
"current": 75,
"charged": true,
"forecast": 85
},
"sleep": {
"duration_hours": 7.2,
"quality": "good",
"deep_sleep_hours": 1.8,
"rem_hours": 1.5
},
"training_status": {
"status": "productive",
"vo2_max": 52,
"recovery_time_hours": 12
},
"heart_rate": {
"resting": 48,
"current": 62,
"stress_level": 25
}
}
Without Garmin: "Thursday tempo ride time!"
With Garmin: "You only got 5 hours sleep last night. Maybe take today easy? Light Zone 2 or rest."
Without Garmin: "Tuesday ride day"
With Garmin: "Fully recovered (body battery 85%, 8h sleep) + perfect weather. Great day for that tempo ride! 🚴"
Without Garmin: "Evening gym time!"
With Garmin: "Stress level high today (68). Maybe skip gym and prioritize recovery?"
Current:
🚴 Fitness Update:
Last ride: 2 days ago
This week: 3 rides, 87km
With Garmin:
🚴 Fitness Update:
**Sleep:** 7.5h (good quality, 2h deep)
**Recovery:** ✅ Fully recovered
**Body Battery:** 82% (charged overnight)
**Resting HR:** 48 bpm (normal)
Last ride: 2 days ago
This week: 3 rides, 87km
**Training Status:** Productive (VO2 max: 52)
Edit config.json (create if it doesn't exist):
{
"recovery_thresholds": {
"body_battery_low": 40,
"body_battery_good": 70,
"min_sleep_hours": 6.5,
"max_recovery_time_hours": 12
},
"nudge_modifications": {
"respect_recovery": true,
"downgrade_intensity_if_tired": true,
"skip_gym_if_high_stress": true
}
}
Note: This config.json should be created in the skill's root directory (/root/clawd/skills/garmin/).
Using garminconnect Python library:
get_stats() - Daily stats summaryget_sleep_data() - Sleep metricsget_body_battery() - Energy levelsget_training_status() - Training load, recoveryget_heart_rates() - HR dataRate limits: No official limit, but be reasonable (cache data, don't spam).
garminconnect libraryop)jq for JSON parsing (if needed by other scripts)/tmp/garmin-session//root/clawd/data/fitness/garmin/ as per TOOLS.md)