aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/org/traccar/Context.java31
-rw-r--r--src/org/traccar/FilterHandler.java21
-rw-r--r--src/org/traccar/api/resource/EventResource.java4
-rw-r--r--src/org/traccar/api/resource/MaintenanceResource.java36
-rw-r--r--src/org/traccar/database/CommandsManager.java7
-rw-r--r--src/org/traccar/database/DataManager.java29
-rw-r--r--src/org/traccar/database/LdapProvider.java2
-rw-r--r--src/org/traccar/database/MaintenancesManager.java27
-rw-r--r--src/org/traccar/database/NotificationManager.java6
-rw-r--r--src/org/traccar/database/PermissionsManager.java15
-rw-r--r--src/org/traccar/events/MaintenanceEventHandler.java55
-rw-r--r--src/org/traccar/geocoder/GeocodeXyzGeocoder.java60
-rw-r--r--src/org/traccar/model/Event.java10
-rw-r--r--src/org/traccar/model/Maintenance.java61
-rw-r--r--src/org/traccar/model/Position.java1
-rw-r--r--src/org/traccar/model/User.java10
-rw-r--r--src/org/traccar/notification/EventForwarder.java8
-rw-r--r--src/org/traccar/notification/NotificationFormatter.java7
-rw-r--r--src/org/traccar/protocol/AquilaProtocolDecoder.java15
-rw-r--r--src/org/traccar/protocol/AtrackFrameDecoder.java4
-rw-r--r--src/org/traccar/protocol/AtrackProtocolDecoder.java98
-rw-r--r--src/org/traccar/protocol/ContinentalProtocol.java2
-rw-r--r--src/org/traccar/protocol/ContinentalProtocolDecoder.java34
-rw-r--r--src/org/traccar/protocol/EelinkProtocolDecoder.java70
-rw-r--r--src/org/traccar/protocol/EskyProtocolDecoder.java33
-rw-r--r--src/org/traccar/protocol/GatorProtocolDecoder.java8
-rw-r--r--src/org/traccar/protocol/Gl200TextProtocolDecoder.java5
-rw-r--r--src/org/traccar/protocol/H02ProtocolDecoder.java4
-rw-r--r--src/org/traccar/protocol/L100FrameDecoder.java5
-rw-r--r--src/org/traccar/protocol/L100Protocol.java6
-rw-r--r--src/org/traccar/protocol/L100ProtocolDecoder.java37
-rw-r--r--src/org/traccar/protocol/Pt502Protocol.java1
-rw-r--r--src/org/traccar/protocol/Pt60ProtocolDecoder.java49
-rw-r--r--src/org/traccar/protocol/TeltonikaProtocolDecoder.java10
-rw-r--r--src/org/traccar/protocol/Tk103Protocol.java3
-rw-r--r--src/org/traccar/protocol/Tk103ProtocolEncoder.java2
-rw-r--r--src/org/traccar/protocol/TotemProtocolDecoder.java5
-rw-r--r--src/org/traccar/protocol/WatchProtocolDecoder.java2
-rw-r--r--src/org/traccar/reports/Events.java22
-rw-r--r--src/org/traccar/reports/ReportUtils.java46
-rw-r--r--src/org/traccar/reports/Summary.java11
-rw-r--r--src/org/traccar/reports/model/BaseReport.java19
42 files changed, 688 insertions, 193 deletions
diff --git a/src/org/traccar/Context.java b/src/org/traccar/Context.java
index 09e3c619b..ee14eb1f7 100644
--- a/src/org/traccar/Context.java
+++ b/src/org/traccar/Context.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2015 - 2017 Anton Tananaev (anton@traccar.org)
+ * Copyright 2015 - 2018 Anton Tananaev (anton@traccar.org)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -23,6 +23,7 @@ import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.Properties;
+import com.ning.http.client.AsyncHttpClientConfigDefaults;
import org.apache.velocity.app.VelocityEngine;
import org.eclipse.jetty.util.URIUtil;
import org.traccar.database.CalendarManager;
@@ -35,6 +36,7 @@ import org.traccar.database.DeviceManager;
import org.traccar.database.DriversManager;
import org.traccar.database.IdentityManager;
import org.traccar.database.LdapProvider;
+import org.traccar.database.MaintenancesManager;
import org.traccar.database.MediaManager;
import org.traccar.database.NotificationManager;
import org.traccar.database.PermissionsManager;
@@ -48,6 +50,7 @@ import org.traccar.geocoder.AddressFormat;
import org.traccar.geocoder.BingMapsGeocoder;
import org.traccar.geocoder.FactualGeocoder;
import org.traccar.geocoder.GeocodeFarmGeocoder;
+import org.traccar.geocoder.GeocodeXyzGeocoder;
import org.traccar.geocoder.GisgraphyGeocoder;
import org.traccar.geocoder.GoogleGeocoder;
import org.traccar.geocoder.MapQuestGeocoder;
@@ -64,6 +67,7 @@ import org.traccar.model.Device;
import org.traccar.model.Driver;
import org.traccar.model.Geofence;
import org.traccar.model.Group;
+import org.traccar.model.Maintenance;
import org.traccar.model.Notification;
import org.traccar.model.User;
import org.traccar.geolocation.GoogleGeolocationProvider;
@@ -79,6 +83,9 @@ import org.traccar.web.WebServer;
public final class Context {
+ private static final String USER_AGENT =
+ "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:59.0) Gecko/20100101 Firefox/59.0";
+
private Context() {
}
@@ -202,10 +209,15 @@ public final class Context {
return velocityEngine;
}
- private static final AsyncHttpClient ASYNC_HTTP_CLIENT = new AsyncHttpClient();
+ private static AsyncHttpClient asyncHttpClient;
+
+ static {
+ System.setProperty(AsyncHttpClientConfigDefaults.ASYNC_CLIENT + "userAgent", USER_AGENT);
+ asyncHttpClient = new AsyncHttpClient();
+ }
public static AsyncHttpClient getAsyncHttpClient() {
- return ASYNC_HTTP_CLIENT;
+ return asyncHttpClient;
}
private static EventForwarder eventForwarder;
@@ -232,6 +244,12 @@ public final class Context {
return commandsManager;
}
+ private static MaintenancesManager maintenancesManager;
+
+ public static MaintenancesManager getMaintenancesManager() {
+ return maintenancesManager;
+ }
+
private static StatisticsManager statisticsManager;
public static StatisticsManager getStatisticsManager() {
@@ -303,6 +321,8 @@ public final class Context {
return new FactualGeocoder(url, key, cacheSize, addressFormat);
case "geocodefarm":
return new GeocodeFarmGeocoder(key, language, cacheSize, addressFormat);
+ case "geocodexyz":
+ return new GeocodeXyzGeocoder(key, cacheSize, addressFormat);
default:
return new GoogleGeocoder(key, language, cacheSize, addressFormat);
}
@@ -383,7 +403,7 @@ public final class Context {
driversManager = new DriversManager(dataManager);
- commandsManager = new CommandsManager(dataManager);
+ commandsManager = new CommandsManager(dataManager, config.getBoolean("commands.queueing"));
statisticsManager = new StatisticsManager();
@@ -419,6 +439,7 @@ public final class Context {
geofenceManager = new GeofenceManager(dataManager);
calendarManager = new CalendarManager(dataManager);
+ maintenancesManager = new MaintenancesManager(dataManager);
notificationManager = new NotificationManager(dataManager);
Properties velocityProperties = new Properties();
velocityProperties.setProperty("file.resource.loader.path",
@@ -469,6 +490,8 @@ public final class Context {
return (BaseObjectManager<T>) driversManager;
} else if (clazz.equals(Command.class)) {
return (BaseObjectManager<T>) commandsManager;
+ } else if (clazz.equals(Maintenance.class)) {
+ return (BaseObjectManager<T>) maintenancesManager;
} else if (clazz.equals(Notification.class)) {
return (BaseObjectManager<T>) notificationManager;
}
diff --git a/src/org/traccar/FilterHandler.java b/src/org/traccar/FilterHandler.java
index 93f71d4e1..c6363813c 100644
--- a/src/org/traccar/FilterHandler.java
+++ b/src/org/traccar/FilterHandler.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2014 - 2017 Anton Tananaev (anton@traccar.org)
+ * Copyright 2014 - 2018 Anton Tananaev (anton@traccar.org)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -30,6 +30,7 @@ public class FilterHandler extends BaseDataHandler {
private boolean filterStatic;
private int filterDistance;
private int filterMaxSpeed;
+ private long filterMinPeriod;
private long skipLimit;
private boolean skipAttributes;
@@ -69,6 +70,10 @@ public class FilterHandler extends BaseDataHandler {
this.filterMaxSpeed = filterMaxSpeed;
}
+ public void setFilterMinPeriod(int filterMinPeriod) {
+ this.filterMinPeriod = filterMinPeriod;
+ }
+
public void setSkipLimit(long skipLimit) {
this.skipLimit = skipLimit;
}
@@ -89,6 +94,7 @@ public class FilterHandler extends BaseDataHandler {
filterStatic = config.getBoolean("filter.static");
filterDistance = config.getInteger("filter.distance");
filterMaxSpeed = config.getInteger("filter.maxSpeed");
+ filterMinPeriod = config.getInteger("filter.minPeriod") * 1000;
skipLimit = config.getLong("filter.skipLimit") * 1000;
skipAttributes = config.getBoolean("filter.skipAttributes.enable");
}
@@ -148,6 +154,14 @@ public class FilterHandler extends BaseDataHandler {
return false;
}
+ private boolean filterMinPeriod(Position position, Position last) {
+ if (filterMinPeriod != 0 && last != null) {
+ long time = position.getFixTime().getTime() - last.getFixTime().getTime();
+ return time > 0 && time < filterMinPeriod;
+ }
+ return false;
+ }
+
private boolean skipLimit(Position position, Position last) {
if (skipLimit != 0 && last != null) {
return (position.getServerTime().getTime() - last.getServerTime().getTime()) > skipLimit;
@@ -208,6 +222,9 @@ public class FilterHandler extends BaseDataHandler {
if (filterMaxSpeed(position, last)) {
filterType.append("MaxSpeed ");
}
+ if (filterMinPeriod(position, last)) {
+ filterType.append("MinPeriod ");
+ }
if (filterType.length() > 0) {
@@ -216,8 +233,6 @@ public class FilterHandler extends BaseDataHandler {
message.append(filterType.toString());
message.append("filters from device: ");
message.append(Context.getIdentityManager().getById(position.getDeviceId()).getUniqueId());
- message.append(" with id: ");
- message.append(position.getDeviceId());
Log.info(message.toString());
return true;
diff --git a/src/org/traccar/api/resource/EventResource.java b/src/org/traccar/api/resource/EventResource.java
index a7cf9edbd..e0ccf7020 100644
--- a/src/org/traccar/api/resource/EventResource.java
+++ b/src/org/traccar/api/resource/EventResource.java
@@ -13,6 +13,7 @@ import org.traccar.Context;
import org.traccar.api.BaseResource;
import org.traccar.model.Event;
import org.traccar.model.Geofence;
+import org.traccar.model.Maintenance;
@Path("events")
@Produces(MediaType.APPLICATION_JSON)
@@ -28,6 +29,9 @@ public class EventResource extends BaseResource {
if (event.getGeofenceId() != 0) {
Context.getPermissionsManager().checkPermission(Geofence.class, getUserId(), event.getGeofenceId());
}
+ if (event.getMaintenanceId() != 0) {
+ Context.getPermissionsManager().checkPermission(Maintenance.class, getUserId(), event.getMaintenanceId());
+ }
return event;
}
diff --git a/src/org/traccar/api/resource/MaintenanceResource.java b/src/org/traccar/api/resource/MaintenanceResource.java
new file mode 100644
index 000000000..b3726b429
--- /dev/null
+++ b/src/org/traccar/api/resource/MaintenanceResource.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2018 Anton Tananaev (anton@traccar.org)
+ * Copyright 2018 Andrey Kunitsyn (andrey@traccar.org)
+ *
+ * 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.api.resource;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.MediaType;
+
+import org.traccar.api.ExtendedObjectResource;
+import org.traccar.model.Maintenance;
+
+@Path("maintenances")
+@Produces(MediaType.APPLICATION_JSON)
+@Consumes(MediaType.APPLICATION_JSON)
+public class MaintenanceResource extends ExtendedObjectResource<Maintenance> {
+
+ public MaintenanceResource() {
+ super(Maintenance.class);
+ }
+
+}
diff --git a/src/org/traccar/database/CommandsManager.java b/src/org/traccar/database/CommandsManager.java
index 9ceb995ef..8ddced5f7 100644
--- a/src/org/traccar/database/CommandsManager.java
+++ b/src/org/traccar/database/CommandsManager.java
@@ -37,8 +37,11 @@ public class CommandsManager extends ExtendedObjectManager<Command> {
private final Map<Long, Queue<Command>> deviceQueues = new ConcurrentHashMap<>();
- public CommandsManager(DataManager dataManager) {
+ private boolean queueing;
+
+ public CommandsManager(DataManager dataManager, boolean queueing) {
super(dataManager, Command.class);
+ this.queueing = queueing;
}
public boolean checkDeviceCommand(long deviceId, long commandId) {
@@ -70,6 +73,8 @@ public class CommandsManager extends ExtendedObjectManager<Command> {
ActiveDevice activeDevice = Context.getConnectionManager().getActiveDevice(deviceId);
if (activeDevice != null) {
activeDevice.sendCommand(command);
+ } else if (!queueing) {
+ throw new RuntimeException("Device is not online");
} else {
getDeviceQueue(deviceId).add(command);
return false;
diff --git a/src/org/traccar/database/DataManager.java b/src/org/traccar/database/DataManager.java
index a997a89f6..3c26685bd 100644
--- a/src/org/traccar/database/DataManager.java
+++ b/src/org/traccar/database/DataManager.java
@@ -48,6 +48,7 @@ import org.traccar.model.Driver;
import org.traccar.model.Event;
import org.traccar.model.Geofence;
import org.traccar.model.Group;
+import org.traccar.model.Maintenance;
import org.traccar.model.ManagedUser;
import org.traccar.model.Notification;
import org.traccar.model.Permission;
@@ -189,19 +190,19 @@ public class DataManager {
public static String constructPermissionQuery(String action, Class<?> owner, Class<?> property) {
switch (action) {
- case ACTION_SELECT_ALL:
- return "SELECT " + makeNameId(owner) + ", " + makeNameId(property) + " FROM "
- + getPermissionsTableName(owner, property);
- case ACTION_INSERT:
- return "INSERT INTO " + getPermissionsTableName(owner, property)
- + " (" + makeNameId(owner) + ", " + makeNameId(property) + ") VALUES (:"
- + makeNameId(owner) + ", :" + makeNameId(property) + ")";
- case ACTION_DELETE:
- return "DELETE FROM " + getPermissionsTableName(owner, property)
- + " WHERE " + makeNameId(owner) + " = :" + makeNameId(owner)
- + " AND " + makeNameId(property) + " = :" + makeNameId(property);
- default:
- throw new IllegalArgumentException("Unknown action");
+ case ACTION_SELECT_ALL:
+ return "SELECT " + makeNameId(owner) + ", " + makeNameId(property) + " FROM "
+ + getPermissionsTableName(owner, property);
+ case ACTION_INSERT:
+ return "INSERT INTO " + getPermissionsTableName(owner, property)
+ + " (" + makeNameId(owner) + ", " + makeNameId(property) + ") VALUES (:"
+ + makeNameId(owner) + ", :" + makeNameId(property) + ")";
+ case ACTION_DELETE:
+ return "DELETE FROM " + getPermissionsTableName(owner, property)
+ + " WHERE " + makeNameId(owner) + " = :" + makeNameId(owner)
+ + " AND " + makeNameId(property) + " = :" + makeNameId(property);
+ default:
+ throw new IllegalArgumentException("Unknown action");
}
}
@@ -405,6 +406,8 @@ public class DataManager {
return Calendar.class;
case "command":
return Command.class;
+ case "maintenance":
+ return Maintenance.class;
case "notification":
return Notification.class;
default:
diff --git a/src/org/traccar/database/LdapProvider.java b/src/org/traccar/database/LdapProvider.java
index 44dd386ed..eb975ad0f 100644
--- a/src/org/traccar/database/LdapProvider.java
+++ b/src/org/traccar/database/LdapProvider.java
@@ -150,7 +150,7 @@ public class LdapProvider {
user.setEmail(accountName);
}
}
- user.setAdmin(isAdmin(accountName));
+ user.setAdministrator(isAdmin(accountName));
} catch (NamingException e) {
user.setLogin(accountName);
user.setName(accountName);
diff --git a/src/org/traccar/database/MaintenancesManager.java b/src/org/traccar/database/MaintenancesManager.java
new file mode 100644
index 000000000..4e266cb78
--- /dev/null
+++ b/src/org/traccar/database/MaintenancesManager.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright 2018 Anton Tananaev (anton@traccar.org)
+ * Copyright 2018 Andrey Kunitsyn (andrey@traccar.org)
+ *
+ * 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.database;
+
+import org.traccar.model.Maintenance;
+
+public class MaintenancesManager extends ExtendedObjectManager<Maintenance> {
+
+ public MaintenancesManager(DataManager dataManager) {
+ super(dataManager, Maintenance.class);
+ }
+
+}
diff --git a/src/org/traccar/database/NotificationManager.java b/src/org/traccar/database/NotificationManager.java
index 1c59a8666..3bc048356 100644
--- a/src/org/traccar/database/NotificationManager.java
+++ b/src/org/traccar/database/NotificationManager.java
@@ -78,8 +78,10 @@ public class NotificationManager extends ExtendedObjectManager<Notification> {
usersToForward = new HashSet<>();
}
for (long userId : users) {
- if (event.getGeofenceId() == 0 || Context.getGeofenceManager() != null
- && Context.getGeofenceManager().checkItemPermission(userId, event.getGeofenceId())) {
+ if ((event.getGeofenceId() == 0
+ || Context.getGeofenceManager().checkItemPermission(userId, event.getGeofenceId()))
+ && (event.getMaintenanceId() == 0
+ || Context.getMaintenancesManager().checkItemPermission(userId, event.getMaintenanceId()))) {
if (usersToForward != null) {
usersToForward.add(userId);
}
diff --git a/src/org/traccar/database/PermissionsManager.java b/src/org/traccar/database/PermissionsManager.java
index 3ae5961ce..1c19f2374 100644
--- a/src/org/traccar/database/PermissionsManager.java
+++ b/src/org/traccar/database/PermissionsManager.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2015 - 2017 Anton Tananaev (anton@traccar.org)
+ * Copyright 2015 - 2018 Anton Tananaev (anton@traccar.org)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -25,6 +25,7 @@ import org.traccar.model.Device;
import org.traccar.model.Driver;
import org.traccar.model.Geofence;
import org.traccar.model.Group;
+import org.traccar.model.Maintenance;
import org.traccar.model.ManagedUser;
import org.traccar.model.Notification;
import org.traccar.model.Permission;
@@ -155,7 +156,7 @@ public class PermissionsManager {
public boolean getUserAdmin(long userId) {
User user = getUser(userId);
- return user != null && user.getAdmin();
+ return user != null && user.getAdministrator();
}
public void checkAdmin(long userId) throws SecurityException {
@@ -257,7 +258,7 @@ public class PermissionsManager {
}
public void checkUserUpdate(long userId, User before, User after) throws SecurityException {
- if (before.getAdmin() != after.getAdmin()
+ if (before.getAdministrator() != after.getAdministrator()
|| before.getDeviceLimit() != after.getDeviceLimit()
|| before.getUserLimit() != after.getUserLimit()) {
checkAdmin(userId);
@@ -337,6 +338,8 @@ public class PermissionsManager {
manager = Context.getCalendarManager();
} else if (object.equals(Command.class)) {
manager = Context.getCommandsManager();
+ } else if (object.equals(Maintenance.class)) {
+ manager = Context.getMaintenancesManager();
} else if (object.equals(Notification.class)) {
manager = Context.getNotificationManager();
} else {
@@ -362,6 +365,7 @@ public class PermissionsManager {
Context.getDriversManager().refreshUserItems();
Context.getAttributesManager().refreshUserItems();
Context.getCommandsManager().refreshUserItems();
+ Context.getMaintenancesManager().refreshUserItems();
if (Context.getNotificationManager() != null) {
Context.getNotificationManager().refreshUserItems();
}
@@ -374,6 +378,7 @@ public class PermissionsManager {
Context.getDriversManager().refreshExtendedPermissions();
Context.getAttributesManager().refreshExtendedPermissions();
Context.getCommandsManager().refreshExtendedPermissions();
+ Context.getMaintenancesManager().refreshExtendedPermissions();
}
public void refreshPermissions(Permission permission) {
@@ -394,6 +399,8 @@ public class PermissionsManager {
Context.getCalendarManager().refreshUserItems();
} else if (permission.getPropertyClass().equals(Command.class)) {
Context.getCommandsManager().refreshUserItems();
+ } else if (permission.getPropertyClass().equals(Maintenance.class)) {
+ Context.getMaintenancesManager().refreshUserItems();
} else if (permission.getPropertyClass().equals(Notification.class)
&& Context.getNotificationManager() != null) {
Context.getNotificationManager().refreshUserItems();
@@ -407,6 +414,8 @@ public class PermissionsManager {
Context.getAttributesManager().refreshExtendedPermissions();
} else if (permission.getPropertyClass().equals(Command.class)) {
Context.getCommandsManager().refreshExtendedPermissions();
+ } else if (permission.getPropertyClass().equals(Maintenance.class)) {
+ Context.getMaintenancesManager().refreshExtendedPermissions();
} else if (permission.getPropertyClass().equals(Notification.class)
&& Context.getNotificationManager() != null) {
Context.getNotificationManager().refreshExtendedPermissions();
diff --git a/src/org/traccar/events/MaintenanceEventHandler.java b/src/org/traccar/events/MaintenanceEventHandler.java
index 86abf7c17..4a6122826 100644
--- a/src/org/traccar/events/MaintenanceEventHandler.java
+++ b/src/org/traccar/events/MaintenanceEventHandler.java
@@ -1,6 +1,6 @@
/*
- * Copyright 2016 Anton Tananaev (anton@traccar.org)
- * Copyright 2016 Andrey Kunitsyn (andrey@traccar.org)
+ * Copyright 2016 - 2018 Anton Tananaev (anton@traccar.org)
+ * Copyright 2016 - 2018 Andrey Kunitsyn (andrey@traccar.org)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,54 +16,47 @@
*/
package org.traccar.events;
-import java.util.Collections;
+import java.util.HashMap;
import java.util.Map;
import org.traccar.BaseEventHandler;
import org.traccar.Context;
-import org.traccar.model.Device;
import org.traccar.model.Event;
+import org.traccar.model.Maintenance;
import org.traccar.model.Position;
public class MaintenanceEventHandler extends BaseEventHandler {
- public static final String ATTRIBUTE_MAINTENANCE_START = "maintenance.start";
- public static final String ATTRIBUTE_MAINTENANCE_INTERVAL = "maintenance.interval";
-
@Override
protected Map<Event, Position> analyzePosition(Position position) {
- Device device = Context.getIdentityManager().getById(position.getDeviceId());
- if (device == null || !Context.getIdentityManager().isLatestPosition(position)) {
- return null;
- }
-
- double maintenanceInterval = Context.getDeviceManager()
- .lookupAttributeDouble(device.getId(), ATTRIBUTE_MAINTENANCE_INTERVAL, 0, false);
- if (maintenanceInterval == 0) {
+ if (Context.getIdentityManager().getById(position.getDeviceId()) == null
+ || !Context.getIdentityManager().isLatestPosition(position)) {
return null;
}
- double maintenanceStart = Context.getDeviceManager()
- .lookupAttributeDouble(device.getId(), ATTRIBUTE_MAINTENANCE_START, 0, false);
-
- double oldTotalDistance = 0.0;
- double newTotalDistance = 0.0;
Position lastPosition = Context.getIdentityManager().getLastPosition(position.getDeviceId());
- if (lastPosition != null) {
- oldTotalDistance = lastPosition.getDouble(Position.KEY_TOTAL_DISTANCE);
+ if (lastPosition == null) {
+ return null;
}
- newTotalDistance = position.getDouble(Position.KEY_TOTAL_DISTANCE);
-
- oldTotalDistance -= maintenanceStart;
- newTotalDistance -= maintenanceStart;
- if ((long) (oldTotalDistance / maintenanceInterval) < (long) (newTotalDistance / maintenanceInterval)) {
- Event event = new Event(Event.TYPE_MAINTENANCE, position.getDeviceId(), position.getId());
- event.set(Position.KEY_TOTAL_DISTANCE, newTotalDistance);
- return Collections.singletonMap(event, position);
+ Map<Event, Position> events = new HashMap<>();
+ for (long maintenanceId : Context.getMaintenancesManager().getAllDeviceItems(position.getDeviceId())) {
+ Maintenance maintenance = Context.getMaintenancesManager().getById(maintenanceId);
+ if (maintenance.getPeriod() != 0) {
+ double oldValue = lastPosition.getDouble(maintenance.getType());
+ double newValue = position.getDouble(maintenance.getType());
+ if (oldValue != 0.0 && newValue != 0.0
+ && (long) ((oldValue - maintenance.getStart()) / maintenance.getPeriod())
+ < (long) ((newValue - maintenance.getStart()) / maintenance.getPeriod())) {
+ Event event = new Event(Event.TYPE_MAINTENANCE, position.getDeviceId(), position.getId());
+ event.setMaintenanceId(maintenanceId);
+ event.set(maintenance.getType(), newValue);
+ events.put(event, position);
+ }
+ }
}
- return null;
+ return events;
}
}
diff --git a/src/org/traccar/geocoder/GeocodeXyzGeocoder.java b/src/org/traccar/geocoder/GeocodeXyzGeocoder.java
new file mode 100644
index 000000000..aca360c3d
--- /dev/null
+++ b/src/org/traccar/geocoder/GeocodeXyzGeocoder.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2018 Anton Tananaev (anton@traccar.org)
+ *
+ * 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.geocoder;
+
+import javax.json.JsonObject;
+
+public class GeocodeXyzGeocoder extends JsonGeocoder {
+
+ private static String formatUrl(String key) {
+ String url = "https://geocode.xyz/%f,%f?geoit=JSON";
+ if (key != null) {
+ url += "&key=" + key;
+ }
+ return url;
+ }
+
+ public GeocodeXyzGeocoder(String key, int cacheSize, AddressFormat addressFormat) {
+ super(formatUrl(key), cacheSize, addressFormat);
+ }
+
+ @Override
+ public Address parseAddress(JsonObject json) {
+ Address address = new Address();
+
+ if (json.containsKey("stnumber")) {
+ address.setHouse(json.getString("stnumber"));
+ }
+ if (json.containsKey("staddress")) {
+ address.setStreet(json.getString("staddress"));
+ }
+ if (json.containsKey("city")) {
+ address.setSettlement(json.getString("city"));
+ }
+ if (json.containsKey("region")) {
+ address.setState(json.getString("region"));
+ }
+ if (json.containsKey("prov")) {
+ address.setCountry(json.getString("prov"));
+ }
+ if (json.containsKey("postal")) {
+ address.setPostcode(json.getString("postal"));
+ }
+
+ return address;
+ }
+
+}
diff --git a/src/org/traccar/model/Event.java b/src/org/traccar/model/Event.java
index 465afeb35..ee7fcc679 100644
--- a/src/org/traccar/model/Event.java
+++ b/src/org/traccar/model/Event.java
@@ -91,4 +91,14 @@ public class Event extends Message {
this.geofenceId = geofenceId;
}
+ private long maintenanceId = 0;
+
+ public long getMaintenanceId() {
+ return maintenanceId;
+ }
+
+ public void setMaintenanceId(long maintenanceId) {
+ this.maintenanceId = maintenanceId;
+ }
+
}
diff --git a/src/org/traccar/model/Maintenance.java b/src/org/traccar/model/Maintenance.java
new file mode 100644
index 000000000..73f67ea96
--- /dev/null
+++ b/src/org/traccar/model/Maintenance.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright 2018 Anton Tananaev (anton@traccar.org)
+ * Copyright 2018 Andrey Kunitsyn (andrey@traccar.org)
+ *
+ * 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.model;
+
+public class Maintenance extends ExtendedModel {
+
+ private String name;
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ private String type;
+
+ public String getType() {
+ return type;
+ }
+
+ public void setType(String type) {
+ this.type = type;
+ }
+
+ private double start;
+
+ public double getStart() {
+ return start;
+ }
+
+ public void setStart(double start) {
+ this.start = start;
+ }
+
+ private double period;
+
+ public double getPeriod() {
+ return period;
+ }
+
+ public void setPeriod(double period) {
+ this.period = period;
+ }
+
+}
diff --git a/src/org/traccar/model/Position.java b/src/org/traccar/model/Position.java
index fca0f16e3..b0e08244c 100644
--- a/src/org/traccar/model/Position.java
+++ b/src/org/traccar/model/Position.java
@@ -39,6 +39,7 @@ public class Position extends Message {
public static final String KEY_ODOMETER_TRIP = "tripOdometer"; // meters
public static final String KEY_HOURS = "hours";
public static final String KEY_STEPS = "steps";
+ public static final String KEY_HEART_RATE = "heartRate";
public static final String KEY_INPUT = "input";
public static final String KEY_OUTPUT = "output";
public static final String KEY_IMAGE = "image";
diff --git a/src/org/traccar/model/User.java b/src/org/traccar/model/User.java
index 1a131a4e8..99e12a072 100644
--- a/src/org/traccar/model/User.java
+++ b/src/org/traccar/model/User.java
@@ -75,14 +75,14 @@ public class User extends ExtendedModel {
this.readonly = readonly;
}
- private boolean admin;
+ private boolean administrator;
- public boolean getAdmin() {
- return admin;
+ public boolean getAdministrator() {
+ return administrator;
}
- public void setAdmin(boolean admin) {
- this.admin = admin;
+ public void setAdministrator(boolean administrator) {
+ this.administrator = administrator;
}
private String map;
diff --git a/src/org/traccar/notification/EventForwarder.java b/src/org/traccar/notification/EventForwarder.java
index b13f8fe43..9d2181e21 100644
--- a/src/org/traccar/notification/EventForwarder.java
+++ b/src/org/traccar/notification/EventForwarder.java
@@ -25,6 +25,7 @@ import org.traccar.helper.Log;
import org.traccar.model.Device;
import org.traccar.model.Event;
import org.traccar.model.Geofence;
+import org.traccar.model.Maintenance;
import org.traccar.model.Position;
import java.nio.charset.StandardCharsets;
@@ -48,6 +49,7 @@ public abstract class EventForwarder {
private static final String KEY_EVENT = "event";
private static final String KEY_GEOFENCE = "geofence";
private static final String KEY_DEVICE = "device";
+ private static final String KEY_MAINTENANCE = "maintenance";
private static final String KEY_USERS = "users";
public final void forwardEvent(Event event, Position position, Set<Long> users) {
@@ -98,6 +100,12 @@ public abstract class EventForwarder {
data.put(KEY_GEOFENCE, geofence);
}
}
+ if (event.getMaintenanceId() != 0) {
+ Maintenance maintenance = Context.getMaintenancesManager().getById(event.getMaintenanceId());
+ if (maintenance != null) {
+ data.put(KEY_MAINTENANCE, maintenance);
+ }
+ }
data.put(KEY_USERS, Context.getUsersManager().getItems(users));
try {
return Context.getObjectMapper().writeValueAsString(data);
diff --git a/src/org/traccar/notification/NotificationFormatter.java b/src/org/traccar/notification/NotificationFormatter.java
index 114825a83..524153721 100644
--- a/src/org/traccar/notification/NotificationFormatter.java
+++ b/src/org/traccar/notification/NotificationFormatter.java
@@ -1,6 +1,6 @@
/*
- * Copyright 2016 - 2017 Anton Tananaev (anton@traccar.org)
- * Copyright 2017 Andrey Kunitsyn (andrey@traccar.org)
+ * Copyright 2016 - 2018 Anton Tananaev (anton@traccar.org)
+ * Copyright 2017 - 2018 Andrey Kunitsyn (andrey@traccar.org)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -57,6 +57,9 @@ public final class NotificationFormatter {
if (event.getGeofenceId() != 0) {
velocityContext.put("geofence", Context.getGeofenceManager().getById(event.getGeofenceId()));
}
+ if (event.getMaintenanceId() != 0) {
+ velocityContext.put("maintenance", Context.getMaintenancesManager().getById(event.getMaintenanceId()));
+ }
String driverUniqueId = event.getString(Position.KEY_DRIVER_UNIQUE_ID);
if (driverUniqueId != null) {
velocityContext.put("driver", Context.getDriversManager().getDriverByUniqueId(driverUniqueId));
diff --git a/src/org/traccar/protocol/AquilaProtocolDecoder.java b/src/org/traccar/protocol/AquilaProtocolDecoder.java
index 960139b3f..9963ead34 100644
--- a/src/org/traccar/protocol/AquilaProtocolDecoder.java
+++ b/src/org/traccar/protocol/AquilaProtocolDecoder.java
@@ -17,6 +17,7 @@ package org.traccar.protocol;
import org.jboss.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
+import org.traccar.Context;
import org.traccar.DeviceSession;
import org.traccar.helper.Parser;
import org.traccar.helper.PatternBuilder;
@@ -242,7 +243,7 @@ public class AquilaProtocolDecoder extends BaseProtocolDecoder {
.number("([01]),") // charge
.number("(d+.d+),") // power
.number("(d+.d+),") // battery
- .number("[01],") // emergency
+ .number("([01]),") // emergency
.expression("[CO],") // tamper
.number("(d+),") // rssi
.number("(d+),") // mcc
@@ -269,7 +270,8 @@ public class AquilaProtocolDecoder extends BaseProtocolDecoder {
return null;
}
- DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next());
+ String id = parser.next();
+ DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, id);
if (deviceSession == null) {
return null;
}
@@ -295,6 +297,15 @@ public class AquilaProtocolDecoder extends BaseProtocolDecoder {
position.set(Position.KEY_POWER, parser.nextDouble());
position.set(Position.KEY_BATTERY, parser.nextDouble());
+ if (parser.nextInt() == 1) {
+ position.set(Position.KEY_ALARM, Position.ALARM_SOS);
+ if (channel != null) {
+ String password = Context.getIdentityManager().lookupAttributeString(
+ position.getDeviceId(), getProtocolName() + ".language", "aquila123", true);
+ channel.write("#set$" + id + "@" + password + "#EMR_MODE:0*");
+ }
+ }
+
Network network = new Network();
int rssi = parser.nextInt();
diff --git a/src/org/traccar/protocol/AtrackFrameDecoder.java b/src/org/traccar/protocol/AtrackFrameDecoder.java
index ce4a9a65f..224679bde 100644
--- a/src/org/traccar/protocol/AtrackFrameDecoder.java
+++ b/src/org/traccar/protocol/AtrackFrameDecoder.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2017 Anton Tananaev (anton@traccar.org)
+ * Copyright 2017 - 2018 Anton Tananaev (anton@traccar.org)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -37,7 +37,7 @@ public class AtrackFrameDecoder extends FrameDecoder {
return buf.readBytes(KEEPALIVE_LENGTH);
}
- } else if (buf.getUnsignedShort(buf.readerIndex()) == 0x4050) {
+ } else if (buf.getUnsignedShort(buf.readerIndex()) == 0x4050 && buf.getByte(buf.readerIndex() + 2) != ',') {
if (buf.readableBytes() > 6) {
int length = buf.getUnsignedShort(buf.readerIndex() + 4) + 4 + 2;
diff --git a/src/org/traccar/protocol/AtrackProtocolDecoder.java b/src/org/traccar/protocol/AtrackProtocolDecoder.java
index 8138f0fcb..b0f094103 100644
--- a/src/org/traccar/protocol/AtrackProtocolDecoder.java
+++ b/src/org/traccar/protocol/AtrackProtocolDecoder.java
@@ -21,6 +21,7 @@ import org.jboss.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
import org.traccar.Context;
import org.traccar.DeviceSession;
+import org.traccar.helper.DataConverter;
import org.traccar.helper.DateBuilder;
import org.traccar.helper.Parser;
import org.traccar.helper.PatternBuilder;
@@ -219,7 +220,8 @@ public class AtrackProtocolDecoder extends BaseProtocolDecoder {
.any()
.compile();
- private Position decodeString(Channel channel, SocketAddress remoteAddress, String sentence) {
+ private Position decodeInfo(Channel channel, SocketAddress remoteAddress, String sentence) {
+
Position position = new Position(getProtocolName());
getLastLocation(position, null);
@@ -258,21 +260,70 @@ public class AtrackProtocolDecoder extends BaseProtocolDecoder {
}
}
- @Override
- protected Object decode(
- Channel channel, SocketAddress remoteAddress, Object msg) throws Exception {
+ private static final Pattern PATTERN = new PatternBuilder()
+ .text("@P,")
+ .number("x+,") // checksum
+ .number("d+,") // length
+ .number("d+,") // index
+ .number("(d+),") // imei
+ .number("(dddd)(dd)(dd)") // date (yymmdd)
+ .number("(dd)(dd)(dd),") // time (hhmmss)
+ .number("d+,") // rtc date and time
+ .number("d+,") // device date and time
+ .number("(-?d+),") // longitude
+ .number("(-?d+),") // latitude
+ .number("(d+),") // course
+ .number("(d+),") // report id
+ .number("(d+.d+),") // odometer
+ .number("(d+),") // hdop
+ .number("(d+),") // inputs
+ .number("(d+),") // speed
+ .number("(d+),") // outputs
+ .number("(d+),") // adc
+ .number("[^,]*,") // driver
+ .number("(d+),") // temp1
+ .number("(d+),") // temp2
+ .any()
+ .compile();
- ChannelBuffer buf = (ChannelBuffer) msg;
+ private Position decodeText(Channel channel, SocketAddress remoteAddress, String sentence) {
- if (buf.getUnsignedShort(buf.readerIndex()) == 0xfe02) {
- if (channel != null) {
- channel.write(buf, remoteAddress); // keep-alive message
- }
+ Parser parser = new Parser(PATTERN, sentence);
+ if (!parser.matches()) {
return null;
- } else if (buf.getByte(buf.readerIndex()) == '$') {
- return decodeString(channel, remoteAddress, buf.toString(StandardCharsets.US_ASCII).trim());
}
+ DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next());
+ if (deviceSession == null) {
+ return null;
+ }
+
+ Position position = new Position(getProtocolName());
+ position.setDeviceId(deviceSession.getDeviceId());
+
+ position.setValid(true);
+ position.setTime(parser.nextDateTime());
+ position.setLongitude(parser.nextInt() * 0.000001);
+ position.setLatitude(parser.nextInt() * 0.000001);
+ position.setCourse(parser.nextInt());
+
+ position.set(Position.KEY_EVENT, parser.nextInt());
+ position.set(Position.KEY_ODOMETER, parser.nextDouble() * 100);
+ position.set(Position.KEY_HDOP, parser.nextInt() * 0.1);
+ position.set(Position.KEY_INPUT, parser.nextInt());
+
+ position.setSpeed(UnitsConverter.knotsFromKph(parser.nextInt()));
+
+ position.set(Position.KEY_OUTPUT, parser.nextInt());
+ position.set(Position.PREFIX_ADC + 1, parser.nextInt());
+ position.set(Position.PREFIX_TEMP + 1, parser.nextInt());
+ position.set(Position.PREFIX_TEMP + 2, parser.nextInt());
+
+ return position;
+ }
+
+ private List<Position> decodeBinary(Channel channel, SocketAddress remoteAddress, ChannelBuffer buf) {
+
buf.skipBytes(2); // prefix
buf.readUnsignedShort(); // checksum
buf.readUnsignedShort(); // length
@@ -360,4 +411,29 @@ public class AtrackProtocolDecoder extends BaseProtocolDecoder {
return positions;
}
+ private void sendResponse(Channel channel, SocketAddress remoteAddress) {
+ if (channel != null) {
+ channel.write(ChannelBuffers.wrappedBuffer(DataConverter.parseHex("fe02")), remoteAddress);
+ }
+ }
+
+ @Override
+ protected Object decode(
+ Channel channel, SocketAddress remoteAddress, Object msg) throws Exception {
+
+ ChannelBuffer buf = (ChannelBuffer) msg;
+
+ sendResponse(channel, remoteAddress);
+
+ if (buf.getUnsignedShort(buf.readerIndex()) == 0xfe02) {
+ return null;
+ } else if (buf.getByte(buf.readerIndex()) == '$') {
+ return decodeInfo(channel, remoteAddress, buf.toString(StandardCharsets.US_ASCII).trim());
+ } else if (buf.getByte(buf.readerIndex() + 2) == ',') {
+ return decodeText(channel, remoteAddress, buf.toString(StandardCharsets.US_ASCII).trim());
+ } else {
+ return decodeBinary(channel, remoteAddress, buf);
+ }
+ }
+
}
diff --git a/src/org/traccar/protocol/ContinentalProtocol.java b/src/org/traccar/protocol/ContinentalProtocol.java
index e2b1226cf..5f43a51f7 100644
--- a/src/org/traccar/protocol/ContinentalProtocol.java
+++ b/src/org/traccar/protocol/ContinentalProtocol.java
@@ -34,7 +34,7 @@ public class ContinentalProtocol extends BaseProtocol {
serverList.add(new TrackerServer(new ServerBootstrap(), getName()) {
@Override
protected void addSpecificHandlers(ChannelPipeline pipeline) {
- pipeline.addLast("frameDecoder", new LengthFieldBasedFrameDecoder(1024, 2, 2));
+ pipeline.addLast("frameDecoder", new LengthFieldBasedFrameDecoder(1024, 2, 2, -4, 0));
pipeline.addLast("objectDecoder", new ContinentalProtocolDecoder(ContinentalProtocol.this));
}
});
diff --git a/src/org/traccar/protocol/ContinentalProtocolDecoder.java b/src/org/traccar/protocol/ContinentalProtocolDecoder.java
index 726d9e16b..37913b657 100644
--- a/src/org/traccar/protocol/ContinentalProtocolDecoder.java
+++ b/src/org/traccar/protocol/ContinentalProtocolDecoder.java
@@ -16,10 +16,10 @@
package org.traccar.protocol;
import org.jboss.netty.buffer.ChannelBuffer;
-import org.jboss.netty.buffer.ChannelBuffers;
import org.jboss.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
import org.traccar.DeviceSession;
+import org.traccar.helper.BitUtil;
import org.traccar.helper.UnitsConverter;
import org.traccar.model.Position;
@@ -37,22 +37,6 @@ public class ContinentalProtocolDecoder extends BaseProtocolDecoder {
public static final int MSG_ACK = 0x06;
public static final int MSG_NACK = 0x15;
- private void sendResponse(Channel channel, long serialNumber) {
- if (channel != null) {
- ChannelBuffer response = ChannelBuffers.dynamicBuffer();
-
- response.writeByte('S');
- response.writeByte('V');
- response.writeShort(2 + 2 + 1 + 4 + 2); // length
- response.writeByte(1); // version
- response.writeInt((int) serialNumber);
- response.writeByte(0); // product
- response.writeByte(MSG_ACK);
-
- channel.write(response);
- }
- }
-
@Override
protected Object decode(
Channel channel, SocketAddress remoteAddress, Object msg) throws Exception {
@@ -69,8 +53,6 @@ public class ContinentalProtocolDecoder extends BaseProtocolDecoder {
return null;
}
- sendResponse(channel, serialNumber);
-
buf.readUnsignedByte(); // product
int type = buf.readUnsignedByte();
@@ -96,13 +78,25 @@ public class ContinentalProtocolDecoder extends BaseProtocolDecoder {
position.setDeviceTime(new Date(buf.readUnsignedInt() * 1000L));
position.set(Position.KEY_EVENT, buf.readUnsignedShort());
- position.set(Position.KEY_INPUT, buf.readUnsignedShort());
+
+ int input = buf.readUnsignedShort();
+ position.set(Position.KEY_IGNITION, BitUtil.check(input, 0));
+ position.set(Position.KEY_INPUT, input);
+
position.set(Position.KEY_OUTPUT, buf.readUnsignedShort());
position.set(Position.KEY_BATTERY, buf.readUnsignedByte());
position.set(Position.KEY_DEVICE_TEMP, buf.readByte());
buf.readUnsignedShort(); // reserved
+ if (buf.readableBytes() > 4) {
+ position.set(Position.KEY_ODOMETER, buf.readUnsignedInt());
+ }
+
+ if (buf.readableBytes() > 4) {
+ position.set(Position.KEY_HOURS, buf.readUnsignedInt());
+ }
+
return position;
}
diff --git a/src/org/traccar/protocol/EelinkProtocolDecoder.java b/src/org/traccar/protocol/EelinkProtocolDecoder.java
index 0ed81c925..0fda6fb74 100644
--- a/src/org/traccar/protocol/EelinkProtocolDecoder.java
+++ b/src/org/traccar/protocol/EelinkProtocolDecoder.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2014 - 2017 Anton Tananaev (anton@traccar.org)
+ * Copyright 2014 - 2018 Anton Tananaev (anton@traccar.org)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -170,7 +170,7 @@ public class EelinkProtocolDecoder extends BaseProtocolDecoder {
return position;
}
- private Position decodeNew(DeviceSession deviceSession, ChannelBuffer buf, int index) {
+ private Position decodeNew(DeviceSession deviceSession, ChannelBuffer buf, int type, int index) {
Position position = new Position(getProtocolName());
position.setDeviceId(deviceSession.getDeviceId());
@@ -218,43 +218,59 @@ public class EelinkProtocolDecoder extends BaseProtocolDecoder {
buf.skipBytes(7); // bss2
}
- if (buf.readableBytes() >= 2) {
+ if (type == MSG_WARNING) {
+
+ position.set(Position.KEY_ALARM, decodeAlarm(buf.readUnsignedByte()));
+
+ } else if (type == MSG_REPORT) {
+
+ buf.readUnsignedByte(); // report type
+
+ }
+
+ if (type == MSG_NORMAL || type == MSG_WARNING || type == MSG_REPORT) {
+
int status = buf.readUnsignedShort();
position.setValid(BitUtil.check(status, 0));
if (BitUtil.check(status, 1)) {
position.set(Position.KEY_IGNITION, BitUtil.check(status, 2));
}
position.set(Position.KEY_STATUS, status);
- }
- if (buf.readableBytes() >= 2) {
- position.set(Position.KEY_BATTERY, buf.readUnsignedShort() * 0.001);
}
- if (buf.readableBytes() >= 4) {
- position.set(Position.PREFIX_ADC + 0, buf.readUnsignedShort());
- position.set(Position.PREFIX_ADC + 1, buf.readUnsignedShort());
- }
+ if (type == MSG_NORMAL) {
- if (buf.readableBytes() >= 4) {
- position.set(Position.KEY_ODOMETER, buf.readUnsignedInt());
- }
+ if (buf.readableBytes() >= 2) {
+ position.set(Position.KEY_BATTERY, buf.readUnsignedShort() * 0.001);
+ }
- if (buf.readableBytes() >= 4) {
- buf.readUnsignedShort(); // gsm counter
- buf.readUnsignedShort(); // gps counter
- }
+ if (buf.readableBytes() >= 4) {
+ position.set(Position.PREFIX_ADC + 0, buf.readUnsignedShort());
+ position.set(Position.PREFIX_ADC + 1, buf.readUnsignedShort());
+ }
- if (buf.readableBytes() >= 4) {
- position.set(Position.KEY_STEPS, buf.readUnsignedShort());
- buf.readUnsignedShort(); // walking time
- }
+ if (buf.readableBytes() >= 4) {
+ position.set(Position.KEY_ODOMETER, buf.readUnsignedInt());
+ }
+
+ if (buf.readableBytes() >= 4) {
+ buf.readUnsignedShort(); // gsm counter
+ buf.readUnsignedShort(); // gps counter
+ }
+
+ if (buf.readableBytes() >= 4) {
+ position.set(Position.KEY_STEPS, buf.readUnsignedShort());
+ buf.readUnsignedShort(); // walking time
+ }
+
+ if (buf.readableBytes() >= 12) {
+ position.set(Position.PREFIX_TEMP + 1, buf.readUnsignedShort() / 256.0);
+ position.set("humidity", buf.readUnsignedShort() * 0.1);
+ position.set("illuminance", buf.readUnsignedInt() / 256.0);
+ position.set("co2", buf.readUnsignedInt());
+ }
- if (buf.readableBytes() >= 12) {
- position.set(Position.PREFIX_TEMP + 1, buf.readUnsignedShort() / 256.0);
- position.set("humidity", buf.readUnsignedShort() * 0.1);
- position.set("illuminance", buf.readUnsignedInt() / 256.0);
- position.set("co2", buf.readUnsignedInt());
}
return position;
@@ -355,7 +371,7 @@ public class EelinkProtocolDecoder extends BaseProtocolDecoder {
} else if (type >= MSG_NORMAL && type <= MSG_OBD_CODE) {
- return decodeNew(deviceSession, buf, index);
+ return decodeNew(deviceSession, buf, type, index);
} else if (type == MSG_HEARTBEAT && buf.readableBytes() >= 2) {
diff --git a/src/org/traccar/protocol/EskyProtocolDecoder.java b/src/org/traccar/protocol/EskyProtocolDecoder.java
index 60ef4f846..bf790541b 100644
--- a/src/org/traccar/protocol/EskyProtocolDecoder.java
+++ b/src/org/traccar/protocol/EskyProtocolDecoder.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2017 Anton Tananaev (anton@traccar.org)
+ * Copyright 2017 - 2018 Anton Tananaev (anton@traccar.org)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -37,16 +37,18 @@ public class EskyProtocolDecoder extends BaseProtocolDecoder {
.number("d+;") // index
.number("(d+);") // imei
.text("R;") // data type
- .number("(d+)").text("+") // satellites
+ .number("(d+)[+;]") // satellites
.number("(dd)(dd)(dd)") // date
- .number("(dd)(dd)(dd)").text("+") // time
- .number("(-?d+.d+)").text("+") // latitude
- .number("(-?d+.d+)").text("+") // longitude
- .number("(d+.d+)").text("+") // speed
- .number("(d+)").text("+") // course
- .text("0x").number("(d+)").text("+") // input
- .number("(d+)").text("+") // message type
- .number("(d+)").text("+") // odometer
+ .number("(dd)(dd)(dd)[+;]") // time
+ .number("(-?d+.d+)[+;]") // latitude
+ .number("(-?d+.d+)[+;]") // longitude
+ .number("(d+.d+)[+;]") // speed
+ .number("(d+)[+;]") // course
+ .groupBegin()
+ .text("0x").number("(d+)[+;]") // input
+ .number("(d+)[+;]") // message type
+ .number("(d+)[+;]") // odometer
+ .groupEnd("?")
.number("(d+)") // voltage
.any()
.compile();
@@ -77,10 +79,13 @@ public class EskyProtocolDecoder extends BaseProtocolDecoder {
position.setSpeed(UnitsConverter.knotsFromMps(parser.nextDouble()));
position.setCourse(parser.nextDouble());
- position.set(Position.KEY_INPUT, parser.nextHexInt());
- position.set(Position.KEY_EVENT, parser.nextInt());
- position.set(Position.KEY_ODOMETER, parser.nextInt());
- position.set(Position.KEY_POWER, parser.nextInt());
+ if (parser.hasNext(3)) {
+ position.set(Position.KEY_INPUT, parser.nextHexInt());
+ position.set(Position.KEY_EVENT, parser.nextInt());
+ position.set(Position.KEY_ODOMETER, parser.nextInt());
+ }
+
+ position.set(Position.KEY_BATTERY, parser.nextInt() * 0.001);
return position;
}
diff --git a/src/org/traccar/protocol/GatorProtocolDecoder.java b/src/org/traccar/protocol/GatorProtocolDecoder.java
index 9cd746f51..b38214457 100644
--- a/src/org/traccar/protocol/GatorProtocolDecoder.java
+++ b/src/org/traccar/protocol/GatorProtocolDecoder.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2013 - 2017 Anton Tananaev (anton@traccar.org)
+ * Copyright 2013 - 2018 Anton Tananaev (anton@traccar.org)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -56,7 +56,7 @@ public class GatorProtocolDecoder extends BaseProtocolDecoder {
return String.format("%02d%02d%02d%02d%02d", d1, d2, d3, d4, d5);
}
- private void sendResponse(Channel channel, byte calibration) {
+ private void sendResponse(Channel channel, SocketAddress remoteAddress, byte calibration) {
if (channel != null) {
ChannelBuffer response = ChannelBuffers.dynamicBuffer();
response.writeByte(0x24); response.writeByte(0x24); // header
@@ -67,7 +67,7 @@ public class GatorProtocolDecoder extends BaseProtocolDecoder {
response.writeByte(0); // slave order
response.writeByte(1); // calibration
response.writeByte(0x0D);
- channel.write(response);
+ channel.write(response, remoteAddress);
}
}
@@ -85,7 +85,7 @@ public class GatorProtocolDecoder extends BaseProtocolDecoder {
buf.readUnsignedByte(), buf.readUnsignedByte(),
buf.readUnsignedByte(), buf.readUnsignedByte());
- sendResponse(channel, buf.getByte(buf.writerIndex() - 2));
+ sendResponse(channel, remoteAddress, buf.getByte(buf.writerIndex() - 2));
if (type == MSG_POSITION_DATA || type == MSG_ROLLCALL_RESPONSE
|| type == MSG_ALARM_DATA || type == MSG_BLIND_AREA) {
diff --git a/src/org/traccar/protocol/Gl200TextProtocolDecoder.java b/src/org/traccar/protocol/Gl200TextProtocolDecoder.java
index ff300d429..598cee814 100644
--- a/src/org/traccar/protocol/Gl200TextProtocolDecoder.java
+++ b/src/org/traccar/protocol/Gl200TextProtocolDecoder.java
@@ -828,6 +828,7 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder {
decodeLocation(position, parser);
+ position.set(Position.KEY_IGNITION, sentence.contains("IGN"));
position.set(Position.KEY_HOURS, parser.next());
position.set(Position.KEY_ODOMETER, parser.nextDouble() * 1000);
@@ -918,6 +919,10 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder {
position.set(Position.KEY_MOTION, reportType == 1);
} else if (type.equals("SOS")) {
position.set(Position.KEY_ALARM, Position.ALARM_SOS);
+ } else if (type.equals("DIS")) {
+ position.set(Position.PREFIX_IN + reportType / 10, reportType % 10 == 1);
+ } else if (type.equals("IGL")) {
+ position.set(Position.KEY_IGNITION, reportType % 10 == 0);
}
decodeLocation(position, parser);
diff --git a/src/org/traccar/protocol/H02ProtocolDecoder.java b/src/org/traccar/protocol/H02ProtocolDecoder.java
index 9764adf04..54671bdbf 100644
--- a/src/org/traccar/protocol/H02ProtocolDecoder.java
+++ b/src/org/traccar/protocol/H02ProtocolDecoder.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2012 - 2017 Anton Tananaev (anton@traccar.org)
+ * Copyright 2012 - 2018 Anton Tananaev (anton@traccar.org)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -148,7 +148,7 @@ public class H02ProtocolDecoder extends BaseProtocolDecoder {
private static final Pattern PATTERN = new PatternBuilder()
.text("*")
.expression("..,") // manufacturer
- .number("(d+),") // imei
+ .number("(d+)?,") // imei
.groupBegin()
.text("VP1,")
.or()
diff --git a/src/org/traccar/protocol/L100FrameDecoder.java b/src/org/traccar/protocol/L100FrameDecoder.java
index a597cbd7d..98c2f9768 100644
--- a/src/org/traccar/protocol/L100FrameDecoder.java
+++ b/src/org/traccar/protocol/L100FrameDecoder.java
@@ -41,7 +41,10 @@ public class L100FrameDecoder extends FrameDecoder {
index += 2; // checksum
if (buf.readableBytes() >= index - buf.readerIndex()) {
- return buf.readBytes(index - buf.readerIndex());
+ buf.skipBytes(2); // header
+ ChannelBuffer frame = buf.readBytes(index - buf.readerIndex() - 2);
+ buf.skipBytes(2); // footer
+ return frame;
}
return null;
diff --git a/src/org/traccar/protocol/L100Protocol.java b/src/org/traccar/protocol/L100Protocol.java
index 2bcef4caa..245f073fb 100644
--- a/src/org/traccar/protocol/L100Protocol.java
+++ b/src/org/traccar/protocol/L100Protocol.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2016 Anton Tananaev (anton@traccar.org)
+ * Copyright 2016 - 2018 Anton Tananaev (anton@traccar.org)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -17,6 +17,8 @@ package org.traccar.protocol;
import org.jboss.netty.bootstrap.ServerBootstrap;
import org.jboss.netty.channel.ChannelPipeline;
+import org.jboss.netty.handler.codec.string.StringDecoder;
+import org.jboss.netty.handler.codec.string.StringEncoder;
import org.traccar.BaseProtocol;
import org.traccar.TrackerServer;
@@ -34,6 +36,8 @@ public class L100Protocol extends BaseProtocol {
@Override
protected void addSpecificHandlers(ChannelPipeline pipeline) {
pipeline.addLast("frameDecoder", new L100FrameDecoder());
+ pipeline.addLast("stringEncoder", new StringEncoder());
+ pipeline.addLast("stringDecoder", new StringDecoder());
pipeline.addLast("objectDecoder", new L100ProtocolDecoder(L100Protocol.this));
}
});
diff --git a/src/org/traccar/protocol/L100ProtocolDecoder.java b/src/org/traccar/protocol/L100ProtocolDecoder.java
index de966d7af..1fe18ff5e 100644
--- a/src/org/traccar/protocol/L100ProtocolDecoder.java
+++ b/src/org/traccar/protocol/L100ProtocolDecoder.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2016 Anton Tananaev (anton@traccar.org)
+ * Copyright 2016 - 2018 Anton Tananaev (anton@traccar.org)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -15,7 +15,6 @@
*/
package org.traccar.protocol;
-import org.jboss.netty.buffer.ChannelBuffer;
import org.jboss.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
import org.traccar.DeviceSession;
@@ -27,7 +26,6 @@ import org.traccar.model.Network;
import org.traccar.model.Position;
import java.net.SocketAddress;
-import java.nio.charset.StandardCharsets;
import java.util.regex.Pattern;
public class L100ProtocolDecoder extends BaseProtocolDecoder {
@@ -43,9 +41,9 @@ public class L100ProtocolDecoder extends BaseProtocolDecoder {
.number("(dd)(dd)(dd)") // time (hhmmss.sss)
.number(".(ddd)").optional()
.expression(",([AV]),") // validity
- .number("(dd)(dd.d+),") // latitude
+ .number("(d+)(dd.d+),") // latitude
.expression("([NS]),")
- .number("(ddd)(dd.d+),") // longitude
+ .number("(d+)(dd.d+),") // longitude
.expression("([EW]),")
.number("(d+.?d*)?,") // speed
.number("(d+.?d*)?,") // course
@@ -59,7 +57,7 @@ public class L100ProtocolDecoder extends BaseProtocolDecoder {
.number("(d+.d+),") // odometer
.number("(d+.d+),") // temperature
.number("(d+.d+),") // battery
- .number("(d+),") // gsm
+ .number("(d+),") // rssi
.number("(d+),") // mcc
.number("(d+),") // mnc
.number("(x+),") // lac
@@ -71,12 +69,7 @@ public class L100ProtocolDecoder extends BaseProtocolDecoder {
protected Object decode(
Channel channel, SocketAddress remoteAddress, Object msg) throws Exception {
- ChannelBuffer buf = (ChannelBuffer) msg;
-
- buf.readUnsignedByte(); // start marker
- buf.readUnsignedByte(); // type
-
- String sentence = buf.readBytes(buf.readableBytes() - 2).toString(StandardCharsets.US_ASCII);
+ String sentence = (String) msg;
Parser parser = new Parser(PATTERN, sentence);
if (!parser.matches()) {
@@ -92,7 +85,7 @@ public class L100ProtocolDecoder extends BaseProtocolDecoder {
position.setDeviceId(deviceSession.getDeviceId());
DateBuilder dateBuilder = new DateBuilder()
- .setTime(parser.nextInt(0), parser.nextInt(0), parser.nextInt(0), parser.nextInt(0));
+ .setTime(parser.nextInt(), parser.nextInt(), parser.nextInt(), parser.nextInt(0));
position.setValid(parser.next().equals("A"));
position.setLatitude(parser.nextCoordinate());
@@ -100,18 +93,20 @@ public class L100ProtocolDecoder extends BaseProtocolDecoder {
position.setSpeed(parser.nextDouble(0));
position.setCourse(parser.nextDouble(0));
- dateBuilder.setDateReverse(parser.nextInt(0), parser.nextInt(0), parser.nextInt(0));
+ dateBuilder.setDateReverse(parser.nextInt(), parser.nextInt(), parser.nextInt());
position.setTime(dateBuilder.getDate());
position.set(Position.KEY_STATUS, parser.next());
position.set(Position.PREFIX_ADC + 1, parser.next());
- position.set(Position.KEY_ODOMETER, parser.nextDouble(0));
- position.set(Position.PREFIX_TEMP + 1, parser.nextDouble(0));
- position.set(Position.KEY_BATTERY, parser.nextDouble(0));
-
- int rssi = parser.nextInt(0);
- position.setNetwork(new Network(CellTower.from(
- parser.nextInt(0), parser.nextInt(0), parser.nextHexInt(0), parser.nextHexInt(0), rssi)));
+ position.set(Position.KEY_ODOMETER, parser.nextDouble());
+ position.set(Position.PREFIX_TEMP + 1, parser.nextDouble());
+ position.set(Position.KEY_BATTERY, parser.nextDouble());
+
+ int rssi = parser.nextInt();
+ if (rssi > 0) {
+ position.setNetwork(new Network(CellTower.from(
+ parser.nextInt(), parser.nextInt(), parser.nextHexInt(), parser.nextHexInt(), rssi)));
+ }
return position;
}
diff --git a/src/org/traccar/protocol/Pt502Protocol.java b/src/org/traccar/protocol/Pt502Protocol.java
index ba820a6a1..f7d0d04a2 100644
--- a/src/org/traccar/protocol/Pt502Protocol.java
+++ b/src/org/traccar/protocol/Pt502Protocol.java
@@ -17,7 +17,6 @@ package org.traccar.protocol;
import org.jboss.netty.bootstrap.ServerBootstrap;
import org.jboss.netty.channel.ChannelPipeline;
-import org.jboss.netty.handler.codec.string.StringDecoder;
import org.jboss.netty.handler.codec.string.StringEncoder;
import org.traccar.BaseProtocol;
import org.traccar.TrackerServer;
diff --git a/src/org/traccar/protocol/Pt60ProtocolDecoder.java b/src/org/traccar/protocol/Pt60ProtocolDecoder.java
index c87c22c5f..26f07a0a9 100644
--- a/src/org/traccar/protocol/Pt60ProtocolDecoder.java
+++ b/src/org/traccar/protocol/Pt60ProtocolDecoder.java
@@ -34,16 +34,19 @@ public class Pt60ProtocolDecoder extends BaseProtocolDecoder {
super(protocol);
}
+ public static final int MSG_TRACK = 6;
+ public static final int MSG_STEP_COUNT = 13;
+ public static final int MSG_HEART_RATE = 14;
+
private static final Pattern PATTERN = new PatternBuilder()
.text("@G#@,") // header
.number("Vdd,") // protocol version
- .number("d,") // type
+ .number("(d+),") // type
.number("(d+),") // imei
.number("(d+),") // imsi
.number("(dddd)(dd)(dd)") // date (yyyymmdd)
.number("(dd)(dd)(dd),") // time (hhmmss)
- .number("(-?d+.d+);") // latitude
- .number("(-?d+.d+),") // longitude
+ .expression("(.*)") // data
.compile();
private void sendResponse(Channel channel) {
@@ -64,6 +67,12 @@ public class Pt60ProtocolDecoder extends BaseProtocolDecoder {
return null;
}
+ int type = parser.nextInt();
+
+ if (type != MSG_TRACK && type != MSG_STEP_COUNT && type != MSG_HEART_RATE) {
+ return null;
+ }
+
Position position = new Position(getProtocolName());
DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next(), parser.next());
@@ -72,10 +81,36 @@ public class Pt60ProtocolDecoder extends BaseProtocolDecoder {
}
position.setDeviceId(deviceSession.getDeviceId());
- position.setValid(true);
- position.setTime(parser.nextDateTime());
- position.setLatitude(parser.nextDouble());
- position.setLongitude(parser.nextDouble());
+ position.setDeviceTime(parser.nextDateTime());
+
+ String[] values = parser.next().split(",");
+
+ if (type == MSG_TRACK) {
+
+ position.setValid(true);
+ position.setFixTime(position.getDeviceTime());
+
+ String[] coordinates = values[0].split(";");
+ position.setLatitude(Double.parseDouble(coordinates[0]));
+ position.setLongitude(Double.parseDouble(coordinates[1]));
+
+ } else {
+
+ getLastLocation(position, position.getDeviceTime());
+
+ switch (type) {
+ case MSG_STEP_COUNT:
+ position.set(Position.KEY_STEPS, Integer.parseInt(values[0]));
+ break;
+ case MSG_HEART_RATE:
+ position.set(Position.KEY_HEART_RATE, Integer.parseInt(values[0]));
+ position.set(Position.KEY_BATTERY, Integer.parseInt(values[1]));
+ break;
+ default:
+ break;
+ }
+
+ }
return position;
}
diff --git a/src/org/traccar/protocol/TeltonikaProtocolDecoder.java b/src/org/traccar/protocol/TeltonikaProtocolDecoder.java
index d2069e6c9..3935ebd60 100644
--- a/src/org/traccar/protocol/TeltonikaProtocolDecoder.java
+++ b/src/org/traccar/protocol/TeltonikaProtocolDecoder.java
@@ -141,6 +141,16 @@ public class TeltonikaProtocolDecoder extends BaseProtocolDecoder {
case 80:
position.set("workMode", readValue(buf, length, false));
break;
+ case 129:
+ case 130:
+ case 131:
+ case 132:
+ case 133:
+ case 134:
+ String driver = id == 129 || id == 132 ? "" : position.getString("driver1");
+ position.set("driver" + (id >= 132 ? 2 : 1),
+ driver + buf.readBytes(length).toString(StandardCharsets.US_ASCII).trim());
+ break;
case 179:
position.set(Position.PREFIX_OUT + 1, readValue(buf, length, false) == 1);
break;
diff --git a/src/org/traccar/protocol/Tk103Protocol.java b/src/org/traccar/protocol/Tk103Protocol.java
index 6ef9c0a56..e23982c74 100644
--- a/src/org/traccar/protocol/Tk103Protocol.java
+++ b/src/org/traccar/protocol/Tk103Protocol.java
@@ -47,7 +47,8 @@ public class Tk103Protocol extends BaseProtocol {
Command.TYPE_REBOOT_DEVICE,
Command.TYPE_SET_ODOMETER,
Command.TYPE_ENGINE_STOP,
- Command.TYPE_ENGINE_RESUME);
+ Command.TYPE_ENGINE_RESUME,
+ Command.TYPE_OUTPUT_CONTROL);
}
@Override
diff --git a/src/org/traccar/protocol/Tk103ProtocolEncoder.java b/src/org/traccar/protocol/Tk103ProtocolEncoder.java
index 946f3ad73..3ec562cc3 100644
--- a/src/org/traccar/protocol/Tk103ProtocolEncoder.java
+++ b/src/org/traccar/protocol/Tk103ProtocolEncoder.java
@@ -97,6 +97,8 @@ public class Tk103ProtocolEncoder extends StringProtocolEncoder {
return formatCommand(command, "({%s}AV010)", Command.KEY_UNIQUE_ID);
case Command.TYPE_ENGINE_RESUME:
return formatCommand(command, "({%s}AV011)", Command.KEY_UNIQUE_ID);
+ case Command.TYPE_OUTPUT_CONTROL:
+ return formatCommand(command, "({%s}AV00{%s})", Command.KEY_UNIQUE_ID, Command.KEY_DATA);
default:
Log.warning(new UnsupportedOperationException(command.getType()));
return null;
diff --git a/src/org/traccar/protocol/TotemProtocolDecoder.java b/src/org/traccar/protocol/TotemProtocolDecoder.java
index 5a2c203d2..06a1fbc41 100644
--- a/src/org/traccar/protocol/TotemProtocolDecoder.java
+++ b/src/org/traccar/protocol/TotemProtocolDecoder.java
@@ -245,6 +245,9 @@ public class TotemProtocolDecoder extends BaseProtocolDecoder {
int io = parser.nextBinInt();
if (pattern == PATTERN1) {
+ if (BitUtil.check(io, 0)) {
+ position.set(Position.KEY_ALARM, Position.ALARM_SOS);
+ }
for (int i = 1; i <= 4; i++) {
position.set(Position.PREFIX_IN + i, BitUtil.check(io, 3 + i));
}
@@ -364,7 +367,7 @@ public class TotemProtocolDecoder extends BaseProtocolDecoder {
String sentence = (String) msg;
Pattern pattern = PATTERN3;
- if (sentence.indexOf("A") == 6) {
+ if (sentence.charAt(2) == '0') {
pattern = PATTERN4;
} else if (sentence.contains("$GPRMC")) {
pattern = PATTERN1;
diff --git a/src/org/traccar/protocol/WatchProtocolDecoder.java b/src/org/traccar/protocol/WatchProtocolDecoder.java
index b58c3b6a1..f55b6f7be 100644
--- a/src/org/traccar/protocol/WatchProtocolDecoder.java
+++ b/src/org/traccar/protocol/WatchProtocolDecoder.java
@@ -273,7 +273,7 @@ public class WatchProtocolDecoder extends BaseProtocolDecoder {
position.set("pressureHigh", values[valueIndex++]);
position.set("pressureLow", values[valueIndex++]);
}
- position.set("pulse", values[valueIndex]);
+ position.set(Position.KEY_HEART_RATE, Integer.parseInt(values[valueIndex]));
return position;
diff --git a/src/org/traccar/reports/Events.java b/src/org/traccar/reports/Events.java
index 7cb6ef6eb..66d9e708d 100644
--- a/src/org/traccar/reports/Events.java
+++ b/src/org/traccar/reports/Events.java
@@ -1,6 +1,6 @@
/*
- * Copyright 2016 Anton Tananaev (anton@traccar.org)
- * Copyright 2016 Andrey Kunitsyn (andrey@traccar.org)
+ * Copyright 2016 - 2018 Anton Tananaev (anton@traccar.org)
+ * Copyright 2016 - 2018 Andrey Kunitsyn (andrey@traccar.org)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -33,6 +33,7 @@ import org.traccar.model.Device;
import org.traccar.model.Event;
import org.traccar.model.Geofence;
import org.traccar.model.Group;
+import org.traccar.model.Maintenance;
import org.traccar.reports.model.DeviceReport;
public final class Events {
@@ -51,7 +52,10 @@ public final class Events {
for (Event event : events) {
if (all || types.contains(event.getType())) {
long geofenceId = event.getGeofenceId();
- if (geofenceId == 0 || Context.getGeofenceManager().checkItemPermission(userId, geofenceId)) {
+ long maintenanceId = event.getMaintenanceId();
+ if ((geofenceId == 0 || Context.getGeofenceManager().checkItemPermission(userId, geofenceId))
+ && (maintenanceId == 0
+ || Context.getMaintenancesManager().checkItemPermission(userId, maintenanceId))) {
result.add(event);
}
}
@@ -67,6 +71,7 @@ public final class Events {
ArrayList<DeviceReport> devicesEvents = new ArrayList<>();
ArrayList<String> sheetNames = new ArrayList<>();
HashMap<Long, String> geofenceNames = new HashMap<>();
+ HashMap<Long, String> maintenanceNames = new HashMap<>();
for (long deviceId: ReportUtils.getDeviceList(deviceIds, groupIds)) {
Context.getPermissionsManager().checkDevice(userId, deviceId);
Collection<Event> events = Context.getDataManager().getEvents(deviceId, from, to);
@@ -75,6 +80,7 @@ public final class Events {
Event event = iterator.next();
if (all || types.contains(event.getType())) {
long geofenceId = event.getGeofenceId();
+ long maintenanceId = event.getMaintenanceId();
if (geofenceId != 0) {
if (Context.getGeofenceManager().checkItemPermission(userId, geofenceId)) {
Geofence geofence = Context.getGeofenceManager().getById(geofenceId);
@@ -84,6 +90,15 @@ public final class Events {
} else {
iterator.remove();
}
+ } else if (maintenanceId != 0) {
+ if (Context.getMaintenancesManager().checkItemPermission(userId, maintenanceId)) {
+ Maintenance maintenance = Context.getMaintenancesManager().getById(maintenanceId);
+ if (maintenance != null) {
+ maintenanceNames.put(maintenanceId, maintenance.getName());
+ }
+ } else {
+ iterator.remove();
+ }
}
} else {
iterator.remove();
@@ -109,6 +124,7 @@ public final class Events {
jxlsContext.putVar("devices", devicesEvents);
jxlsContext.putVar("sheetNames", sheetNames);
jxlsContext.putVar("geofenceNames", geofenceNames);
+ jxlsContext.putVar("maintenanceNames", maintenanceNames);
jxlsContext.putVar("from", from);
jxlsContext.putVar("to", to);
ReportUtils.processTemplateWithSheets(inputStream, outputStream, jxlsContext);
diff --git a/src/org/traccar/reports/ReportUtils.java b/src/org/traccar/reports/ReportUtils.java
index e04f2f90c..010c88b22 100644
--- a/src/org/traccar/reports/ReportUtils.java
+++ b/src/org/traccar/reports/ReportUtils.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2016 - 2017 Anton Tananaev (anton@traccar.org)
+ * Copyright 2016 - 2018 Anton Tananaev (anton@traccar.org)
* Copyright 2016 - 2017 Andrey Kunitsyn (andrey@traccar.org)
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -151,8 +151,10 @@ public final class ReportUtils {
return jxlsContext;
}
- public static void processTemplateWithSheets(InputStream templateStream, OutputStream targetStream,
+ public static void processTemplateWithSheets(
+ InputStream templateStream, OutputStream targetStream,
org.jxls.common.Context jxlsContext) throws IOException {
+
Transformer transformer = TransformerFactory.createTransformer(templateStream, targetStream);
List<Area> xlsAreas = new XlsCommentAreaBuilder(transformer).build();
for (Area xlsArea : xlsAreas) {
@@ -166,6 +168,7 @@ public final class ReportUtils {
private static TripReport calculateTrip(
ArrayList<Position> positions, int startIndex, int endIndex, boolean ignoreOdometer) {
+
Position startTrip = positions.get(startIndex);
Position endTrip = positions.get(endIndex);
@@ -217,10 +220,22 @@ public final class ReportUtils {
trip.setDriverUniqueId(findDriver(startTrip, endTrip));
trip.setDriverName(findDriverName(trip.getDriverUniqueId()));
+ if (!ignoreOdometer
+ && startTrip.getDouble(Position.KEY_ODOMETER) != 0
+ && endTrip.getDouble(Position.KEY_ODOMETER) != 0) {
+ trip.setStartOdometer(startTrip.getDouble(Position.KEY_ODOMETER));
+ trip.setEndOdometer(endTrip.getDouble(Position.KEY_ODOMETER));
+ } else {
+ trip.setStartOdometer(startTrip.getDouble(Position.KEY_TOTAL_DISTANCE));
+ trip.setEndOdometer(endTrip.getDouble(Position.KEY_TOTAL_DISTANCE));
+ }
+
return trip;
}
- private static StopReport calculateStop(ArrayList<Position> positions, int startIndex, int endIndex) {
+ private static StopReport calculateStop(
+ ArrayList<Position> positions, int startIndex, int endIndex, boolean ignoreOdometer) {
+
Position startStop = positions.get(startIndex);
Position endStop = positions.get(endIndex);
@@ -256,16 +271,27 @@ public final class ReportUtils {
}
stop.setEngineHours(engineHours);
+ if (!ignoreOdometer
+ && startStop.getDouble(Position.KEY_ODOMETER) != 0
+ && endStop.getDouble(Position.KEY_ODOMETER) != 0) {
+ stop.setStartOdometer(startStop.getDouble(Position.KEY_ODOMETER));
+ stop.setEndOdometer(endStop.getDouble(Position.KEY_ODOMETER));
+ } else {
+ stop.setStartOdometer(startStop.getDouble(Position.KEY_TOTAL_DISTANCE));
+ stop.setEndOdometer(endStop.getDouble(Position.KEY_TOTAL_DISTANCE));
+ }
+
return stop;
}
- private static <T extends BaseReport> T calculateTripOrStop(ArrayList<Position> positions, int startIndex,
- int endIndex, boolean ignoreOdometer, Class<T> reportClass) {
+ private static <T extends BaseReport> T calculateTripOrStop(
+ ArrayList<Position> positions, int startIndex, int endIndex, boolean ignoreOdometer, Class<T> reportClass) {
+
if (reportClass.equals(TripReport.class)) {
return (T) calculateTrip(positions, startIndex, endIndex, ignoreOdometer);
} else {
- return (T) calculateStop(positions, startIndex, endIndex);
+ return (T) calculateStop(positions, startIndex, endIndex, ignoreOdometer);
}
}
@@ -289,12 +315,14 @@ public final class ReportUtils {
}
}
- public static <T extends BaseReport> Collection<T> detectTripsAndStops(Collection<Position> positionCollection,
+ public static <T extends BaseReport> Collection<T> detectTripsAndStops(
+ Collection<Position> positionCollection,
TripsConfig tripsConfig, boolean ignoreOdometer, Class<T> reportClass) {
+
Collection<T> result = new ArrayList<>();
ArrayList<Position> positions = new ArrayList<>(positionCollection);
- if (positions != null && !positions.isEmpty()) {
+ if (!positions.isEmpty()) {
boolean trips = reportClass.equals(TripReport.class);
MotionEventHandler motionHandler = new MotionEventHandler(tripsConfig);
DeviceState deviceState = new DeviceState();
@@ -333,6 +361,8 @@ public final class ReportUtils {
ignoreOdometer, reportClass));
}
}
+
return result;
}
+
}
diff --git a/src/org/traccar/reports/Summary.java b/src/org/traccar/reports/Summary.java
index 366e40421..d789a0a9b 100644
--- a/src/org/traccar/reports/Summary.java
+++ b/src/org/traccar/reports/Summary.java
@@ -62,6 +62,17 @@ public final class Summary {
result.setDistance(ReportUtils.calculateDistance(firstPosition, previousPosition, !ignoreOdometer));
result.setAverageSpeed(speedSum / positions.size());
result.setSpentFuel(ReportUtils.calculateFuel(firstPosition, previousPosition));
+
+ if (!ignoreOdometer
+ && firstPosition.getDouble(Position.KEY_ODOMETER) != 0
+ && previousPosition.getDouble(Position.KEY_ODOMETER) != 0) {
+ result.setStartOdometer(firstPosition.getDouble(Position.KEY_ODOMETER));
+ result.setEndOdometer(previousPosition.getDouble(Position.KEY_ODOMETER));
+ } else {
+ result.setStartOdometer(firstPosition.getDouble(Position.KEY_TOTAL_DISTANCE));
+ result.setEndOdometer(previousPosition.getDouble(Position.KEY_TOTAL_DISTANCE));
+ }
+
}
return result;
}
diff --git a/src/org/traccar/reports/model/BaseReport.java b/src/org/traccar/reports/model/BaseReport.java
index 941e2757f..9f2d1188c 100644
--- a/src/org/traccar/reports/model/BaseReport.java
+++ b/src/org/traccar/reports/model/BaseReport.java
@@ -84,4 +84,23 @@ public class BaseReport {
this.spentFuel = spentFuel;
}
+ private double startOdometer;
+
+ public double getStartOdometer() {
+ return startOdometer;
+ }
+
+ public void setStartOdometer(double startOdometer) {
+ this.startOdometer = startOdometer;
+ }
+ private double endOdometer;
+
+ public double getEndOdometer() {
+ return endOdometer;
+ }
+
+ public void setEndOdometer(double endOdometer) {
+ this.endOdometer = endOdometer;
+ }
+
}