Ich tracke meine sportlichen Aktivitäten seit einer Weile über eine Garmin-Uhr. Skating, Radfahren, Tennis. Irgendwann wollte ich die Daten nicht nur in der Garmin-App sehen, sondern direkt in Home Assistant. Also habe ich mir ein eigenes Fitness-Dashboard gebaut, das Monats- und Jahresstatistiken, Fortschrittsanzeigen und ein automatisches Wochen-Highlight anzeigt. Das Ganze läuft komplett über YAML, mit Input Helpern, Template-Sensoren und ein paar Automationen. Ich zeige dir Schritt für Schritt, wie du das bei dir einrichten kannst.
Was das Dashboard kann
Das Dashboard zeigt mir auf einen Blick, wo ich sportlich gerade stehe. Kilometer und Minuten pro Monat und pro Jahr, getrennt nach Sportart. Dazu ein Jahresfortschritt für mein Skating-Ziel, eine Hochrechnung ob ich das Ziel bis Jahresende schaffe, und das sportliche Highlight der Woche. Alles automatisch berechnet, ich muss da nichts manuell eintragen.
Die Daten kommen aus der Garmin-Integration und werden über Automationen in Input Helper geschrieben. Template-Sensoren rechnen daraus Fortschritte und Prognosen. Im Dashboard selbst stecken Mushroom Cards, Gauge Cards und ein Statistics Graph für den Skating-Verlauf der letzten 30 Tage.
Voraussetzungen
Damit das Setup funktioniert, brauchst du eine laufende Garmin-Anbindung in Home Assistant. Konkret brauchst du einen Sensor sensor.last_activities, der eine Liste der letzten Workouts als Attribut last_activities bereitstellt. Die offizielle Garmin Connect Integration liefert genau das.
Dazu brauchst du die Packages-Struktur in deiner configuration.yaml, damit du alles sauber in eine eigene Datei auslagern kannst:
homeassistant:
packages: !include_dir_named packages/An optionalen Frontend-Erweiterungen empfehle ich Mushroom Cards und card-mod aus HACS. Die sind nicht zwingend nötig, machen das Dashboard aber deutlich übersichtlicher.
Schritt 1: Input Helper anlegen
Die Basis bilden Input Helper, die Kilometer, Minuten und Einheiten pro Sportart speichern. Ich habe das nach Monat und Jahr getrennt, damit ich die Monatswerte am Ersten automatisch zurücksetzen kann, ohne die Jahreswerte zu verlieren.
Erstelle eine Datei packages/garmin.yaml mit folgendem Inhalt:
1input_text:
2 garmin_last_logged_activity_id:
3 name: Garmin – Letzte geloggte Aktivität
4 max: 20
5
6
7input_number:
8 # Tennis
9 garmin_tennis_month_km:
10 name: Garmin – Tennis Monat (km)
11 min: 0
12 max: 10000
13 step: 0.01
14 unit_of_measurement: "km"
15 mode: box
16
17 garmin_tennis_year_km:
18 name: Garmin – Tennis Jahr (km)
19 min: 0
20 max: 50000
21 step: 0.01
22 unit_of_measurement: "km"
23 mode: box
24
25 garmin_tennis_month_min:
26 name: Garmin – Tennis Monat (Min)
27 min: 0
28 max: 10000
29 step: 1
30 unit_of_measurement: "min"
31 mode: box
32
33 garmin_tennis_year_min:
34 name: Garmin – Tennis Jahr (Min)
35 min: 0
36 max: 50000
37 step: 1
38 unit_of_measurement: "min"
39 mode: box
40
41 # Radfahren
42 garmin_bike_month_km:
43 name: Garmin – Radfahren Monat (km)
44 min: 0
45 max: 10000
46 step: 0.01
47 unit_of_measurement: "km"
48 mode: box
49
50 garmin_bike_year_km:
51 name: Garmin – Radfahren Jahr (km)
52 min: 0
53 max: 50000
54 step: 0.01
55 unit_of_measurement: "km"
56 mode: box
57
58 garmin_bike_month_min:
59 name: Garmin – Radfahren Monat (Min)
60 min: 0
61 max: 10000
62 step: 1
63 unit_of_measurement: "min"
64 mode: box
65
66 garmin_bike_year_min:
67 name: Garmin – Radfahren Jahr (Min)
68 min: 0
69 max: 50000
70 step: 1
71 unit_of_measurement: "min"
72 mode: box
73
74 # Skaten
75 garmin_skate_month_km:
76 name: Garmin – Skating Monat (km)
77 min: 0
78 max: 10000
79 step: 0.01
80 unit_of_measurement: "km"
81 mode: box
82
83 garmin_skate_year_km:
84 name: Garmin – Skating Jahr (km)
85 min: 0
86 max: 50000
87 step: 0.01
88 unit_of_measurement: "km"
89 mode: box
90
91 garmin_skate_month_min:
92 name: Garmin – Skating Monat (Min)
93 min: 0
94 max: 10000
95 step: 1
96 unit_of_measurement: "min"
97 mode: box
98
99 garmin_skate_year_min:
100 name: Garmin – Skating Jahr (Min)
101 min: 0
102 max: 50000
103 step: 1
104 unit_of_measurement: "min"
105 mode: box
106
107counter:
108 garmin_tennis_sessions:
109 name: Garmin – Tennis-Einheiten
110 initial: 0
111 step: 1
112
113 garmin_bike_sessions:
114 name: Garmin – Radfahr-Einheiten
115 initial: 0
116 step: 1
117
118 garmin_skate_sessions:
119 name: Garmin – Skating-Einheiten
120 initial: 0
121 step: 1Der input_text für garmin_last_logged_activity_id ist wichtig: Damit merkt sich die Automation später, welche Aktivität zuletzt verarbeitet wurde. So werden keine Einheiten doppelt gezählt.
Schritt 2: Template-Sensoren erstellen
Auf Basis der Input Helper kannst du jetzt Template-Sensoren bauen, die automatisch rechnen. Der Skating-Jahresfortschritt zum Beispiel zeigt dir in Prozent, wie nah du an deinem Jahresziel bist. Die Prognose rechnet hoch, ob du es bei gleichbleibendem Tempo bis Jahresende schaffst.
Füge diese Sensoren in die gleiche packages/garmin.yaml ein:
1template:
2 - sensor:
3 - name: "garmin_skating_year_progress"
4 unique_id: garmin_skating_year_progress
5 unit_of_measurement: "%"
6 device_class: battery
7 state_class: measurement
8 state: >
9 {% set km = states('input_number.garmin_skate_year_km') | float(0) %}
10 {{ ((km / 2025) * 100) | round(1) }}
11 attributes:
12 ziel_km: 2025
13 availability: >
14 {{ states('input_number.garmin_skate_year_km') not in ['unknown', 'unavailable'] }}
15 - sensor:
16 - name: "garmin_skating_min_month"
17 unique_id: garmin_skating_min_month
18 unit_of_measurement: "min"
19 device_class: duration
20 state_class: measurement
21 state: >
22 {{ states('input_number.garmin_skate_month_min') | float }}
23 availability: >
24 {{ states('input_number.garmin_skate_month_min') not in ['unknown', 'unavailable'] }}
25 - sensor:
26 - name: "garmin_skating_projection_2025"
27 unique_id: garmin_skating_projection_2025
28 unit_of_measurement: "km"
29 state_class: measurement
30 device_class: distance
31 state: >
32 {% set current_km = states('input_number.garmin_skate_year_km') | float(0) %}
33 {% set day = now().timetuple().tm_yday %}
34 {% if day > 0 %}
35 {{ (current_km / day * 365) | round(1) }}
36 {% else %}
37 0
38 {% endif %}
39 attributes:
40 friendly_name: "Skating-Projektion 2025"
41 availability: >
42 {{ states('input_number.garmin_skate_year_km') not in ['unknown', 'unavailable'] }}
43 - sensor:
44 - name: "garmin_weekly_highlight"
45 unique_id: garmin_weekly_highlight
46 state: >
47 {% set activities = state_attr('sensor.last_activities', 'last_activities') | default([]) %}
48 {% set this_week = now().strftime('%Y-%m-%d')[:7] %}
49 {% set week_activities = activities
50 | selectattr('startTimeLocal', 'defined')
51 | selectattr('startTimeLocal', 'search', this_week)
52 | list %}
53 {% set best = week_activities | sort(attribute='distance', reverse=true) | first %}
54 {{ best.activityName if best else 'Keine Aktivität' }}
55 attributes:
56 activityName: >
57 {% set activities = state_attr('sensor.last_activities', 'last_activities') | default([]) %}
58 {% set this_week = now().strftime('%Y-%m-%d')[:7] %}
59 {% set best = activities
60 | selectattr('startTimeLocal', 'defined')
61 | selectattr('startTimeLocal', 'search', this_week)
62 | sort(attribute='distance', reverse=true) | first %}
63 {{ best.activityName if best else '–' }}
64 distance: >
65 {% set activities = state_attr('sensor.last_activities', 'last_activities') | default([]) %}
66 {% set this_week = now().strftime('%Y-%m-%d')[:7] %}
67 {% set best = activities
68 | selectattr('startTimeLocal', 'defined')
69 | selectattr('startTimeLocal', 'search', this_week)
70 | sort(attribute='distance', reverse=true) | first %}
71 {{ (best.distance / 1000) | round(1) if best and best.distance is defined else 0 }}
72 duration: >
73 {% set activities = state_attr('sensor.last_activities', 'last_activities') | default([]) %}
74 {% set this_week = now().strftime('%Y-%m-%d')[:7] %}
75 {% set best = activities
76 | selectattr('startTimeLocal', 'defined')
77 | selectattr('startTimeLocal', 'search', this_week)
78 | sort(attribute='distance', reverse=true) | first %}
79 {{ (best.duration / 60) | round(0) if best and best.duration is defined else 0 }}
80 calories: >
81 {% set activities = state_attr('sensor.last_activities', 'last_activities') | default([]) %}
82 {% set this_week = now().strftime('%Y-%m-%d')[:7] %}
83 {% set best = activities
84 | selectattr('startTimeLocal', 'defined')
85 | selectattr('startTimeLocal', 'search', this_week)
86 | sort(attribute='distance', reverse=true) | first %}
87 {{ best.calories | round(0) if best and best.calories is defined else 0 }}
88 date: >
89 {% set activities = state_attr('sensor.last_activities', 'last_activities') | default([]) %}
90 {% set this_week = now().strftime('%Y-%m-%d')[:7] %}
91 {% set best = activities
92 | selectattr('startTimeLocal', 'defined')
93 | selectattr('startTimeLocal', 'search', this_week)
94 | sort(attribute='distance', reverse=true) | first %}
95 {{ best.startTimeLocal[:10] if best and best.startTimeLocal is defined else '–' }}
96 availability: >
97 {{ state_attr('sensor.last_activities', 'last_activities') is defined }}Den Wert 2025 im Skating-Fortschritt musst du an dein eigenes Jahresziel anpassen. Bei mir sind es 2025 km, weil ich mir für 2025 vorgenommen habe, so viele Kilometer auf Inlineskates zurückzulegen wie die Jahreszahl. Ob das klappt, sehe ich dann im Dezember.
Schritt 3: Automationen für die Datenpflege
Damit die Input Helper automatisch gefüllt werden, brauchst du zwei Automationen. Die erste setzt am Monatsanfang alle Monatswerte zurück. Die zweite erkennt neue Aktivitäten und schreibt Kilometer, Minuten und Einheiten in die passenden Helper.
Die Monatsreset-Automation:
1alias: Garmin – Monatswerte zurücksetzen
2trigger:
3 - platform: time
4 at: "00:15:00"
5condition:
6 - condition: template
7 value_template: "{{ now().day == 1 }}"
8action:
9 - service: input_number.set_value
10 data:
11 value: 0
12 target:
13 entity_id:
14 - input_number.garmin_skate_month_km
15 - input_number.garmin_skate_month_min
16 - input_number.garmin_tennis_month_km
17 - input_number.garmin_tennis_month_min
18 - input_number.garmin_bike_month_km
19 - input_number.garmin_bike_month_minFür die Jahreswerte gilt das gleiche Prinzip, nur mit der zusätzlichen Bedingung now().month == 1. Die Counter für die Einheiten setzt du dann ebenfalls auf 0.
Die Aktivitäts-Automation prüft bei Änderungen von sensor.last_activities, ob eine neue Aktivität hinzugekommen ist. Über die gespeicherte Activity-ID in input_text.garmin_last_logged_activity_id wird sichergestellt, dass jede Einheit nur einmal gezählt wird.
Schritt 4: Dashboard anlegen
Für die Darstellung empfehle ich ein separates Dashboard. Geh dafür in Home Assistant auf Einstellungen > Dashboards > Dashboard hinzufügen und wechsle dann in den YAML-Modus.
Das Dashboard nutzt Sections mit maximal 3 Spalten. In der ersten Section siehst du Jahresziel und Fortschritt als Gauge, die Skating-Projektion und dein Fitness-Alter. In der zweiten Section stehen die letzten fünf Aktivitäten mit dynamischen Icons, je nach Sportart. Die dritte zeigt den Skating-Verlauf der letzten 30 Tage als Balkendiagramm. Danach kommen die Detailkarten für jede Sportart einzeln.
Die komplette Dashboard-YAML findest du in der Config-Sammlung. Kopiere den Inhalt, passe die Entity-IDs an dein Setup an und füge ihn im YAML-Modus ein.
Sportarten anpassen und erweitern
Das Setup ist bewusst so gebaut, dass du es einfach erweitern kannst. Wenn du statt Tennis zum Beispiel Laufen trackst, legst du dir die gleichen Input Helper an, mit garmin_run_month_km, garmin_run_year_km und so weiter. Die Automation erkennt den Aktivitätstyp über den Namen aus der Garmin API und ordnet die Werte entsprechend zu.
Bei mir laufen gerade drei Sportarten parallel. Das reicht für meinen Alltag. Du könntest aber ohne Probleme noch Schwimmen, Wandern oder was auch immer ergänzen. Das Muster ist immer das gleiche: Input Helper pro Sportart, Template-Sensoren für Berechnungen, Mushroom Cards im Dashboard.
Warum das Ganze in Home Assistant?
Garmin Connect hat natürlich selbst Statistiken. Aber ich finde es wahnsinnig praktisch, die Fitnessdaten zusammen mit allem anderen Smart-Home-Kram auf einem Dashboard zu haben. Morgens kurz aufs Tablet geschaut und ich sehe Wetter, Energieverbrauch und wie viele Kilometer ich diesen Monat schon geskatet bin. Alles an einem Ort.
Dazu kommt: Die Daten bleiben lokal. Keine Cloud-Abhängigkeit für die Auswertung. Und wenn Garmin irgendwann die App umstellt oder Features streicht, habe ich meine Zahlen trotzdem noch in Home Assistant.
Hast du auch Fitnessdaten in Home Assistant eingebunden? Schreib mir gerne in die Kommentare, was du damit trackst.
