diff options
Diffstat (limited to 'src/org/traccar')
26 files changed, 1101 insertions, 74 deletions
diff --git a/src/org/traccar/BasePipelineFactory.java b/src/org/traccar/BasePipelineFactory.java index 615251d5f..837712e84 100644 --- a/src/org/traccar/BasePipelineFactory.java +++ b/src/org/traccar/BasePipelineFactory.java @@ -229,7 +229,7 @@ public abstract class BasePipelineFactory implements ChannelPipelineFactory { pipeline.addLast("AlertEventHandler", alertEventHandler); } - if (alertEventHandler != null) { + if (ignitionEventHandler != null) { pipeline.addLast("IgnitionEventHandler", ignitionEventHandler); } diff --git a/src/org/traccar/BaseProtocolDecoder.java b/src/org/traccar/BaseProtocolDecoder.java index 00f45727f..15f5471e9 100644 --- a/src/org/traccar/BaseProtocolDecoder.java +++ b/src/org/traccar/BaseProtocolDecoder.java @@ -149,6 +149,9 @@ public abstract class BaseProtocolDecoder extends ExtendedObjectDecoder { @Override protected void onMessageEvent(Channel channel, SocketAddress remoteAddress, Object msg) { + if (Context.getStatisticsManager() != null) { + Context.getStatisticsManager().registerMessageReceived(); + } DeviceSession deviceSession = getDeviceSession(channel, remoteAddress); if (deviceSession != null) { Context.getConnectionManager().updateDevice(deviceSession.getDeviceId(), Device.STATUS_ONLINE, new Date()); diff --git a/src/org/traccar/Context.java b/src/org/traccar/Context.java index c7359e76c..827761cc5 100644 --- a/src/org/traccar/Context.java +++ b/src/org/traccar/Context.java @@ -16,6 +16,8 @@ package org.traccar; import com.ning.http.client.AsyncHttpClient; + +import org.traccar.database.AliasesManager; import org.traccar.database.ConnectionManager; import org.traccar.database.DataManager; import org.traccar.database.DeviceManager; @@ -23,6 +25,7 @@ import org.traccar.database.IdentityManager; import org.traccar.database.NotificationManager; import org.traccar.database.PermissionsManager; import org.traccar.database.GeofenceManager; +import org.traccar.database.StatisticsManager; import org.traccar.geocode.BingMapsReverseGeocoder; import org.traccar.geocode.FactualReverseGeocoder; import org.traccar.geocode.GeocodeFarmReverseGeocoder; @@ -134,13 +137,27 @@ public final class Context { return eventForwarder; } + private static AliasesManager aliasesManager; + + public static AliasesManager getAliasesManager() { + return aliasesManager; + } + + private static StatisticsManager statisticsManager; + + public static StatisticsManager getStatisticsManager() { + return statisticsManager; + } + public static void init(String[] arguments) throws Exception { config = new Config(); - if (arguments.length > 0) { - config.load(arguments[0]); + if (arguments.length <= 0) { + throw new RuntimeException("Configuration file is not provided"); } + config.load(arguments[0]); + loggerEnabled = config.getBoolean("logger.enable"); if (loggerEnabled) { Log.setupLogger(config); @@ -233,6 +250,10 @@ public final class Context { eventForwarder = new EventForwarder(); } + aliasesManager = new AliasesManager(dataManager); + + statisticsManager = new StatisticsManager(); + } public static void init(IdentityManager testIdentityManager) { diff --git a/src/org/traccar/MainEventHandler.java b/src/org/traccar/MainEventHandler.java index 3f7e68b2a..9f172c584 100644 --- a/src/org/traccar/MainEventHandler.java +++ b/src/org/traccar/MainEventHandler.java @@ -62,6 +62,7 @@ public class MainEventHandler extends IdleStateAwareChannelHandler { } Log.info(s.toString()); + Context.getStatisticsManager().registerMessageStored(position.getDeviceId()); } } diff --git a/src/org/traccar/api/SecurityRequestFilter.java b/src/org/traccar/api/SecurityRequestFilter.java index f0dd363db..9e0f03de7 100644 --- a/src/org/traccar/api/SecurityRequestFilter.java +++ b/src/org/traccar/api/SecurityRequestFilter.java @@ -69,6 +69,7 @@ public class SecurityRequestFilter implements ContainerRequestFilter { String[] auth = decodeBasicAuth(authHeader); User user = Context.getDataManager().login(auth[0], auth[1]); if (user != null) { + Context.getStatisticsManager().registerRequest(user.getId()); securityContext = new UserSecurityContext(new UserPrincipal(user.getId())); } } catch (SQLException e) { @@ -79,6 +80,7 @@ public class SecurityRequestFilter implements ContainerRequestFilter { Long userId = (Long) request.getSession().getAttribute(SessionResource.USER_ID_KEY); if (userId != null) { + Context.getStatisticsManager().registerRequest(userId); securityContext = new UserSecurityContext(new UserPrincipal(userId)); } diff --git a/src/org/traccar/api/resource/AttributeAliasResource.java b/src/org/traccar/api/resource/AttributeAliasResource.java new file mode 100644 index 000000000..2417fb0ec --- /dev/null +++ b/src/org/traccar/api/resource/AttributeAliasResource.java @@ -0,0 +1,90 @@ +/* + * 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.api.resource; + +import java.sql.SQLException; +import java.util.Collection; + +import javax.ws.rs.Consumes; +import javax.ws.rs.DELETE; +import javax.ws.rs.GET; +import javax.ws.rs.POST; +import javax.ws.rs.PUT; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.Produces; +import javax.ws.rs.QueryParam; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; + +import org.traccar.Context; +import org.traccar.api.BaseResource; +import org.traccar.model.AttributeAlias; + +@Path("attributes/aliases") +@Produces(MediaType.APPLICATION_JSON) +@Consumes(MediaType.APPLICATION_JSON) +public class AttributeAliasResource extends BaseResource { + + @GET + public Collection<AttributeAlias> get(@QueryParam("deviceId") long deviceId) throws SQLException { + if (deviceId != 0) { + if (!Context.getPermissionsManager().isAdmin(getUserId())) { + Context.getPermissionsManager().checkDevice(getUserId(), deviceId); + } + return Context.getAliasesManager().getAttributeAliases(deviceId); + } else { + return Context.getAliasesManager().getAllAttributeAliases(getUserId()); + } + } + + @POST + public Response add(AttributeAlias entity) throws SQLException { + Context.getPermissionsManager().checkReadonly(getUserId()); + if (!Context.getPermissionsManager().isAdmin(getUserId())) { + Context.getPermissionsManager().checkDevice(getUserId(), entity.getDeviceId()); + } + Context.getAliasesManager().addAttributeAlias(entity); + return Response.ok(entity).build(); + } + + @Path("{id}") + @PUT + public Response update(@PathParam("id") long id, AttributeAlias entity) throws SQLException { + Context.getPermissionsManager().checkReadonly(getUserId()); + if (!Context.getPermissionsManager().isAdmin(getUserId())) { + AttributeAlias oldEntity = Context.getAliasesManager().getAttributeAlias(entity.getId()); + Context.getPermissionsManager().checkDevice(getUserId(), oldEntity.getDeviceId()); + Context.getPermissionsManager().checkDevice(getUserId(), entity.getDeviceId()); + } + Context.getAliasesManager().updateAttributeAlias(entity); + return Response.ok(entity).build(); + } + + @Path("{id}") + @DELETE + public Response remove(@PathParam("id") long id) throws SQLException { + Context.getPermissionsManager().checkReadonly(getUserId()); + if (!Context.getPermissionsManager().isAdmin(getUserId())) { + AttributeAlias entity = Context.getAliasesManager().getAttributeAlias(id); + Context.getPermissionsManager().checkDevice(getUserId(), entity.getDeviceId()); + } + Context.getAliasesManager().removeArrtibuteAlias(id); + return Response.noContent().build(); + } + +} diff --git a/src/org/traccar/api/resource/DeviceResource.java b/src/org/traccar/api/resource/DeviceResource.java index b12ab8c36..56787b7bb 100644 --- a/src/org/traccar/api/resource/DeviceResource.java +++ b/src/org/traccar/api/resource/DeviceResource.java @@ -88,6 +88,7 @@ public class DeviceResource extends BaseResource { if (Context.getGeofenceManager() != null) { Context.getGeofenceManager().refresh(); } + Context.getAliasesManager().removeDevice(id); return Response.noContent().build(); } diff --git a/src/org/traccar/database/AliasesManager.java b/src/org/traccar/database/AliasesManager.java new file mode 100644 index 000000000..6c09e8731 --- /dev/null +++ b/src/org/traccar/database/AliasesManager.java @@ -0,0 +1,113 @@ +/* + * 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.database; + +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; + +import org.traccar.Context; +import org.traccar.helper.Log; +import org.traccar.model.AttributeAlias; + +public class AliasesManager { + + private final DataManager dataManager; + + private final Map<Long, Set<AttributeAlias>> deviceAliases = new ConcurrentHashMap<>(); + private final Map<Long, AttributeAlias> aliasesById = new ConcurrentHashMap<>(); + + public AliasesManager(DataManager dataManager) { + this.dataManager = dataManager; + if (dataManager != null) { + try { + for (AttributeAlias attributeAlias : dataManager.getAttributeAliases()) { + getAttributeAliases(attributeAlias.getDeviceId()) + .add(attributeAlias); + aliasesById.put(attributeAlias.getId(), attributeAlias); + } + } catch (SQLException error) { + Log.warning(error); + } + } + } + + public Set<AttributeAlias> getAttributeAliases(long deviceId) { + if (!deviceAliases.containsKey(deviceId)) { + deviceAliases.put(deviceId, new HashSet<AttributeAlias>()); + } + return deviceAliases.get(deviceId); + } + + public void removeDevice(long deviceId) { + for (AttributeAlias attributeAlias : getAttributeAliases(deviceId)) { + aliasesById.remove(attributeAlias.getId()); + } + deviceAliases.remove(deviceId); + } + + public void addAttributeAlias(AttributeAlias attributeAlias) throws SQLException { + dataManager.addAttributeAlias(attributeAlias); + aliasesById.put(attributeAlias.getId(), attributeAlias); + getAttributeAliases(attributeAlias.getDeviceId()).add(attributeAlias); + } + + public void updateAttributeAlias(AttributeAlias attributeAlias) throws SQLException { + dataManager.updateAttributeAlias(attributeAlias); + AttributeAlias cachedAlias = aliasesById.get(attributeAlias.getId()); + if (cachedAlias.getDeviceId() != attributeAlias.getDeviceId()) { + getAttributeAliases(cachedAlias.getDeviceId()).remove(cachedAlias); + cachedAlias.setDeviceId(attributeAlias.getDeviceId()); + getAttributeAliases(cachedAlias.getDeviceId()).add(cachedAlias); + } + cachedAlias.setAttribute(attributeAlias.getAttribute()); + cachedAlias.setAlias(attributeAlias.getAlias()); + } + + public void removeArrtibuteAlias(long attributeAliasId) throws SQLException { + dataManager.removeAttributeAlias(attributeAliasId); + AttributeAlias cachedAlias = aliasesById.get(attributeAliasId); + getAttributeAliases(cachedAlias.getDeviceId()).remove(cachedAlias); + aliasesById.remove(attributeAliasId); + } + + public AttributeAlias getAttributeAlias(long deviceId, String attribute) { + for (AttributeAlias alias : getAttributeAliases(deviceId)) { + if (alias.getAttribute().equals(attribute)) { + return alias; + } + } + return null; + } + + public Collection<AttributeAlias> getAllAttributeAliases(long userId) { + Collection<AttributeAlias> userDevicesAliases = new ArrayList<>(); + for (long deviceId : Context.getPermissionsManager().getDevicePermissions(userId)) { + userDevicesAliases.addAll(getAttributeAliases(deviceId)); + } + return userDevicesAliases; + } + + public AttributeAlias getAttributeAlias(long id) { + return aliasesById.get(id); + } + +} diff --git a/src/org/traccar/database/DataManager.java b/src/org/traccar/database/DataManager.java index abc48f063..c58fe40a5 100644 --- a/src/org/traccar/database/DataManager.java +++ b/src/org/traccar/database/DataManager.java @@ -37,6 +37,7 @@ import liquibase.resource.ResourceAccessor; import org.traccar.Config; import org.traccar.helper.Log; +import org.traccar.model.AttributeAlias; import org.traccar.model.Device; import org.traccar.model.DevicePermission; import org.traccar.model.Event; @@ -47,6 +48,7 @@ import org.traccar.model.GroupPermission; import org.traccar.model.Notification; import org.traccar.model.Position; import org.traccar.model.Server; +import org.traccar.model.Statistics; import org.traccar.model.User; import org.traccar.model.DeviceGeofence; import org.traccar.model.GeofencePermission; @@ -460,4 +462,39 @@ public class DataManager { .setLong("id", notification.getId()) .executeUpdate(); } + + public Collection<AttributeAlias> getAttributeAliases() throws SQLException { + return QueryBuilder.create(dataSource, getQuery("database.selectAttributeAliases")) + .executeQuery(AttributeAlias.class); + } + + public void addAttributeAlias(AttributeAlias attributeAlias) throws SQLException { + attributeAlias.setId(QueryBuilder.create(dataSource, getQuery("database.insertAttributeAlias"), true) + .setObject(attributeAlias) + .executeUpdate()); + } + + public void updateAttributeAlias(AttributeAlias attributeAlias) throws SQLException { + QueryBuilder.create(dataSource, getQuery("database.updateAttributeAlias")) + .setObject(attributeAlias) + .executeUpdate(); + } + + public void removeAttributeAlias(long attributeAliasId) throws SQLException { + QueryBuilder.create(dataSource, getQuery("database.deleteAttributeAlias")) + .setLong("id", attributeAliasId) + .executeUpdate(); + } + + public Collection<Statistics> getStatistics() throws SQLException { + return QueryBuilder.create(dataSource, getQuery("database.selectStatistics")) + .executeQuery(Statistics.class); + } + + public void addStatistics(Statistics statistics) throws SQLException { + statistics.setId(QueryBuilder.create(dataSource, getQuery("database.insertStatistics"), true) + .setObject(statistics) + .executeUpdate()); + } + } diff --git a/src/org/traccar/database/DeviceManager.java b/src/org/traccar/database/DeviceManager.java index 5f68df831..f32c7edd2 100644 --- a/src/org/traccar/database/DeviceManager.java +++ b/src/org/traccar/database/DeviceManager.java @@ -316,7 +316,87 @@ public class DeviceManager implements IdentityManager { groupsById.remove(groupId); } - public String lookupAttribute(long deviceId, String attributeName) { + public boolean lookupServerBoolean(long deviceId, String attributeName, boolean defaultValue) { + String result = lookupAttribute(deviceId, attributeName, true); + if (result != null) { + return Boolean.parseBoolean(result); + } + return defaultValue; + } + + public String lookupServerString(long deviceId, String attributeName, String defaultValue) { + String result = lookupAttribute(deviceId, attributeName, true); + if (result != null) { + return result; + } + return defaultValue; + } + + public int lookupServerInteger(long deviceId, String attributeName, int defaultValue) { + String result = lookupAttribute(deviceId, attributeName, true); + if (result != null) { + return Integer.parseInt(result); + } + return defaultValue; + } + + public long lookupServerLong(long deviceId, String attributeName, long defaultValue) { + String result = lookupAttribute(deviceId, attributeName, true); + if (result != null) { + return Long.parseLong(result); + } + return defaultValue; + } + + public double lookupServerDouble(long deviceId, String attributeName, double defaultValue) { + String result = lookupAttribute(deviceId, attributeName, true); + if (result != null) { + return Double.parseDouble(result); + } + return defaultValue; + } + + public boolean lookupConfigBoolean(long deviceId, String attributeName, boolean defaultValue) { + String result = lookupAttribute(deviceId, attributeName, false); + if (result != null) { + return Boolean.parseBoolean(result); + } + return defaultValue; + } + + public String lookupConfigString(long deviceId, String attributeName, String defaultValue) { + String result = lookupAttribute(deviceId, attributeName, false); + if (result != null) { + return result; + } + return defaultValue; + } + + public int lookupConfigInteger(long deviceId, String attributeName, int defaultValue) { + String result = lookupAttribute(deviceId, attributeName, false); + if (result != null) { + return Integer.parseInt(result); + } + return defaultValue; + } + + public long lookupConfigLong(long deviceId, String attributeName, long defaultValue) { + String result = lookupAttribute(deviceId, attributeName, false); + if (result != null) { + return Long.parseLong(result); + } + return defaultValue; + } + + public double lookupConfigDouble(long deviceId, String attributeName, double defaultValue) { + String result = lookupAttribute(deviceId, attributeName, false); + if (result != null) { + return Double.parseDouble(result); + } + return defaultValue; + } + + private String lookupAttribute(long deviceId, String attributeName, boolean lookupServer) { String result = null; Device device = getDeviceById(deviceId); if (device != null) { @@ -338,8 +418,12 @@ public class DeviceManager implements IdentityManager { } } if (result == null) { - Server server = Context.getPermissionsManager().getServer(); - result = (String) server.getAttributes().get(attributeName); + if (lookupServer) { + Server server = Context.getPermissionsManager().getServer(); + result = (String) server.getAttributes().get(attributeName); + } else { + result = Context.getConfig().getString(attributeName); + } } } return result; diff --git a/src/org/traccar/database/StatisticsManager.java b/src/org/traccar/database/StatisticsManager.java new file mode 100644 index 000000000..b9af4d9b7 --- /dev/null +++ b/src/org/traccar/database/StatisticsManager.java @@ -0,0 +1,88 @@ +/* + * Copyright 2016 Anton Tananaev (anton.tananaev@gmail.com) + * + * 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.Context; +import org.traccar.helper.Log; +import org.traccar.model.Statistics; + +import java.sql.SQLException; +import java.util.Calendar; +import java.util.Date; +import java.util.HashSet; +import java.util.Set; + +public class StatisticsManager { + + private static final int SPLIT_MODE = Calendar.DAY_OF_MONTH; + + private int lastUpdate = Calendar.getInstance().get(SPLIT_MODE); + + private Set<Long> users = new HashSet<>(); + private Set<Long> devices = new HashSet<>(); + + private int requests; + private int messagesReceived; + private int messagesStored; + + private void checkSplit() { + int currentUpdate = Calendar.getInstance().get(SPLIT_MODE); + if (lastUpdate != currentUpdate) { + Statistics statistics = new Statistics(); + statistics.setCaptureTime(new Date()); + statistics.setActiveUsers(users.size()); + statistics.setActiveDevices(devices.size()); + statistics.setRequests(requests); + statistics.setMessagesReceived(messagesReceived); + statistics.setMessagesStored(messagesStored); + + try { + Context.getDataManager().addStatistics(statistics); + } catch (SQLException e) { + Log.warning(e); + } + + users.clear(); + devices.clear(); + requests = 0; + messagesReceived = 0; + messagesStored = 0; + lastUpdate = currentUpdate; + } + } + + public synchronized void registerRequest(long userId) { + checkSplit(); + requests += 1; + if (userId != 0) { + users.add(userId); + } + } + + public synchronized void registerMessageReceived() { + checkSplit(); + messagesReceived += 1; + } + + public synchronized void registerMessageStored(long deviceId) { + checkSplit(); + messagesStored += 1; + if (deviceId != 0) { + devices.add(deviceId); + } + } + +} diff --git a/src/org/traccar/events/OverspeedEventHandler.java b/src/org/traccar/events/OverspeedEventHandler.java index 302fa87cd..57f60d864 100644 --- a/src/org/traccar/events/OverspeedEventHandler.java +++ b/src/org/traccar/events/OverspeedEventHandler.java @@ -47,11 +47,8 @@ public class OverspeedEventHandler extends BaseEventHandler { Collection<Event> events = new ArrayList<>(); double speed = position.getSpeed(); - double speedLimit = 0; - String speedLimitAttribute = Context.getDeviceManager().lookupAttribute(device.getId(), ATTRIBUTE_SPEED_LIMIT); - if (speedLimitAttribute != null) { - speedLimit = Double.parseDouble(speedLimitAttribute); - } + double speedLimit = Context.getDeviceManager() + .lookupServerDouble(device.getId(), ATTRIBUTE_SPEED_LIMIT, 0); if (speedLimit == 0) { return null; } diff --git a/src/org/traccar/model/AttributeAlias.java b/src/org/traccar/model/AttributeAlias.java new file mode 100644 index 000000000..023925ac3 --- /dev/null +++ b/src/org/traccar/model/AttributeAlias.java @@ -0,0 +1,61 @@ +/* + * 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.model; + +public class AttributeAlias { + + private long id; + + public long getId() { + return id; + } + + public void setId(long id) { + this.id = id; + } + + private long deviceId; + + public long getDeviceId() { + return deviceId; + } + + public void setDeviceId(long deviceId) { + this.deviceId = deviceId; + } + + private String attribute; + + public String getAttribute() { + return attribute; + } + + public void setAttribute(String attribute) { + this.attribute = attribute; + } + + private String alias; + + public String getAlias() { + return alias; + } + + public void setAlias(String alias) { + this.alias = alias; + } + +} diff --git a/src/org/traccar/model/Position.java b/src/org/traccar/model/Position.java index 710dd1e83..c1058aef9 100644 --- a/src/org/traccar/model/Position.java +++ b/src/org/traccar/model/Position.java @@ -57,6 +57,7 @@ public class Position extends Message { public static final String KEY_THROTTLE = "throttle"; public static final String KEY_MOTION = "motion"; public static final String KEY_ARMED = "armed"; + public static final String KEY_ACCURACY = "accuracy"; public static final String KEY_OBD_SPEED = "obdSpeed"; public static final String KEY_OBD_ODOMETER = "obdOdometer"; diff --git a/src/org/traccar/model/Statistics.java b/src/org/traccar/model/Statistics.java new file mode 100644 index 000000000..0461ebd7e --- /dev/null +++ b/src/org/traccar/model/Statistics.java @@ -0,0 +1,90 @@ +/* + * Copyright 2016 Anton Tananaev (anton.tananaev@gmail.com) + * + * 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; + +import java.util.Date; + +public class Statistics extends Extensible { + + private Date captureTime; + + public Date getCaptureTime() { + if (captureTime != null) { + return new Date(captureTime.getTime()); + } else { + return null; + } + } + + public void setCaptureTime(Date captureTime) { + if (captureTime != null) { + this.captureTime = new Date(captureTime.getTime()); + } else { + this.captureTime = null; + } + } + + private int activeUsers; + + public int getActiveUsers() { + return activeUsers; + } + + public void setActiveUsers(int activeUsers) { + this.activeUsers = activeUsers; + } + + private int activeDevices; + + public int getActiveDevices() { + return activeDevices; + } + + public void setActiveDevices(int activeDevices) { + this.activeDevices = activeDevices; + } + + private int requests; + + public int getRequests() { + return requests; + } + + public void setRequests(int requests) { + this.requests = requests; + } + + private int messagesReceived; + + public int getMessagesReceived() { + return messagesReceived; + } + + public void setMessagesReceived(int messagesReceived) { + this.messagesReceived = messagesReceived; + } + + private int messagesStored; + + public int getMessagesStored() { + return messagesStored; + } + + public void setMessagesStored(int messagesStored) { + this.messagesStored = messagesStored; + } + +} diff --git a/src/org/traccar/protocol/AplicomProtocolDecoder.java b/src/org/traccar/protocol/AplicomProtocolDecoder.java index 23397b51c..d1f92ea0a 100644 --- a/src/org/traccar/protocol/AplicomProtocolDecoder.java +++ b/src/org/traccar/protocol/AplicomProtocolDecoder.java @@ -1,5 +1,5 @@ /* - * Copyright 2013 - 2015 Anton Tananaev (anton.tananaev@gmail.com) + * Copyright 2013 - 2016 Anton Tananaev (anton.tananaev@gmail.com) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -27,6 +27,7 @@ import org.traccar.helper.UnitsConverter; import org.traccar.model.Position; import java.net.SocketAddress; +import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.Date; @@ -75,11 +76,12 @@ public class AplicomProtocolDecoder extends BaseProtocolDecoder { return unitId; } - private static final int DEFAULT_SELECTOR = 0x0002FC; + private static final int DEFAULT_SELECTOR_D = 0x0002fC; + private static final int DEFAULT_SELECTOR_E = 0x007ffc; private static final int EVENT_DATA = 119; - private void decodeEventData(int event, ChannelBuffer buf) { + private void decodeEventData(Position position, ChannelBuffer buf, int event) { switch (event) { case 2: case 40: @@ -106,6 +108,9 @@ public class AplicomProtocolDecoder extends BaseProtocolDecoder { case 130: buf.readUnsignedInt(); // incorrect break; + case 188: + decodeEB(position, buf); + break; default: break; } @@ -191,44 +196,12 @@ public class AplicomProtocolDecoder extends BaseProtocolDecoder { } } - @Override - protected Object decode(Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { - - ChannelBuffer buf = (ChannelBuffer) msg; - - buf.readUnsignedByte(); // marker - int version = buf.readUnsignedByte(); - - String imei; - if ((version & 0x80) != 0) { - imei = String.valueOf((buf.readUnsignedInt() << (3 * 8)) | buf.readUnsignedMedium()); - } else { - imei = String.valueOf(imeiFromUnitId(buf.readUnsignedMedium())); - } - - buf.readUnsignedShort(); // length - - int selector = DEFAULT_SELECTOR; - if ((version & 0x40) != 0) { - selector = buf.readUnsignedMedium(); - } - - Position position = new Position(); - position.setProtocol(getProtocolName()); - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, imei); - if (deviceSession == null) { - return null; - } - position.setDeviceId(deviceSession.getDeviceId()); - - int event = buf.readUnsignedByte(); - position.set(Position.KEY_EVENT, event); - position.set("eventInfo", buf.readUnsignedByte()); + private void decodeD(Position position, ChannelBuffer buf, int selector, int event) { if ((selector & 0x0008) != 0) { position.setValid((buf.readUnsignedByte() & 0x40) != 0); } else { - return null; // no location data + getLastLocation(position, null); } if ((selector & 0x0004) != 0) { @@ -313,14 +286,261 @@ public class AplicomProtocolDecoder extends BaseProtocolDecoder { } if ((selector & 0x1000) != 0) { - decodeEventData(event, buf); + decodeEventData(position, buf, event); } if (Context.getConfig().getBoolean(getProtocolName() + ".can") && buf.readable() && (selector & 0x1000) != 0 && event == EVENT_DATA) { - decodeCanData(buf, position); } + } + + private void decodeE(Position position, ChannelBuffer buf, int selector) { + + if ((selector & 0x0008) != 0) { + position.set("tachographEvent", buf.readUnsignedShort()); + } + + if ((selector & 0x0004) != 0) { + getLastLocation(position, new Date(buf.readUnsignedInt() * 1000)); + } else { + getLastLocation(position, null); + } + + if ((selector & 0x0010) != 0) { + String time = buf.readUnsignedByte() + "s " + buf.readUnsignedByte() + "m " + buf.readUnsignedByte() + "h " + + buf.readUnsignedByte() + "M " + buf.readUnsignedByte() + "D " + buf.readUnsignedByte() + "Y " + + buf.readByte() + "m " + buf.readByte() + "h"; + position.set("tachographTime", time); + } + + position.set("workState", buf.readUnsignedByte()); + position.set("driver1State", buf.readUnsignedByte()); + position.set("driver2State", buf.readUnsignedByte()); + + if ((selector & 0x0020) != 0) { + position.set("tachographStatus", buf.readUnsignedByte()); + } + + if ((selector & 0x0040) != 0) { + position.set(Position.KEY_OBD_SPEED, buf.readUnsignedShort() / 256.0); + } + + if ((selector & 0x0080) != 0) { + position.set(Position.KEY_OBD_ODOMETER, buf.readUnsignedInt() * 5); + } + + if ((selector & 0x0100) != 0) { + position.set(Position.KEY_TRIP_ODOMETER, buf.readUnsignedInt() * 5); + } + + if ((selector & 0x8000) != 0) { + position.set("kFactor", buf.readUnsignedShort() * 0.001 + " pulses/m"); + } + + if ((selector & 0x0200) != 0) { + position.set(Position.KEY_RPM, buf.readUnsignedShort() * 0.125); + } + + if ((selector & 0x0400) != 0) { + position.set("extraInfo", buf.readUnsignedShort()); + } + + if ((selector & 0x0800) != 0) { + position.set(Position.KEY_VIN, buf.readBytes(18).toString(StandardCharsets.US_ASCII).trim()); + } + } + + private void decodeH(Position position, ChannelBuffer buf, int selector) { + + if ((selector & 0x0004) != 0) { + getLastLocation(position, new Date(buf.readUnsignedInt() * 1000)); + } else { + getLastLocation(position, null); + } + + if ((selector & 0x0040) != 0) { + buf.readUnsignedInt(); // reset time + } + + if ((selector & 0x2000) != 0) { + buf.readUnsignedShort(); // snapshot counter + } + + int index = 1; + while (buf.readableBytes() > 0) { + + position.set("h" + index + "Index", buf.readUnsignedByte()); + + buf.readUnsignedShort(); // length + + int n = buf.readUnsignedByte(); + int m = buf.readUnsignedByte(); + + position.set("h" + index + "XLength", n); + position.set("h" + index + "YLength", m); + + if ((selector & 0x0008) != 0) { + position.set("h" + index + "XType", buf.readUnsignedByte()); + position.set("h" + index + "YType", buf.readUnsignedByte()); + position.set("h" + index + "Parameters", buf.readUnsignedByte()); + } + + boolean percentageFormat = (selector & 0x0020) != 0; + + StringBuilder data = new StringBuilder(); + for (int i = 0; i < n * m; i++) { + if (percentageFormat) { + data.append(buf.readUnsignedByte() * 0.5).append("%").append(" "); + } else { + data.append(buf.readUnsignedShort()).append(" "); + } + } + + position.set("h" + index + "Data", data.toString().trim()); + + position.set("h" + index + "Total", buf.readUnsignedInt()); + + if ((selector & 0x0010) != 0) { + int k = buf.readUnsignedByte(); + + data = new StringBuilder(); + for (int i = 1; i < n; i++) { + if (k == 1) { + data.append(buf.readByte()).append(" "); + } else if (k == 2) { + data.append(buf.readShort()).append(" "); + } + } + position.set("h" + index + "XLimits", data.toString().trim()); + + data = new StringBuilder(); + for (int i = 1; i < m; i++) { + if (k == 1) { + data.append(buf.readByte()).append(" "); + } else if (k == 2) { + data.append(buf.readShort()).append(" "); + } + } + position.set("h" + index + "YLimits", data.toString().trim()); + } + + index += 1; + } + } + + private void decodeEB(Position position, ChannelBuffer buf) { + + if (buf.readByte() != (byte) 'E' || buf.readByte() != (byte) 'B') { + return; + } + + buf.readUnsignedByte(); // version + buf.readUnsignedShort(); // event + buf.readUnsignedByte(); // data validity + buf.readUnsignedByte(); // towed + buf.readUnsignedShort(); // length + + while (buf.readableBytes() > 0) { + buf.readUnsignedByte(); // towed position + int type = buf.readUnsignedByte(); + int length = buf.readUnsignedByte(); + + if (type == 0x01) { + position.set("brakeFlags", ChannelBuffers.hexDump(buf.readBytes(length))); + } else if (type == 0x02) { + position.set("wheelSpeed", buf.readUnsignedShort() / 256.0); + position.set("wheelSpeedDifference", buf.readUnsignedShort() / 256.0 - 125.0); + position.set("lateralAcceleration", buf.readUnsignedByte() / 10.0 - 12.5); + position.set("vehicleSpeed", buf.readUnsignedShort() / 256.0); + } else if (type == 0x03) { + position.set("axleLoadSum", buf.readUnsignedShort() * 2); + } else if (type == 0x04) { + position.set("tyrePressure", buf.readUnsignedByte() * 10); + position.set("pneumaticPressure", buf.readUnsignedByte() * 5); + } else if (type == 0x05) { + position.set("brakeLining", buf.readUnsignedByte() * 0.4); + position.set("brakeTemperature", buf.readUnsignedByte() * 10); + } else if (type == 0x06) { + position.set("totalDistance", buf.readUnsignedInt() * 5); + position.set("tripDistance", buf.readUnsignedInt() * 5); + position.set("serviceDistance", (buf.readUnsignedInt() - 2105540607) * 5); + } else if (type == 0x0A) { + position.set("brakeData", ChannelBuffers.hexDump(buf.readBytes(length))); + } else if (type == 0x0B) { + position.set("brakeMinMaxData", ChannelBuffers.hexDump(buf.readBytes(length))); + } else if (type == 0x0C) { + position.set("missingPgn", ChannelBuffers.hexDump(buf.readBytes(length))); + } else if (type == 0x0D) { + switch (buf.readUnsignedByte()) { + case 1: + position.set("brakeManufacturer", "Wabco"); + break; + case 2: + position.set("brakeManufacturer", "Knorr"); + break; + case 3: + position.set("brakeManufacturer", "Haldex"); + break; + default: + position.set("brakeManufacturer", "Unknown"); + break; + } + buf.readUnsignedByte(); + buf.readBytes(17); // vin + position.set("towedDetectionStatus", buf.readUnsignedByte()); + } else if (type == 0x0E) { + buf.skipBytes(length); + } + } + } + + @Override + protected Object decode(Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { + + ChannelBuffer buf = (ChannelBuffer) msg; + + char protocol = (char) buf.readByte(); + int version = buf.readUnsignedByte(); + + String imei; + if ((version & 0x80) != 0) { + imei = String.valueOf((buf.readUnsignedInt() << (3 * 8)) | buf.readUnsignedMedium()); + } else { + imei = String.valueOf(imeiFromUnitId(buf.readUnsignedMedium())); + } + + buf.readUnsignedShort(); // length + + int selector = DEFAULT_SELECTOR_D; + if (protocol == 'E') { + selector = DEFAULT_SELECTOR_E; + } + if ((version & 0x40) != 0) { + selector = buf.readUnsignedMedium(); + } + + Position position = new Position(); + position.setProtocol(getProtocolName()); + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, imei); + if (deviceSession == null) { + return null; + } + position.setDeviceId(deviceSession.getDeviceId()); + + int event = buf.readUnsignedByte(); + position.set(Position.KEY_EVENT, event); + position.set("eventInfo", buf.readUnsignedByte()); + + if (protocol == 'D') { + decodeD(position, buf, selector, event); + } else if (protocol == 'E') { + decodeE(position, buf, selector); + } else if (protocol == 'H') { + decodeH(position, buf, selector); + } else { + return null; + } return position; } diff --git a/src/org/traccar/protocol/CellocatorProtocol.java b/src/org/traccar/protocol/CellocatorProtocol.java index 6d8eea8f5..e5f6ac8f6 100644 --- a/src/org/traccar/protocol/CellocatorProtocol.java +++ b/src/org/traccar/protocol/CellocatorProtocol.java @@ -15,6 +15,7 @@ */ package org.traccar.protocol; +import org.jboss.netty.bootstrap.ConnectionlessBootstrap; import org.jboss.netty.bootstrap.ServerBootstrap; import org.jboss.netty.channel.ChannelPipeline; import org.traccar.BaseProtocol; @@ -40,6 +41,15 @@ public class CellocatorProtocol extends BaseProtocol { }; server.setEndianness(ByteOrder.LITTLE_ENDIAN); serverList.add(server); + + server = new TrackerServer(new ConnectionlessBootstrap(), getName()) { + @Override + protected void addSpecificHandlers(ChannelPipeline pipeline) { + pipeline.addLast("objectDecoder", new CellocatorProtocolDecoder(CellocatorProtocol.this)); + } + }; + server.setEndianness(ByteOrder.LITTLE_ENDIAN); + serverList.add(server); } } diff --git a/src/org/traccar/protocol/CguardProtocol.java b/src/org/traccar/protocol/CguardProtocol.java new file mode 100644 index 000000000..1e6d212c8 --- /dev/null +++ b/src/org/traccar/protocol/CguardProtocol.java @@ -0,0 +1,47 @@ +/* + * Copyright 2016 Anton Tananaev (anton.tananaev@gmail.com) + * + * 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.protocol; + +import org.jboss.netty.bootstrap.ServerBootstrap; +import org.jboss.netty.channel.ChannelPipeline; +import org.jboss.netty.handler.codec.frame.LineBasedFrameDecoder; +import org.jboss.netty.handler.codec.string.StringDecoder; +import org.jboss.netty.handler.codec.string.StringEncoder; +import org.traccar.BaseProtocol; +import org.traccar.TrackerServer; + +import java.util.List; + +public class CguardProtocol extends BaseProtocol { + + public CguardProtocol() { + super("cguard"); + } + + @Override + public void initTrackerServers(List<TrackerServer> serverList) { + serverList.add(new TrackerServer(new ServerBootstrap(), getName()) { + @Override + protected void addSpecificHandlers(ChannelPipeline pipeline) { + pipeline.addLast("frameDecoder", new LineBasedFrameDecoder(1024)); + pipeline.addLast("stringDecoder", new StringDecoder()); + pipeline.addLast("stringEncoder", new StringEncoder()); + pipeline.addLast("objectDecoder", new CguardProtocolDecoder(CguardProtocol.this)); + } + }); + } + +} diff --git a/src/org/traccar/protocol/CguardProtocolDecoder.java b/src/org/traccar/protocol/CguardProtocolDecoder.java new file mode 100644 index 000000000..1646363e5 --- /dev/null +++ b/src/org/traccar/protocol/CguardProtocolDecoder.java @@ -0,0 +1,91 @@ +/* + * Copyright 2016 Anton Tananaev (anton.tananaev@gmail.com) + * + * 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.protocol; + +import org.jboss.netty.channel.Channel; +import org.traccar.BaseProtocolDecoder; +import org.traccar.DeviceSession; +import org.traccar.helper.DateBuilder; +import org.traccar.helper.Parser; +import org.traccar.helper.PatternBuilder; +import org.traccar.helper.UnitsConverter; +import org.traccar.model.Position; + +import java.net.SocketAddress; +import java.util.regex.Pattern; + +public class CguardProtocolDecoder extends BaseProtocolDecoder { + + public CguardProtocolDecoder(CguardProtocol protocol) { + super(protocol); + } + + private static final Pattern PATTERN = new PatternBuilder() + .text("NV:") + .number("(dd)(dd)(dd) ") // date + .number("(dd)(dd)(dd):") // time + .number("(-?d+.d+):") // longitude + .number("(-?d+.d+):") // latitude + .number("(d+.?d*):") // speed + .number("(?:NAN|(d+.?d*)):") // accuracy + .number("(?:NAN|(d+.?d*)):") // course + .number("(?:NAN|(d+.?d*))") // altitude + .compile(); + + @Override + protected Object decode( + Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { + + String sentence = (String) msg; + + if (sentence.startsWith("ID:") || sentence.startsWith("IDRO:")) { + getDeviceSession(channel, remoteAddress, sentence.substring(sentence.indexOf(':') + 1)); + return null; + } + + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress); + if (deviceSession == null) { + return null; + } + + Parser parser = new Parser(PATTERN, (String) msg); + if (!parser.matches()) { + return null; + } + + Position position = new Position(); + position.setProtocol(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + DateBuilder dateBuilder = new DateBuilder() + .setDate(parser.nextInt(), parser.nextInt(), parser.nextInt()) + .setTime(parser.nextInt(), parser.nextInt(), parser.nextInt()); + position.setTime(dateBuilder.getDate()); + + position.setValid(true); + position.setLatitude(parser.nextDouble()); + position.setLongitude(parser.nextDouble()); + position.setSpeed(UnitsConverter.knotsFromKph(parser.nextDouble())); + + position.set(Position.KEY_ACCURACY, parser.nextDouble()); + + position.setCourse(parser.nextDouble()); + position.setAltitude(parser.nextDouble()); + + return position; + } + +} diff --git a/src/org/traccar/protocol/Gt06ProtocolEncoder.java b/src/org/traccar/protocol/Gt06ProtocolEncoder.java index e478424f9..e78a1b388 100644 --- a/src/org/traccar/protocol/Gt06ProtocolEncoder.java +++ b/src/org/traccar/protocol/Gt06ProtocolEncoder.java @@ -66,9 +66,9 @@ public class Gt06ProtocolEncoder extends BaseProtocolEncoder { switch (command.getType()) { case Command.TYPE_ENGINE_STOP: - return encodeContent(alternative ? "DYD,123456#\r\n" : "Relay,1#"); + return encodeContent(alternative ? "DYD,123456#" : "Relay,1#"); case Command.TYPE_ENGINE_RESUME: - return encodeContent(alternative ? "HFYD,123456#\r\n" : "Relay,0#"); + return encodeContent(alternative ? "HFYD,123456#" : "Relay,0#"); default: Log.warning(new UnsupportedOperationException(command.getType())); break; diff --git a/src/org/traccar/protocol/Jt600ProtocolDecoder.java b/src/org/traccar/protocol/Jt600ProtocolDecoder.java index b7193d24b..b30bd7b85 100644 --- a/src/org/traccar/protocol/Jt600ProtocolDecoder.java +++ b/src/org/traccar/protocol/Jt600ProtocolDecoder.java @@ -1,5 +1,5 @@ /* - * Copyright 2012 - 2015 Anton Tananaev (anton.tananaev@gmail.com) + * Copyright 2012 - 2016 Anton Tananaev (anton.tananaev@gmail.com) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -43,7 +43,7 @@ public class Jt600ProtocolDecoder extends BaseProtocolDecoder { return degrees + minutes / 60; } - private Position decodeNormalMessage(ChannelBuffer buf, Channel channel, SocketAddress remoteAddress) { + private Position decodeBinary(ChannelBuffer buf, Channel channel, SocketAddress remoteAddress) { Position position = new Position(); position.setProtocol(getProtocolName()); @@ -120,7 +120,7 @@ public class Jt600ProtocolDecoder extends BaseProtocolDecoder { return position; } - private static final Pattern PATTERN = new PatternBuilder() + private static final Pattern PATTERN_W01 = new PatternBuilder() .text("(") .number("(d+),") // id .text("W01,") // type @@ -138,25 +138,22 @@ public class Jt600ProtocolDecoder extends BaseProtocolDecoder { .number("(d+),") // gsm signal .number("(d+),") // alert type .any() - .text(")") .compile(); - private Position decodeAlertMessage(ChannelBuffer buf, Channel channel, SocketAddress remoteAddress) { + private Position decodeW01(String sentence, Channel channel, SocketAddress remoteAddress) { - Parser parser = new Parser(PATTERN, buf.toString(StandardCharsets.US_ASCII)); + Parser parser = new Parser(PATTERN_W01, sentence); if (!parser.matches()) { return null; } - Position position = new Position(); - position.setProtocol(getProtocolName()); - - position.set(Position.KEY_ALARM, Position.ALARM_GENERAL); - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); if (deviceSession == null) { return null; } + + Position position = new Position(); + position.setProtocol(getProtocolName()); position.setDeviceId(deviceSession.getDeviceId()); position.setLongitude(parser.nextCoordinate()); @@ -176,6 +173,68 @@ public class Jt600ProtocolDecoder extends BaseProtocolDecoder { return position; } + private static final Pattern PATTERN_U01 = new PatternBuilder() + .text("(") + .number("(d+),") // id + .number("Udd,") // type + .number("d+,").optional() // alarm + .number("(dd)(dd)(dd),") // date (ddmmyy) + .number("(dd)(dd)(dd),") // time + .expression("([TF]),") // validity + .number("(d+.d+),([NS]),") // latitude + .number("(d+.d+),([EW]),") // longitude + .number("(d+.?d*),") // speed + .number("(d+),") // course + .number("(d+),") // satellites + .number("(d+%),") // battery + .expression("([01]+),") // status + .number("(d+),") // cid + .number("(d+),") // lac + .number("(d+),") // gsm signal + .number("(d+),") // odometer + .number("(d+)") // index + .any() + .compile(); + + private Position decodeU01(String sentence, Channel channel, SocketAddress remoteAddress) { + + Parser parser = new Parser(PATTERN_U01, sentence); + if (!parser.matches()) { + return null; + } + + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); + if (deviceSession == null) { + return null; + } + + Position position = new Position(); + position.setProtocol(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + DateBuilder dateBuilder = new DateBuilder() + .setDateReverse(parser.nextInt(), parser.nextInt(), parser.nextInt()) + .setTime(parser.nextInt(), parser.nextInt(), parser.nextInt()); + position.setTime(dateBuilder.getDate()); + + position.setValid(parser.next().equals("T")); + position.setLatitude(parser.nextCoordinate(Parser.CoordinateFormat.DEG_HEM)); + position.setLongitude(parser.nextCoordinate(Parser.CoordinateFormat.DEG_HEM)); + + position.setSpeed(UnitsConverter.knotsFromMph(parser.nextDouble())); + position.setCourse(parser.nextDouble()); + + position.set(Position.KEY_SATELLITES, parser.nextInt()); + position.set(Position.KEY_BATTERY, parser.next()); + position.set(Position.KEY_STATUS, parser.nextInt(2)); + position.set(Position.KEY_CID, parser.nextInt()); + position.set(Position.KEY_LAC, parser.nextInt()); + position.set(Position.KEY_GSM, parser.nextInt()); + position.set(Position.KEY_ODOMETER, parser.nextLong() * 1000); + position.set(Position.KEY_INDEX, parser.nextInt()); + + return position; + } @Override protected Object decode( Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { @@ -184,9 +243,14 @@ public class Jt600ProtocolDecoder extends BaseProtocolDecoder { char first = (char) buf.getByte(0); if (first == '$') { - return decodeNormalMessage(buf, channel, remoteAddress); + return decodeBinary(buf, channel, remoteAddress); } else if (first == '(') { - return decodeAlertMessage(buf, channel, remoteAddress); + String sentence = buf.toString(StandardCharsets.US_ASCII); + if (sentence.contains("W01")) { + return decodeW01(sentence, channel, remoteAddress); + } else { + return decodeU01(sentence, channel, remoteAddress); + } } return null; diff --git a/src/org/traccar/protocol/OigoProtocolDecoder.java b/src/org/traccar/protocol/OigoProtocolDecoder.java index 799f47ea3..bbea38183 100644 --- a/src/org/traccar/protocol/OigoProtocolDecoder.java +++ b/src/org/traccar/protocol/OigoProtocolDecoder.java @@ -54,7 +54,7 @@ public class OigoProtocolDecoder extends BaseProtocolDecoder { DeviceSession deviceSession; switch (BitUtil.to(tag, 3)) { case 0: - String imei = ChannelBuffers.hexDump(buf.readBytes(9)).substring(1, 1 + 15); + String imei = ChannelBuffers.hexDump(buf.readBytes(8)).substring(1); deviceSession = getDeviceSession(channel, remoteAddress, imei); break; case 1: @@ -75,6 +75,8 @@ public class OigoProtocolDecoder extends BaseProtocolDecoder { position.setProtocol(getProtocolName()); position.setDeviceId(deviceSession.getDeviceId()); + position.set(Position.KEY_EVENT, buf.readUnsignedByte()); + int mask = buf.readInt(); if (BitUtil.check(mask, 0)) { diff --git a/src/org/traccar/reports/Summary.java b/src/org/traccar/reports/Summary.java index 44fb1dd4c..d4171f644 100644 --- a/src/org/traccar/reports/Summary.java +++ b/src/org/traccar/reports/Summary.java @@ -37,7 +37,7 @@ public final class Summary { private static SummaryReport calculateSummaryResult(long deviceId, Date from, Date to) throws SQLException { SummaryReport result = new SummaryReport(); result.setDeviceId(deviceId); - result.setDeviceName(Context.getDeviceManager().getDeviceById(deviceId).getName()); + result.setDeviceName(Context.getIdentityManager().getDeviceById(deviceId).getName()); Collection<Position> positions = Context.getDataManager().getPositions(deviceId, from, to); if (positions != null && !positions.isEmpty()) { Position firstPosition = null; @@ -60,7 +60,9 @@ public final class Summary { speedSum += position.getSpeed(); result.setMaxSpeed(position.getSpeed()); } - result.setDistance(ReportUtils.calculateDistance(firstPosition, previousPosition)); + boolean ignoreOdometer = Context.getDeviceManager() + .lookupConfigBoolean(deviceId, "report.ignoreOdometer", false); + result.setDistance(ReportUtils.calculateDistance(firstPosition, previousPosition, !ignoreOdometer)); result.setAverageSpeed(speedSum / positions.size()); } return result; diff --git a/src/org/traccar/reports/Trips.java b/src/org/traccar/reports/Trips.java index 2171d5f93..f0a10edbd 100644 --- a/src/org/traccar/reports/Trips.java +++ b/src/org/traccar/reports/Trips.java @@ -53,15 +53,16 @@ public final class Trips { 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.setDeviceName(Context.getIdentityManager().getDeviceById(deviceId).getName()); 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)); + boolean ignoreOdometer = Context.getDeviceManager() + .lookupConfigBoolean(deviceId, "report.ignoreOdometer", false); + trip.setDistance(ReportUtils.calculateDistance(startTrip, endTrip, !ignoreOdometer)); trip.setDuration(tripDuration); trip.setAverageSpeed(speedSum / (endIndex - startIndex)); trip.setMaxSpeed(speedMax); diff --git a/src/org/traccar/web/CsvBuilder.java b/src/org/traccar/web/CsvBuilder.java index a25b839a9..f59aabc7f 100644 --- a/src/org/traccar/web/CsvBuilder.java +++ b/src/org/traccar/web/CsvBuilder.java @@ -37,10 +37,10 @@ public class CsvBuilder { SortedSet<Method> methods = new TreeSet<Method>(new Comparator<Method>() { @Override public int compare(Method m1, Method m2) { - if (m1.getName().equals("getAttributes") & !m1.getName().equals(m2.getName())) { + if (m1.getName().equals("getAttributes") && !m1.getName().equals(m2.getName())) { return 1; } - if (m2.getName().equals("getAttributes") & !m1.getName().equals(m2.getName())) { + if (m2.getName().equals("getAttributes") && !m1.getName().equals(m2.getName())) { return -1; } return m1.getName().compareTo(m2.getName()); diff --git a/src/org/traccar/web/WebServer.java b/src/org/traccar/web/WebServer.java index e022a9285..ec15ea2be 100644 --- a/src/org/traccar/web/WebServer.java +++ b/src/org/traccar/web/WebServer.java @@ -34,6 +34,7 @@ import org.traccar.api.CorsResponseFilter; import org.traccar.api.ObjectMapperProvider; import org.traccar.api.ResourceErrorHandler; import org.traccar.api.SecurityRequestFilter; +import org.traccar.api.resource.AttributeAliasResource; import org.traccar.api.resource.CommandResource; import org.traccar.api.resource.GroupPermissionResource; import org.traccar.api.resource.ServerResource; @@ -161,7 +162,7 @@ public class WebServer { GroupResource.class, DeviceResource.class, PositionResource.class, CommandTypeResource.class, EventResource.class, GeofenceResource.class, DeviceGeofenceResource.class, GeofencePermissionResource.class, GroupGeofenceResource.class, - NotificationResource.class, ReportResource.class); + NotificationResource.class, ReportResource.class, AttributeAliasResource.class); servletHandler.addServlet(new ServletHolder(new ServletContainer(resourceConfig)), "/*"); handlers.addHandler(servletHandler); |