-
-
Save mike-kilo/a6cef38223795bc24ee09b2b00c8da56 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python | |
# -*- mode:python -*- | |
# | |
# Converts suunto zip files (which contain json files) to a gpx file | |
# until Suunto gets their act together and let me have my own data in | |
# a normal way. | |
# Needs: python 3.7 | |
# | |
# These zip files are producted by the Suunto app and typically on | |
# android are located at: | |
# <Internal Storage>/Android/data/com.stt.suunto/files/smlzip/ | |
# | |
import sys | |
import gpxpy | |
import gpxpy.gpx | |
import json | |
import datetime | |
import zipfile | |
import math | |
from backports.datetime_fromisoformat import MonkeyPatch | |
MonkeyPatch.patch_fromisoformat() | |
# The relevant json snippet which is in a json array 'Samples' | |
# looks like this: | |
# { | |
# "Attributes": { | |
# "suunto/sml": { | |
# "Sample": { | |
# "GPSAltitude": 94, <-- assuming meters | |
# "Latitude": 0.88924328690504395, <-- in radians | |
# "Longitude": 0.10261437316962527, <-- in radians | |
# "UTC": "2019-04-18T07:25:29.000+00:00" <-- assumed what gps thinks of time? | |
# } | |
# } | |
# }, | |
# "Source": "suunto-123456789", <-- number is the id of the device | |
# "TimeISO8601": "2019-04-18T09:25:29.000+02:00" <-- assumed what watch thinks of time? | |
# }, | |
# Suunto specific stuff | |
SUUNTO_SAMPLES = 'samples.json' | |
def gpx_track(zip): | |
# Three keys make a trackpoint | |
TRKPT = ('Latitude', 'Longitude', 'UTC') | |
# Create the main gpx object | |
gpx = gpxpy.gpx.GPX() | |
# We are getting one track presumably from the points we recorded | |
track = gpxpy.gpx.GPXTrack() | |
gpx.tracks.append(track) | |
# Points are added to segments (take breaks into account later?) | |
segment = gpxpy.gpx.GPXTrackSegment() | |
track.segments.append(segment) | |
# Read in the json file | |
with zip.open(SUUNTO_SAMPLES, 'r') as json_data: | |
suunto_json = json.loads(json_data.read().decode('utf-8')) | |
for s in suunto_json["Samples"]: | |
if "Sample" in s["Attributes"]["suunto/sml"]: | |
sample = s["Attributes"]["suunto/sml"]["Sample"] | |
# See if we have enough for a trackpoint | |
if all(key in sample for key in TRKPT): | |
# Lat and long are radians | |
# To decimal degrees = * 180 / PI | |
lat = (sample["Latitude"] * 180) / math.pi | |
lon = (sample["Longitude"] * 180) / math.pi | |
# I'm assuming this is in meters, and we can use it as is | |
ele = sample['GPSAltitude'] if 'GPSAltitude' in sample else 0 | |
time = datetime.datetime.fromisoformat(sample['UTC']) | |
# Create the gpx point | |
point = gpxpy.gpx.GPXTrackPoint(latitude=lat, longitude=lon, | |
time=time, elevation=ele) | |
segment.points.append(point) | |
# Write out the gpx file | |
with open(zip.filename.replace(".zip", ".gpx"), "w") as out: | |
out.write(gpx.to_xml()) | |
if __name__ == "__main__": | |
# Argument is expected to be a zip file | |
with zipfile.ZipFile(sys.argv[1]) as zip: | |
# There should be a samples.json in the zip file | |
if SUUNTO_SAMPLES in zip.namelist(): | |
gpx_track(zip) | |
else: | |
print("No track samples found in zip file!") |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment