Skip to content

Commit 286ea6f

Browse files
authored
feat(export): Add TCX support for Codoon activities without GPS data (#1000)
Codoon records for indoor activities contain valuable heart rate data but lack GPS track points. This commit enables exporting these activities specifically to the TCX format. TCX is chosen because it is designed to handle fitness data that may not include a GPS track, making it the ideal format for this use case.
1 parent ec93868 commit 286ea6f

File tree

1 file changed

+26
-4
lines changed

1 file changed

+26
-4
lines changed

run_page/codoon_sync.py

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,15 @@
4242
"formats": ["i", "S4", "S32", "S32", "S8"],
4343
}
4444
)
45+
FitTypeHRT = np.dtype(
46+
{
47+
"names": [
48+
"time",
49+
"bpm",
50+
], # unix timestamp, heart bpm
51+
"formats": ["i", "S4"],
52+
}
53+
)
4554

4655
# device info
4756
user_agent = "CodoonSport(8.9.0 1170;Android 7;Sony XZ1)"
@@ -192,14 +201,14 @@ def tcx_output(fit_array, run_data):
192201
# HeartRateBpm
193202
# None was converted to bytes by np.dtype, becoming a string "None" after decode...-_-
194203
# as well as LatitudeDegrees and LongitudeDegrees below
195-
if not bytes.decode(i["bpm"]) == "None":
204+
if "bpm" in i and not bytes.decode(i["bpm"]) == "None":
196205
bpm = ET.Element("HeartRateBpm")
197206
bpm_value = ET.Element("Value")
198207
bpm.append(bpm_value)
199208
bpm_value.text = bytes.decode(i["bpm"])
200209
tp.append(bpm)
201210
# Position
202-
if not bytes.decode(i["lati"]) == "None":
211+
if "lati" in i and not bytes.decode(i["lati"]) == "None":
203212
position = ET.Element("Position")
204213
tp.append(position)
205214
# LatitudeDegrees
@@ -278,13 +287,26 @@ def tcx_job(run_data):
278287
hr = fit_hrs.get(unix_time, None)
279288

280289
fit_list.append((unix_time, hr, latitude, longitude, elevation))
281-
282-
if fit_list:
290+
elif fit_hrs:
291+
# only heart rates
292+
print("No track points, only heart rates " + str(run_data["id"]))
293+
for unix_time, hr in fit_hrs.items():
294+
fit_list.append((unix_time, hr))
295+
296+
if len(own_points) > 0 and fit_list:
297+
# track points
283298
fit_array = np.array(fit_list, dtype=FitType)
284299
# order array
285300
fit_array = np.sort(fit_array, order="time")
286301
# write to TCX file
287302
tcx_output(fit_array, run_data)
303+
elif len(own_points) == 0 and fit_hrs and fit_list:
304+
# only heart rate
305+
fit_array = np.array(fit_list, dtype=FitTypeHRT)
306+
# order array
307+
fit_array = np.sort(fit_array, order="time")
308+
# write to TCX file
309+
tcx_output(fit_array, run_data)
288310
else:
289311
print("No data in " + str(run_data["id"]))
290312

0 commit comments

Comments
 (0)