15th Aug 2006
Hacking the Nike+iPod
I recently got a Nike+iPod sport kit and shoes. They are really damn cool. It does what it is meant to do quite well (tracking your run and giving you all kinds of fun motivating statistics) but I had always wondered how it recorded the information, and if there was anything else fun I could get it to do.
Luckily for everyone, Apple and nike chose to record this data as clean XML. Here’s what a workout file looks like:
<?xml version="1.0" encoding="UTF-8"?>
<sportsData><vers>1</vers>
<runSummary><workoutName>Basic</workoutName>
<time>2006-08-13T00:54:49-04:00</time>
<duration>1716812</duration>
<durationString>28:36</durationString>
<distance unit="km">4.3527</distance>
<distanceString>4.35 km</distanceString>
<pace>6:34 min/km</pace>
<calories>355</calories>
<battery></battery>
<playlistList><playlist><playlistName>Running</playlistName>
</playlist>
</playlistList>
<stepCounts><walkBegin>124</walkBegin>
<walkEnd>1316</walkEnd>
<runBegin>98</runBegin>
<runEnd>3028</runEnd>
</stepCounts>
</runSummary>
<template><templateID>8D495DCE</templateID>
<templateName>Basic</templateName>
</template>
<goal type="" value="" unit=""></goal>
<userInfo><empedID>5C6284WFVSX</empedID>
<weight>79.4</weight>
<device>iPod</device>
<calibration>000000004170000001fe00230000000041f0000004a1000000002b0000000000</calibration>
</userInfo>
<startTime>2006-08-13T00:54:49-04:00</startTime>
<snapShotList snapShotType="userClick"><snapShot event="onDemandVP"><duration>313248</duration>
<distance>0.92</distance>
</snapShot>
<snapShot event="onDemandVP"><duration>528706</duration>
<distance>1.548</distance>
</snapShot>
<snapShot event="onDemandVP"><duration>755721</duration>
<distance>2.222</distance>
</snapShot>
<snapShot event="onDemandVP"><duration>790638</duration>
<distance>2.284</distance>
</snapShot>
<snapShot event="onDemandVP"><duration>1066793</duration>
<distance>2.714</distance>
</snapShot>
<snapShot event="onDemandVP"><duration>1277388</duration>
<distance>3.341</distance>
</snapShot>
<snapShot event="onDemandVP"><duration>1410509</duration>
<distance>3.552</distance>
</snapShot>
<snapShot event="powerSong"><duration>1412404</duration>
<distance>3.554</distance>
</snapShot>
<snapShot event="stop"><duration>1716780</duration>
<distance>4.352</distance>
</snapShot>
</snapShotList>
<snapShotList snapShotType="kmSplit"><snapShot><duration>339859</duration>
<distance>1.0</distance>
</snapShot>
<snapShot><duration>677423</duration>
<distance>2.001</distance>
</snapShot>
<snapShot><duration>1168834</duration>
<distance>3.0</distance>
</snapShot>
<snapShot><duration>1558960</duration>
<distance>4.0</distance>
</snapShot>
</snapShotList>
<snapShotList snapShotType="mileSplit"><snapShot><duration>549808</duration>
<distance>1.611</distance>
</snapShot>
<snapShot><duration>1236915</duration>
<distance>3.219</distance>
</snapShot>
</snapShotList>
<extendedDataList><extendedData dataType="distance" intervalType="time" intervalUnit="s" intervalValue="10">0.0, 0.0201, 0.0331, 0.0608, 0.098, 0.13, 0.1586, 0.1899, 0.2219, 0.2542, 0.2858, 0.3174, 0.3447, 0.3745, 0.4045, 0.4323, 0.467, 0.4948, 0.526, 0.5579, 0.586, 0.6159, 0.6486, 0.6789, 0.706, 0.7344, 0.7678, 0.795, 0.8255, 0.8592, 0.8852, 0.9146, 0.9445, 0.9711, 1.0004, 1.0296, 1.0563, 1.0882, 1.1148, 1.1447, 1.1753, 1.2036, 1.2338, 1.2632, 1.2934, 1.3219, 1.3515, 1.3811, 1.4105, 1.4401, 1.4656, 1.4948, 1.5246, 1.5509, 1.5808, 1.6115, 1.6395, 1.6729, 1.7034, 1.7304, 1.7604, 1.7922, 1.8245, 1.8536, 1.8847, 1.9164, 1.9476, 1.9793, 2.0107, 2.0425, 2.0697, 2.1003, 2.1317, 2.1616, 2.1865, 2.2137, 2.2369, 2.2516, 2.2664, 2.2846, 2.2988, 2.3148, 2.3308, 2.3471, 2.3633, 2.3775, 2.3936, 2.41, 2.4263, 2.4407, 2.4581, 2.4716, 2.4872, 2.5027, 2.5192, 2.5334, 2.5487, 2.5662, 2.5804, 2.5962, 2.6108, 2.6263, 2.6424, 2.6584, 2.6744, 2.6902, 2.704, 2.7188, 2.7341, 2.75, 2.7794, 2.8115, 2.8469, 2.8768, 2.9089, 2.9377, 2.9728, 3.0067, 3.0369, 3.0706, 3.102, 3.1347, 3.1682, 3.2005, 3.2293, 3.2613, 3.2906, 3.3215, 3.3471, 3.3636, 3.3782, 3.3931, 3.411, 3.427, 3.4416, 3.4579, 3.4742, 3.4888, 3.5074, 3.5213, 3.5383, 3.5518, 3.5634, 3.5822, 3.5978, 3.6106, 3.6486, 3.6933, 3.7372, 3.7769, 3.8201, 3.8626, 3.9049, 3.9381, 3.9691, 3.986, 4.0022, 4.0185, 4.0331, 4.0489, 4.0654, 4.0831, 4.098, 4.1143, 4.1303, 4.1463, 4.176, 4.2112, 4.2456, 4.2796, 4.3102, 4.3404</extendedData>
</extendedDataList>
</sportsData>
As you can see, the extendedData tag holds the real meat of the workout: the distance ran (in kilometers, since that’s how I set mine up) recorded every 10 seconds. We also get interesting snapShot items, that tell us the exact moment, to 1/1000 of a second, when we hit certain kilometer or mile milestones, or when the user hit the Voice Feedback button (the “onDemandVP” event).
You can also see, closer to the top, basic workout info such as how many calories burned duration, distance, average pace, etc.
Some things of interest include the stepCounts tag, which I guess counts steps, but isn’t used at all in the Nike+iPod interface.
It’s cool that this data is totally open and free to be hacked upon, although I’m not quite sure what I would use if for just yet, as the Nike+iPod web app seems to handle pretty much all my needs thus far. It’s nice to know that should the Nike+ service ever die, writing your own desktop app (that is much more precise and feature-ful) would not be difficult.
Hopefully this will be of use to someone or even just the curious like me.
I recently got a Nike+iPod sport kit and shoes. They are really damn cool. It does what it is meant to do quite well (tracking your run and giving you all kinds of fun motivating statistics) but I had always wondered how it recorded the information, and if there was anything else fun I could get it to do.
Luckily for everyone, Apple and nike chose to record this data as clean XML. Here’s what a workout file looks like:
<?xml version="1.0" encoding="UTF-8"?>
<sportsData><vers>1</vers>
<runSummary><workoutName>Basic</workoutName>
<time>2006-08-13T00:54:49-04:00</time>
<duration>1716812</duration>
<durationString>28:36</durationString>
<distance unit="km">4.3527</distance>
<distanceString>4.35 km</distanceString>
<pace>6:34 min/km</pace>
<calories>355</calories>
<battery></battery>
<playlistList><playlist><playlistName>Running</playlistName>
</playlist>
</playlistList>
<stepCounts><walkBegin>124</walkBegin>
<walkEnd>1316</walkEnd>
<runBegin>98</runBegin>
<runEnd>3028</runEnd>
</stepCounts>
</runSummary>
<template><templateID>8D495DCE</templateID>
<templateName>Basic</templateName>
</template>
<goal type="" value="" unit=""></goal>
<userInfo><empedID>5C6284WFVSX</empedID>
<weight>79.4</weight>
<device>iPod</device>
<calibration>000000004170000001fe00230000000041f0000004a1000000002b0000000000</calibration>
</userInfo>
<startTime>2006-08-13T00:54:49-04:00</startTime>
<snapShotList snapShotType="userClick"><snapShot event="onDemandVP"><duration>313248</duration>
<distance>0.92</distance>
</snapShot>
<snapShot event="onDemandVP"><duration>528706</duration>
<distance>1.548</distance>
</snapShot>
<snapShot event="onDemandVP"><duration>755721</duration>
<distance>2.222</distance>
</snapShot>
<snapShot event="onDemandVP"><duration>790638</duration>
<distance>2.284</distance>
</snapShot>
<snapShot event="onDemandVP"><duration>1066793</duration>
<distance>2.714</distance>
</snapShot>
<snapShot event="onDemandVP"><duration>1277388</duration>
<distance>3.341</distance>
</snapShot>
<snapShot event="onDemandVP"><duration>1410509</duration>
<distance>3.552</distance>
</snapShot>
<snapShot event="powerSong"><duration>1412404</duration>
<distance>3.554</distance>
</snapShot>
<snapShot event="stop"><duration>1716780</duration>
<distance>4.352</distance>
</snapShot>
</snapShotList>
<snapShotList snapShotType="kmSplit"><snapShot><duration>339859</duration>
<distance>1.0</distance>
</snapShot>
<snapShot><duration>677423</duration>
<distance>2.001</distance>
</snapShot>
<snapShot><duration>1168834</duration>
<distance>3.0</distance>
</snapShot>
<snapShot><duration>1558960</duration>
<distance>4.0</distance>
</snapShot>
</snapShotList>
<snapShotList snapShotType="mileSplit"><snapShot><duration>549808</duration>
<distance>1.611</distance>
</snapShot>
<snapShot><duration>1236915</duration>
<distance>3.219</distance>
</snapShot>
</snapShotList>
<extendedDataList><extendedData dataType="distance" intervalType="time" intervalUnit="s" intervalValue="10">0.0, 0.0201, 0.0331, 0.0608, 0.098, 0.13, 0.1586, 0.1899, 0.2219, 0.2542, 0.2858, 0.3174, 0.3447, 0.3745, 0.4045, 0.4323, 0.467, 0.4948, 0.526, 0.5579, 0.586, 0.6159, 0.6486, 0.6789, 0.706, 0.7344, 0.7678, 0.795, 0.8255, 0.8592, 0.8852, 0.9146, 0.9445, 0.9711, 1.0004, 1.0296, 1.0563, 1.0882, 1.1148, 1.1447, 1.1753, 1.2036, 1.2338, 1.2632, 1.2934, 1.3219, 1.3515, 1.3811, 1.4105, 1.4401, 1.4656, 1.4948, 1.5246, 1.5509, 1.5808, 1.6115, 1.6395, 1.6729, 1.7034, 1.7304, 1.7604, 1.7922, 1.8245, 1.8536, 1.8847, 1.9164, 1.9476, 1.9793, 2.0107, 2.0425, 2.0697, 2.1003, 2.1317, 2.1616, 2.1865, 2.2137, 2.2369, 2.2516, 2.2664, 2.2846, 2.2988, 2.3148, 2.3308, 2.3471, 2.3633, 2.3775, 2.3936, 2.41, 2.4263, 2.4407, 2.4581, 2.4716, 2.4872, 2.5027, 2.5192, 2.5334, 2.5487, 2.5662, 2.5804, 2.5962, 2.6108, 2.6263, 2.6424, 2.6584, 2.6744, 2.6902, 2.704, 2.7188, 2.7341, 2.75, 2.7794, 2.8115, 2.8469, 2.8768, 2.9089, 2.9377, 2.9728, 3.0067, 3.0369, 3.0706, 3.102, 3.1347, 3.1682, 3.2005, 3.2293, 3.2613, 3.2906, 3.3215, 3.3471, 3.3636, 3.3782, 3.3931, 3.411, 3.427, 3.4416, 3.4579, 3.4742, 3.4888, 3.5074, 3.5213, 3.5383, 3.5518, 3.5634, 3.5822, 3.5978, 3.6106, 3.6486, 3.6933, 3.7372, 3.7769, 3.8201, 3.8626, 3.9049, 3.9381, 3.9691, 3.986, 4.0022, 4.0185, 4.0331, 4.0489, 4.0654, 4.0831, 4.098, 4.1143, 4.1303, 4.1463, 4.176, 4.2112, 4.2456, 4.2796, 4.3102, 4.3404</extendedData>
</extendedDataList>
</sportsData>
As you can see, the extendedData tag holds the real meat of the workout: the distance ran (in kilometers, since that’s how I set mine up) recorded every 10 seconds. We also get interesting snapShot items, that tell us the exact moment, to 1/1000 of a second, when we hit certain kilometer or mile milestones, or when the user hit the Voice Feedback button (the “onDemandVP” event).
You can also see, closer to the top, basic workout info such as how many calories burned duration, distance, average pace, etc.
Some things of interest include the stepCounts tag, which I guess counts steps, but isn’t used at all in the Nike+iPod interface.
It’s cool that this data is totally open and free to be hacked upon, although I’m not quite sure what I would use if for just yet, as the Nike+iPod web app seems to handle pretty much all my needs thus far. It’s nice to know that should the Nike+ service ever die, writing your own desktop app (that is much more precise and feature-ful) would not be difficult.
Hopefully this will be of use to someone or even just the curious like me.
Posted by patrick under
apple, hacking, nike+ipod
3 Comments »