{% extends "base.html" %} {% block title %}Dashboard · hevy2garmin{% endblock %} {% block head %} {% endblock %} {% block content %} {% if not garmin_connected %}
Garmin not connected

Log in to Garmin Connect to start syncing your workouts.

Connect Garmin
{% endif %} {% if needs_actions_setup %}
Setting up automatic sync...
Enabling GitHub Actions and configuring secrets...
{% endif %} {% if synced_count == 0 and hevy_total > 0 %}
{{ hevy_total }} workouts ready to sync

Your Hevy workouts are not on Garmin yet. Click Sync Now below to start.

{% endif %} {% set on_garmin = [synced_count, matched_count]|max %}
{{ on_garmin }}
On Garmin
{{ hevy_total }}
In Hevy
{% set pending = hevy_total - on_garmin %}
{{ pending }}
Pending
Sync
{% set pending = hevy_total - [synced_count, matched_count]|max %} {% if pending > 1 %}

Uploads one workout at a time (~{{ ((pending * 8) / 60) | round(0) | int }} min for {{ pending }}). You can close this page and come back — it picks up where it left off.

{% endif %}
{% if sync_log %}
Last synced: {{ sync_log[0].time }} ({{ sync_log[0].trigger }})
{% endif %}
Auto-sync (new workouts only)
{% if auto_sync.enabled %} {% if auto_sync.last_sync %}Last: {{ auto_sync.last_sync }}{% endif %} {% if auto_sync.next_sync %} · Next: {{ auto_sync.next_sync }}{% endif %} {% endif %}
Recent Uploads All →
{% if recent %} {% for r in recent %}
{{ r.title }}
{{ r.synced_at.strftime('%Y-%m-%d') if r.synced_at is not string else r.synced_at[:10] }} {% if r.calories %} · {{ r.calories }} kcal{% endif %}
{% endfor %} {% else %}

No uploads yet. Click Sync Now to start.

{% endif %}
Sync Log
{% if sync_log %} {% for entry in sync_log[:7] %}
{{ entry.time.strftime('%Y-%m-%d %H:%M') if entry.time.strftime is defined else entry.time[:16] }}
{% if entry.synced > 0 %} {{ entry.synced }} {% endif %} {% if entry.skipped > 0 %} {{ entry.skipped }} skip {% endif %} {% if entry.failed > 0 %} {{ entry.failed }} fail {% endif %} {{ entry.trigger }}
{% endfor %} {% else %}

No sync runs yet.

{% endif %}
Pipeline
Hevy API Fetch workouts Map Exercises {{ mapping_count }} categories Generate FIT + HR data + calories Garmin Upload activity Fetch HR Data Daily watch monitoring Match HR & Calc Cal Align HR to exercises enriches No watch HR? Falls back to default 90 bpm estimate sync flow HR enrichment
HR Fusion pulls your Garmin watch's daily heart rate monitoring and aligns it to each workout's time window, producing an HR timeline with color-coded exercise segments. Cached locally after first load. Configure →
{% endblock %}