I want to share a package file for integrate information from a Garmin LiveTrack event.
I use the IMAP sensor get the url automatic. IMAP integration need to fetch the first 21000 bytes because where the link is placed in the mail.
It’s also possible to share the url into the input field. input_text.garmin_livetrack_link
garmin_livetrack.yaml package file
# Garmin Livetrack
# homeassistant:
# packages: !include_dir_named packages
# packages/garmin_livetrack.yaml
input_text:
garmin_livetrack_link:
name: Garmin LiveTrack link
max: 250
icon: mdi:link
initial: ""
rest:
- resource: "https://livetrack.garmin.com/apollo/graphql"
scan_interval: 2592000 #30 d (we update it manually in automation)
method: POST
headers:
Content-Type: application/json
payload_template: >
{{ {
'query': "query sessionAndPoints($sessionId:String!,$token:String!,$begin:String){\n"
" session:sessionById(sessionId:$sessionId,token:$token){start end sessionId}\n"
" points:trackPointsBySessionId(sessionId:$sessionId,token:$token,begin:$begin){\n"
" trackPoints{fitnessPointData{totalDurationSecs speedMetersPerSec totalDistanceMeters activityType cadenceCyclesPerMin distanceMeters durationSecs elevationGainMeters elevationSource eventTypes heartRateBeatsPerMin pointStatus powerWatts} position{lat lon} dateTime speed altitude}}\n"
"}",
'variables': {
'sessionId': states('sensor.garmin_livetrack_id'),
'token' : state_attr('sensor.garmin_livetrack_id','token'),
'begin' : [states('sensor.garmin_livetrack_points_rest'), state_attr('sensor.garmin_livetrack_session_rest','start')] | select | max
if states('sensor.garmin_livetrack_id') == state_attr('sensor.garmin_livetrack_session_rest','sessionId')
else none
}
} | to_json }}
sensor:
#used to get last point info. Using begin we only fetch points >= to last (must be >= start or null)
- name: "Garmin LiveTrack Points Rest"
unique_id: garmin_livetrack_points_rest
value_template: >-
{{ value_json.data.points.trackPoints[-1].dateTime if (value_json.data.points.trackPoints | count) }}"
json_attributes_path: "$.data.points.trackPoints[-1:]"
json_attributes:
- dateTime
- position
- altitude
- fitnessPointData
- speed
#used to get session start/end times and to determine if session is in_progress (if end is start + 1 day)
- name: "Garmin LiveTrack Session Rest"
unique_id: garmin_livetrack_session_rest
value_template: >-
{%- set s = value_json.data.session %}
{%- if s and s.start and s.end %}
{{ as_timestamp(s.end) == as_timestamp(s.start) + 86400 }}
{%- else %}
False
{%- endif %}
json_attributes_path: "$.data.session"
json_attributes:
- start
- end
- sessionId
template:
- trigger:
- platform: state
entity_id: input_text.garmin_livetrack_link
- platform: state
entity_id: sensor.garmin_livetrack_link_from_email
sensor:
- name: Garmin LiveTrack id
state: >-
{%- if "livetrack.garmin.com" in trigger.to_state.state -%}
{{- (trigger.to_state.state | regex_findall(find='https://livetrack.garmin.com/session/([a-z0-9-\n\r=]+)/token/([a-z0-9-\n\r=][^"]+)', ignorecase=True))[0] -}}
{%- elif trigger.entity_id == "sensor.garmin_livetrack_link_from_email" and trigger.to_state.state != "" -%}
{{- trigger.to_state.state -}}
{%- endif -%}
attributes:
link: >-
https://livetrack.garmin.com/session/
{%- if "livetrack.garmin.com" in trigger.to_state.state -%}
{{- (trigger.to_state.state | regex_findall(find='https://livetrack.garmin.com/session/([a-z0-9-\n\r=]+)/token/([a-z0-9-\n\r=][^"]+)', ignorecase=True))[0] -}}
{%- elif trigger.entity_id == "sensor.garmin_livetrack_link_from_email" and trigger.to_state.state != "" -%}
{{- trigger.to_state.state -}}/token/{{- trigger.to_state.attributes.token -}}
{%- endif -%}
session: >-
{%- if "livetrack.garmin.com" in trigger.to_state.state -%}
{{- (trigger.to_state.state | regex_findall(find='https://livetrack.garmin.com/session/([a-z0-9-\n\r=]+)/token/([a-z0-9-\n\r=][^"]+)', ignorecase=True))[0].0 -}}
{%- elif trigger.entity_id == "sensor.garmin_livetrack_link_from_email" and trigger.to_state.state != "" -%}
{{- trigger.to_state.attributes.session -}}
{%- endif -%}
token: >-
{%- if "livetrack.garmin.com" in trigger.to_state.state -%}
{{- (trigger.to_state.state | regex_findall(find='https://livetrack.garmin.com/session/([a-z0-9-\n\r=]+)/token/([a-z0-9-\n\r=][^"]+)', ignorecase=True))[0].1 -}}
{%- elif trigger.entity_id == "sensor.garmin_livetrack_link_from_email" and trigger.to_state.state != "" -%}
{{- trigger.to_state.attributes.token -}}
{%- endif -%}
icon: mdi:map
# Sensor to get link from email with integration: https://www.home-assistant.io/integrations/imap_email_content/
- trigger:
- platform: event
event_type: "imap_content"
event_data:
sender: [email protected]
sensor:
- name: Garmin LiveTrack link from email
state: >-
{{ (trigger.event.data['text'] | regex_findall(find='https://livetrack.garmin.com/session/([a-z0-9-\n\r=]+)/token', ignorecase=True))[0] | replace('\n','') | replace('\r','') | replace('=','') }}
attributes:
date: "{{ trigger.event.data['date'] }}"
link: >-
https://livetrack.garmin.com/session/
{{- ((trigger.event.data['text'] | regex_findall(find='https://livetrack.garmin.com/session/([a-z0-9-\n\r=]+)/token/([a-z0-9-\n\r=][^"]+)', ignorecase=True))[0].0) | replace('\n','') | replace('\r','') | replace('=','') }}
{{- '/token/' }}
{{- ((trigger.event.data['text'] | regex_findall(find='https://livetrack.garmin.com/session/([a-z0-9-\n\r=]+)/token/([a-z0-9-\n\r=][^"]+)', ignorecase=True))[0].1) | replace('\n','') | replace('\r','') | replace('=','') }}
session: >-
{{ ((trigger.event.data['text'] | regex_findall(find='https://livetrack.garmin.com/session/([a-z0-9-\n\r=]+)/token/([a-z0-9-\n\r=][^"]+)', ignorecase=True))[0].0) | replace('\n','') | replace('\r','') | replace('=','') }}
token: >-
{{ ((trigger.event.data['text'] | regex_findall(find='https://livetrack.garmin.com/session/([a-z0-9-\n\r=]+)/token/([a-z0-9-\n\r=][^"]+)', ignorecase=True))[0].1) | replace('\n','') | replace('\r','') | replace('=','') }}
- binary_sensor:
- name: Garmin Livetrack
state: "{{ is_state_attr('automation.garmin_livetrack', 'current',1) }}"
attributes:
latitude: "{{ trigger.to_state.attributes.position.lat }}"
longitude: "{{ trigger.to_state.attributes.position.lon }}"
start: "{{ state_attr('sensor.garmin_livetrack_session_rest','start') }}"
datetime: "{{ trigger.to_state.attributes.dateTime }}"
duration: "{{ timedelta(seconds=(float(trigger.to_state.attributes.fitnessPointData.totalDurationSecs,0))) }}"
durationSec: "{{ float(trigger.to_state.attributes.fitnessPointData.totalDurationSecs,0) }}"
activity: "{{ trigger.to_state.attributes.fitnessPointData.activityType | lower }}"
speed: "{{ trigger.to_state.attributes.speed }}"
speed_ms: "{{ trigger.to_state.attributes.fitnessPointData.speedMetersPerSec }}"
pace: "{{ 16.666666667/float(trigger.to_state.attributes.speed,0) }}"
altitude: "{{ trigger.to_state.attributes.altitude }}"
elevation_gain: "{{ int(trigger.to_state.attributes.fitnessPointData.elevationGainMeters,0) }}"
elevation_source: "{{ trigger.to_state.attributes.fitnessPointData.elevationSource }}"
distance: "{{ int(trigger.to_state.attributes.fitnessPointData.distanceMeters,0) /1000 | round(1) }}"
heartbeats: "{{ trigger.to_state.attributes.fitnessPointData.heartRateBeatsPerMin }}"
watt: "{{ trigger.to_state.attributes.fitnessPointData.powerWatts }}"
event: "{{ trigger.to_state.attributes.fitnessPointData.eventTypes }}"
status: "{{ trigger.to_state.attributes.fitnessPointData.pointStatus | lower }}"
link: "{{ state_attr('sensor.garmin_livetrack_id','link') }}"
automation:
- alias: Garmin LiveTrack new link
id: "garmin_livetrack_new_link"
mode: restart
trigger:
- platform: state
entity_id: sensor.garmin_livetrack_id
condition:
- condition: template
value_template: "{{ trigger.to_state.state != '' }}"
- condition: template
value_template: "{{ trigger.to_state.state != 'unknown' }}"
- condition: template
value_template: '{{ trigger.from_state.state != trigger.to_state.state }}'
action:
- variables:
update_min: 2
- alias: "Test if any data is present"
repeat:
until:
- condition: or
conditions:
- condition: template
value_template: "{{ as_timestamp(now()) - as_timestamp(states('sensor.garmin_livetrack_points_rest'), now()) > 0 }}"
- condition: template
value_template: "{{ repeat.index >= 15 }}"
sequence:
- alias: "Update sensor.garmin_livetrack_points_rest"
service: homeassistant.update_entity
entity_id: sensor.garmin_livetrack_points_rest
- alias: "Wait 15 sec"
delay: "00:00:15"
- repeat:
until:
- condition: or
conditions:
- alias: "Test if END in eventTypes"
condition: template
value_template: "{{ 'END' in state_attr('sensor.garmin_livetrack_points_rest','fitnessPointData')['eventTypes'] if state_attr('sensor.garmin_livetrack_points_rest','fitnessPointData') }}"
- alias: "Test if last update update > 30min"
condition: template
value_template: "{{ as_timestamp(now())-int(as_timestamp(states('sensor.garmin_livetrack_points_rest'),as_timestamp(now())),0) > 60*60 }}"
- alias: "Test if new id"
condition: template
value_template: "{{ trigger.to_state.state != states('sensor.garmin_livetrack_id') }}"
- alias: "Test if loop run for 11h"
condition: template
value_template: "{{ repeat.index > (11*60/update_min) }}"
sequence:
- service: homeassistant.update_entity
entity_id: sensor.garmin_livetrack_points_rest
- delay:
minutes: "{{ update_min }}"
# Custom notification
- alias: Garmin LiveTrack start
id: "garmin_livetrack_start"
mode: restart
trigger:
- platform: state
entity_id: binary_sensor.garmin_livetrack
to: "on"
action:
- alias: "Notify start"
service: notify.mobile_app_user
data:
title: "Garmin LiveTrack"
message: "Startar"
data:
ledColor: green
color: green
group: Garmin
tag: garmin_livetrack
sticky: true
clickAction: "entityId:binary_sensor.garmin_livetrack"
timeout: 270
notification_icon: mdi:map-clock
actions:
- action: "URI"
uri: "{{ state_attr('sensor.garmin_livetrack_id','link') }}"
title: "Visa Garmin LiveTrack"
- alias: "Turn on automations with actions depending on Livetrack"
service: automation.turn_on
entity_id:
- automation.garmin_livetrack_plats
- wait_for_trigger:
- trigger: state
entity_id: binary_sensor.garmin_livetrack
to: "off"
- alias: "Notify end"
service: notify.mobile_app_user
data:
title: "Garmin Livetrack"
message: |
Slut!
{{ state_attr('binary_sensor.garmin_livetrack','duration') }}
{{ state_attr('binary_sensor.garmin_livetrack','distance') }}
{{ state_attr('binary_sensor.garmin_livetrack','activity') }}
{{ state_attr('binary_sensor.garmin_livetrack','event') }}
data:
group: Garmin
tag: garmin_livetrack
clickAction: "entityId:binary_sensor.garmin_livetrack"
timeout: 300
notification_icon: mdi:stop-circle
actions:
- action: "URI"
uri: "{{ state_attr('sensor.garmin_livetrack_id','link') }}"
title: "Visa Garmin LiveTrack"
- service: automation.turn_off
entity_id:
- automation.garmin_livetrack_plats
#logger:
# filters:
# homeassistant.components.rest.sensor:
# - "JSON result was not a dictionary or list with 0th element a dictionary"
Good luck! ![]()
![]()
![]()
![]()



