also download .gpx and .fit file for each activity

This commit is contained in:
petergardfjall 2014-11-09 13:32:20 +01:00
parent a8572d7e13
commit 35aea411d0
3 changed files with 61 additions and 6 deletions

View File

@ -35,10 +35,21 @@ Once started, the program will prompt you for your account password and then
log in to your Garmin Connect account to download all activities to a destination log in to your Garmin Connect account to download all activities to a destination
directory on your machine. directory on your machine.
For each activity, three files are stored: an activity summary (JSON), For each activity, these files are stored:
activity details (JSON) and the activity GPX file. All files are written
to the same directory (``activities/<timestamp>/`` by default). - an activity summary file (JSON)
Each activity file is prefixed by its upload timestamp and its activity id.
- an activity details file (JSON)
- an activity GPX file (XML)
- an activity TCX file (XML)
- an activity FIT file (binary)
All files are written to the same directory (``activities/<timestamp>/``
by default). Each activity file is prefixed by its upload timestamp and its
activity id.
Library import Library import

View File

@ -67,7 +67,9 @@ if __name__ == "__main__":
activity_summary = client.get_activity_summary(id) activity_summary = client.get_activity_summary(id)
activity_details = client.get_activity_details(id) activity_details = client.get_activity_details(id)
activity_gpx = client.get_activity_gpx(id) activity_gpx = client.get_activity_gpx(id)
activity_tcx = client.get_activity_tcx(id)
activity_fit = client.get_activity_fit(id)
# for each activitity save the summary, details and GPX file. # for each activitity save the summary, details and GPX file.
creation_millis = activity_summary["activity"]["uploadDate"]["millis"] creation_millis = activity_summary["activity"]["uploadDate"]["millis"]
timestamp = datetime.fromtimestamp(int(creation_millis)/1000.0) timestamp = datetime.fromtimestamp(int(creation_millis)/1000.0)
@ -78,6 +80,8 @@ if __name__ == "__main__":
summary_file = path_prefix + "_summary.json" summary_file = path_prefix + "_summary.json"
details_file = path_prefix + "_details.json" details_file = path_prefix + "_details.json"
gpx_file = path_prefix + ".gpx" gpx_file = path_prefix + ".gpx"
tcx_file = path_prefix + ".tcx"
fit_file = path_prefix + ".fit"
with codecs.open(summary_file, encoding="utf-8", mode="w") as f: with codecs.open(summary_file, encoding="utf-8", mode="w") as f:
f.write(json.dumps( f.write(json.dumps(
activity_summary, ensure_ascii=False, indent=4)) activity_summary, ensure_ascii=False, indent=4))
@ -85,7 +89,11 @@ if __name__ == "__main__":
f.write(json.dumps( f.write(json.dumps(
activity_details, ensure_ascii=False, indent=4)) activity_details, ensure_ascii=False, indent=4))
with codecs.open(gpx_file, encoding="utf-8", mode="w") as f: with codecs.open(gpx_file, encoding="utf-8", mode="w") as f:
f.write(activity_gpx) f.write(activity_gpx)
with codecs.open(tcx_file, encoding="utf-8", mode="w") as f:
f.write(activity_tcx)
with open(fit_file, mode="wb") as f:
f.write(activity_fit)
except Exception as e: except Exception as e:
exc_type, exc_value, exc_traceback = sys.exc_info() exc_type, exc_value, exc_traceback = sys.exc_info()
log.error(u"failed with exception: %s", e) log.error(u"failed with exception: %s", e)

View File

@ -7,7 +7,9 @@ import json
import logging import logging
import re import re
import requests import requests
from StringIO import StringIO
import sys import sys
import zipfile
# #
# Note: For more detailed information about the API services # Note: For more detailed information about the API services
@ -250,3 +252,37 @@ class GarminClient(object):
activity_id, response.status_code, response.text)) activity_id, response.status_code, response.text))
return response.text return response.text
def get_activity_tcx(self, activity_id):
"""Return a TCX (Training Center XML) representation of a
given activity.
:param activity_id: Activity identifier.
:type activity_id: int
:returns: The TCX representation of the activity as an XML string.
:rtype: str
"""
response = self.session.get("https://connect.garmin.com/proxy/activity-service-1.3/tcx/course/{}".format(activity_id))
if response.status_code != 200:
raise Exception(u"failed to fetch TCX for activity {}: {}\n{}".format(
activity_id, response.status_code, response.text))
return response.text
def get_activity_fit(self, activity_id):
"""Return a FIT representation for a given activity.
:param activity_id: Activity identifier.
:type activity_id: int
:returns: A string with a FIT file for the activity.
:rtype: str
"""
response = self.session.get("https://connect.garmin.com/proxy/download-service/files/activity/{}".format(activity_id))
if response.status_code != 200:
raise Exception(u"failed to fetch FIT for activity {}: {}\n{}".format(
activity_id, response.status_code, response.text))
# fit file returned from server is in a zip archive
zipped_fit_file = response.content
zip = zipfile.ZipFile(StringIO(zipped_fit_file), mode="r")
# return the "<activity-id>.fit" entry from the zip archive
return zip.open(str(activity_id) + ".fit").read()