Decoding a Specialized E-bike FIT file
My Review of my Specialized Turbo Levo Kids ebike mentioned that the Specialized phone app had some fun features, but also some annoying problems. (I'm using it on Android. Dave doesn't use the app on his iPhone, so I don't know how the iPhone version compares.)
First, it has data galore. Obvious things like distance, average and
max speed, elevation gain and loss; but also cadence,
average and max rider power,
average motor power,
and an estimate of calories burned
(best not to look too hard at that last one, if you were hoping to
justify that double-fudge ice cream sundae after your ride).
I haven't figured out anything useful to do with all this data, but
as a confirmed data hoarder, I'm convinced that some day I'll want it.
That's all great, but trying to explore what's available on a small phone screen gets old fast. I want it on my big computer screen.
That gets us to the things I don't like about the app.
First, when you tap Finish at the end of the ride, the app immediately wants to upload it ... somewhere.
So that means if I go to Specialized.com and log in to the account the app insisted that I register, I'll be able to see it all there on a big screen, right?
No such luck. I've been unable to find any mention of any ride recordings on Specialized.com, and web searching has not turned up anyone who knows anything about such a thing. There's a FAQ on Specialized.com that says "If you wish to review your post-ride metrics on a wider screen or save your ride as a route, go to Ride.specialized.com", but there is no such subdomain registered.
So basically, you have to register an account so that the app can store your data in a secret cloud that you can't access yourself, except through the app on your phone. Great.
Okay, but if I connect to my phone over USB using adb, I should be able to upload the files to my computer, right?
Nope. Poking around in
/storage/emulated/0/Android/data/com.specialized.android
reveals a lot of empty directories plus cache/diskcache/,
which has three files,
map_cache.db map_cache.db-shm map_cache.db-wal
none of which sound much like ride data. map_cache.db is an sqlite3 database
containing four tables:
pinned_tiles resources settings tiles.
tiles and pinned tiles are presumably related to the tiles used in the
map display;
SELECT * FROM resources;
dumps a bunch of unprintable characters. It's possible that decoding them
would yield something useful, but that's as far as I got.
(The app must store the current ride somewhere,
but I can't figure out where.)
Okay, so I can't download the ride data from specialized.com, and I can't copy it from the app's file space. Is there any way to get at this data so I can view it on a reasonably-sized screen?
I eventually found one way. There's a three-dots menu button when you're viewing a ride which gives an Export FIT file option. And if you export it using a file manager (I use Fx File Manager), you can save it to an accessible place like Downloads where you can then access it with adb or whatever file copy program you prefer. Except that it always defaults the export filename to "Share.data", so don't forget to laboriously type a better name before you export if you don't want to risk overwriting any previously exported files.
Viewing a FIT
Then what do you do with that FIT file?
If all you want is the GPS track, you can use gpsbabel: gpsbabel -i garmin_fit -f 2025-06-24.fit -o gpx -F 2025-06-24.gpx
But if that's all you want, why use the Specialized app at all? Use something more friendly and flexible, like OsmAnd.
To get the other data, you need something that can decode the FIT file format. The best I've found is fitdecode, which has Python bindings plus a couple of commandline apps.
You can see what all is stored in the FIT file with fitjson:
pip install fitdecode fitjson ride-22753369.fit >ride-22753369.json
fitjson will spew a huge number of long error lines, because apparently Specialized's version of FIT doesn't match fitdecode's, but it will convert the file anyway.
Although I generally like JSON as a format, the JSON thus produced isn't very useful, since it's split into frames and a lot of redundant chatter. fitdecode's other commandline utility, fittxt, is much the same.
So I wrote a little Python script that uses fitdecode to split the FIT file into a GPX of the map data and a CSV of everything else: fitsplit.py It normally depends on a file from one of my other programs, pytopo, to produce a nice GPX file, but I added code to use gpsbabel if pytopo isn't installed.
I confess I haven't actually found a way to use any of that data
yet. But I will some day! Maybe after I figure out how to get the data
from the heart rate monitor I'm currently wearing ... but that's a whole
other story.
[ 17:39 Sep 09, 2025 More bike | permalink to this entry | ]