[Amazfit] Michael Inkster:
hope this helps for Stratos tcx exports

I started to look through the coding for the tcx output on the stratos. ("pgm\tcx\amazfit_exporter_new.py")

I created a version that does laps (pool based on distance in sport summary, or distance based with swim 100, bike 5000 and everything else 1000).

It also handles multisport (duathlon and triathlon) and follows the standards rigidly so that it will uploads without problems to everything including training peaks which is notorious for it's error of "could not parse file".

I can't find a way to upload the file itself but the code is below (minus the schema location because I can't post links). I have placed "<TRAINING_CENTER_SCHEMA_LOCATION_LINE_FROM_FILE>" which you will need find and replace with the schema information from the original file. This is use at own risk and the code is everything below this:

#!/usr/bin/python3

import sqlite3 as lite

import sys

import datetime

import time as t

import os

import json

from collections import deque

def db_to_tcx(db,dest,begtime,tz,wmodel):

# Connect to the sport database

con = lite.connect(db)

with con:

cur = con.cursor()

cur.execute('SELECT track_id, start_time, type, content, parent_trackid from sport_summary where track_id >'+ str(begtime) + '')

activities = cur.fetchall()

if wmodel == 1:

wname = "Pace"

elif wmodel == 2:

wname = "Stratos"

Parent_Activity = (activity for activity in activities if activity[4] == -1)

for activity in Parent_Activity:

# load the summary information JSON

content_json = json.loads(activity[3])

# Get the track ID and starting time

track_id=activity[0]

start_time=activity[1]

Activity_Type = int(activity[2])

parent_trackid = activity[4]

# get multisport session child list

child_list = str(content_json['child_list'])

# find out what type of activity it is

if (parent_trackid == -1) and (child_list == '[]'):

if Activity_Type == 1:

type = "Running"

description = "Run"

elif Activity_Type == 6:

type = "Other"

description = "Walk"

elif Activity_Type == 7:

type = "Running"

description = "Trail Run"

elif Activity_Type == 8:

type = "Running"

description = "Treadmill"

elif Activity_Type == 9:

type = "Biking"

description = "Outdoor Cycling"

elif Activity_Type == 10:

type = "Biking"

description = "Indoor Cycling"

elif Activity_Type == 12:

type = "Other"

description = "Elliptical"

elif Activity_Type == 13:

type = "Other"

description = "Climb"

elif Activity_Type == 14:

type = "Other"

description = "Pool Swim"

elif Activity_Type == 15:

type = "Other"

description = "Outdoor Swim"

else:

type = "Other"

elif (parent_trackid == -1) and (child_list != '[]'):

type = "MultiSportSession"

if Activity_Type == 2001:

description = "Triathlon"

elif Activity_Type == 2002:

description = "Duathlon"

#initialize local variables

cad = deque([])

stride = 0

cad_avg = 0

step_cum = 0

dist_cum = 0

lap_count = 1

lap_dist = 0

lap_length = 0

total_rows = 0

count_rows = 0

# get activity data

duration = str(int(content_json['duration'])/1000)

total_dist = int(content_json['distance'])

sport_dist = str(content_json['distance'])

activity_latitude = str(content_json['latitude'])

calorie = str(int(int(content_json['calorie'])/1000))

if (total_dist > 0):

calorie_m = int(int(content_json['calorie'])/1000)/int(content_json['distance'])

else:

calorie_m = 0

avg_heart_rate = str(int(content_json['avg_heart_rate']))

max_heart_rate = str(int(content_json['max_heart_rate']))

# calculate stride length for treadmill runs because Amazfit stride info is incorrect

step_tot = int(content_json['step_count'])

dist_tot = int(content_json['distance'])

if step_tot > 0:

stride = float(dist_tot)/float(step_tot)

# Get timestamps in UTC timezone for activity

session_utc = activity[1]/1000+tz

timestamp_utc = str(datetime.datetime.utcfromtimestamp(activity[1]/1000+tz).isoformat()) + 'Z'

# Get timestamps in Local timezone for activity

session_local = str(datetime.datetime.fromtimestamp(activity[1]/1000+tz).strftime('%Y%m%d_%H%M%S'))

# set filename for activity

fileName = dest+'/tcx/'+session_local+'_'+description+'('+str(Activity_Type)+')'+'.tcx'

# check if file exists

if not os.path.exists(fileName):

try:

os.remove(fileName)

except OSError:

pass

with open(fileName, 'a') as out:

# Write Header

print(session_local+' - type: ' + type + ' - Exporting...')

out.write('<?xml version="1.0" encoding="UTF-8"?>' + '\n')

out.write('<TRAINING_CENTER_SCHEMA_LOCATION_LINE_FROM_FILE>' + '\n')

out.write(' <Activities>' + '\n')

if (type == "MultiSportSession"):

out.write(' <MultiSportSession>'+ '\n')

out.write(' <Id>' + timestamp_utc + '</Id>'+ '\n')

out.write(' <FirstSport>' + '\n')

else:

# set lap distances. Pool swim is based off stored pool length

bike_lap = [9, 10]

if (Activity_Type==14):

lap_length = int(content_json['swim_pool_length'])

elif (Activity_Type in bike_lap):

lap_length = 5000

else:

lap_length = 1000

out.write(' <Activity Sport="'+ type + '">' + '\n')

out.write(' <Id>' + timestamp_utc + '</Id>'+ '\n')

# Non GPS Activities without distances

if (total_dist == 0):

expmode = "noGPS"

out.write(' <Lap StartTime="' + timestamp_utc + '">' + '\n')

out.write(' <TotalTimeSeconds>'+ duration +'</TotalTimeSeconds>' + '\n')

out.write(' <DistanceMeters>'+ sport_dist +'</DistanceMeters>' + '\n')

out.write(' <Calories>'+ calorie +'</Calories>' + '\n')

if (avg_heart_rate != '0'):

out.write(' <AverageHeartRateBpm><Value>'+ avg_heart_rate +'</Value></AverageHeartRateBpm>' + '\n')

out.write(' <MaximumHeartRateBpm><Value>'+ max_heart_rate +'</Value></MaximumHeartRateBpm>' + '\n')

out.write(' <Intensity>Active</Intensity>' + '\n')

out.write(' <TriggerMethod>Manual</TriggerMethod>' + '\n')

out.write(' <Track>' + '\n')

cur.execute('SELECT rate, step_count, time from heart_rate where track_id=' + str(track_id))

data_rows = cur.fetchall()

for data_row in data_rows:

timestamp_utc = str(datetime.datetime.utcfromtimestamp(data_row[2]/1000+tz).isoformat()) + 'Z'

# Write the trackpoint

out.write(' <Trackpoint>' + '\n')

out.write(' <Time>'+timestamp_utc+ '</Time>'+ '\n')

# Check that you have a valid HR reading

if (avg_heart_rate != '0'):

# Write the HR

out.write(' <HeartRateBpm>' + '\n')

out.write(' <Value>'+ str(data_row[0]) +'</Value>' + '\n')

out.write(' </HeartRateBpm>' + '\n')

# push the new step count in and recalculate the cadence

---------- Post added at 06:27 AM ---------- Previous post was at 06:23 AM ----------

Sorry, looks like it can't handle the full amount of information and removed the indents and truncated most of the code (it's 502 lines). If I find a good way to contribute it later I will post it then.