fleetmap-reports 2.0.379 → 2.0.380
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/package.json
CHANGED
package/src/activity-report.js
CHANGED
|
@@ -219,10 +219,11 @@ async function processDevices (from, to, devices, data, userData, traccarInstanc
|
|
|
219
219
|
summaryCurrentDay.distance = summaryByDevice.distance
|
|
220
220
|
summaryCurrentDay.averageSpeed = distance > 0 ? ((tripsByDay.reduce((a, b) => a + (b.averageSpeed * b.distance), 0)) / distance) : 0
|
|
221
221
|
summaryCurrentDay.maxSpeed = tripsByDay.reduce((a, b) => { return a > b.maxSpeed ? a : b.maxSpeed }, 0)
|
|
222
|
-
//
|
|
223
|
-
//
|
|
224
|
-
//
|
|
225
|
-
|
|
222
|
+
// Prefer Traccar's own per-trip spentFuel (tripsByDay) - it's already correctly
|
|
223
|
+
// scaled server-side, unlike a raw fuelUsed-counter subtraction which some
|
|
224
|
+
// devices/protocols report non-monotonically or in different units. route/fromDay/
|
|
225
|
+
// toDay remain the fallback for days with no trips.
|
|
226
|
+
summaryCurrentDay.convertedSpentFuel = calculateConsumption(d, { trips: tripsByDay, stops: [], route: deviceRoute.length ? deviceRoute : routeByDay, from: fromDay, to: toDay })
|
|
226
227
|
summaryCurrentDay.startTime = tripsByDay.length && tripsByDay[0].startTime
|
|
227
228
|
summaryCurrentDay.startAddress = tripsByDay.length && tripsByDay[0].startAddress
|
|
228
229
|
summaryCurrentDay.endTime = tripsByDay.length && tripsByDay[tripsByDay.length - 1].endTime
|
|
@@ -259,7 +260,9 @@ async function processDevices (from, to, devices, data, userData, traccarInstanc
|
|
|
259
260
|
if (summary.length) {
|
|
260
261
|
summary.forEach(s => {
|
|
261
262
|
s.engineHours = deviceTrips.reduce((a, b) => a + b.duration, 0)
|
|
262
|
-
s
|
|
263
|
+
// Prefer Traccar's own per-trip spentFuel over the period summary/raw route
|
|
264
|
+
// counter - see the per-day branch above for why.
|
|
265
|
+
s.convertedSpentFuel = calculateConsumption(d, { trips: deviceTrips, stops: [], route: deviceRoute, summary: s })
|
|
263
266
|
s.startTime = deviceTrips.length && deviceTrips[0].startTime
|
|
264
267
|
s.startAddress = deviceTrips.length && deviceTrips[0].startAddress
|
|
265
268
|
s.endTime = deviceTrips.length && deviceTrips[deviceTrips.length - 1].endTime
|
|
@@ -8,7 +8,7 @@ const { getStyle } = require('./reportStyle')
|
|
|
8
8
|
const { getUserPartner } = require('fleetmap-partners')
|
|
9
9
|
const { addTable, headerFromUser } = require('./util/pdfDocument')
|
|
10
10
|
const jsPDF = require('jspdf')
|
|
11
|
-
const { calculateConsumption, calculateTotalFuelFromSensor } = require('./util/fuel')
|
|
11
|
+
const { calculateConsumption, calculateTotalFuelFromSensor, shouldUseFuelSensor } = require('./util/fuel')
|
|
12
12
|
const { getSummary } = require('./util/traccar')
|
|
13
13
|
const { calculatePartialTrip } = require('./util/trips')
|
|
14
14
|
|
|
@@ -171,6 +171,12 @@ async function createFuelConsumptionReport (from, to, userData, traccar) {
|
|
|
171
171
|
|
|
172
172
|
if (trips.length > 0) {
|
|
173
173
|
const refuelingPositions = await refuelingReport.calculateRefuelingPositions(userData, d, { route, trips, fuelServices: deviceFuelServices })
|
|
174
|
+
// The CAN "fuelUsed" counter - when the device actually reports it - is what the
|
|
175
|
+
// Manager shows as "Fuel Used", so shouldUseFuelSensor() makes it win over the analog
|
|
176
|
+
// tank-level sensor below regardless of whether fuel_low_threshold/fuel_high_threshold
|
|
177
|
+
// happen to be configured on the device (that config alone doesn't mean the analog
|
|
178
|
+
// input is wired or reporting; some CAN vehicles carry stale/unrelated thresholds).
|
|
179
|
+
const useFuelSensor = shouldUseFuelSensor(d, route)
|
|
174
180
|
const days = daysByDevice.get(d.id) || []
|
|
175
181
|
for (const date of dates) {
|
|
176
182
|
const [dayStart, dayEnd] = getDayWindow(date, timezone)
|
|
@@ -181,15 +187,12 @@ async function createFuelConsumptionReport (from, to, userData, traccar) {
|
|
|
181
187
|
const firstStopIndex = !stopsByDay.length || !tripsByDay.length ? 0 : (new Date(tripsByDay[0].startTime) < new Date(stopsByDay[0].startTime) ? 0 : 1)
|
|
182
188
|
const distance = summaryByDevice.distance
|
|
183
189
|
|
|
184
|
-
const hasFuelSensor = 'fuel_low_threshold' in d.attributes &&
|
|
185
|
-
'fuel_high_threshold' in d.attributes &&
|
|
186
|
-
d.attributes.fuel_tank_capacity
|
|
187
|
-
|
|
188
190
|
// For CAN vehicles calculateConsumption reads the "fuelUsed" counter directly from
|
|
189
191
|
// the full chunk route between dayStart/dayEnd, so the day value matches the
|
|
190
192
|
// Manager's "Fuel Used" even when routeByDay itself has too few (or no) fuelUsed
|
|
191
|
-
// readings - e.g. on a day with a refuel or sparse CAN reporting.
|
|
192
|
-
|
|
193
|
+
// readings - e.g. on a day with a refuel or sparse CAN reporting. The analog
|
|
194
|
+
// tank-level sensor is only used as a fallback for vehicles with no CAN fuel data.
|
|
195
|
+
const spentFuel = useFuelSensor
|
|
193
196
|
? tripsByDay.length > 0 ? calculateTotalFuelFromSensor(tripsByDay, stopsByDay, route, d, firstStopIndex) : 0
|
|
194
197
|
: calculateConsumption(d, { trips: tripsByDay, stops: stopsByDay, route, summary: summaryByDevice, from: dayStart, to: dayEnd })
|
|
195
198
|
|
|
@@ -0,0 +1,1034 @@
|
|
|
1
|
+
{
|
|
2
|
+
"trips": [
|
|
3
|
+
{
|
|
4
|
+
"startTime": "2026-06-25T04:34:28.000+00:00",
|
|
5
|
+
"endTime": "2026-06-25T04:55:18.000+00:00",
|
|
6
|
+
"spentFuel": 3.3,
|
|
7
|
+
"distance": 13895
|
|
8
|
+
},
|
|
9
|
+
{
|
|
10
|
+
"startTime": "2026-06-25T07:11:25.000+00:00",
|
|
11
|
+
"endTime": "2026-06-25T07:12:29.000+00:00",
|
|
12
|
+
"spentFuel": 0,
|
|
13
|
+
"distance": 0
|
|
14
|
+
},
|
|
15
|
+
{
|
|
16
|
+
"startTime": "2026-06-25T07:46:06.000+00:00",
|
|
17
|
+
"endTime": "2026-06-25T08:30:19.000+00:00",
|
|
18
|
+
"spentFuel": 8.3,
|
|
19
|
+
"distance": 26675
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
"startTime": "2026-06-25T08:49:34.000+00:00",
|
|
23
|
+
"endTime": "2026-06-25T08:51:14.000+00:00",
|
|
24
|
+
"spentFuel": 0,
|
|
25
|
+
"distance": 5
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
"startTime": "2026-06-25T09:24:38.000+00:00",
|
|
29
|
+
"endTime": "2026-06-25T09:25:40.000+00:00",
|
|
30
|
+
"spentFuel": 0,
|
|
31
|
+
"distance": 0
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
"startTime": "2026-06-25T10:51:08.000+00:00",
|
|
35
|
+
"endTime": "2026-06-25T10:52:17.000+00:00",
|
|
36
|
+
"spentFuel": 0,
|
|
37
|
+
"distance": 0
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
"startTime": "2026-06-25T10:59:45.000+00:00",
|
|
41
|
+
"endTime": "2026-06-25T11:01:13.000+00:00",
|
|
42
|
+
"spentFuel": 0.1,
|
|
43
|
+
"distance": 50
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
"startTime": "2026-06-25T11:45:44.000+00:00",
|
|
47
|
+
"endTime": "2026-06-25T14:26:14.000+00:00",
|
|
48
|
+
"spentFuel": 56.1,
|
|
49
|
+
"distance": 201545
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
"startTime": "2026-06-25T15:09:00.000+00:00",
|
|
53
|
+
"endTime": "2026-06-25T15:13:11.000+00:00",
|
|
54
|
+
"spentFuel": 0.1,
|
|
55
|
+
"distance": 15
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
"startTime": "2026-06-25T16:54:01.000+00:00",
|
|
59
|
+
"endTime": "2026-06-25T19:37:39.000+00:00",
|
|
60
|
+
"spentFuel": 41.9,
|
|
61
|
+
"distance": 196270
|
|
62
|
+
},
|
|
63
|
+
{
|
|
64
|
+
"startTime": "2026-06-25T19:44:38.000+00:00",
|
|
65
|
+
"endTime": "2026-06-25T19:55:15.000+00:00",
|
|
66
|
+
"spentFuel": 0.8,
|
|
67
|
+
"distance": 2765
|
|
68
|
+
}
|
|
69
|
+
],
|
|
70
|
+
"stops": [
|
|
71
|
+
{
|
|
72
|
+
"startTime": "2026-06-25T04:32:53.000+00:00",
|
|
73
|
+
"endTime": "2026-06-25T04:34:28.000+00:00",
|
|
74
|
+
"spentFuel": -18045.3
|
|
75
|
+
},
|
|
76
|
+
{
|
|
77
|
+
"startTime": "2026-06-25T04:55:18.000+00:00",
|
|
78
|
+
"endTime": "2026-06-25T07:11:25.000+00:00",
|
|
79
|
+
"spentFuel": 0
|
|
80
|
+
},
|
|
81
|
+
{
|
|
82
|
+
"startTime": "2026-06-25T07:12:29.000+00:00",
|
|
83
|
+
"endTime": "2026-06-25T07:46:06.000+00:00",
|
|
84
|
+
"spentFuel": 0
|
|
85
|
+
},
|
|
86
|
+
{
|
|
87
|
+
"startTime": "2026-06-25T08:30:19.000+00:00",
|
|
88
|
+
"endTime": "2026-06-25T08:49:34.000+00:00",
|
|
89
|
+
"spentFuel": 0.7
|
|
90
|
+
},
|
|
91
|
+
{
|
|
92
|
+
"startTime": "2026-06-25T08:51:14.000+00:00",
|
|
93
|
+
"endTime": "2026-06-25T09:24:38.000+00:00",
|
|
94
|
+
"spentFuel": 0
|
|
95
|
+
},
|
|
96
|
+
{
|
|
97
|
+
"startTime": "2026-06-25T09:25:40.000+00:00",
|
|
98
|
+
"endTime": "2026-06-25T10:51:08.000+00:00",
|
|
99
|
+
"spentFuel": 0
|
|
100
|
+
},
|
|
101
|
+
{
|
|
102
|
+
"startTime": "2026-06-25T10:52:17.000+00:00",
|
|
103
|
+
"endTime": "2026-06-25T10:59:45.000+00:00",
|
|
104
|
+
"spentFuel": 0
|
|
105
|
+
},
|
|
106
|
+
{
|
|
107
|
+
"startTime": "2026-06-25T11:01:13.000+00:00",
|
|
108
|
+
"endTime": "2026-06-25T11:45:44.000+00:00",
|
|
109
|
+
"spentFuel": 0.1
|
|
110
|
+
},
|
|
111
|
+
{
|
|
112
|
+
"startTime": "2026-06-25T14:26:14.000+00:00",
|
|
113
|
+
"endTime": "2026-06-25T15:09:00.000+00:00",
|
|
114
|
+
"spentFuel": 0
|
|
115
|
+
},
|
|
116
|
+
{
|
|
117
|
+
"startTime": "2026-06-25T15:13:11.000+00:00",
|
|
118
|
+
"endTime": "2026-06-25T16:54:01.000+00:00",
|
|
119
|
+
"spentFuel": 0
|
|
120
|
+
},
|
|
121
|
+
{
|
|
122
|
+
"startTime": "2026-06-25T19:37:39.000+00:00",
|
|
123
|
+
"endTime": "2026-06-25T19:44:38.000+00:00",
|
|
124
|
+
"spentFuel": 0
|
|
125
|
+
},
|
|
126
|
+
{
|
|
127
|
+
"startTime": "2026-06-25T19:55:15.000+00:00",
|
|
128
|
+
"endTime": "2026-06-25T20:41:17.000+00:00",
|
|
129
|
+
"spentFuel": 0
|
|
130
|
+
}
|
|
131
|
+
],
|
|
132
|
+
"route": [
|
|
133
|
+
{
|
|
134
|
+
"fixTime": "2026-06-25T04:32:53.000+00:00",
|
|
135
|
+
"attributes": {
|
|
136
|
+
"fuelUsed": 33439.5
|
|
137
|
+
}
|
|
138
|
+
},
|
|
139
|
+
{
|
|
140
|
+
"fixTime": "2026-06-25T04:33:04.000+00:00",
|
|
141
|
+
"attributes": {
|
|
142
|
+
"fuelUsed": 15394.2
|
|
143
|
+
}
|
|
144
|
+
},
|
|
145
|
+
{
|
|
146
|
+
"fixTime": "2026-06-25T04:34:10.000+00:00",
|
|
147
|
+
"attributes": {
|
|
148
|
+
"fuelUsed": 15394.2
|
|
149
|
+
}
|
|
150
|
+
},
|
|
151
|
+
{
|
|
152
|
+
"fixTime": "2026-06-25T04:34:28.000+00:00",
|
|
153
|
+
"attributes": {
|
|
154
|
+
"fuelUsed": 15394.2
|
|
155
|
+
}
|
|
156
|
+
},
|
|
157
|
+
{
|
|
158
|
+
"fixTime": "2026-06-25T04:34:32.000+00:00",
|
|
159
|
+
"attributes": {
|
|
160
|
+
"fuelUsed": 15394.2
|
|
161
|
+
}
|
|
162
|
+
},
|
|
163
|
+
{
|
|
164
|
+
"fixTime": "2026-06-25T04:34:33.000+00:00",
|
|
165
|
+
"attributes": {
|
|
166
|
+
"fuelUsed": 15394.2
|
|
167
|
+
}
|
|
168
|
+
},
|
|
169
|
+
{
|
|
170
|
+
"fixTime": "2026-06-25T04:34:43.000+00:00",
|
|
171
|
+
"attributes": {
|
|
172
|
+
"fuelUsed": 15394.2
|
|
173
|
+
}
|
|
174
|
+
},
|
|
175
|
+
{
|
|
176
|
+
"fixTime": "2026-06-25T04:34:44.000+00:00",
|
|
177
|
+
"attributes": {
|
|
178
|
+
"fuelUsed": 15394.2
|
|
179
|
+
}
|
|
180
|
+
},
|
|
181
|
+
{
|
|
182
|
+
"fixTime": "2026-06-25T04:34:45.000+00:00",
|
|
183
|
+
"attributes": {
|
|
184
|
+
"fuelUsed": 15394.2
|
|
185
|
+
}
|
|
186
|
+
},
|
|
187
|
+
{
|
|
188
|
+
"fixTime": "2026-06-25T04:34:47.000+00:00",
|
|
189
|
+
"attributes": {
|
|
190
|
+
"fuelUsed": 15394.2
|
|
191
|
+
}
|
|
192
|
+
},
|
|
193
|
+
{
|
|
194
|
+
"fixTime": "2026-06-25T04:34:48.000+00:00",
|
|
195
|
+
"attributes": {
|
|
196
|
+
"fuelUsed": 15394.2
|
|
197
|
+
}
|
|
198
|
+
},
|
|
199
|
+
{
|
|
200
|
+
"fixTime": "2026-06-25T04:37:33.000+00:00",
|
|
201
|
+
"attributes": {
|
|
202
|
+
"fuelUsed": 15394.6
|
|
203
|
+
}
|
|
204
|
+
},
|
|
205
|
+
{
|
|
206
|
+
"fixTime": "2026-06-25T04:41:08.000+00:00",
|
|
207
|
+
"attributes": {
|
|
208
|
+
"fuelUsed": 15395.2
|
|
209
|
+
}
|
|
210
|
+
},
|
|
211
|
+
{
|
|
212
|
+
"fixTime": "2026-06-25T04:43:06.000+00:00",
|
|
213
|
+
"attributes": {
|
|
214
|
+
"fuelUsed": 15395.6
|
|
215
|
+
}
|
|
216
|
+
},
|
|
217
|
+
{
|
|
218
|
+
"fixTime": "2026-06-25T04:45:54.000+00:00",
|
|
219
|
+
"attributes": {
|
|
220
|
+
"fuelUsed": 15396.1
|
|
221
|
+
}
|
|
222
|
+
},
|
|
223
|
+
{
|
|
224
|
+
"fixTime": "2026-06-25T04:48:26.000+00:00",
|
|
225
|
+
"attributes": {
|
|
226
|
+
"fuelUsed": 15396.5
|
|
227
|
+
}
|
|
228
|
+
},
|
|
229
|
+
{
|
|
230
|
+
"fixTime": "2026-06-25T04:51:22.000+00:00",
|
|
231
|
+
"attributes": {
|
|
232
|
+
"fuelUsed": 15397.4
|
|
233
|
+
}
|
|
234
|
+
},
|
|
235
|
+
{
|
|
236
|
+
"fixTime": "2026-06-25T05:08:18.000+00:00",
|
|
237
|
+
"attributes": {
|
|
238
|
+
"fuelUsed": 15397.5
|
|
239
|
+
}
|
|
240
|
+
},
|
|
241
|
+
{
|
|
242
|
+
"fixTime": "2026-06-25T05:48:18.000+00:00",
|
|
243
|
+
"attributes": {
|
|
244
|
+
"fuelUsed": 15397.5
|
|
245
|
+
}
|
|
246
|
+
},
|
|
247
|
+
{
|
|
248
|
+
"fixTime": "2026-06-25T06:28:18.000+00:00",
|
|
249
|
+
"attributes": {
|
|
250
|
+
"fuelUsed": 15397.5
|
|
251
|
+
}
|
|
252
|
+
},
|
|
253
|
+
{
|
|
254
|
+
"fixTime": "2026-06-25T07:06:52.000+00:00",
|
|
255
|
+
"attributes": {
|
|
256
|
+
"fuelUsed": 15397.5
|
|
257
|
+
}
|
|
258
|
+
},
|
|
259
|
+
{
|
|
260
|
+
"fixTime": "2026-06-25T07:40:29.000+00:00",
|
|
261
|
+
"attributes": {
|
|
262
|
+
"fuelUsed": 15397.5
|
|
263
|
+
}
|
|
264
|
+
},
|
|
265
|
+
{
|
|
266
|
+
"fixTime": "2026-06-25T07:53:15.000+00:00",
|
|
267
|
+
"attributes": {
|
|
268
|
+
"fuelUsed": 15398.5
|
|
269
|
+
}
|
|
270
|
+
},
|
|
271
|
+
{
|
|
272
|
+
"fixTime": "2026-06-25T07:56:50.000+00:00",
|
|
273
|
+
"attributes": {
|
|
274
|
+
"fuelUsed": 15399.4
|
|
275
|
+
}
|
|
276
|
+
},
|
|
277
|
+
{
|
|
278
|
+
"fixTime": "2026-06-25T07:59:29.000+00:00",
|
|
279
|
+
"attributes": {
|
|
280
|
+
"fuelUsed": 15399.9
|
|
281
|
+
}
|
|
282
|
+
},
|
|
283
|
+
{
|
|
284
|
+
"fixTime": "2026-06-25T08:03:03.000+00:00",
|
|
285
|
+
"attributes": {
|
|
286
|
+
"fuelUsed": 15400.7
|
|
287
|
+
}
|
|
288
|
+
},
|
|
289
|
+
{
|
|
290
|
+
"fixTime": "2026-06-25T08:07:34.000+00:00",
|
|
291
|
+
"attributes": {
|
|
292
|
+
"fuelUsed": 15401.6
|
|
293
|
+
}
|
|
294
|
+
},
|
|
295
|
+
{
|
|
296
|
+
"fixTime": "2026-06-25T08:11:33.000+00:00",
|
|
297
|
+
"attributes": {
|
|
298
|
+
"fuelUsed": 15402.8
|
|
299
|
+
}
|
|
300
|
+
},
|
|
301
|
+
{
|
|
302
|
+
"fixTime": "2026-06-25T08:15:30.000+00:00",
|
|
303
|
+
"attributes": {
|
|
304
|
+
"fuelUsed": 15403.7
|
|
305
|
+
}
|
|
306
|
+
},
|
|
307
|
+
{
|
|
308
|
+
"fixTime": "2026-06-25T08:19:19.000+00:00",
|
|
309
|
+
"attributes": {
|
|
310
|
+
"fuelUsed": 15404.4
|
|
311
|
+
}
|
|
312
|
+
},
|
|
313
|
+
{
|
|
314
|
+
"fixTime": "2026-06-25T08:22:32.000+00:00",
|
|
315
|
+
"attributes": {
|
|
316
|
+
"fuelUsed": 15405.4
|
|
317
|
+
}
|
|
318
|
+
},
|
|
319
|
+
{
|
|
320
|
+
"fixTime": "2026-06-25T08:32:19.000+00:00",
|
|
321
|
+
"attributes": {
|
|
322
|
+
"fuelUsed": 15405.9
|
|
323
|
+
}
|
|
324
|
+
},
|
|
325
|
+
{
|
|
326
|
+
"fixTime": "2026-06-25T09:06:25.000+00:00",
|
|
327
|
+
"attributes": {
|
|
328
|
+
"fuelUsed": 15406.5
|
|
329
|
+
}
|
|
330
|
+
},
|
|
331
|
+
{
|
|
332
|
+
"fixTime": "2026-06-25T09:42:40.000+00:00",
|
|
333
|
+
"attributes": {
|
|
334
|
+
"fuelUsed": 15406.5
|
|
335
|
+
}
|
|
336
|
+
},
|
|
337
|
+
{
|
|
338
|
+
"fixTime": "2026-06-25T10:21:04.000+00:00",
|
|
339
|
+
"attributes": {
|
|
340
|
+
"fuelUsed": 15406.5
|
|
341
|
+
}
|
|
342
|
+
},
|
|
343
|
+
{
|
|
344
|
+
"fixTime": "2026-06-25T10:57:17.000+00:00",
|
|
345
|
+
"attributes": {
|
|
346
|
+
"fuelUsed": 15406.5
|
|
347
|
+
}
|
|
348
|
+
},
|
|
349
|
+
{
|
|
350
|
+
"fixTime": "2026-06-25T11:32:56.000+00:00",
|
|
351
|
+
"attributes": {
|
|
352
|
+
"fuelUsed": 15406.6
|
|
353
|
+
}
|
|
354
|
+
},
|
|
355
|
+
{
|
|
356
|
+
"fixTime": "2026-06-25T11:47:11.000+00:00",
|
|
357
|
+
"attributes": {
|
|
358
|
+
"fuelUsed": 15406.9
|
|
359
|
+
}
|
|
360
|
+
},
|
|
361
|
+
{
|
|
362
|
+
"fixTime": "2026-06-25T11:50:29.000+00:00",
|
|
363
|
+
"attributes": {
|
|
364
|
+
"fuelUsed": 15408
|
|
365
|
+
}
|
|
366
|
+
},
|
|
367
|
+
{
|
|
368
|
+
"fixTime": "2026-06-25T11:53:46.000+00:00",
|
|
369
|
+
"attributes": {
|
|
370
|
+
"fuelUsed": 15408.9
|
|
371
|
+
}
|
|
372
|
+
},
|
|
373
|
+
{
|
|
374
|
+
"fixTime": "2026-06-25T11:57:12.000+00:00",
|
|
375
|
+
"attributes": {
|
|
376
|
+
"fuelUsed": 15410.2
|
|
377
|
+
}
|
|
378
|
+
},
|
|
379
|
+
{
|
|
380
|
+
"fixTime": "2026-06-25T12:00:19.000+00:00",
|
|
381
|
+
"attributes": {
|
|
382
|
+
"fuelUsed": 15411.1
|
|
383
|
+
}
|
|
384
|
+
},
|
|
385
|
+
{
|
|
386
|
+
"fixTime": "2026-06-25T12:02:55.000+00:00",
|
|
387
|
+
"attributes": {
|
|
388
|
+
"fuelUsed": 15412.2
|
|
389
|
+
}
|
|
390
|
+
},
|
|
391
|
+
{
|
|
392
|
+
"fixTime": "2026-06-25T12:06:19.000+00:00",
|
|
393
|
+
"attributes": {
|
|
394
|
+
"fuelUsed": 15413.4
|
|
395
|
+
}
|
|
396
|
+
},
|
|
397
|
+
{
|
|
398
|
+
"fixTime": "2026-06-25T12:09:16.000+00:00",
|
|
399
|
+
"attributes": {
|
|
400
|
+
"fuelUsed": 15414.7
|
|
401
|
+
}
|
|
402
|
+
},
|
|
403
|
+
{
|
|
404
|
+
"fixTime": "2026-06-25T12:11:52.000+00:00",
|
|
405
|
+
"attributes": {
|
|
406
|
+
"fuelUsed": 15415.8
|
|
407
|
+
}
|
|
408
|
+
},
|
|
409
|
+
{
|
|
410
|
+
"fixTime": "2026-06-25T12:14:44.000+00:00",
|
|
411
|
+
"attributes": {
|
|
412
|
+
"fuelUsed": 15417.1
|
|
413
|
+
}
|
|
414
|
+
},
|
|
415
|
+
{
|
|
416
|
+
"fixTime": "2026-06-25T12:17:34.000+00:00",
|
|
417
|
+
"attributes": {
|
|
418
|
+
"fuelUsed": 15418.3
|
|
419
|
+
}
|
|
420
|
+
},
|
|
421
|
+
{
|
|
422
|
+
"fixTime": "2026-06-25T12:20:58.000+00:00",
|
|
423
|
+
"attributes": {
|
|
424
|
+
"fuelUsed": 15419.4
|
|
425
|
+
}
|
|
426
|
+
},
|
|
427
|
+
{
|
|
428
|
+
"fixTime": "2026-06-25T12:24:10.000+00:00",
|
|
429
|
+
"attributes": {
|
|
430
|
+
"fuelUsed": 15420.4
|
|
431
|
+
}
|
|
432
|
+
},
|
|
433
|
+
{
|
|
434
|
+
"fixTime": "2026-06-25T12:26:59.000+00:00",
|
|
435
|
+
"attributes": {
|
|
436
|
+
"fuelUsed": 15421.6
|
|
437
|
+
}
|
|
438
|
+
},
|
|
439
|
+
{
|
|
440
|
+
"fixTime": "2026-06-25T12:29:57.000+00:00",
|
|
441
|
+
"attributes": {
|
|
442
|
+
"fuelUsed": 15422.8
|
|
443
|
+
}
|
|
444
|
+
},
|
|
445
|
+
{
|
|
446
|
+
"fixTime": "2026-06-25T12:32:38.000+00:00",
|
|
447
|
+
"attributes": {
|
|
448
|
+
"fuelUsed": 15423.8
|
|
449
|
+
}
|
|
450
|
+
},
|
|
451
|
+
{
|
|
452
|
+
"fixTime": "2026-06-25T12:35:29.000+00:00",
|
|
453
|
+
"attributes": {
|
|
454
|
+
"fuelUsed": 15425
|
|
455
|
+
}
|
|
456
|
+
},
|
|
457
|
+
{
|
|
458
|
+
"fixTime": "2026-06-25T12:38:15.000+00:00",
|
|
459
|
+
"attributes": {
|
|
460
|
+
"fuelUsed": 15426.2
|
|
461
|
+
}
|
|
462
|
+
},
|
|
463
|
+
{
|
|
464
|
+
"fixTime": "2026-06-25T12:40:50.000+00:00",
|
|
465
|
+
"attributes": {
|
|
466
|
+
"fuelUsed": 15427.3
|
|
467
|
+
}
|
|
468
|
+
},
|
|
469
|
+
{
|
|
470
|
+
"fixTime": "2026-06-25T12:43:24.000+00:00",
|
|
471
|
+
"attributes": {
|
|
472
|
+
"fuelUsed": 15428
|
|
473
|
+
}
|
|
474
|
+
},
|
|
475
|
+
{
|
|
476
|
+
"fixTime": "2026-06-25T12:46:03.000+00:00",
|
|
477
|
+
"attributes": {
|
|
478
|
+
"fuelUsed": 15429.1
|
|
479
|
+
}
|
|
480
|
+
},
|
|
481
|
+
{
|
|
482
|
+
"fixTime": "2026-06-25T12:48:57.000+00:00",
|
|
483
|
+
"attributes": {
|
|
484
|
+
"fuelUsed": 15430
|
|
485
|
+
}
|
|
486
|
+
},
|
|
487
|
+
{
|
|
488
|
+
"fixTime": "2026-06-25T12:51:45.000+00:00",
|
|
489
|
+
"attributes": {
|
|
490
|
+
"fuelUsed": 15431.2
|
|
491
|
+
}
|
|
492
|
+
},
|
|
493
|
+
{
|
|
494
|
+
"fixTime": "2026-06-25T12:54:15.000+00:00",
|
|
495
|
+
"attributes": {
|
|
496
|
+
"fuelUsed": 15432
|
|
497
|
+
}
|
|
498
|
+
},
|
|
499
|
+
{
|
|
500
|
+
"fixTime": "2026-06-25T12:56:54.000+00:00",
|
|
501
|
+
"attributes": {
|
|
502
|
+
"fuelUsed": 15433.4
|
|
503
|
+
}
|
|
504
|
+
},
|
|
505
|
+
{
|
|
506
|
+
"fixTime": "2026-06-25T12:59:27.000+00:00",
|
|
507
|
+
"attributes": {
|
|
508
|
+
"fuelUsed": 15434.8
|
|
509
|
+
}
|
|
510
|
+
},
|
|
511
|
+
{
|
|
512
|
+
"fixTime": "2026-06-25T13:02:20.000+00:00",
|
|
513
|
+
"attributes": {
|
|
514
|
+
"fuelUsed": 15435.5
|
|
515
|
+
}
|
|
516
|
+
},
|
|
517
|
+
{
|
|
518
|
+
"fixTime": "2026-06-25T13:04:44.000+00:00",
|
|
519
|
+
"attributes": {
|
|
520
|
+
"fuelUsed": 15436.1
|
|
521
|
+
}
|
|
522
|
+
},
|
|
523
|
+
{
|
|
524
|
+
"fixTime": "2026-06-25T13:07:26.000+00:00",
|
|
525
|
+
"attributes": {
|
|
526
|
+
"fuelUsed": 15437.3
|
|
527
|
+
}
|
|
528
|
+
},
|
|
529
|
+
{
|
|
530
|
+
"fixTime": "2026-06-25T13:10:02.000+00:00",
|
|
531
|
+
"attributes": {
|
|
532
|
+
"fuelUsed": 15438.6
|
|
533
|
+
}
|
|
534
|
+
},
|
|
535
|
+
{
|
|
536
|
+
"fixTime": "2026-06-25T13:13:06.000+00:00",
|
|
537
|
+
"attributes": {
|
|
538
|
+
"fuelUsed": 15439.4
|
|
539
|
+
}
|
|
540
|
+
},
|
|
541
|
+
{
|
|
542
|
+
"fixTime": "2026-06-25T13:16:00.000+00:00",
|
|
543
|
+
"attributes": {
|
|
544
|
+
"fuelUsed": 15440.2
|
|
545
|
+
}
|
|
546
|
+
},
|
|
547
|
+
{
|
|
548
|
+
"fixTime": "2026-06-25T13:19:00.000+00:00",
|
|
549
|
+
"attributes": {
|
|
550
|
+
"fuelUsed": 15441.7
|
|
551
|
+
}
|
|
552
|
+
},
|
|
553
|
+
{
|
|
554
|
+
"fixTime": "2026-06-25T13:21:43.000+00:00",
|
|
555
|
+
"attributes": {
|
|
556
|
+
"fuelUsed": 15442.2
|
|
557
|
+
}
|
|
558
|
+
},
|
|
559
|
+
{
|
|
560
|
+
"fixTime": "2026-06-25T13:24:27.000+00:00",
|
|
561
|
+
"attributes": {
|
|
562
|
+
"fuelUsed": 15443.8
|
|
563
|
+
}
|
|
564
|
+
},
|
|
565
|
+
{
|
|
566
|
+
"fixTime": "2026-06-25T13:27:30.000+00:00",
|
|
567
|
+
"attributes": {
|
|
568
|
+
"fuelUsed": 15446
|
|
569
|
+
}
|
|
570
|
+
},
|
|
571
|
+
{
|
|
572
|
+
"fixTime": "2026-06-25T13:30:27.000+00:00",
|
|
573
|
+
"attributes": {
|
|
574
|
+
"fuelUsed": 15447.6
|
|
575
|
+
}
|
|
576
|
+
},
|
|
577
|
+
{
|
|
578
|
+
"fixTime": "2026-06-25T13:33:10.000+00:00",
|
|
579
|
+
"attributes": {
|
|
580
|
+
"fuelUsed": 15448.2
|
|
581
|
+
}
|
|
582
|
+
},
|
|
583
|
+
{
|
|
584
|
+
"fixTime": "2026-06-25T13:36:05.000+00:00",
|
|
585
|
+
"attributes": {
|
|
586
|
+
"fuelUsed": 15448.9
|
|
587
|
+
}
|
|
588
|
+
},
|
|
589
|
+
{
|
|
590
|
+
"fixTime": "2026-06-25T13:38:50.000+00:00",
|
|
591
|
+
"attributes": {
|
|
592
|
+
"fuelUsed": 15449.8
|
|
593
|
+
}
|
|
594
|
+
},
|
|
595
|
+
{
|
|
596
|
+
"fixTime": "2026-06-25T13:41:40.000+00:00",
|
|
597
|
+
"attributes": {
|
|
598
|
+
"fuelUsed": 15450.3
|
|
599
|
+
}
|
|
600
|
+
},
|
|
601
|
+
{
|
|
602
|
+
"fixTime": "2026-06-25T13:44:52.000+00:00",
|
|
603
|
+
"attributes": {
|
|
604
|
+
"fuelUsed": 15451.5
|
|
605
|
+
}
|
|
606
|
+
},
|
|
607
|
+
{
|
|
608
|
+
"fixTime": "2026-06-25T13:48:25.000+00:00",
|
|
609
|
+
"attributes": {
|
|
610
|
+
"fuelUsed": 15452.3
|
|
611
|
+
}
|
|
612
|
+
},
|
|
613
|
+
{
|
|
614
|
+
"fixTime": "2026-06-25T13:51:32.000+00:00",
|
|
615
|
+
"attributes": {
|
|
616
|
+
"fuelUsed": 15453.8
|
|
617
|
+
}
|
|
618
|
+
},
|
|
619
|
+
{
|
|
620
|
+
"fixTime": "2026-06-25T13:54:23.000+00:00",
|
|
621
|
+
"attributes": {
|
|
622
|
+
"fuelUsed": 15454.6
|
|
623
|
+
}
|
|
624
|
+
},
|
|
625
|
+
{
|
|
626
|
+
"fixTime": "2026-06-25T13:57:24.000+00:00",
|
|
627
|
+
"attributes": {
|
|
628
|
+
"fuelUsed": 15455.9
|
|
629
|
+
}
|
|
630
|
+
},
|
|
631
|
+
{
|
|
632
|
+
"fixTime": "2026-06-25T14:00:15.000+00:00",
|
|
633
|
+
"attributes": {
|
|
634
|
+
"fuelUsed": 15457.1
|
|
635
|
+
}
|
|
636
|
+
},
|
|
637
|
+
{
|
|
638
|
+
"fixTime": "2026-06-25T14:03:24.000+00:00",
|
|
639
|
+
"attributes": {
|
|
640
|
+
"fuelUsed": 15458.1
|
|
641
|
+
}
|
|
642
|
+
},
|
|
643
|
+
{
|
|
644
|
+
"fixTime": "2026-06-25T14:06:39.000+00:00",
|
|
645
|
+
"attributes": {
|
|
646
|
+
"fuelUsed": 15458.9
|
|
647
|
+
}
|
|
648
|
+
},
|
|
649
|
+
{
|
|
650
|
+
"fixTime": "2026-06-25T14:10:00.000+00:00",
|
|
651
|
+
"attributes": {
|
|
652
|
+
"fuelUsed": 15459.8
|
|
653
|
+
}
|
|
654
|
+
},
|
|
655
|
+
{
|
|
656
|
+
"fixTime": "2026-06-25T14:14:03.000+00:00",
|
|
657
|
+
"attributes": {
|
|
658
|
+
"fuelUsed": 15460.8
|
|
659
|
+
}
|
|
660
|
+
},
|
|
661
|
+
{
|
|
662
|
+
"fixTime": "2026-06-25T14:18:24.000+00:00",
|
|
663
|
+
"attributes": {
|
|
664
|
+
"fuelUsed": 15461.7
|
|
665
|
+
}
|
|
666
|
+
},
|
|
667
|
+
{
|
|
668
|
+
"fixTime": "2026-06-25T14:22:44.000+00:00",
|
|
669
|
+
"attributes": {
|
|
670
|
+
"fuelUsed": 15462.6
|
|
671
|
+
}
|
|
672
|
+
},
|
|
673
|
+
{
|
|
674
|
+
"fixTime": "2026-06-25T14:24:15.000+00:00",
|
|
675
|
+
"attributes": {
|
|
676
|
+
"fuelUsed": 15462.7
|
|
677
|
+
}
|
|
678
|
+
},
|
|
679
|
+
{
|
|
680
|
+
"fixTime": "2026-06-25T15:02:55.000+00:00",
|
|
681
|
+
"attributes": {
|
|
682
|
+
"fuelUsed": 15462.8
|
|
683
|
+
}
|
|
684
|
+
},
|
|
685
|
+
{
|
|
686
|
+
"fixTime": "2026-06-25T15:35:11.000+00:00",
|
|
687
|
+
"attributes": {
|
|
688
|
+
"fuelUsed": 15462.9
|
|
689
|
+
}
|
|
690
|
+
},
|
|
691
|
+
{
|
|
692
|
+
"fixTime": "2026-06-25T16:15:11.000+00:00",
|
|
693
|
+
"attributes": {
|
|
694
|
+
"fuelUsed": 15462.9
|
|
695
|
+
}
|
|
696
|
+
},
|
|
697
|
+
{
|
|
698
|
+
"fixTime": "2026-06-25T16:54:01.000+00:00",
|
|
699
|
+
"attributes": {
|
|
700
|
+
"fuelUsed": 15462.9
|
|
701
|
+
}
|
|
702
|
+
},
|
|
703
|
+
{
|
|
704
|
+
"fixTime": "2026-06-25T16:58:54.000+00:00",
|
|
705
|
+
"attributes": {
|
|
706
|
+
"fuelUsed": 15463.4
|
|
707
|
+
}
|
|
708
|
+
},
|
|
709
|
+
{
|
|
710
|
+
"fixTime": "2026-06-25T17:03:04.000+00:00",
|
|
711
|
+
"attributes": {
|
|
712
|
+
"fuelUsed": 15463.7
|
|
713
|
+
}
|
|
714
|
+
},
|
|
715
|
+
{
|
|
716
|
+
"fixTime": "2026-06-25T17:07:00.000+00:00",
|
|
717
|
+
"attributes": {
|
|
718
|
+
"fuelUsed": 15464.2
|
|
719
|
+
}
|
|
720
|
+
},
|
|
721
|
+
{
|
|
722
|
+
"fixTime": "2026-06-25T17:10:26.000+00:00",
|
|
723
|
+
"attributes": {
|
|
724
|
+
"fuelUsed": 15464.8
|
|
725
|
+
}
|
|
726
|
+
},
|
|
727
|
+
{
|
|
728
|
+
"fixTime": "2026-06-25T17:14:13.000+00:00",
|
|
729
|
+
"attributes": {
|
|
730
|
+
"fuelUsed": 15465.4
|
|
731
|
+
}
|
|
732
|
+
},
|
|
733
|
+
{
|
|
734
|
+
"fixTime": "2026-06-25T17:17:11.000+00:00",
|
|
735
|
+
"attributes": {
|
|
736
|
+
"fuelUsed": 15466.4
|
|
737
|
+
}
|
|
738
|
+
},
|
|
739
|
+
{
|
|
740
|
+
"fixTime": "2026-06-25T17:20:32.000+00:00",
|
|
741
|
+
"attributes": {
|
|
742
|
+
"fuelUsed": 15467.4
|
|
743
|
+
}
|
|
744
|
+
},
|
|
745
|
+
{
|
|
746
|
+
"fixTime": "2026-06-25T17:23:26.000+00:00",
|
|
747
|
+
"attributes": {
|
|
748
|
+
"fuelUsed": 15468.5
|
|
749
|
+
}
|
|
750
|
+
},
|
|
751
|
+
{
|
|
752
|
+
"fixTime": "2026-06-25T17:26:16.000+00:00",
|
|
753
|
+
"attributes": {
|
|
754
|
+
"fuelUsed": 15469.2
|
|
755
|
+
}
|
|
756
|
+
},
|
|
757
|
+
{
|
|
758
|
+
"fixTime": "2026-06-25T17:29:13.000+00:00",
|
|
759
|
+
"attributes": {
|
|
760
|
+
"fuelUsed": 15470.4
|
|
761
|
+
}
|
|
762
|
+
},
|
|
763
|
+
{
|
|
764
|
+
"fixTime": "2026-06-25T17:32:13.000+00:00",
|
|
765
|
+
"attributes": {
|
|
766
|
+
"fuelUsed": 15471.5
|
|
767
|
+
}
|
|
768
|
+
},
|
|
769
|
+
{
|
|
770
|
+
"fixTime": "2026-06-25T17:36:09.000+00:00",
|
|
771
|
+
"attributes": {
|
|
772
|
+
"fuelUsed": 15472.3
|
|
773
|
+
}
|
|
774
|
+
},
|
|
775
|
+
{
|
|
776
|
+
"fixTime": "2026-06-25T17:39:07.000+00:00",
|
|
777
|
+
"attributes": {
|
|
778
|
+
"fuelUsed": 15473.2
|
|
779
|
+
}
|
|
780
|
+
},
|
|
781
|
+
{
|
|
782
|
+
"fixTime": "2026-06-25T17:42:03.000+00:00",
|
|
783
|
+
"attributes": {
|
|
784
|
+
"fuelUsed": 15474.4
|
|
785
|
+
}
|
|
786
|
+
},
|
|
787
|
+
{
|
|
788
|
+
"fixTime": "2026-06-25T17:45:57.000+00:00",
|
|
789
|
+
"attributes": {
|
|
790
|
+
"fuelUsed": 15475.1
|
|
791
|
+
}
|
|
792
|
+
},
|
|
793
|
+
{
|
|
794
|
+
"fixTime": "2026-06-25T17:49:06.000+00:00",
|
|
795
|
+
"attributes": {
|
|
796
|
+
"fuelUsed": 15476.5
|
|
797
|
+
}
|
|
798
|
+
},
|
|
799
|
+
{
|
|
800
|
+
"fixTime": "2026-06-25T17:51:56.000+00:00",
|
|
801
|
+
"attributes": {
|
|
802
|
+
"fuelUsed": 15477.6
|
|
803
|
+
}
|
|
804
|
+
},
|
|
805
|
+
{
|
|
806
|
+
"fixTime": "2026-06-25T17:54:52.000+00:00",
|
|
807
|
+
"attributes": {
|
|
808
|
+
"fuelUsed": 15478.3
|
|
809
|
+
}
|
|
810
|
+
},
|
|
811
|
+
{
|
|
812
|
+
"fixTime": "2026-06-25T17:57:44.000+00:00",
|
|
813
|
+
"attributes": {
|
|
814
|
+
"fuelUsed": 15478.8
|
|
815
|
+
}
|
|
816
|
+
},
|
|
817
|
+
{
|
|
818
|
+
"fixTime": "2026-06-25T18:00:38.000+00:00",
|
|
819
|
+
"attributes": {
|
|
820
|
+
"fuelUsed": 15479.4
|
|
821
|
+
}
|
|
822
|
+
},
|
|
823
|
+
{
|
|
824
|
+
"fixTime": "2026-06-25T18:03:35.000+00:00",
|
|
825
|
+
"attributes": {
|
|
826
|
+
"fuelUsed": 15480.5
|
|
827
|
+
}
|
|
828
|
+
},
|
|
829
|
+
{
|
|
830
|
+
"fixTime": "2026-06-25T18:06:23.000+00:00",
|
|
831
|
+
"attributes": {
|
|
832
|
+
"fuelUsed": 15481.3
|
|
833
|
+
}
|
|
834
|
+
},
|
|
835
|
+
{
|
|
836
|
+
"fixTime": "2026-06-25T18:09:17.000+00:00",
|
|
837
|
+
"attributes": {
|
|
838
|
+
"fuelUsed": 15482.4
|
|
839
|
+
}
|
|
840
|
+
},
|
|
841
|
+
{
|
|
842
|
+
"fixTime": "2026-06-25T18:12:02.000+00:00",
|
|
843
|
+
"attributes": {
|
|
844
|
+
"fuelUsed": 15483.5
|
|
845
|
+
}
|
|
846
|
+
},
|
|
847
|
+
{
|
|
848
|
+
"fixTime": "2026-06-25T18:14:56.000+00:00",
|
|
849
|
+
"attributes": {
|
|
850
|
+
"fuelUsed": 15484.2
|
|
851
|
+
}
|
|
852
|
+
},
|
|
853
|
+
{
|
|
854
|
+
"fixTime": "2026-06-25T18:17:51.000+00:00",
|
|
855
|
+
"attributes": {
|
|
856
|
+
"fuelUsed": 15485.1
|
|
857
|
+
}
|
|
858
|
+
},
|
|
859
|
+
{
|
|
860
|
+
"fixTime": "2026-06-25T18:20:46.000+00:00",
|
|
861
|
+
"attributes": {
|
|
862
|
+
"fuelUsed": 15486.2
|
|
863
|
+
}
|
|
864
|
+
},
|
|
865
|
+
{
|
|
866
|
+
"fixTime": "2026-06-25T18:23:43.000+00:00",
|
|
867
|
+
"attributes": {
|
|
868
|
+
"fuelUsed": 15486.8
|
|
869
|
+
}
|
|
870
|
+
},
|
|
871
|
+
{
|
|
872
|
+
"fixTime": "2026-06-25T18:26:37.000+00:00",
|
|
873
|
+
"attributes": {
|
|
874
|
+
"fuelUsed": 15487.6
|
|
875
|
+
}
|
|
876
|
+
},
|
|
877
|
+
{
|
|
878
|
+
"fixTime": "2026-06-25T18:29:40.000+00:00",
|
|
879
|
+
"attributes": {
|
|
880
|
+
"fuelUsed": 15488.6
|
|
881
|
+
}
|
|
882
|
+
},
|
|
883
|
+
{
|
|
884
|
+
"fixTime": "2026-06-25T18:32:34.000+00:00",
|
|
885
|
+
"attributes": {
|
|
886
|
+
"fuelUsed": 15489.6
|
|
887
|
+
}
|
|
888
|
+
},
|
|
889
|
+
{
|
|
890
|
+
"fixTime": "2026-06-25T18:35:27.000+00:00",
|
|
891
|
+
"attributes": {
|
|
892
|
+
"fuelUsed": 15490.5
|
|
893
|
+
}
|
|
894
|
+
},
|
|
895
|
+
{
|
|
896
|
+
"fixTime": "2026-06-25T18:38:22.000+00:00",
|
|
897
|
+
"attributes": {
|
|
898
|
+
"fuelUsed": 15491.5
|
|
899
|
+
}
|
|
900
|
+
},
|
|
901
|
+
{
|
|
902
|
+
"fixTime": "2026-06-25T18:41:11.000+00:00",
|
|
903
|
+
"attributes": {
|
|
904
|
+
"fuelUsed": 15492.4
|
|
905
|
+
}
|
|
906
|
+
},
|
|
907
|
+
{
|
|
908
|
+
"fixTime": "2026-06-25T18:44:03.000+00:00",
|
|
909
|
+
"attributes": {
|
|
910
|
+
"fuelUsed": 15493.3
|
|
911
|
+
}
|
|
912
|
+
},
|
|
913
|
+
{
|
|
914
|
+
"fixTime": "2026-06-25T18:46:56.000+00:00",
|
|
915
|
+
"attributes": {
|
|
916
|
+
"fuelUsed": 15494.2
|
|
917
|
+
}
|
|
918
|
+
},
|
|
919
|
+
{
|
|
920
|
+
"fixTime": "2026-06-25T18:49:50.000+00:00",
|
|
921
|
+
"attributes": {
|
|
922
|
+
"fuelUsed": 15495.1
|
|
923
|
+
}
|
|
924
|
+
},
|
|
925
|
+
{
|
|
926
|
+
"fixTime": "2026-06-25T18:52:48.000+00:00",
|
|
927
|
+
"attributes": {
|
|
928
|
+
"fuelUsed": 15496
|
|
929
|
+
}
|
|
930
|
+
},
|
|
931
|
+
{
|
|
932
|
+
"fixTime": "2026-06-25T18:55:40.000+00:00",
|
|
933
|
+
"attributes": {
|
|
934
|
+
"fuelUsed": 15496.9
|
|
935
|
+
}
|
|
936
|
+
},
|
|
937
|
+
{
|
|
938
|
+
"fixTime": "2026-06-25T18:58:52.000+00:00",
|
|
939
|
+
"attributes": {
|
|
940
|
+
"fuelUsed": 15497.7
|
|
941
|
+
}
|
|
942
|
+
},
|
|
943
|
+
{
|
|
944
|
+
"fixTime": "2026-06-25T19:01:44.000+00:00",
|
|
945
|
+
"attributes": {
|
|
946
|
+
"fuelUsed": 15498.6
|
|
947
|
+
}
|
|
948
|
+
},
|
|
949
|
+
{
|
|
950
|
+
"fixTime": "2026-06-25T19:04:38.000+00:00",
|
|
951
|
+
"attributes": {
|
|
952
|
+
"fuelUsed": 15499.5
|
|
953
|
+
}
|
|
954
|
+
},
|
|
955
|
+
{
|
|
956
|
+
"fixTime": "2026-06-25T19:07:36.000+00:00",
|
|
957
|
+
"attributes": {
|
|
958
|
+
"fuelUsed": 15500.3
|
|
959
|
+
}
|
|
960
|
+
},
|
|
961
|
+
{
|
|
962
|
+
"fixTime": "2026-06-25T19:10:34.000+00:00",
|
|
963
|
+
"attributes": {
|
|
964
|
+
"fuelUsed": 15501.2
|
|
965
|
+
}
|
|
966
|
+
},
|
|
967
|
+
{
|
|
968
|
+
"fixTime": "2026-06-25T19:13:33.000+00:00",
|
|
969
|
+
"attributes": {
|
|
970
|
+
"fuelUsed": 15502.1
|
|
971
|
+
}
|
|
972
|
+
},
|
|
973
|
+
{
|
|
974
|
+
"fixTime": "2026-06-25T19:16:47.000+00:00",
|
|
975
|
+
"attributes": {
|
|
976
|
+
"fuelUsed": 15502.5
|
|
977
|
+
}
|
|
978
|
+
},
|
|
979
|
+
{
|
|
980
|
+
"fixTime": "2026-06-25T19:20:05.000+00:00",
|
|
981
|
+
"attributes": {
|
|
982
|
+
"fuelUsed": 15503.2
|
|
983
|
+
}
|
|
984
|
+
},
|
|
985
|
+
{
|
|
986
|
+
"fixTime": "2026-06-25T19:23:50.000+00:00",
|
|
987
|
+
"attributes": {
|
|
988
|
+
"fuelUsed": 15503.7
|
|
989
|
+
}
|
|
990
|
+
},
|
|
991
|
+
{
|
|
992
|
+
"fixTime": "2026-06-25T19:27:08.000+00:00",
|
|
993
|
+
"attributes": {
|
|
994
|
+
"fuelUsed": 15504
|
|
995
|
+
}
|
|
996
|
+
},
|
|
997
|
+
{
|
|
998
|
+
"fixTime": "2026-06-25T19:30:05.000+00:00",
|
|
999
|
+
"attributes": {
|
|
1000
|
+
"fuelUsed": 15504.3
|
|
1001
|
+
}
|
|
1002
|
+
},
|
|
1003
|
+
{
|
|
1004
|
+
"fixTime": "2026-06-25T19:34:16.000+00:00",
|
|
1005
|
+
"attributes": {
|
|
1006
|
+
"fuelUsed": 15504.5
|
|
1007
|
+
}
|
|
1008
|
+
},
|
|
1009
|
+
{
|
|
1010
|
+
"fixTime": "2026-06-25T19:43:39.000+00:00",
|
|
1011
|
+
"attributes": {
|
|
1012
|
+
"fuelUsed": 15504.8
|
|
1013
|
+
}
|
|
1014
|
+
},
|
|
1015
|
+
{
|
|
1016
|
+
"fixTime": "2026-06-25T19:48:22.000+00:00",
|
|
1017
|
+
"attributes": {
|
|
1018
|
+
"fuelUsed": 15505
|
|
1019
|
+
}
|
|
1020
|
+
},
|
|
1021
|
+
{
|
|
1022
|
+
"fixTime": "2026-06-25T19:52:30.000+00:00",
|
|
1023
|
+
"attributes": {
|
|
1024
|
+
"fuelUsed": 15505.6
|
|
1025
|
+
}
|
|
1026
|
+
},
|
|
1027
|
+
{
|
|
1028
|
+
"fixTime": "2026-06-25T20:24:17.000+00:00",
|
|
1029
|
+
"attributes": {
|
|
1030
|
+
"fuelUsed": 15505.6
|
|
1031
|
+
}
|
|
1032
|
+
}
|
|
1033
|
+
]
|
|
1034
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/* eslint-disable no-undef */
|
|
2
2
|
const assert = require('assert')
|
|
3
|
-
const { getFuelUsedBetween, calculateConsumption } = require('../util/fuel')
|
|
3
|
+
const { getFuelUsedBetween, calculateConsumption, shouldUseFuelSensor } = require('../util/fuel')
|
|
4
4
|
|
|
5
5
|
function pos (iso, fuelUsed, extra = {}) {
|
|
6
6
|
return { fixTime: new Date(iso).toISOString(), attributes: { fuelUsed, ...extra } }
|
|
@@ -59,3 +59,49 @@ describe('fuelUsed counter based consumption', function () {
|
|
|
59
59
|
assert.strictEqual(calculateConsumption(device, { route: noCan, summary: { spentFuel: 12 } }), 12)
|
|
60
60
|
})
|
|
61
61
|
})
|
|
62
|
+
|
|
63
|
+
describe('shouldUseFuelSensor', function () {
|
|
64
|
+
const sensorDevice = { attributes: { fuel_low_threshold: 10, fuel_high_threshold: 90, fuel_tank_capacity: 500 } }
|
|
65
|
+
|
|
66
|
+
// Reproduces the Fuel Consumption Report bug still seen after the fuelUsed fix: a
|
|
67
|
+
// vehicle configured with analog sensor thresholds (fuel_low/high_threshold, tank
|
|
68
|
+
// capacity) that ALSO reports the CAN fuelUsed counter. The report must still prefer
|
|
69
|
+
// fuelUsed (== Manager "Fuel Used"), not fall back to the analog tank-level segmentation,
|
|
70
|
+
// which produced 0 on refuel days (e.g. FORD CARGO / 28669-B-59, 25/06/2026).
|
|
71
|
+
it('prefers the CAN counter over the analog sensor when both are configured', () => {
|
|
72
|
+
assert.strictEqual(shouldUseFuelSensor(sensorDevice, route), false)
|
|
73
|
+
})
|
|
74
|
+
|
|
75
|
+
it('uses the analog sensor when the device has no CAN fuelUsed data', () => {
|
|
76
|
+
const noCan = [{ fixTime: new Date('2026-06-01T06:00:00Z').toISOString(), attributes: { fuel: 50 } }]
|
|
77
|
+
assert.strictEqual(shouldUseFuelSensor(sensorDevice, noCan), true)
|
|
78
|
+
})
|
|
79
|
+
|
|
80
|
+
it('does not use the sensor when thresholds are not configured', () => {
|
|
81
|
+
assert.strictEqual(shouldUseFuelSensor({ attributes: {} }, []), false)
|
|
82
|
+
})
|
|
83
|
+
})
|
|
84
|
+
|
|
85
|
+
describe('calculateConsumption against real production data (FORD CARGO / 28669-B-59)', function () {
|
|
86
|
+
// Trimmed allinone response for 25/06/2026 (route thinned to every ~40th position plus
|
|
87
|
+
// its fuelUsed min/max, trips/stops kept in full). This device's route reports fuelUsed
|
|
88
|
+
// NON-monotonically that day (33439.5 -> 15505.6, i.e. a raw delta of about -17934) -
|
|
89
|
+
// subtracting it directly is wrong, and is exactly why the report still read 0.0 L after
|
|
90
|
+
// the fuelUsed-counter fix (PRs #258/#259) shipped. Traccar's own per-trip/per-stop
|
|
91
|
+
// spentFuel (11 trips summing to 110.6, one stray stop at -18045.3 that gets floored to 0,
|
|
92
|
+
// two small positive stops totalling 0.8) is correct and must be preferred: 110.6 + 0.8 =
|
|
93
|
+
// 111.4, matching the ~111 L the user confirmed via the Manager's "Fuel Used".
|
|
94
|
+
const fixture = require('./fixtures/ford-cargo-28669-2026-06-25.json')
|
|
95
|
+
const device = { attributes: {} }
|
|
96
|
+
const from = new Date('2026-06-24T23:00:00.000Z')
|
|
97
|
+
const to = new Date('2026-06-25T22:59:59.000Z')
|
|
98
|
+
|
|
99
|
+
it('sums Traccar trip/stop spentFuel instead of the non-monotonic raw fuelUsed counter', () => {
|
|
100
|
+
const result = calculateConsumption(device, { trips: fixture.trips, stops: fixture.stops, route: fixture.route, summary: null, from, to })
|
|
101
|
+
assert.ok(Math.abs(result - 111.4) < 0.01, result)
|
|
102
|
+
})
|
|
103
|
+
|
|
104
|
+
it('sanity check: a naive route fuelUsed(last)-fuelUsed(first) would be deeply negative here', () => {
|
|
105
|
+
assert.ok(getFuelUsedBetween(fixture.route, from, to) === 0) // clamped from a large negative
|
|
106
|
+
})
|
|
107
|
+
})
|
package/src/util/fuel.js
CHANGED
|
@@ -9,6 +9,23 @@ function getRefuelingLiters (d, position, diff) {
|
|
|
9
9
|
return Math.round(diff * d.attributes.fuel_tank_capacity / 100)
|
|
10
10
|
}
|
|
11
11
|
|
|
12
|
+
function hasCanFuelUsed (route) {
|
|
13
|
+
return Array.isArray(route) && route.some(p => p && p.attributes && p.attributes.fuelUsed)
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
// Whether a report should fall back to the analog tank-level sensor (calculateTotalFuelFromSensor)
|
|
17
|
+
// for this device/route. The CAN "fuelUsed" counter - when the device actually reports it - is
|
|
18
|
+
// the exact value the Manager shows as "Fuel Used", so it must always win over the analog sensor,
|
|
19
|
+
// even if fuel_low_threshold/fuel_high_threshold/fuel_tank_capacity happen to be configured on the
|
|
20
|
+
// device: that config alone doesn't mean the analog input is wired or currently reporting, and a
|
|
21
|
+
// device can carry stale/unrelated sensor thresholds while actually being CAN-fuelled.
|
|
22
|
+
function shouldUseFuelSensor (device, route) {
|
|
23
|
+
return !hasCanFuelUsed(route) &&
|
|
24
|
+
'fuel_low_threshold' in device.attributes &&
|
|
25
|
+
'fuel_high_threshold' in device.attributes &&
|
|
26
|
+
!!device.attributes.fuel_tank_capacity
|
|
27
|
+
}
|
|
28
|
+
|
|
12
29
|
function calculateTotalFuelFromSensor(trips, stops, positions, device, firstStopIndex) {
|
|
13
30
|
const lastStopIndex = firstStopIndex + trips.length - 1
|
|
14
31
|
const lastStop = stops.length > lastStopIndex ? stops[lastStopIndex] : null
|
|
@@ -120,13 +137,24 @@ function getFuelUsedBetween (route, from, to) {
|
|
|
120
137
|
function calculateConsumption (d, data) {
|
|
121
138
|
let fuelConsumption = 0
|
|
122
139
|
const withFuelUsed = data.route && data.route.find(p => p.attributes.fuelUsed)
|
|
123
|
-
if (
|
|
124
|
-
//
|
|
140
|
+
if (data.trips && data.stops) {
|
|
141
|
+
// Trust Traccar's own already-computed per-trip/per-stop spentFuel over any
|
|
142
|
+
// period-level aggregate. Two other sources have each turned out unreliable for
|
|
143
|
+
// real devices: the daily summary's spentFuel (tank-level based - goes <= 0 on a
|
|
144
|
+
// refuel day) and a naive fuelUsed(last)-fuelUsed(first) over the raw route (some
|
|
145
|
+
// devices/protocols report that counter non-monotonically or in units other than
|
|
146
|
+
// litres, e.g. FORD CARGO / 28669-B-59 - the raw route delta comes out at -18000+
|
|
147
|
+
// while Traccar's own per-trip spentFuel sums to the correct ~111L for that day).
|
|
148
|
+
// Each individual trip/stop value is still floored at 0 below so one bad segment
|
|
149
|
+
// (e.g. a counter glitch) can't drag the whole sum negative.
|
|
150
|
+
fuelConsumption = data.trips.reduce((a, b) => a + calculateSpentFuel(b.spentFuel, d, withFuelUsed), 0) + data.stops.reduce((a, b) => a + calculateSpentFuel(b.spentFuel, d, withFuelUsed), 0)
|
|
151
|
+
} else if (withFuelUsed && data.route.length > 1) {
|
|
152
|
+
// No trips/stops to sum (e.g. a period-only aggregate) - fall back to the raw
|
|
153
|
+
// fuelUsed counter delta, which matches the Manager's "Fuel Used" for devices
|
|
154
|
+
// that do report it monotonically in litres.
|
|
125
155
|
fuelConsumption = getFuelUsedBetween(data.route, data.from, data.to)
|
|
126
156
|
} else if (data.summary && withFuelUsed) {
|
|
127
157
|
fuelConsumption = calculateSpentFuel(data.summary.spentFuel, d, withFuelUsed)
|
|
128
|
-
} else if (data.trips && data.stops) {
|
|
129
|
-
fuelConsumption = data.trips.reduce((a, b) => a + calculateSpentFuel(b.spentFuel, d, withFuelUsed), 0) + data.stops.reduce((a, b) => a + calculateSpentFuel(b.spentFuel, d, withFuelUsed), 0)
|
|
130
158
|
} else if (data.summary) {
|
|
131
159
|
fuelConsumption = data.summary.spentFuel
|
|
132
160
|
}
|
|
@@ -162,3 +190,5 @@ exports.calculateConsumption = calculateConsumption
|
|
|
162
190
|
exports.getFuelUsedBetween = getFuelUsedBetween
|
|
163
191
|
exports.useOdooFuelData = useOdooFuelData
|
|
164
192
|
exports.calculateTotalFuelFromSensor = calculateTotalFuelFromSensor
|
|
193
|
+
exports.hasCanFuelUsed = hasCanFuelUsed
|
|
194
|
+
exports.shouldUseFuelSensor = shouldUseFuelSensor
|