aboutsummaryrefslogtreecommitdiff
path: root/src/org/traccar
diff options
context:
space:
mode:
authorAnton Tananaev <anton.tananaev@gmail.com>2016-08-20 13:13:09 +0300
committerGitHub <noreply@github.com>2016-08-20 13:13:09 +0300
commit6c6b62351aadd68928b9bd3e39e2bf96d78695e8 (patch)
tree8d9f5617aada94e3c8784c0bee6a201fbced54b3 /src/org/traccar
parent6b6d28695600fee509ee37a7225dd6518879ac9c (diff)
parent804c56a76dc8406e4ff072289a4a9f97322dfe83 (diff)
downloadtraccar-server-6c6b62351aadd68928b9bd3e39e2bf96d78695e8.tar.gz
traccar-server-6c6b62351aadd68928b9bd3e39e2bf96d78695e8.tar.bz2
traccar-server-6c6b62351aadd68928b9bd3e39e2bf96d78695e8.zip
Merge pull request #2228 from Abyss777/reports_trips
Implement trips reports
Diffstat (limited to 'src/org/traccar')
-rw-r--r--src/org/traccar/api/resource/ReportResource.java23
-rw-r--r--src/org/traccar/reports/ReportUtils.java45
-rw-r--r--src/org/traccar/reports/Summary.java20
-rw-r--r--src/org/traccar/reports/Trips.java160
-rw-r--r--src/org/traccar/reports/model/BaseReport.java67
-rw-r--r--src/org/traccar/reports/model/SummaryReport.java50
-rw-r--r--src/org/traccar/reports/model/TripReport.java87
7 files changed, 386 insertions, 66 deletions
diff --git a/src/org/traccar/api/resource/ReportResource.java b/src/org/traccar/api/resource/ReportResource.java
index e87d6401c..0dd0452ff 100644
--- a/src/org/traccar/api/resource/ReportResource.java
+++ b/src/org/traccar/api/resource/ReportResource.java
@@ -15,6 +15,7 @@ import javax.ws.rs.core.Response;
import org.traccar.api.BaseResource;
import org.traccar.reports.Events;
import org.traccar.reports.Summary;
+import org.traccar.reports.Trips;
import org.traccar.reports.Route;
import org.traccar.web.JsonConverter;
@@ -93,4 +94,26 @@ public class ReportResource extends BaseResource {
.build();
}
+ @Path("trips")
+ @GET
+ @Produces(MediaType.APPLICATION_JSON)
+ public Response getTripsJson(
+ @QueryParam("deviceId") final List<Long> deviceIds, @QueryParam("groupId") final List<Long> groupIds,
+ @QueryParam("from") String from, @QueryParam("to") String to) throws SQLException {
+ return Response.ok(Trips.getJson(getUserId(), deviceIds, groupIds,
+ JsonConverter.parseDate(from), JsonConverter.parseDate(to))).build();
+ }
+
+ @Path("trips")
+ @GET
+ @Produces(TEXT_CSV)
+ public Response getTripsCsv(
+ @QueryParam("deviceId") final List<Long> deviceIds, @QueryParam("groupId") final List<Long> groupIds,
+ @QueryParam("from") String from, @QueryParam("to") String to) throws SQLException {
+ return Response.ok(Trips.getCsv(getUserId(), deviceIds, groupIds,
+ JsonConverter.parseDate(from), JsonConverter.parseDate(to)))
+ .header(HttpHeaders.CONTENT_DISPOSITION, CONTENT_DISPOSITION_VALUE)
+ .build();
+ }
+
}
diff --git a/src/org/traccar/reports/ReportUtils.java b/src/org/traccar/reports/ReportUtils.java
index 9f6d34860..34f04ac87 100644
--- a/src/org/traccar/reports/ReportUtils.java
+++ b/src/org/traccar/reports/ReportUtils.java
@@ -16,10 +16,14 @@
*/
package org.traccar.reports;
+import java.math.BigDecimal;
+import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.Collection;
import org.traccar.Context;
+import org.traccar.helper.Log;
+import org.traccar.model.Position;
public final class ReportUtils {
@@ -35,4 +39,45 @@ public final class ReportUtils {
return result;
}
+ public static double calculateDistance(Position firstPosition, Position lastPosition) {
+ return calculateDistance(firstPosition, lastPosition, true);
+ }
+
+ public static double calculateDistance(Position firstPosition, Position lastPosition, boolean useOdometer) {
+ double distance = 0.0;
+ if (useOdometer && firstPosition.getAttributes().containsKey(Position.KEY_ODOMETER)
+ && lastPosition.getAttributes().containsKey(Position.KEY_ODOMETER)) {
+ distance = (((Number) lastPosition.getAttributes().get(Position.KEY_ODOMETER)).doubleValue()
+ - ((Number) firstPosition.getAttributes().get(Position.KEY_ODOMETER)).doubleValue())
+ * 1000;
+ } else if (firstPosition.getAttributes().containsKey(Position.KEY_TOTAL_DISTANCE)
+ && lastPosition.getAttributes().containsKey(Position.KEY_TOTAL_DISTANCE)) {
+ distance = ((Number) lastPosition.getAttributes().get(Position.KEY_TOTAL_DISTANCE)).doubleValue()
+ - ((Number) firstPosition.getAttributes().get(Position.KEY_TOTAL_DISTANCE)).doubleValue();
+ }
+ return distance;
+ }
+
+ public static String calculateFuel(Position firstPosition, Position lastPosition) {
+
+ if (firstPosition.getAttributes().get(Position.KEY_FUEL) != null
+ && lastPosition.getAttributes().get(Position.KEY_FUEL) != null) {
+ try {
+ switch (firstPosition.getProtocol()) {
+ case "meitrack":
+ case "galileo":
+ case "noran":
+ return new BigDecimal(firstPosition.getAttributes().get(Position.KEY_FUEL).toString())
+ .subtract(new BigDecimal(lastPosition.getAttributes().get(Position.KEY_FUEL).toString()))
+ .setScale(2, RoundingMode.HALF_EVEN).toString() + " %";
+ default:
+ break;
+ }
+ } catch (Exception error) {
+ Log.warning(error);
+ }
+ }
+ return "-";
+ }
+
}
diff --git a/src/org/traccar/reports/Summary.java b/src/org/traccar/reports/Summary.java
index 402e6d432..44fb1dd4c 100644
--- a/src/org/traccar/reports/Summary.java
+++ b/src/org/traccar/reports/Summary.java
@@ -16,8 +16,6 @@
*/
package org.traccar.reports;
-import java.math.BigDecimal;
-import java.math.RoundingMode;
import java.sql.SQLException;
import java.util.Collection;
import java.util.Date;
@@ -62,22 +60,8 @@ public final class Summary {
speedSum += position.getSpeed();
result.setMaxSpeed(position.getSpeed());
}
- if (firstPosition.getAttributes().containsKey(Position.KEY_ODOMETER)
- && previousPosition.getAttributes().containsKey(Position.KEY_ODOMETER)) {
- result.setDistance((Integer.parseInt(previousPosition.getAttributes().get(Position.KEY_ODOMETER)
- .toString())
- - Integer.parseInt(firstPosition.getAttributes().get(Position.KEY_ODOMETER).toString()))
- * 1000);
- } else if (firstPosition.getAttributes().containsKey(Position.KEY_TOTAL_DISTANCE)
- && previousPosition.getAttributes().containsKey(Position.KEY_TOTAL_DISTANCE)) {
- result.setDistance(((Number) previousPosition.getAttributes().get(Position.KEY_TOTAL_DISTANCE))
- .doubleValue()
- - ((Number) firstPosition.getAttributes().get(Position.KEY_TOTAL_DISTANCE)).doubleValue());
- }
- result.setDistance(new BigDecimal(result.getDistance())
- .setScale(2, RoundingMode.HALF_EVEN).doubleValue());
- result.setAverageSpeed(new BigDecimal(speedSum / positions.size())
- .setScale(3, RoundingMode.HALF_EVEN).doubleValue());
+ result.setDistance(ReportUtils.calculateDistance(firstPosition, previousPosition));
+ result.setAverageSpeed(speedSum / positions.size());
}
return result;
}
diff --git a/src/org/traccar/reports/Trips.java b/src/org/traccar/reports/Trips.java
new file mode 100644
index 000000000..b661ffffa
--- /dev/null
+++ b/src/org/traccar/reports/Trips.java
@@ -0,0 +1,160 @@
+/*
+ * Copyright 2016 Anton Tananaev (anton.tananaev@gmail.com)
+ * Copyright 2016 Andrey Kunitsyn (abyss@fox5.ru)
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.traccar.reports;
+
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Date;
+
+import javax.json.Json;
+import javax.json.JsonArrayBuilder;
+
+import org.traccar.Context;
+import org.traccar.model.Position;
+import org.traccar.reports.model.TripReport;
+import org.traccar.web.CsvBuilder;
+import org.traccar.web.JsonConverter;
+
+public final class Trips {
+
+ private Trips() {
+ }
+
+ private static TripReport calculateTrip(ArrayList<Position> positions, int startIndex, int endIndex) {
+ Position startTrip = positions.get(startIndex);
+ Position endTrip = positions.get(endIndex);
+
+ double speedMax = 0.0;
+ double speedSum = 0.0;
+ for (int i = startIndex; i <= endIndex; i++) {
+ double speed = positions.get(i).getSpeed();
+ speedSum += speed;
+ if (speed > speedMax) {
+ speedMax = speed;
+ }
+ }
+
+ TripReport trip = new TripReport();
+ long tripDuration = endTrip.getFixTime().getTime() - positions.get(startIndex).getFixTime().getTime();
+ long deviceId = startTrip.getDeviceId();
+ trip.setDeviceId(deviceId);
+ String deviceName = Context.getDeviceManager().getDeviceById(deviceId).getName();
+ trip.setDeviceName(deviceName);
+ trip.setStartPositionId(startTrip.getId());
+ trip.setStartTime(startTrip.getFixTime());
+ trip.setStartAddress(startTrip.getAddress());
+ trip.setEndPositionId(endTrip.getId());
+ trip.setEndTime(endTrip.getFixTime());
+ trip.setEndAddress(endTrip.getAddress());
+ trip.setDistance(ReportUtils.calculateDistance(startTrip, endTrip));
+ trip.setDuration(tripDuration);
+ trip.setAverageSpeed(speedSum / (endIndex - startIndex));
+ trip.setMaxSpeed(speedMax);
+ trip.setSpentFuel(ReportUtils.calculateFuel(startTrip, endTrip));
+
+ return trip;
+ }
+
+ private static Collection<TripReport> detectTrips(long deviceId, Date from, Date to) throws SQLException {
+ double speedThreshold = Context.getConfig().getDouble("event.motion.speedThreshold", 0.01);
+ long minimalTripDuration = Context.getConfig().getLong("report.trip.minimalTripDuration", 300) * 1000;
+ double minimalTripDistance = Context.getConfig().getLong("report.trip.minimalTripDistance", 500);
+ long minimalParkingDuration = Context.getConfig().getLong("report.trip.minimalParkingDuration", 300) * 1000;
+ Collection<TripReport> result = new ArrayList<>();
+
+ ArrayList<Position> positions = new ArrayList<>(Context.getDataManager().getPositions(deviceId, from, to));
+ if (positions != null && !positions.isEmpty()) {
+ int previousStartParkingIndex = 0;
+ int startParkingIndex = -1;
+ int previousEndParkingIndex = 0;
+ int endParkingIndex = 0;
+
+ boolean isMoving = false;
+ boolean isLast = false;
+ boolean skipped = false;
+ boolean tripFiltered = false;
+
+ for (int i = 0; i < positions.size(); i++) {
+ isMoving = positions.get(i).getSpeed() > speedThreshold;
+ isLast = i == positions.size() - 1;
+
+ if ((isMoving || isLast) && startParkingIndex != -1) {
+ if (!skipped || previousEndParkingIndex == 0) {
+ previousEndParkingIndex = endParkingIndex;
+ }
+ endParkingIndex = i;
+ }
+ if (!isMoving && startParkingIndex == -1) {
+ long tripDuration = positions.get(i).getFixTime().getTime()
+ - positions.get(endParkingIndex).getFixTime().getTime();
+ double tripDistance = ReportUtils.calculateDistance(positions.get(endParkingIndex),
+ positions.get(i), false);
+ tripFiltered = tripDuration < minimalTripDuration && tripDistance < minimalTripDistance;
+ if (tripFiltered) {
+ startParkingIndex = previousStartParkingIndex;
+ endParkingIndex = previousEndParkingIndex;
+ tripFiltered = false;
+ } else {
+ previousStartParkingIndex = i;
+ startParkingIndex = i;
+ }
+
+ }
+ if (startParkingIndex != -1 && (endParkingIndex > startParkingIndex || isLast)) {
+ long parkingDuration = positions.get(endParkingIndex).getFixTime().getTime()
+ - positions.get(startParkingIndex).getFixTime().getTime();
+ if ((parkingDuration >= minimalParkingDuration || isLast)
+ && previousEndParkingIndex < startParkingIndex) {
+ if (!tripFiltered) {
+ result.add(calculateTrip(positions, previousEndParkingIndex, startParkingIndex));
+ }
+ previousEndParkingIndex = endParkingIndex;
+ skipped = false;
+ } else {
+ skipped = true;
+ }
+ startParkingIndex = -1;
+ }
+ }
+ }
+ return result;
+ }
+
+ public static String getJson(long userId, Collection<Long> deviceIds, Collection<Long> groupIds,
+ Date from, Date to) throws SQLException {
+ JsonArrayBuilder json = Json.createArrayBuilder();
+ for (long deviceId: ReportUtils.getDeviceList(deviceIds, groupIds)) {
+ Context.getPermissionsManager().checkDevice(userId, deviceId);
+ for (TripReport tripReport : detectTrips(deviceId, from, to)) {
+ json.add(JsonConverter.objectToJson(tripReport));
+ }
+ }
+ return json.build().toString();
+ }
+
+ public static String getCsv(long userId, Collection<Long> deviceIds, Collection<Long> groupIds,
+ Date from, Date to) throws SQLException {
+ CsvBuilder csv = new CsvBuilder();
+ csv.addHeaderLine(new TripReport());
+ for (long deviceId: ReportUtils.getDeviceList(deviceIds, groupIds)) {
+ Context.getPermissionsManager().checkDevice(userId, deviceId);
+ csv.addArray(detectTrips(deviceId, from, to));
+ }
+ return csv.build();
+ }
+}
diff --git a/src/org/traccar/reports/model/BaseReport.java b/src/org/traccar/reports/model/BaseReport.java
new file mode 100644
index 000000000..246cdede0
--- /dev/null
+++ b/src/org/traccar/reports/model/BaseReport.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright 2016 Anton Tananaev (anton.tananaev@gmail.com)
+ * Copyright 2016 Andrey Kunitsyn (abyss@fox5.ru)
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.traccar.reports.model;
+
+public class BaseReport {
+
+ private long deviceId;
+ public long getDeviceId() {
+ return deviceId;
+ }
+ public void setDeviceId(long deviceId) {
+ this.deviceId = deviceId;
+ }
+
+ private String deviceName;
+ public String getDeviceName() {
+ return deviceName;
+ }
+ public void setDeviceName(String deviceName) {
+ this.deviceName = deviceName;
+ }
+
+ private double distance; // meters
+ public double getDistance() {
+ return distance;
+ }
+ public void setDistance(double distance) {
+ this.distance = distance;
+ }
+
+ public void addDistance(double distance) {
+ this.distance += distance;
+ }
+
+ private double averageSpeed; // knots
+ public double getAverageSpeed() {
+ return averageSpeed;
+ }
+ public void setAverageSpeed(Double averageSpeed) {
+ this.averageSpeed = averageSpeed;
+ }
+
+ private double maxSpeed; // knots
+ public double getMaxSpeed() {
+ return maxSpeed;
+ }
+ public void setMaxSpeed(double maxSpeed) {
+ if (maxSpeed > this.maxSpeed) {
+ this.maxSpeed = maxSpeed;
+ }
+ }
+
+}
diff --git a/src/org/traccar/reports/model/SummaryReport.java b/src/org/traccar/reports/model/SummaryReport.java
index 271d0c7c2..1e6655904 100644
--- a/src/org/traccar/reports/model/SummaryReport.java
+++ b/src/org/traccar/reports/model/SummaryReport.java
@@ -16,55 +16,9 @@
*/
package org.traccar.reports.model;
-public class SummaryReport {
+public class SummaryReport extends BaseReport {
- private long deviceId;
- public long getDeviceId() {
- return deviceId;
- }
- public void setDeviceId(long deviceId) {
- this.deviceId = deviceId;
- }
-
- private String deviceName;
- public String getDeviceName() {
- return deviceName;
- }
- public void setDeviceName(String deviceName) {
- this.deviceName = deviceName;
- }
-
- private double distance;
- public double getDistance() {
- return distance;
- }
- public void setDistance(double distance) {
- this.distance = distance;
- }
-
- public void addDistance(double distance) {
- this.distance += distance;
- }
-
- private double averageSpeed;
- public double getAverageSpeed() {
- return averageSpeed;
- }
- public void setAverageSpeed(double averageSpeed) {
- this.averageSpeed = averageSpeed;
- }
-
- private double maxSpeed;
- public double getMaxSpeed() {
- return maxSpeed;
- }
- public void setMaxSpeed(double maxSpeed) {
- if (maxSpeed > this.maxSpeed) {
- this.maxSpeed = maxSpeed;
- }
- }
-
- private long engineHours;
+ private long engineHours; // milliseconds
public long getEngineHours() {
return engineHours;
}
diff --git a/src/org/traccar/reports/model/TripReport.java b/src/org/traccar/reports/model/TripReport.java
new file mode 100644
index 000000000..3a77b02ca
--- /dev/null
+++ b/src/org/traccar/reports/model/TripReport.java
@@ -0,0 +1,87 @@
+package org.traccar.reports.model;
+
+import java.util.Date;
+
+public class TripReport extends BaseReport {
+
+ private long startPositionId;
+ public long getStartPositionId() {
+ return startPositionId;
+ }
+ public void setStartPositionId(long startPositionId) {
+ this.startPositionId = startPositionId;
+ }
+
+ private long endPositionId;
+ public long getEndPositionId() {
+ return endPositionId;
+ }
+ public void setEndPositionId(long endPositionId) {
+ this.endPositionId = endPositionId;
+ }
+
+ private Date startTime;
+ public Date getStartTime() {
+ if (startTime != null) {
+ return new Date(startTime.getTime());
+ } else {
+ return null;
+ }
+ }
+ public void setStartTime(Date startTime) {
+ if (startTime != null) {
+ this.startTime = new Date(startTime.getTime());
+ } else {
+ this.startTime = null;
+ }
+ }
+
+ private String startAddress;
+ public String getStartAddress() {
+ return startAddress;
+ }
+ public void setStartAddress(String address) {
+ this.startAddress = address;
+ }
+
+ private Date endTime;
+ public Date getEndTime() {
+ if (endTime != null) {
+ return new Date(endTime.getTime());
+ } else {
+ return null;
+ }
+ }
+ public void setEndTime(Date endTime) {
+ if (endTime != null) {
+ this.endTime = new Date(endTime.getTime());
+ } else {
+ this.endTime = null;
+ }
+ }
+
+ private String endAddress;
+ public String getEndAddress() {
+ return endAddress;
+ }
+ public void setEndAddress(String address) {
+ this.endAddress = address;
+ }
+
+ private long duration;
+ public long getDuration() {
+ return duration;
+ }
+ public void setDuration(long duration) {
+ this.duration = duration;
+ }
+
+ private String spentFuel;
+ public String getSpentFuel() {
+ return spentFuel;
+ }
+ public void setSpentFuel(String spentFuel) {
+ this.spentFuel = spentFuel;
+ }
+
+}