aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authordrecchia <danilo@deltatecnologia.com>2016-06-01 21:08:05 -0300
committerdrecchia <danilo@deltatecnologia.com>2016-06-01 21:08:05 -0300
commite4ba1ebf54838041fae352d95e399b1fb3483458 (patch)
tree334626820ff4efa4583bb5257d19a18cd0ebf631
parent5df7c128af15e9d1021b7570f081185f14467f09 (diff)
parentd2c85b59bde4729d027ef1bb6e874d1fd1a02c68 (diff)
downloadtrackermap-server-e4ba1ebf54838041fae352d95e399b1fb3483458.tar.gz
trackermap-server-e4ba1ebf54838041fae352d95e399b1fb3483458.tar.bz2
trackermap-server-e4ba1ebf54838041fae352d95e399b1fb3483458.zip
Merge branch 'master' of https://github.com/tananaev/traccar
Conflicts: src/org/traccar/database/DataManager.java
-rw-r--r--database/changelog-3.6.xml34
-rw-r--r--database/changelog-master.xml1
-rw-r--r--setup/unix/traccar.xml22
-rw-r--r--setup/windows/traccar.xml22
-rw-r--r--src/org/traccar/BaseEventHandler.java35
-rw-r--r--src/org/traccar/BasePipelineFactory.java33
-rw-r--r--src/org/traccar/api/AsyncSocket.java7
-rw-r--r--src/org/traccar/api/resource/EventResource.java39
-rw-r--r--src/org/traccar/database/ConnectionManager.java42
-rw-r--r--src/org/traccar/database/DataManager.java36
-rw-r--r--src/org/traccar/events/CommandResultEventHandler.java18
-rw-r--r--src/org/traccar/events/MotionEventHandler.java55
-rw-r--r--src/org/traccar/events/OverspeedEventHandler.java45
-rw-r--r--src/org/traccar/model/Device.java13
-rw-r--r--src/org/traccar/model/Event.java74
-rw-r--r--src/org/traccar/web/WebServer.java4
-rw-r--r--web/app/view/DevicesController.js11
-rw-r--r--web/app/view/MapController.js2
-rw-r--r--web/app/view/ReportController.js34
19 files changed, 500 insertions, 27 deletions
diff --git a/database/changelog-3.6.xml b/database/changelog-3.6.xml
new file mode 100644
index 000000000..378ec741f
--- /dev/null
+++ b/database/changelog-3.6.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<databaseChangeLog
+ xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog
+ http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.4.xsd">
+
+ <changeSet author="author" id="changelog-3.6">
+
+ <createTable tableName="events">
+ <column name="id" type="INT" autoIncrement="true">
+ <constraints primaryKey="true" />
+ </column>
+ <column name="type" type="VARCHAR(128)">
+ <constraints nullable="false" />
+ </column>
+ <column name="servertime" type="TIMESTAMP">
+ <constraints nullable="false" />
+ </column>
+ <column name="deviceid" type="INT" />
+ <column name="positionid" type="INT" />
+ <column name="attributes" type="VARCHAR(4096)">
+ <constraints nullable="false" />
+ </column>
+ </createTable>
+
+ <addForeignKeyConstraint baseTableName="events" baseColumnNames="deviceid" constraintName="fk_event_deviceid" referencedTableName="devices" referencedColumnNames="id" onDelete="CASCADE" />
+
+ <addColumn tableName="devices">
+ <column name="motion" type="VARCHAR(128)" />
+ </addColumn>
+
+ </changeSet>
+</databaseChangeLog>
diff --git a/database/changelog-master.xml b/database/changelog-master.xml
index 269a0da1a..399cd3c8d 100644
--- a/database/changelog-master.xml
+++ b/database/changelog-master.xml
@@ -7,4 +7,5 @@
<include file="changelog-3.3.xml" relativeToChangelogFile="true" />
<include file="changelog-3.5.xml" relativeToChangelogFile="true" />
+ <include file="changelog-3.6.xml" relativeToChangelogFile="true" />
</databaseChangeLog>
diff --git a/setup/unix/traccar.xml b/setup/unix/traccar.xml
index 2ddf6551f..a0233e601 100644
--- a/setup/unix/traccar.xml
+++ b/setup/unix/traccar.xml
@@ -17,6 +17,13 @@
<entry key='logger.level'>all</entry>
<entry key='logger.file'>/opt/traccar/logs/tracker-server.log</entry>
+ <entry key='event.suppressRepeated'>60</entry>
+
+ <entry key='event.overspeedHandler'>true</entry>
+ <entry key='event.globalSpeedLimit'>90</entry>
+
+ <entry key='event.motionHandler'>true</entry>
+
<!-- DATABASE CONFIG -->
<entry key='database.driver'>org.h2.Driver</entry>
@@ -109,7 +116,7 @@
</entry>
<entry key='database.updateDeviceStatus'>
- UPDATE devices SET status = :status, lastUpdate = :lastUpdate WHERE id = :id;
+ UPDATE devices SET status = :status, lastUpdate = :lastUpdate, motion = :motion WHERE id = :id;
</entry>
<entry key='database.deleteDevice'>
@@ -165,6 +172,19 @@
UPDATE devices SET positionId = :id WHERE id = :deviceId;
</entry>
+ <entry key='database.selectEvent'>
+ SELECT * FROM events WHERE id = :id;
+ </entry>
+
+ <entry key='database.insertEvent'>
+ INSERT INTO events (type, serverTime, deviceId, positionId, attributes)
+ VALUES (:type, :serverTime, :deviceId, :positionId, :attributes);
+ </entry>
+
+ <entry key='database.selectEvents'>
+ SELECT * FROM events WHERE deviceId = :deviceId AND type LIKE :type AND serverTime BETWEEN :from AND :to ORDER BY serverTime DESC;
+ </entry>
+
<!-- PROTOCOL CONFIG -->
<entry key='gps103.port'>5001</entry>
diff --git a/setup/windows/traccar.xml b/setup/windows/traccar.xml
index bf1b216af..5748f3993 100644
--- a/setup/windows/traccar.xml
+++ b/setup/windows/traccar.xml
@@ -17,6 +17,13 @@
<entry key='logger.level'>all</entry>
<entry key='logger.file'>[LOG]</entry>
+ <entry key='event.suppressRepeated'>60</entry>
+
+ <entry key='event.overspeedHandler'>true</entry>
+ <entry key='event.globalSpeedLimit'>90</entry>
+
+ <entry key='event.motionHandler'>true</entry>
+
<!-- DATABASE CONFIG -->
<entry key='database.driver'>org.h2.Driver</entry>
@@ -109,7 +116,7 @@
</entry>
<entry key='database.updateDeviceStatus'>
- UPDATE devices SET status = :status, lastUpdate = :lastUpdate WHERE id = :id;
+ UPDATE devices SET status = :status, lastUpdate = :lastUpdate, motion = :motion WHERE id = :id;
</entry>
<entry key='database.deleteDevice'>
@@ -165,6 +172,19 @@
UPDATE devices SET positionId = :id WHERE id = :deviceId;
</entry>
+ <entry key='database.selectEvent'>
+ SELECT * FROM events WHERE id = :id;
+ </entry>
+
+ <entry key='database.insertEvent'>
+ INSERT INTO events (type, serverTime, deviceId, positionId, attributes)
+ VALUES (:type, :serverTime, :deviceId, :positionId, :attributes);
+ </entry>
+
+ <entry key='database.selectEvents'>
+ SELECT * FROM events WHERE deviceId = :deviceId AND type LIKE :type AND serverTime BETWEEN :from AND :to ORDER BY serverTime DESC;
+ </entry>
+
<!-- PROTOCOL CONFIG -->
<entry key='gps103.port'>5001</entry>
diff --git a/src/org/traccar/BaseEventHandler.java b/src/org/traccar/BaseEventHandler.java
new file mode 100644
index 000000000..fde57748c
--- /dev/null
+++ b/src/org/traccar/BaseEventHandler.java
@@ -0,0 +1,35 @@
+package org.traccar;
+
+import org.traccar.model.Device;
+import org.traccar.model.Event;
+import org.traccar.model.Position;
+
+public abstract class BaseEventHandler extends BaseDataHandler {
+
+ private boolean isLastPosition = false;
+
+ public boolean isLastPosition() {
+ return isLastPosition;
+ }
+
+ @Override
+ protected Position handlePosition(Position position) {
+
+ Device device = Context.getDataManager().getDeviceById(position.getDeviceId());
+ if (device != null) {
+ long lastPositionId = device.getPositionId();
+ if (position.getId() == lastPositionId) {
+ isLastPosition = true;
+ }
+ }
+
+ Event event = analizePosition(position);
+ if (event != null) {
+ Context.getConnectionManager().updateEvent(event);
+ }
+ return position;
+ }
+
+ protected abstract Event analizePosition(Position position);
+
+}
diff --git a/src/org/traccar/BasePipelineFactory.java b/src/org/traccar/BasePipelineFactory.java
index 6e350f61d..634c6d6a4 100644
--- a/src/org/traccar/BasePipelineFactory.java
+++ b/src/org/traccar/BasePipelineFactory.java
@@ -29,6 +29,9 @@ import org.jboss.netty.channel.MessageEvent;
import org.jboss.netty.channel.SimpleChannelHandler;
import org.jboss.netty.handler.logging.LoggingHandler;
import org.jboss.netty.handler.timeout.IdleStateHandler;
+import org.traccar.events.CommandResultEventHandler;
+import org.traccar.events.MotionEventHandler;
+import org.traccar.events.OverspeedEventHandler;
import org.traccar.helper.Log;
import java.net.InetSocketAddress;
@@ -44,6 +47,10 @@ public abstract class BasePipelineFactory implements ChannelPipelineFactory {
private LocationProviderHandler locationProviderHandler;
private HemisphereHandler hemisphereHandler;
+ private CommandResultEventHandler commandResultEventHandler;
+ private OverspeedEventHandler overspeedEventHandler;
+ private MotionEventHandler motionEventHandler;
+
private static final class OpenChannelHandler extends SimpleChannelHandler {
private final TrackerServer server;
@@ -122,6 +129,17 @@ public abstract class BasePipelineFactory implements ChannelPipelineFactory {
|| Context.getConfig().hasKey("location.longitudeHemisphere")) {
hemisphereHandler = new HemisphereHandler();
}
+
+ commandResultEventHandler = new CommandResultEventHandler();
+
+ if (Context.getConfig().getBoolean("event.overspeedHandler")) {
+ overspeedEventHandler = new OverspeedEventHandler();
+ }
+
+ if (Context.getConfig().getBoolean("event.motionHandler")) {
+ motionEventHandler = new MotionEventHandler();
+ }
+
}
protected abstract void addSpecificHandlers(ChannelPipeline pipeline);
@@ -162,9 +180,23 @@ public abstract class BasePipelineFactory implements ChannelPipelineFactory {
if (Context.getDataManager() != null) {
pipeline.addLast("dataHandler", new DefaultDataHandler());
}
+
if (Context.getConfig().getBoolean("forward.enable")) {
pipeline.addLast("webHandler", new WebDataHandler(Context.getConfig().getString("forward.url")));
}
+
+ if (commandResultEventHandler != null) {
+ pipeline.addLast("CommandResultEventHandler", commandResultEventHandler);
+ }
+
+ if (overspeedEventHandler != null) {
+ pipeline.addLast("OverspeedEventHandler", overspeedEventHandler);
+ }
+
+ if (motionEventHandler != null) {
+ pipeline.addLast("MotionEventHandler", motionEventHandler);
+ }
+
pipeline.addLast("mainHandler", new MainEventHandler());
return pipeline;
}
@@ -181,5 +213,4 @@ public abstract class BasePipelineFactory implements ChannelPipelineFactory {
}
}
}
-
}
diff --git a/src/org/traccar/api/AsyncSocket.java b/src/org/traccar/api/AsyncSocket.java
index 35e760613..2259f840f 100644
--- a/src/org/traccar/api/AsyncSocket.java
+++ b/src/org/traccar/api/AsyncSocket.java
@@ -20,6 +20,7 @@ import org.eclipse.jetty.websocket.api.WebSocketAdapter;
import org.traccar.Context;
import org.traccar.database.ConnectionManager;
import org.traccar.model.Device;
+import org.traccar.model.Event;
import org.traccar.model.Position;
import org.traccar.web.JsonConverter;
@@ -32,6 +33,7 @@ public class AsyncSocket extends WebSocketAdapter implements ConnectionManager.U
private static final String KEY_DEVICES = "devices";
private static final String KEY_POSITIONS = "positions";
+ private static final String KEY_EVENTS = "events";
private long userId;
@@ -65,6 +67,11 @@ public class AsyncSocket extends WebSocketAdapter implements ConnectionManager.U
sendData(KEY_POSITIONS, Collections.singletonList(position));
}
+ @Override
+ public void onUpdateEvent(Event event) {
+ sendData(KEY_EVENTS, Collections.singletonList(event));
+ }
+
private void sendData(String key, Collection<?> data) {
if (!data.isEmpty() && isConnected()) {
JsonObjectBuilder json = Json.createObjectBuilder();
diff --git a/src/org/traccar/api/resource/EventResource.java b/src/org/traccar/api/resource/EventResource.java
new file mode 100644
index 000000000..74a748ea5
--- /dev/null
+++ b/src/org/traccar/api/resource/EventResource.java
@@ -0,0 +1,39 @@
+package org.traccar.api.resource;
+
+import java.sql.SQLException;
+import java.util.Collection;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.GET;
+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 org.traccar.Context;
+import org.traccar.api.BaseResource;
+import org.traccar.model.Event;
+
+@Path("events")
+@Produces(MediaType.APPLICATION_JSON)
+@Consumes(MediaType.APPLICATION_JSON)
+
+public class EventResource extends BaseResource {
+
+ @Path("{id}")
+ @GET
+ public Event get(@PathParam("id") long id) throws SQLException {
+ Event event = Context.getDataManager().getEvent(id);
+ Context.getPermissionsManager().checkDevice(getUserId(), event.getDeviceId());
+ return event;
+ }
+
+ @GET
+ public Collection<Event> get(
+ @QueryParam("deviceId") long deviceId, @QueryParam("type") String type,
+ @QueryParam("interval") int interval) throws SQLException {
+ Context.getPermissionsManager().checkDevice(getUserId(), deviceId);
+ return Context.getDataManager().getLastEvents(deviceId, type, interval);
+ }
+}
diff --git a/src/org/traccar/database/ConnectionManager.java b/src/org/traccar/database/ConnectionManager.java
index bb9958232..9e0da8485 100644
--- a/src/org/traccar/database/ConnectionManager.java
+++ b/src/org/traccar/database/ConnectionManager.java
@@ -23,6 +23,7 @@ import org.traccar.GlobalTimer;
import org.traccar.Protocol;
import org.traccar.helper.Log;
import org.traccar.model.Device;
+import org.traccar.model.Event;
import org.traccar.model.Position;
import java.net.SocketAddress;
@@ -85,14 +86,26 @@ public class ConnectionManager {
return;
}
- device.setStatus(status);
- if (time != null) {
- device.setLastUpdate(time);
+ if (status.equals(Device.STATUS_MOVING) || status.equals(Device.STATUS_STOPPED)) {
+ device.setMotion(status);
+ } else {
+ if (!status.equals(device.getStatus())) {
+ Event event = new Event(Event.TYPE_DEVICE_OFFLINE, deviceId);
+ if (status.equals(Device.STATUS_ONLINE)) {
+ event.setType(Event.TYPE_DEVICE_ONLINE);
+ }
+ updateEvent(event);
+ }
+ device.setStatus(status);
+
+ Timeout timeout = timeouts.remove(deviceId);
+ if (timeout != null) {
+ timeout.cancel();
+ }
}
- Timeout timeout = timeouts.remove(deviceId);
- if (timeout != null) {
- timeout.cancel();
+ if (time != null) {
+ device.setLastUpdate(time);
}
if (status.equals(Device.STATUS_ONLINE)) {
@@ -134,6 +147,22 @@ public class ConnectionManager {
}
}
+ public synchronized void updateEvent(Event event) {
+ long deviceId = event.getDeviceId();
+ try {
+ Context.getDataManager().addEvent(event);
+ } catch (SQLException error) {
+ Log.warning(error);
+ }
+ for (long userId : Context.getPermissionsManager().getDeviceUsers(deviceId)) {
+ if (listeners.containsKey(userId)) {
+ for (UpdateListener listener : listeners.get(userId)) {
+ listener.onUpdateEvent(event);
+ }
+ }
+ }
+ }
+
public Position getLastPosition(long deviceId) {
return positions.get(deviceId);
}
@@ -154,6 +183,7 @@ public class ConnectionManager {
public interface UpdateListener {
void onUpdateDevice(Device device);
void onUpdatePosition(Position position);
+ void onUpdateEvent(Event event);
}
public synchronized void addListener(long userId, UpdateListener listener) {
diff --git a/src/org/traccar/database/DataManager.java b/src/org/traccar/database/DataManager.java
index 19560db5c..839cf8cad 100644
--- a/src/org/traccar/database/DataManager.java
+++ b/src/org/traccar/database/DataManager.java
@@ -21,6 +21,7 @@ import java.net.URL;
import java.net.URLClassLoader;
import java.sql.SQLException;
import java.util.ArrayList;
+import java.util.Calendar;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
@@ -46,6 +47,7 @@ import org.traccar.Context;
import org.traccar.helper.Log;
import org.traccar.model.Device;
import org.traccar.model.DevicePermission;
+import org.traccar.model.Event;
import org.traccar.model.Group;
import org.traccar.model.GroupPermission;
import org.traccar.model.Position;
@@ -363,6 +365,9 @@ public class DataManager implements IdentityManager {
QueryBuilder.create(dataSource, getQuery("database.updateDeviceStatus"))
.setObject(device)
.executeUpdate();
+ Device cachedDevice = getDeviceById(device.getId());
+ cachedDevice.setStatus(device.getStatus());
+ cachedDevice.setMotion(device.getMotion());
}
public void removeDevice(long deviceId) throws SQLException {
@@ -471,6 +476,8 @@ public class DataManager implements IdentityManager {
.setDate("now", new Date())
.setObject(position)
.executeUpdate();
+ Device device = getDeviceById(position.getDeviceId());
+ device.setPositionId(position.getId());
}
public Collection<Position> getLatestPositions() throws SQLException {
@@ -488,4 +495,33 @@ public class DataManager implements IdentityManager {
.setObject(server)
.executeUpdate();
}
+
+ public Event getEvent(long eventId) throws SQLException {
+ return QueryBuilder.create(dataSource, getQuery("database.selectEvent"))
+ .setLong("id", eventId)
+ .executeQuerySingle(Event.class);
+ }
+
+ public void addEvent(Event event) throws SQLException {
+ event.setId(QueryBuilder.create(dataSource, getQuery("database.insertEvent"), true)
+ .setObject(event)
+ .executeUpdate());
+ }
+
+ public Collection<Event> getEvents(long deviceId, String type, Date from, Date to) throws SQLException {
+ return QueryBuilder.create(dataSource, getQuery("database.selectEvents"))
+ .setLong("deviceId", deviceId)
+ .setString("type", type)
+ .setDate("from", from)
+ .setDate("to", to)
+ .executeQuery(Event.class);
+ }
+
+ public Collection<Event> getLastEvents(long deviceId, String type, int interval) throws SQLException {
+ Calendar calendar = Calendar.getInstance();
+ calendar.add(Calendar.SECOND, -interval);
+ Date to = calendar.getTime();
+ return getEvents(deviceId, type, new Date(), to);
+ }
+
}
diff --git a/src/org/traccar/events/CommandResultEventHandler.java b/src/org/traccar/events/CommandResultEventHandler.java
new file mode 100644
index 000000000..23c62566a
--- /dev/null
+++ b/src/org/traccar/events/CommandResultEventHandler.java
@@ -0,0 +1,18 @@
+package org.traccar.events;
+
+import org.traccar.BaseEventHandler;
+import org.traccar.model.Event;
+import org.traccar.model.Position;
+
+public class CommandResultEventHandler extends BaseEventHandler {
+
+ @Override
+ protected Event analizePosition(Position position) {
+ Object commandResult = position.getAttributes().get(Position.KEY_RESULT);
+ if (commandResult != null) {
+ return new Event(Event.TYPE_COMMAND_RESULT, position.getDeviceId(), position.getId());
+ }
+ return null;
+ }
+
+}
diff --git a/src/org/traccar/events/MotionEventHandler.java b/src/org/traccar/events/MotionEventHandler.java
new file mode 100644
index 000000000..a3b81ddc4
--- /dev/null
+++ b/src/org/traccar/events/MotionEventHandler.java
@@ -0,0 +1,55 @@
+package org.traccar.events;
+
+import java.sql.SQLException;
+
+import org.traccar.BaseEventHandler;
+import org.traccar.Context;
+import org.traccar.helper.Log;
+import org.traccar.model.Device;
+import org.traccar.model.Event;
+import org.traccar.model.Position;
+
+public class MotionEventHandler extends BaseEventHandler {
+
+ private static final double SPEED_THRESHOLD = 0.01;
+ private int suppressRepeated;
+
+ public MotionEventHandler() {
+ suppressRepeated = Context.getConfig().getInteger("event.suppressRepeated", 60);
+ }
+
+ @Override
+ protected Event analizePosition(Position position) {
+ Event event = null;
+
+ if (!isLastPosition()) {
+ return event;
+ }
+
+ double speed = position.getSpeed();
+ boolean valid = position.getValid();
+ Device device = Context.getIdentityManager().getDeviceById(position.getDeviceId());
+ if (device == null) {
+ return event;
+ }
+ String motion = device.getMotion();
+ if (valid && speed > SPEED_THRESHOLD && !motion.equals(Device.STATUS_MOVING)) {
+ Context.getConnectionManager().updateDevice(position.getDeviceId(), Device.STATUS_MOVING, null);
+ event = new Event(Event.TYPE_DEVICE_MOVING, position.getDeviceId(), position.getId());
+ } else if (valid && speed < SPEED_THRESHOLD && motion.equals(Device.STATUS_MOVING)) {
+ Context.getConnectionManager().updateDevice(position.getDeviceId(), Device.STATUS_STOPPED, null);
+ event = new Event(Event.TYPE_DEVICE_STOPPED, position.getDeviceId(), position.getId());
+ }
+ try {
+ if (event != null && !Context.getDataManager().getLastEvents(
+ position.getDeviceId(), event.getType(), suppressRepeated).isEmpty()) {
+ event = null;
+ }
+
+ } catch (SQLException error) {
+ Log.warning(error);
+ }
+ return event;
+ }
+
+}
diff --git a/src/org/traccar/events/OverspeedEventHandler.java b/src/org/traccar/events/OverspeedEventHandler.java
new file mode 100644
index 000000000..30410ff32
--- /dev/null
+++ b/src/org/traccar/events/OverspeedEventHandler.java
@@ -0,0 +1,45 @@
+package org.traccar.events;
+
+import java.sql.SQLException;
+
+import org.traccar.BaseEventHandler;
+import org.traccar.Context;
+import org.traccar.model.Event;
+import org.traccar.model.Position;
+import org.traccar.helper.Log;
+import org.traccar.helper.UnitsConverter;
+
+public class OverspeedEventHandler extends BaseEventHandler {
+
+ private double globalSpeedLimit;
+ private int suppressRepeated;
+
+ public OverspeedEventHandler() {
+ globalSpeedLimit = UnitsConverter.knotsFromKph(Context.getConfig().getInteger("event.globalSpeedLimit", 0));
+ suppressRepeated = Context.getConfig().getInteger("event.suppressRepeated", 60);
+ }
+
+ @Override
+ protected Event analizePosition(Position position) {
+ Event event = null;
+ if (!isLastPosition()) {
+ return event;
+ }
+ double speed = position.getSpeed();
+ boolean valid = position.getValid();
+
+ if (valid && globalSpeedLimit != 0 && speed > globalSpeedLimit) {
+ try {
+ if (Context.getDataManager().getLastEvents(
+ position.getDeviceId(), Event.TYPE_DEVICE_OVERSPEED, suppressRepeated).isEmpty()) {
+ event = new Event(Event.TYPE_DEVICE_OVERSPEED, position.getDeviceId(), position.getId());
+ }
+ } catch (SQLException error) {
+ Log.warning(error);
+ }
+
+ }
+ return event;
+ }
+
+}
diff --git a/src/org/traccar/model/Device.java b/src/org/traccar/model/Device.java
index 934e753b1..d32f9f851 100644
--- a/src/org/traccar/model/Device.java
+++ b/src/org/traccar/model/Device.java
@@ -101,4 +101,17 @@ public class Device {
this.groupId = groupId;
}
+ public static final String STATUS_MOVING = "moving";
+ public static final String STATUS_STOPPED = "stopped";
+
+ private String motion;
+
+ public String getMotion() {
+ return motion;
+ }
+
+ public void setMotion(String motion) {
+ this.motion = motion;
+ }
+
}
diff --git a/src/org/traccar/model/Event.java b/src/org/traccar/model/Event.java
new file mode 100644
index 000000000..6de885c70
--- /dev/null
+++ b/src/org/traccar/model/Event.java
@@ -0,0 +1,74 @@
+package org.traccar.model;
+
+import java.util.Date;
+
+public class Event extends Message {
+
+ public Event(String type, long deviceId, long positionId) {
+ this.setType(type);
+ this.setDeviceId(deviceId);
+ this.setPositionId(positionId);
+ this.serverTime = new Date();
+ }
+
+ public Event(String type, long deviceId) {
+ this.setType(type);
+ this.setDeviceId(deviceId);
+ this.serverTime = new Date();
+ }
+
+ public Event() {
+ }
+
+ private long id;
+
+ public long getId() {
+ return id;
+ }
+
+ public void setId(long id) {
+ this.id = id;
+ }
+
+ public static final String TYPE_COMMAND_RESULT = "commandResult";
+
+ public static final String TYPE_DEVICE_ONLINE = "deviceOnline";
+ public static final String TYPE_DEVICE_OFFLINE = "deviceOffline";
+
+ public static final String TYPE_DEVICE_MOVING = "deviceMoving";
+ public static final String TYPE_DEVICE_STOPPED = "deviceStopped";
+
+ public static final String TYPE_DEVICE_OVERSPEED = "deviceOverspeed";
+
+ public static final String TYPE_GEOFENCE_ENTER = "geofenceEnter";
+ public static final String TYPE_GEOFENCE_EXIT = "geofenceExit";
+
+ private Date serverTime;
+
+ public Date getServerTime() {
+ if (serverTime != null) {
+ return new Date(serverTime.getTime());
+ } else {
+ return null;
+ }
+ }
+
+ public void setServerTime(Date serverTime) {
+ if (serverTime != null) {
+ this.serverTime = new Date(serverTime.getTime());
+ } else {
+ this.serverTime = null;
+ }
+ }
+
+ private long positionId;
+
+ public long getPositionId() {
+ return positionId;
+ }
+
+ public void setPositionId(long positionId) {
+ this.positionId = positionId;
+ }
+
+}
diff --git a/src/org/traccar/web/WebServer.java b/src/org/traccar/web/WebServer.java
index 8144af0b6..751db7a33 100644
--- a/src/org/traccar/web/WebServer.java
+++ b/src/org/traccar/web/WebServer.java
@@ -44,6 +44,7 @@ import org.traccar.api.resource.GroupResource;
import org.traccar.api.resource.DeviceResource;
import org.traccar.api.resource.PositionResource;
import org.traccar.api.resource.CommandTypeResource;
+import org.traccar.api.resource.EventResource;
import org.traccar.helper.Log;
import javax.naming.InitialContext;
@@ -148,7 +149,8 @@ public class WebServer {
resourceConfig.register(CorsResponseFilter.class);
resourceConfig.registerClasses(ServerResource.class, SessionResource.class, CommandResource.class,
GroupPermissionResource.class, DevicePermissionResource.class, UserResource.class,
- GroupResource.class, DeviceResource.class, PositionResource.class, CommandTypeResource.class);
+ GroupResource.class, DeviceResource.class, PositionResource.class,
+ CommandTypeResource.class, EventResource.class);
servletHandler.addServlet(new ServletHolder(new ServletContainer(resourceConfig)), "/*");
handlers.addHandler(servletHandler);
diff --git a/web/app/view/DevicesController.js b/web/app/view/DevicesController.js
index 9dee0ff7c..6b79a6804 100644
--- a/web/app/view/DevicesController.js
+++ b/web/app/view/DevicesController.js
@@ -30,6 +30,11 @@ Ext.define('Traccar.view.DevicesController', {
selectDevice: 'selectDevice',
selectReport: 'selectReport'
}
+ },
+ store: {
+ '#Devices': {
+ update: 'onUpdateDevice'
+ }
}
}
},
@@ -103,7 +108,7 @@ Ext.define('Traccar.view.DevicesController', {
var empty = selected.getCount() === 0;
this.lookupReference('toolbarEditButton').setDisabled(empty);
this.lookupReference('toolbarRemoveButton').setDisabled(empty);
- this.lookupReference('deviceCommandButton').setDisabled(empty);
+ this.lookupReference('deviceCommandButton').setDisabled(empty || (selected.getLastSelected().get('status') !== 'online'));
if (!empty) {
this.fireEvent('selectDevice', selected.getLastSelected(), true);
}
@@ -117,5 +122,9 @@ Ext.define('Traccar.view.DevicesController', {
if (position !== undefined) {
this.getView().getSelectionModel().deselectAll();
}
+ },
+
+ onUpdateDevice: function (store, data) {
+ this.onSelectionChange(this.getView().getSelectionModel());
}
});
diff --git a/web/app/view/MapController.js b/web/app/view/MapController.js
index b8b7290b8..eee74099f 100644
--- a/web/app/view/MapController.js
+++ b/web/app/view/MapController.js
@@ -176,6 +176,8 @@ Ext.define('Traccar.view.MapController', {
this.reportRoute.getGeometry().appendCoordinate(point);
}
+
+ this.getView().getMapView().fit(this.reportRoute.getGeometry(), this.getView().getMap().getSize());
},
clearReport: function (store) {
diff --git a/web/app/view/ReportController.js b/web/app/view/ReportController.js
index 9c2abcc71..4fe7c62b8 100644
--- a/web/app/view/ReportController.js
+++ b/web/app/view/ReportController.js
@@ -37,25 +37,27 @@ Ext.define('Traccar.view.ReportController', {
fromDate = this.lookupReference('fromDateField').getValue();
fromTime = this.lookupReference('fromTimeField').getValue();
- from = new Date(
- fromDate.getFullYear(), fromDate.getMonth(), fromDate.getDate(),
- fromTime.getHours(), fromTime.getMinutes(), fromTime.getSeconds(), fromTime.getMilliseconds());
+ if (deviceId) {
+ from = new Date(
+ fromDate.getFullYear(), fromDate.getMonth(), fromDate.getDate(),
+ fromTime.getHours(), fromTime.getMinutes(), fromTime.getSeconds(), fromTime.getMilliseconds());
- toDate = this.lookupReference('toDateField').getValue();
- toTime = this.lookupReference('toTimeField').getValue();
+ toDate = this.lookupReference('toDateField').getValue();
+ toTime = this.lookupReference('toTimeField').getValue();
- to = new Date(
- toDate.getFullYear(), toDate.getMonth(), toDate.getDate(),
- toTime.getHours(), toTime.getMinutes(), toTime.getSeconds(), toTime.getMilliseconds());
+ to = new Date(
+ toDate.getFullYear(), toDate.getMonth(), toDate.getDate(),
+ toTime.getHours(), toTime.getMinutes(), toTime.getSeconds(), toTime.getMilliseconds());
- store = Ext.getStore('Positions');
- store.load({
- params: {
- deviceId: deviceId,
- from: from.toISOString(),
- to: to.toISOString()
- }
- });
+ store = Ext.getStore('Positions');
+ store.load({
+ params: {
+ deviceId: deviceId,
+ from: from.toISOString(),
+ to: to.toISOString()
+ }
+ });
+ }
},
onClearClick: function () {