fit-file-parser 2.1.0 → 2.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/debug_output.json +413301 -0
- package/deep_probe.js +69 -0
- package/dist/binary.js +22 -4
- package/dist/cjs/binary.js +22 -4
- package/dist/cjs/fit-parser.js +10 -0
- package/dist/cjs/fit.js +280 -3
- package/dist/cjs/fit_types.d.ts +33 -1
- package/dist/cjs/helper.js +3 -8
- package/dist/cjs/type_generator.js +1 -0
- package/dist/fit-parser.js +10 -0
- package/dist/fit.js +280 -3
- package/dist/fit_types.d.ts +33 -1
- package/dist/helper.js +3 -8
- package/dist/type_generator.js +1 -0
- package/package.json +1 -1
- package/probe_session.js +44 -0
- package/tsconfig.cjs.json +7 -7
package/deep_probe.js
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
|
|
2
|
+
import fs from 'fs';
|
|
3
|
+
import { createRequire } from 'module';
|
|
4
|
+
const require = createRequire(import.meta.url);
|
|
5
|
+
const FitParser = require('./dist/fit-parser.js').default;
|
|
6
|
+
|
|
7
|
+
const content = fs.readFileSync('/Users/dimitrios/Projects/sports-lib/samples/fit/jumps-mtb.fit');
|
|
8
|
+
const fitParser = new FitParser({
|
|
9
|
+
force: true,
|
|
10
|
+
speedUnit: 'km/h',
|
|
11
|
+
lengthUnit: 'm',
|
|
12
|
+
temperatureUnit: 'celsius',
|
|
13
|
+
elapsedRecordField: true,
|
|
14
|
+
mode: 'both',
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
function search(obj, path = []) {
|
|
18
|
+
if (!obj || typeof obj !== 'object') return;
|
|
19
|
+
|
|
20
|
+
Object.keys(obj).forEach(key => {
|
|
21
|
+
const val = obj[key];
|
|
22
|
+
const newPath = [...path, key];
|
|
23
|
+
|
|
24
|
+
// Check match 11 (Jump Count)
|
|
25
|
+
if (typeof val === 'number' && Math.abs(val - 11) < 0.001) {
|
|
26
|
+
console.log(`>>> FOUND 11 at: ${newPath.join('.')} (Value: ${val})`);
|
|
27
|
+
}
|
|
28
|
+
// Check match 159 (Resting Cals)
|
|
29
|
+
if (typeof val === 'number' && Math.abs(val - 159) < 0.1) {
|
|
30
|
+
console.log(`>>> FOUND 159 at: ${newPath.join('.')} (Value: ${val})`);
|
|
31
|
+
}
|
|
32
|
+
// Check match for Training Load Peak
|
|
33
|
+
if (typeof val === 'number' && Math.abs(val - 6079174) < 100) {
|
|
34
|
+
console.log(`>>> FOUND 6M at: ${newPath.join('.')} (Value: ${val})`);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
if (typeof val === 'object') {
|
|
38
|
+
search(val, newPath);
|
|
39
|
+
}
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
fitParser.parse(content, (error, data) => {
|
|
44
|
+
if (error) {
|
|
45
|
+
console.error(error);
|
|
46
|
+
} else {
|
|
47
|
+
console.log("Starting deep search...");
|
|
48
|
+
search(data);
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
if (data.sessions && data.sessions.length > 0) {
|
|
52
|
+
console.log("\n=== SESSION OBJECT (First) ===");
|
|
53
|
+
const session = data.sessions[0];
|
|
54
|
+
Object.keys(session).forEach(key => {
|
|
55
|
+
console.log(`${key}: ${session[key]}`);
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
// Explicitly check for jump-related keys
|
|
59
|
+
if (data.jumps) {
|
|
60
|
+
console.log("=== JUMPS OBJECT === ");
|
|
61
|
+
console.log(JSON.stringify(data.jumps, null, 2));
|
|
62
|
+
}
|
|
63
|
+
// Also check for jump events in events
|
|
64
|
+
if (data.events) {
|
|
65
|
+
const jumpEvents = data.events.filter(e => JSON.stringify(e).includes('jump'));
|
|
66
|
+
console.log(`Found ${jumpEvents.length} jump events`);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
});
|
package/dist/binary.js
CHANGED
|
@@ -15,6 +15,13 @@ export function addEndian(littleEndian, bytes) {
|
|
|
15
15
|
return result;
|
|
16
16
|
}
|
|
17
17
|
function readData(blob, fDef, startIndex, options) {
|
|
18
|
+
if (fDef.type === 'uint8_array') {
|
|
19
|
+
const array8 = [];
|
|
20
|
+
for (let i = 0; i < fDef.size; i++) {
|
|
21
|
+
array8.push(blob[startIndex + i]);
|
|
22
|
+
}
|
|
23
|
+
return array8;
|
|
24
|
+
}
|
|
18
25
|
if (fDef.endianAbility) {
|
|
19
26
|
const temp = [];
|
|
20
27
|
for (let i = 0; i < fDef.size; i++) {
|
|
@@ -46,11 +53,11 @@ function readData(blob, fDef, startIndex, options) {
|
|
|
46
53
|
return array32;
|
|
47
54
|
}
|
|
48
55
|
case 'uint16_array': {
|
|
49
|
-
const
|
|
56
|
+
const array16 = [];
|
|
50
57
|
for (let i = 0; i < fDef.size; i += 2) {
|
|
51
|
-
|
|
58
|
+
array16.push(dataView.getUint16(i, fDef.littleEndian));
|
|
52
59
|
}
|
|
53
|
-
return
|
|
60
|
+
return array16;
|
|
54
61
|
}
|
|
55
62
|
}
|
|
56
63
|
}
|
|
@@ -93,7 +100,11 @@ function formatByType(data, type, scale, offset) {
|
|
|
93
100
|
return scale ? data / scale + offset : data;
|
|
94
101
|
case 'uint32_array':
|
|
95
102
|
case 'uint16_array':
|
|
96
|
-
|
|
103
|
+
case 'uint8_array':
|
|
104
|
+
if (Array.isArray(data)) {
|
|
105
|
+
return data.map((dataItem) => scale ? dataItem / scale + offset : dataItem);
|
|
106
|
+
}
|
|
107
|
+
return scale ? data / scale + offset : data;
|
|
97
108
|
default:
|
|
98
109
|
{
|
|
99
110
|
if (!FIT.types[type]) {
|
|
@@ -216,6 +227,13 @@ function applyOptions(data, field, options) {
|
|
|
216
227
|
case 'start_pressure':
|
|
217
228
|
case 'end_pressure':
|
|
218
229
|
return convertTo(data, 'pressureUnits', options.pressureUnit);
|
|
230
|
+
case 'ant_id': {
|
|
231
|
+
const n1 = (data >>> 28) & 0xf;
|
|
232
|
+
const n2 = (data >>> 24) & 0xf;
|
|
233
|
+
const n3 = (data >>> 16) & 0xff;
|
|
234
|
+
const n4 = data & 0xffff;
|
|
235
|
+
return `${n1.toString(16).toUpperCase()}-${n2.toString(16).toUpperCase()}-${n3.toString(16).toUpperCase().padStart(2, '0')}-${n4.toString(16).toUpperCase().padStart(4, '0')}`;
|
|
236
|
+
}
|
|
219
237
|
default:
|
|
220
238
|
return data;
|
|
221
239
|
}
|
package/dist/cjs/binary.js
CHANGED
|
@@ -21,6 +21,13 @@ function addEndian(littleEndian, bytes) {
|
|
|
21
21
|
return result;
|
|
22
22
|
}
|
|
23
23
|
function readData(blob, fDef, startIndex, options) {
|
|
24
|
+
if (fDef.type === 'uint8_array') {
|
|
25
|
+
const array8 = [];
|
|
26
|
+
for (let i = 0; i < fDef.size; i++) {
|
|
27
|
+
array8.push(blob[startIndex + i]);
|
|
28
|
+
}
|
|
29
|
+
return array8;
|
|
30
|
+
}
|
|
24
31
|
if (fDef.endianAbility) {
|
|
25
32
|
const temp = [];
|
|
26
33
|
for (let i = 0; i < fDef.size; i++) {
|
|
@@ -52,11 +59,11 @@ function readData(blob, fDef, startIndex, options) {
|
|
|
52
59
|
return array32;
|
|
53
60
|
}
|
|
54
61
|
case 'uint16_array': {
|
|
55
|
-
const
|
|
62
|
+
const array16 = [];
|
|
56
63
|
for (let i = 0; i < fDef.size; i += 2) {
|
|
57
|
-
|
|
64
|
+
array16.push(dataView.getUint16(i, fDef.littleEndian));
|
|
58
65
|
}
|
|
59
|
-
return
|
|
66
|
+
return array16;
|
|
60
67
|
}
|
|
61
68
|
}
|
|
62
69
|
}
|
|
@@ -99,7 +106,11 @@ function formatByType(data, type, scale, offset) {
|
|
|
99
106
|
return scale ? data / scale + offset : data;
|
|
100
107
|
case 'uint32_array':
|
|
101
108
|
case 'uint16_array':
|
|
102
|
-
|
|
109
|
+
case 'uint8_array':
|
|
110
|
+
if (Array.isArray(data)) {
|
|
111
|
+
return data.map((dataItem) => scale ? dataItem / scale + offset : dataItem);
|
|
112
|
+
}
|
|
113
|
+
return scale ? data / scale + offset : data;
|
|
103
114
|
default:
|
|
104
115
|
{
|
|
105
116
|
if (!fit_js_1.FIT.types[type]) {
|
|
@@ -222,6 +233,13 @@ function applyOptions(data, field, options) {
|
|
|
222
233
|
case 'start_pressure':
|
|
223
234
|
case 'end_pressure':
|
|
224
235
|
return convertTo(data, 'pressureUnits', options.pressureUnit);
|
|
236
|
+
case 'ant_id': {
|
|
237
|
+
const n1 = (data >>> 28) & 0xf;
|
|
238
|
+
const n2 = (data >>> 24) & 0xf;
|
|
239
|
+
const n3 = (data >>> 16) & 0xff;
|
|
240
|
+
const n4 = data & 0xffff;
|
|
241
|
+
return `${n1.toString(16).toUpperCase()}-${n2.toString(16).toUpperCase()}-${n3.toString(16).toUpperCase().padStart(2, '0')}-${n4.toString(16).toUpperCase().padStart(4, '0')}`;
|
|
242
|
+
}
|
|
225
243
|
default:
|
|
226
244
|
return data;
|
|
227
245
|
}
|
package/dist/cjs/fit-parser.js
CHANGED
|
@@ -101,6 +101,8 @@ class FitParser {
|
|
|
101
101
|
const lengths = [];
|
|
102
102
|
const tank_updates = [];
|
|
103
103
|
const tank_summaries = [];
|
|
104
|
+
const jumps = [];
|
|
105
|
+
const time_in_zone = [];
|
|
104
106
|
let loopIndex = headerLength;
|
|
105
107
|
const messageTypes = [];
|
|
106
108
|
const developerFields = [];
|
|
@@ -196,6 +198,12 @@ class FitParser {
|
|
|
196
198
|
case 'tank_summary':
|
|
197
199
|
tank_summaries.push(message);
|
|
198
200
|
break;
|
|
201
|
+
case 'jump':
|
|
202
|
+
jumps.push(message);
|
|
203
|
+
break;
|
|
204
|
+
case 'time_in_zone':
|
|
205
|
+
time_in_zone.push(message);
|
|
206
|
+
break;
|
|
199
207
|
default:
|
|
200
208
|
if (messageType !== '') {
|
|
201
209
|
fitObj[messageType] = message;
|
|
@@ -215,6 +223,8 @@ class FitParser {
|
|
|
215
223
|
fitObj.definitions = definitions;
|
|
216
224
|
fitObj.tank_updates = tank_updates;
|
|
217
225
|
fitObj.tank_summaries = tank_summaries;
|
|
226
|
+
fitObj.jumps = jumps;
|
|
227
|
+
fitObj.time_in_zone = time_in_zone;
|
|
218
228
|
if (isCascadeNeeded) {
|
|
219
229
|
laps = (0, helper_js_1.mapDataIntoLap)(laps, 'records', records);
|
|
220
230
|
laps = (0, helper_js_1.mapDataIntoLap)(laps, 'lengths', lengths);
|
package/dist/cjs/fit.js
CHANGED
|
@@ -1083,6 +1083,20 @@ exports.FIT = {
|
|
|
1083
1083
|
offset: 0,
|
|
1084
1084
|
units: '%',
|
|
1085
1085
|
},
|
|
1086
|
+
38: {
|
|
1087
|
+
field: 'end_position_lat',
|
|
1088
|
+
type: 'sint32',
|
|
1089
|
+
scale: null,
|
|
1090
|
+
offset: 0,
|
|
1091
|
+
units: 'semicircles',
|
|
1092
|
+
},
|
|
1093
|
+
39: {
|
|
1094
|
+
field: 'end_position_long',
|
|
1095
|
+
type: 'sint32',
|
|
1096
|
+
scale: null,
|
|
1097
|
+
offset: 0,
|
|
1098
|
+
units: 'semicircles',
|
|
1099
|
+
},
|
|
1086
1100
|
41: {
|
|
1087
1101
|
field: 'avg_stroke_count',
|
|
1088
1102
|
type: 'uint32',
|
|
@@ -1637,7 +1651,7 @@ exports.FIT = {
|
|
|
1637
1651
|
units: 'mm',
|
|
1638
1652
|
},
|
|
1639
1653
|
137: {
|
|
1640
|
-
field: '
|
|
1654
|
+
field: 'total_anaerobic_training_effect',
|
|
1641
1655
|
type: 'uint8',
|
|
1642
1656
|
scale: 10,
|
|
1643
1657
|
offset: 0,
|
|
@@ -1646,9 +1660,9 @@ exports.FIT = {
|
|
|
1646
1660
|
139: {
|
|
1647
1661
|
field: 'avg_vam',
|
|
1648
1662
|
type: 'uint16',
|
|
1649
|
-
scale:
|
|
1663
|
+
scale: 1, // Raw 100 -> 100 (User specific m/h)
|
|
1650
1664
|
offset: 0,
|
|
1651
|
-
units: 'm/
|
|
1665
|
+
units: 'm/h',
|
|
1652
1666
|
},
|
|
1653
1667
|
192: {
|
|
1654
1668
|
field: 'workout_feel',
|
|
@@ -1664,6 +1678,111 @@ exports.FIT = {
|
|
|
1664
1678
|
offset: 0,
|
|
1665
1679
|
units: '',
|
|
1666
1680
|
},
|
|
1681
|
+
110: {
|
|
1682
|
+
field: 'sport_profile_name',
|
|
1683
|
+
type: 'string',
|
|
1684
|
+
scale: null,
|
|
1685
|
+
offset: 0,
|
|
1686
|
+
units: '',
|
|
1687
|
+
},
|
|
1688
|
+
168: {
|
|
1689
|
+
field: 'training_load_peak',
|
|
1690
|
+
type: 'uint32',
|
|
1691
|
+
scale: 1,
|
|
1692
|
+
offset: 0,
|
|
1693
|
+
units: '',
|
|
1694
|
+
},
|
|
1695
|
+
169: {
|
|
1696
|
+
field: 'enhanced_avg_respiration_rate',
|
|
1697
|
+
type: 'uint16',
|
|
1698
|
+
scale: 100,
|
|
1699
|
+
offset: 0,
|
|
1700
|
+
units: 'breaths/min',
|
|
1701
|
+
},
|
|
1702
|
+
150: {
|
|
1703
|
+
field: 'min_temperature',
|
|
1704
|
+
type: 'sint8',
|
|
1705
|
+
scale: null,
|
|
1706
|
+
offset: 0,
|
|
1707
|
+
units: 'C',
|
|
1708
|
+
},
|
|
1709
|
+
170: {
|
|
1710
|
+
field: 'enhanced_max_respiration_rate',
|
|
1711
|
+
type: 'uint16',
|
|
1712
|
+
scale: 100,
|
|
1713
|
+
offset: 0,
|
|
1714
|
+
units: 'breaths/min',
|
|
1715
|
+
},
|
|
1716
|
+
178: {
|
|
1717
|
+
field: 'est_sweat_loss',
|
|
1718
|
+
type: 'uint16',
|
|
1719
|
+
scale: 1, // ml
|
|
1720
|
+
offset: 0,
|
|
1721
|
+
units: 'ml',
|
|
1722
|
+
},
|
|
1723
|
+
180: {
|
|
1724
|
+
field: 'enhanced_min_respiration_rate',
|
|
1725
|
+
type: 'uint16',
|
|
1726
|
+
scale: 100,
|
|
1727
|
+
offset: 0,
|
|
1728
|
+
units: 'breaths/min',
|
|
1729
|
+
},
|
|
1730
|
+
181: {
|
|
1731
|
+
field: 'total_grit',
|
|
1732
|
+
type: 'float32',
|
|
1733
|
+
scale: 1,
|
|
1734
|
+
offset: 0,
|
|
1735
|
+
units: 'kGrit',
|
|
1736
|
+
},
|
|
1737
|
+
183: {
|
|
1738
|
+
field: 'jump_count',
|
|
1739
|
+
type: 'uint16',
|
|
1740
|
+
scale: 1,
|
|
1741
|
+
offset: 0,
|
|
1742
|
+
units: '',
|
|
1743
|
+
},
|
|
1744
|
+
187: {
|
|
1745
|
+
field: 'avg_flow',
|
|
1746
|
+
type: 'float32',
|
|
1747
|
+
scale: 1,
|
|
1748
|
+
offset: 0,
|
|
1749
|
+
units: 'Flow',
|
|
1750
|
+
},
|
|
1751
|
+
188: {
|
|
1752
|
+
field: 'primary_benefit',
|
|
1753
|
+
type: 'uint8',
|
|
1754
|
+
scale: 1,
|
|
1755
|
+
offset: 0,
|
|
1756
|
+
units: '',
|
|
1757
|
+
},
|
|
1758
|
+
196: {
|
|
1759
|
+
field: 'resting_calories',
|
|
1760
|
+
type: 'uint16',
|
|
1761
|
+
scale: 1,
|
|
1762
|
+
offset: 0,
|
|
1763
|
+
units: 'kcal',
|
|
1764
|
+
},
|
|
1765
|
+
214: {
|
|
1766
|
+
field: 'avg_grit',
|
|
1767
|
+
type: 'float32',
|
|
1768
|
+
scale: null,
|
|
1769
|
+
offset: 0,
|
|
1770
|
+
units: '',
|
|
1771
|
+
},
|
|
1772
|
+
215: {
|
|
1773
|
+
field: 'avg_flow',
|
|
1774
|
+
type: 'float32',
|
|
1775
|
+
scale: null,
|
|
1776
|
+
offset: 0,
|
|
1777
|
+
units: '',
|
|
1778
|
+
},
|
|
1779
|
+
140: {
|
|
1780
|
+
field: 'recovery_advisor',
|
|
1781
|
+
type: 'uint16', // Minutes?
|
|
1782
|
+
scale: 1,
|
|
1783
|
+
offset: 0,
|
|
1784
|
+
units: 'min',
|
|
1785
|
+
},
|
|
1667
1786
|
},
|
|
1668
1787
|
19: {
|
|
1669
1788
|
name: 'lap',
|
|
@@ -2407,6 +2526,20 @@ exports.FIT = {
|
|
|
2407
2526
|
offset: 0,
|
|
2408
2527
|
units: 's',
|
|
2409
2528
|
},
|
|
2529
|
+
114: {
|
|
2530
|
+
field: 'grit',
|
|
2531
|
+
type: 'float32',
|
|
2532
|
+
scale: null,
|
|
2533
|
+
offset: 0,
|
|
2534
|
+
units: '',
|
|
2535
|
+
},
|
|
2536
|
+
115: {
|
|
2537
|
+
field: 'flow',
|
|
2538
|
+
type: 'float32',
|
|
2539
|
+
scale: null,
|
|
2540
|
+
offset: 0,
|
|
2541
|
+
units: '',
|
|
2542
|
+
},
|
|
2410
2543
|
0: {
|
|
2411
2544
|
field: 'position_lat',
|
|
2412
2545
|
type: 'sint32',
|
|
@@ -2858,6 +2991,14 @@ exports.FIT = {
|
|
|
2858
2991
|
units: 'percent',
|
|
2859
2992
|
},
|
|
2860
2993
|
},
|
|
2994
|
+
140: {
|
|
2995
|
+
name: 'jump',
|
|
2996
|
+
253: { field: 'timestamp', type: 'date_time', scale: null, offset: 0, units: 's' },
|
|
2997
|
+
9: { field: 'distance', type: 'uint16', scale: 100, offset: 0, units: 'm' },
|
|
2998
|
+
10: { field: 'height', type: 'uint16', scale: 1000, offset: 0, units: 'm' },
|
|
2999
|
+
37: { field: 'score', type: 'sint32', scale: null, offset: 0, units: '' },
|
|
3000
|
+
7: { field: 'enhanced_mets', type: 'uint32', scale: 65536, offset: 0, units: 'METs' },
|
|
3001
|
+
},
|
|
2861
3002
|
21: {
|
|
2862
3003
|
name: 'event',
|
|
2863
3004
|
253: {
|
|
@@ -3000,6 +3141,13 @@ exports.FIT = {
|
|
|
3000
3141
|
offset: 0,
|
|
3001
3142
|
units: 'V',
|
|
3002
3143
|
},
|
|
3144
|
+
32: {
|
|
3145
|
+
field: 'battery_level',
|
|
3146
|
+
type: 'uint8',
|
|
3147
|
+
scale: null,
|
|
3148
|
+
offset: 0,
|
|
3149
|
+
units: 'percent',
|
|
3150
|
+
},
|
|
3003
3151
|
11: {
|
|
3004
3152
|
field: 'battery_status',
|
|
3005
3153
|
type: 'battery_status',
|
|
@@ -3042,6 +3190,13 @@ exports.FIT = {
|
|
|
3042
3190
|
offset: 0,
|
|
3043
3191
|
units: '',
|
|
3044
3192
|
},
|
|
3193
|
+
24: {
|
|
3194
|
+
field: 'ant_id',
|
|
3195
|
+
type: 'uint32z',
|
|
3196
|
+
scale: null,
|
|
3197
|
+
offset: 0,
|
|
3198
|
+
units: '',
|
|
3199
|
+
},
|
|
3045
3200
|
25: {
|
|
3046
3201
|
field: 'source_type',
|
|
3047
3202
|
type: 'source_type',
|
|
@@ -4486,6 +4641,128 @@ exports.FIT = {
|
|
|
4486
4641
|
units: 'cbar',
|
|
4487
4642
|
},
|
|
4488
4643
|
},
|
|
4644
|
+
216: {
|
|
4645
|
+
name: 'time_in_zone',
|
|
4646
|
+
253: {
|
|
4647
|
+
field: 'timestamp',
|
|
4648
|
+
type: 'date_time',
|
|
4649
|
+
scale: null,
|
|
4650
|
+
offset: 0,
|
|
4651
|
+
units: 's',
|
|
4652
|
+
},
|
|
4653
|
+
0: {
|
|
4654
|
+
field: 'reference_mesg',
|
|
4655
|
+
type: 'uint16',
|
|
4656
|
+
scale: null,
|
|
4657
|
+
offset: 0,
|
|
4658
|
+
units: '',
|
|
4659
|
+
},
|
|
4660
|
+
1: {
|
|
4661
|
+
field: 'reference_index',
|
|
4662
|
+
type: 'uint16',
|
|
4663
|
+
scale: null,
|
|
4664
|
+
offset: 0,
|
|
4665
|
+
units: '',
|
|
4666
|
+
},
|
|
4667
|
+
2: {
|
|
4668
|
+
field: 'time_in_hr_zone',
|
|
4669
|
+
type: 'uint32_array',
|
|
4670
|
+
scale: 1000,
|
|
4671
|
+
offset: 0,
|
|
4672
|
+
units: 's',
|
|
4673
|
+
},
|
|
4674
|
+
3: {
|
|
4675
|
+
field: 'time_in_speed_zone',
|
|
4676
|
+
type: 'uint32_array',
|
|
4677
|
+
scale: 1000,
|
|
4678
|
+
offset: 0,
|
|
4679
|
+
units: 's',
|
|
4680
|
+
},
|
|
4681
|
+
4: {
|
|
4682
|
+
field: 'time_in_power_zone',
|
|
4683
|
+
type: 'uint32_array',
|
|
4684
|
+
scale: 1000,
|
|
4685
|
+
offset: 0,
|
|
4686
|
+
units: 's',
|
|
4687
|
+
},
|
|
4688
|
+
5: {
|
|
4689
|
+
field: 'hr_zone_high_boundary_deprecated',
|
|
4690
|
+
type: 'uint8_array',
|
|
4691
|
+
scale: null,
|
|
4692
|
+
offset: 0,
|
|
4693
|
+
units: '',
|
|
4694
|
+
},
|
|
4695
|
+
6: {
|
|
4696
|
+
field: 'hr_zone_high_boundary',
|
|
4697
|
+
type: 'uint8_array',
|
|
4698
|
+
scale: null,
|
|
4699
|
+
offset: 0,
|
|
4700
|
+
units: 'bpm',
|
|
4701
|
+
},
|
|
4702
|
+
7: {
|
|
4703
|
+
field: 'speed_zone_high_boundary',
|
|
4704
|
+
type: 'uint16_array',
|
|
4705
|
+
scale: 1000,
|
|
4706
|
+
offset: 0,
|
|
4707
|
+
units: 'm/s',
|
|
4708
|
+
},
|
|
4709
|
+
8: {
|
|
4710
|
+
field: 'power_zone_high_boundary',
|
|
4711
|
+
type: 'uint16_array',
|
|
4712
|
+
scale: null,
|
|
4713
|
+
offset: 0,
|
|
4714
|
+
units: 'watts',
|
|
4715
|
+
},
|
|
4716
|
+
9: {
|
|
4717
|
+
field: 'hr_calc_type',
|
|
4718
|
+
type: 'hr_zone_calc',
|
|
4719
|
+
scale: null,
|
|
4720
|
+
offset: 0,
|
|
4721
|
+
units: '',
|
|
4722
|
+
},
|
|
4723
|
+
10: {
|
|
4724
|
+
field: 'max_heart_rate_deprecated',
|
|
4725
|
+
type: 'uint8',
|
|
4726
|
+
scale: null,
|
|
4727
|
+
offset: 0,
|
|
4728
|
+
units: 'bpm',
|
|
4729
|
+
},
|
|
4730
|
+
11: {
|
|
4731
|
+
field: 'max_heart_rate',
|
|
4732
|
+
type: 'uint8',
|
|
4733
|
+
scale: null,
|
|
4734
|
+
offset: 0,
|
|
4735
|
+
units: 'bpm',
|
|
4736
|
+
},
|
|
4737
|
+
12: {
|
|
4738
|
+
field: 'resting_heart_rate',
|
|
4739
|
+
type: 'uint8',
|
|
4740
|
+
scale: null,
|
|
4741
|
+
offset: 0,
|
|
4742
|
+
units: 'bpm',
|
|
4743
|
+
},
|
|
4744
|
+
13: {
|
|
4745
|
+
field: 'threshold_heart_rate',
|
|
4746
|
+
type: 'uint8',
|
|
4747
|
+
scale: null,
|
|
4748
|
+
offset: 0,
|
|
4749
|
+
units: 'bpm',
|
|
4750
|
+
},
|
|
4751
|
+
14: {
|
|
4752
|
+
field: 'pwr_calc_type',
|
|
4753
|
+
type: 'pwr_zone_calc',
|
|
4754
|
+
scale: null,
|
|
4755
|
+
offset: 0,
|
|
4756
|
+
units: '',
|
|
4757
|
+
},
|
|
4758
|
+
15: {
|
|
4759
|
+
field: 'functional_threshold_power',
|
|
4760
|
+
type: 'uint16',
|
|
4761
|
+
scale: null,
|
|
4762
|
+
offset: 0,
|
|
4763
|
+
units: 'watts',
|
|
4764
|
+
},
|
|
4765
|
+
},
|
|
4489
4766
|
},
|
|
4490
4767
|
types: {
|
|
4491
4768
|
file: {
|
package/dist/cjs/fit_types.d.ts
CHANGED
|
@@ -16,7 +16,7 @@ export interface MessageIndex {
|
|
|
16
16
|
selected: boolean;
|
|
17
17
|
}
|
|
18
18
|
export type File = 'device' | 'settings' | 'sport' | 'activity' | 'workout' | 'course' | 'schedules' | 'weight' | 'totals' | 'goals' | 'blood_pressure' | 'monitoring_a' | 'activity_summary' | 'monitoring_daily' | 'monitoring_b' | 'segment' | 'segment_list' | 'exd_configuration' | 'mfg_range_min' | 'mfg_range_max';
|
|
19
|
-
export type MesgNum = 'file_id' | 'capabilities' | 'device_settings' | 'user_profile' | 'hrm_profile' | 'sdm_profile' | 'bike_profile' | 'zones_target' | 'hr_zone' | 'power_zone' | 'met_zone' | 'sport' | 'goal' | 'session' | 'lap' | 'record' | 'event' | 'device_info' | 'workout' | 'workout_step' | 'schedule' | 'weight_scale' | 'course' | 'course_point' | 'totals' | 'activity' | 'software' | 'file_capabilities' | 'mesg_capabilities' | 'field_capabilities' | 'file_creator' | 'blood_pressure' | 'speed_zone' | 'monitoring' | 'training_file' | 'hrv' | 'ant_rx' | 'ant_tx' | 'ant_channel_id' | 'length' | 'monitoring_info' | 'pad' | 'slave_device' | 'connectivity' | 'weather_conditions' | 'weather_alert' | 'cadence_zone' | 'hr' | 'segment_lap' | 'memo_glob' | 'segment_id' | 'segment_leaderboard_entry' | 'segment_point' | 'segment_file' | 'workout_session' | 'watchface_settings' | 'gps_metadata' | 'camera_event' | 'timestamp_correlation' | 'gyroscope_data' | 'accelerometer_data' | 'three_d_sensor_calibration' | 'video_frame' | 'obdii_data' | 'nmea_sentence' | 'aviation_attitude' | 'video' | 'video_title' | 'video_description' | 'video_clip' | 'exd_screen_configuration' | 'exd_data_field_configuration' | 'exd_data_concept_configuration' | 'field_description' | 'developer_data_id' | 'magnetometer_data' | 'barometer_data' | 'one_d_sensor_calibration' | 'set' | 'stress_level' | 'dive_settings' | 'dive_gas' | 'dive_alarm' | 'exercise_title' | 'dive_summary' | 'jump' | 'climb_pro' | 'tank_pressure' | 'tank_summary' | 'mfg_range_min' | 'mfg_range_max' | 'o_hr_settings' | 'tank_update' | 'definition';
|
|
19
|
+
export type MesgNum = 'file_id' | 'capabilities' | 'device_settings' | 'user_profile' | 'hrm_profile' | 'sdm_profile' | 'bike_profile' | 'zones_target' | 'hr_zone' | 'power_zone' | 'met_zone' | 'sport' | 'goal' | 'session' | 'lap' | 'record' | 'event' | 'device_info' | 'workout' | 'workout_step' | 'schedule' | 'weight_scale' | 'course' | 'course_point' | 'totals' | 'activity' | 'software' | 'file_capabilities' | 'mesg_capabilities' | 'field_capabilities' | 'file_creator' | 'blood_pressure' | 'speed_zone' | 'monitoring' | 'training_file' | 'hrv' | 'ant_rx' | 'ant_tx' | 'ant_channel_id' | 'length' | 'monitoring_info' | 'pad' | 'slave_device' | 'connectivity' | 'weather_conditions' | 'weather_alert' | 'cadence_zone' | 'hr' | 'segment_lap' | 'memo_glob' | 'segment_id' | 'segment_leaderboard_entry' | 'segment_point' | 'segment_file' | 'workout_session' | 'watchface_settings' | 'gps_metadata' | 'camera_event' | 'timestamp_correlation' | 'gyroscope_data' | 'accelerometer_data' | 'three_d_sensor_calibration' | 'video_frame' | 'obdii_data' | 'nmea_sentence' | 'aviation_attitude' | 'video' | 'video_title' | 'video_description' | 'video_clip' | 'exd_screen_configuration' | 'exd_data_field_configuration' | 'exd_data_concept_configuration' | 'field_description' | 'developer_data_id' | 'magnetometer_data' | 'barometer_data' | 'one_d_sensor_calibration' | 'set' | 'stress_level' | 'dive_settings' | 'dive_gas' | 'dive_alarm' | 'exercise_title' | 'dive_summary' | 'jump' | 'climb_pro' | 'tank_pressure' | 'tank_summary' | 'time_in_zone' | 'mfg_range_min' | 'mfg_range_max' | 'o_hr_settings' | 'tank_update' | 'definition';
|
|
20
20
|
export type Checksum = 'clear' | 'ok';
|
|
21
21
|
export type FileFlags = '0' | 'read' | 'write' | 'erase';
|
|
22
22
|
export type MesgCount = 'num_per_file' | 'max_per_file' | 'max_per_file_type';
|
|
@@ -444,8 +444,12 @@ export interface ParsedSession {
|
|
|
444
444
|
avg_step_length?: number;
|
|
445
445
|
total_anaerobic_effect?: number;
|
|
446
446
|
avg_vam?: number;
|
|
447
|
+
total_grit?: number;
|
|
448
|
+
total_flow?: number;
|
|
447
449
|
workout_feel?: number;
|
|
448
450
|
workout_rpe?: number;
|
|
451
|
+
avg_grit?: number;
|
|
452
|
+
avg_flow?: number;
|
|
449
453
|
timestamp: string;
|
|
450
454
|
message_index?: MessageIndex;
|
|
451
455
|
laps?: ParsedLap[];
|
|
@@ -627,6 +631,8 @@ export interface ParsedRecord {
|
|
|
627
631
|
ndl_time?: number;
|
|
628
632
|
cns_load?: number;
|
|
629
633
|
n2_load?: number;
|
|
634
|
+
grit?: number;
|
|
635
|
+
flow?: number;
|
|
630
636
|
timestamp: string;
|
|
631
637
|
}
|
|
632
638
|
export interface ParsedEvent {
|
|
@@ -662,6 +668,7 @@ export interface ParsedDeviceInfo {
|
|
|
662
668
|
ant_network?: AntNetwork;
|
|
663
669
|
source_type?: SourceType;
|
|
664
670
|
product_name?: string;
|
|
671
|
+
battery_level?: number;
|
|
665
672
|
timestamp: string;
|
|
666
673
|
}
|
|
667
674
|
export interface ParsedWorkout {
|
|
@@ -850,6 +857,12 @@ export interface ParsedOHrSettings {
|
|
|
850
857
|
enabled?: number;
|
|
851
858
|
timestamp: string;
|
|
852
859
|
}
|
|
860
|
+
export interface ParsedJump {
|
|
861
|
+
distance?: number;
|
|
862
|
+
height?: number;
|
|
863
|
+
score?: number;
|
|
864
|
+
timestamp: string;
|
|
865
|
+
}
|
|
853
866
|
export interface ParsedFieldDescription {
|
|
854
867
|
developer_data_index?: number;
|
|
855
868
|
field_definition_number?: number;
|
|
@@ -939,6 +952,23 @@ export interface ParsedTankSummary {
|
|
|
939
952
|
end_pressure?: number;
|
|
940
953
|
volume_used?: number;
|
|
941
954
|
}
|
|
955
|
+
export interface ParsedTimeInZone {
|
|
956
|
+
timestamp: string;
|
|
957
|
+
reference_mesg?: number;
|
|
958
|
+
reference_index?: number;
|
|
959
|
+
time_in_hr_zone?: number[];
|
|
960
|
+
time_in_speed_zone?: number[];
|
|
961
|
+
time_in_power_zone?: number[];
|
|
962
|
+
hr_zone_high_boundary?: number[];
|
|
963
|
+
speed_zone_high_boundary?: number[];
|
|
964
|
+
power_zone_high_boundary?: number[];
|
|
965
|
+
hr_calc_type?: HrZoneCalc;
|
|
966
|
+
max_heart_rate?: number;
|
|
967
|
+
resting_heart_rate?: number;
|
|
968
|
+
threshold_heart_rate?: number;
|
|
969
|
+
pwr_calc_type?: PwrZoneCalc;
|
|
970
|
+
functional_threshold_power?: number;
|
|
971
|
+
}
|
|
942
972
|
export interface ParsedFit {
|
|
943
973
|
protocolVersion?: number;
|
|
944
974
|
profileVersion?: number;
|
|
@@ -971,4 +1001,6 @@ export interface ParsedFit {
|
|
|
971
1001
|
definitions?: unknown[];
|
|
972
1002
|
tank_updates?: ParsedTankUpdate[];
|
|
973
1003
|
tank_summaries?: ParsedTankSummary[];
|
|
1004
|
+
jumps?: ParsedJump[];
|
|
1005
|
+
time_in_zone?: ParsedTimeInZone[];
|
|
974
1006
|
}
|
package/dist/cjs/helper.js
CHANGED
|
@@ -6,18 +6,16 @@ function mapDataIntoLap(inputLaps, lapKey, data) {
|
|
|
6
6
|
const laps = [...inputLaps];
|
|
7
7
|
let index = 0;
|
|
8
8
|
for (let i = 0; i < laps.length; i++) {
|
|
9
|
-
const lap = laps[i];
|
|
10
9
|
const nextLap = laps[i + 1];
|
|
11
10
|
const tempData = [];
|
|
12
|
-
const lapStartTime = new Date(lap.start_time).getTime();
|
|
13
11
|
const nextLapStartTime = nextLap
|
|
14
12
|
? new Date(nextLap.start_time).getTime()
|
|
15
13
|
: null;
|
|
16
14
|
for (let j = index; j < data.length; j++) {
|
|
17
15
|
const row = data[j];
|
|
18
16
|
if (nextLap && nextLapStartTime) {
|
|
19
|
-
const timestamp = new Date(row.timestamp).getTime();
|
|
20
|
-
if (
|
|
17
|
+
const timestamp = new Date(row.timestamp || row.start_time).getTime();
|
|
18
|
+
if (nextLapStartTime > timestamp) {
|
|
21
19
|
tempData.push(row);
|
|
22
20
|
}
|
|
23
21
|
else if (nextLapStartTime <= timestamp) {
|
|
@@ -39,10 +37,8 @@ function mapDataIntoSession(inputSessions, laps) {
|
|
|
39
37
|
const sessions = [...inputSessions];
|
|
40
38
|
let lapIndex = 0;
|
|
41
39
|
for (let i = 0; i < sessions.length; i++) {
|
|
42
|
-
const session = sessions[i];
|
|
43
40
|
const nextSession = sessions[i + 1];
|
|
44
41
|
const tempLaps = [];
|
|
45
|
-
const sessionStartTime = new Date(session.start_time).getTime();
|
|
46
42
|
const nextSessionStartTime = nextSession
|
|
47
43
|
? new Date(nextSession.start_time).getTime()
|
|
48
44
|
: null;
|
|
@@ -50,8 +46,7 @@ function mapDataIntoSession(inputSessions, laps) {
|
|
|
50
46
|
const lap = laps[j];
|
|
51
47
|
if (nextSession && nextSessionStartTime) {
|
|
52
48
|
const lapStartTime = new Date(lap.start_time).getTime();
|
|
53
|
-
if (
|
|
54
|
-
&& nextSessionStartTime > lapStartTime) {
|
|
49
|
+
if (nextSessionStartTime > lapStartTime) {
|
|
55
50
|
tempLaps.push(lap);
|
|
56
51
|
}
|
|
57
52
|
else if (nextSessionStartTime <= lapStartTime) {
|