Skip to content

Instantly share code, notes, and snippets.

@grantstephens
Created September 10, 2017 06:12
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save grantstephens/ea92a638fd79191e251d24d0984ef63f to your computer and use it in GitHub Desktop.
Save grantstephens/ea92a638fd79191e251d24d0984ef63f to your computer and use it in GitHub Desktop.
Garmin Connect Sync Script for Linux (python)
# Syncs files on a garmin device to garmin connect and keeps a local copy.
# auth.json contains your garmin connect username(email) and password.
import json
import os
import shutil
import requests
def auth():
session = requests.Session()
with open('auth.json', 'r') as fn:
data = json.load(fn)
data.update({'eventId': 'submit', 'embed': 'true', })
base_url = 'https://sso.garmin.com/sso'
url_prefix = 'https://connect.garmin.com'
params = {
'service': url_prefix+'/post-auth/login', 'clientId': 'GarminConnect',
'gauthHost': base_url, 'consumeServiceTicket': 'false',
}
preResp = session.get(base_url+'/login', params=params)
ssoResp = session.post(base_url+'/login', params=params,
data=data, allow_redirects=False)
gcRedeemResp = session.get(url_prefix+'/post-auth/login',
allow_redirects=False)
max_redirect_count = 7
current_redirect_count = 1
while True:
url = gcRedeemResp.headers['location']
# Fix up relative redirects.
if url.startswith('/'):
url = url_prefix + url
url_prefix = '/'.join(url.split('/')[:3])
gcRedeemResp = session.get(url, allow_redirects=False)
if ((current_redirect_count >= max_redirect_count) and
(gcRedeemResp.status_code != 200)):
raise Exception('GC redeem %d/%d error %s %s' % (
current_redirect_count, max_redirect_count,
gcRedeemResp.status_code, gcRedeemResp.text))
if gcRedeemResp.status_code == 200 or gcRedeemResp.status_code == 404:
break
current_redirect_count += 1
if current_redirect_count > max_redirect_count:
break
session.headers.update({'Referer': 'https://grant.stephens.com'})
return session
def upload(path, fn, session):
url_prefix = 'https://connect.garmin.com'
return session.post(url_prefix+'/modern/proxy/upload-service/upload/.fit',
files={
'data': (fn, open(os.path.join(path, fn), 'rb'))},
headers={'nk': 'NT'})
if __name__ == "__main__":
session = auth()
path = '/media/{}/GARMIN/Garmin/Activity'.format(
os.environ.get('USERNAME'))
for fn in os.listdir(path):
print('Uploading: {}'.format(fn))
result = upload(path, fn, session).json()
if len(result['detailedImportResult']['successes']) == 1:
print('Moving: {}'.format(fn))
os.makedirs(fn.split('-')[0]+'test', exist_ok=True)
shutil.move(os.path.join(path, fn),
os.path.join(fn.split('-')[0], fn))
else:
os.makedirs('errors', exist_ok=True)
shutil.move(os.path.join(path, fn),
os.path.join('errors', fn))
@Miquel1981
Copy link

Miquel1981 commented May 24, 2018

Hi grantstephens,

Do you know if this works for a Garmin Forerunner 405? I created a script to download my tracks on my computer and I would like to upload on Garmin Connect automatically from my folder. What is the format of the auth.json? I'm Linux user and Garmin connect don't exist on this OS, this is the reason for my query.

Thanks a lot for your work.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment