aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAnton Tananaev <anton.tananaev@gmail.com>2016-08-12 10:13:45 +0300
committerGitHub <noreply@github.com>2016-08-12 10:13:45 +0300
commit5d3b7cbe5924d4a4552035626a83e26b1e756255 (patch)
tree18c1caaba30f7bb9e6c21cce492d93a85ebc1c73
parent1f11fa7db020f8a46e4b298dc61277460d76b678 (diff)
parent9a55f2b000956717d5caf6fb53793264c0376ce7 (diff)
downloadtraccar-server-5d3b7cbe5924d4a4552035626a83e26b1e756255.tar.gz
traccar-server-5d3b7cbe5924d4a4552035626a83e26b1e756255.tar.bz2
traccar-server-5d3b7cbe5924d4a4552035626a83e26b1e756255.zip
Merge pull request #2206 from Abyss777/ignition
Ignition and Motor Hours
-rw-r--r--debug.xml1
-rw-r--r--src/org/traccar/BasePipelineFactory.java9
-rw-r--r--src/org/traccar/database/IdentityManager.java2
-rw-r--r--src/org/traccar/events/GeofenceEventHandler.java2
-rw-r--r--src/org/traccar/events/IgnitionEventHandler.java68
-rw-r--r--src/org/traccar/events/MotionEventHandler.java4
-rw-r--r--src/org/traccar/events/OverspeedEventHandler.java4
-rw-r--r--src/org/traccar/model/Event.java3
-rw-r--r--src/org/traccar/notification/NotificationFormatter.java41
-rw-r--r--src/org/traccar/protocol/IdplProtocolDecoder.java2
-rw-r--r--src/org/traccar/protocol/Stl060ProtocolDecoder.java4
-rw-r--r--src/org/traccar/reports/Events.java16
-rw-r--r--src/org/traccar/reports/ReportUtils.java16
-rw-r--r--src/org/traccar/reports/Route.java16
-rw-r--r--src/org/traccar/reports/Summary.java24
-rw-r--r--src/org/traccar/reports/model/SummaryReport.java27
-rw-r--r--test/org/traccar/EventHandlerTest.java43
-rw-r--r--test/org/traccar/ProtocolTest.java5
-rw-r--r--test/org/traccar/events/AlertEventHandlerTest.java28
-rw-r--r--test/org/traccar/events/CommandResultEventHandlerTest.java28
-rw-r--r--test/org/traccar/events/IgnitionEventHandlerTest.java29
-rw-r--r--test/org/traccar/events/MotionEventHandlerTest.java29
-rwxr-xr-xtools/test-generator.py7
-rw-r--r--web/app/AttributeFormatter.js7
-rw-r--r--web/app/model/ReportSummary.js3
-rw-r--r--web/app/view/ReportController.js5
-rw-r--r--web/l10n/en.json6
27 files changed, 417 insertions, 12 deletions
diff --git a/debug.xml b/debug.xml
index 3f875aae7..8570f6893 100644
--- a/debug.xml
+++ b/debug.xml
@@ -49,6 +49,7 @@
<entry key='event.motionHandler'>true</entry>
<entry key='event.geofenceHandler'>true</entry>
<entry key='event.alertHandler'>true</entry>
+ <entry key='event.ignitionHandler'>true</entry>
<!--<entry key='event.forward.enable'>true</entry>
<entry key='event.forward.url'>http://localhost/</entry>
diff --git a/src/org/traccar/BasePipelineFactory.java b/src/org/traccar/BasePipelineFactory.java
index 2b5028f33..ed7aa0a69 100644
--- a/src/org/traccar/BasePipelineFactory.java
+++ b/src/org/traccar/BasePipelineFactory.java
@@ -31,6 +31,7 @@ import org.jboss.netty.handler.logging.LoggingHandler;
import org.jboss.netty.handler.timeout.IdleStateHandler;
import org.traccar.events.CommandResultEventHandler;
import org.traccar.events.GeofenceEventHandler;
+import org.traccar.events.IgnitionEventHandler;
import org.traccar.events.MotionEventHandler;
import org.traccar.events.OverspeedEventHandler;
import org.traccar.events.AlertEventHandler;
@@ -55,6 +56,7 @@ public abstract class BasePipelineFactory implements ChannelPipelineFactory {
private MotionEventHandler motionEventHandler;
private GeofenceEventHandler geofenceEventHandler;
private AlertEventHandler alertEventHandler;
+ private IgnitionEventHandler ignitionEventHandler;
private static final class OpenChannelHandler extends SimpleChannelHandler {
@@ -156,6 +158,9 @@ public abstract class BasePipelineFactory implements ChannelPipelineFactory {
if (Context.getConfig().getBoolean("event.alertHandler")) {
alertEventHandler = new AlertEventHandler();
}
+ if (Context.getConfig().getBoolean("event.ignitionHandler")) {
+ ignitionEventHandler = new IgnitionEventHandler();
+ }
}
protected abstract void addSpecificHandlers(ChannelPipeline pipeline);
@@ -225,6 +230,10 @@ public abstract class BasePipelineFactory implements ChannelPipelineFactory {
pipeline.addLast("AlertEventHandler", alertEventHandler);
}
+ if (alertEventHandler != null) {
+ pipeline.addLast("IgnitionEventHandler", ignitionEventHandler);
+ }
+
pipeline.addLast("mainHandler", new MainEventHandler());
return pipeline;
}
diff --git a/src/org/traccar/database/IdentityManager.java b/src/org/traccar/database/IdentityManager.java
index 8c0de8b38..8507d1f2e 100644
--- a/src/org/traccar/database/IdentityManager.java
+++ b/src/org/traccar/database/IdentityManager.java
@@ -26,4 +26,6 @@ public interface IdentityManager {
Position getLastPosition(long deviceId);
+ boolean isLatestPosition(Position position);
+
}
diff --git a/src/org/traccar/events/GeofenceEventHandler.java b/src/org/traccar/events/GeofenceEventHandler.java
index a0291dcfa..6126331bd 100644
--- a/src/org/traccar/events/GeofenceEventHandler.java
+++ b/src/org/traccar/events/GeofenceEventHandler.java
@@ -40,7 +40,7 @@ public class GeofenceEventHandler extends BaseEventHandler {
if (device == null) {
return null;
}
- if (!Context.getDeviceManager().isLatestPosition(position) || !position.getValid()) {
+ if (!Context.getIdentityManager().isLatestPosition(position) || !position.getValid()) {
return null;
}
diff --git a/src/org/traccar/events/IgnitionEventHandler.java b/src/org/traccar/events/IgnitionEventHandler.java
new file mode 100644
index 000000000..e241e450b
--- /dev/null
+++ b/src/org/traccar/events/IgnitionEventHandler.java
@@ -0,0 +1,68 @@
+/*
+ * 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.events;
+
+import java.util.ArrayList;
+import java.util.Collection;
+
+import org.traccar.BaseEventHandler;
+import org.traccar.Context;
+import org.traccar.model.Device;
+import org.traccar.model.Event;
+import org.traccar.model.Position;
+
+public class IgnitionEventHandler extends BaseEventHandler {
+
+ @Override
+ protected Collection<Event> analyzePosition(Position position) {
+ Device device = Context.getIdentityManager().getDeviceById(position.getDeviceId());
+ if (device == null) {
+ return null;
+ }
+ if (!Context.getIdentityManager().isLatestPosition(position) || !position.getValid()) {
+ return null;
+ }
+
+ Collection<Event> result = null;
+
+ boolean ignition = false;
+ Object ignitionObject = position.getAttributes().get(Position.KEY_IGNITION);
+ if (ignitionObject != null && ignitionObject instanceof Boolean) {
+ ignition = (Boolean) ignitionObject;
+ }
+
+ boolean oldIgnition = false;
+ Object oldIgnitionObject = null;
+ Position lastPosition = Context.getIdentityManager().getLastPosition(position.getDeviceId());
+ if (lastPosition != null) {
+ oldIgnitionObject = lastPosition.getAttributes().get(Position.KEY_IGNITION);
+ }
+ if (oldIgnitionObject != null && oldIgnitionObject instanceof Boolean) {
+ oldIgnition = (Boolean) oldIgnitionObject;
+ }
+
+ if (ignition && !oldIgnition) {
+ result = new ArrayList<>();
+ result.add(new Event(Event.TYPE_IGNITION_ON, position.getDeviceId(), position.getId()));
+ } else if (!ignition && oldIgnition) {
+ result = new ArrayList<>();
+ result.add(new Event(Event.TYPE_IGNITION_OFF, position.getDeviceId(), position.getId()));
+ }
+ return result;
+ }
+
+}
diff --git a/src/org/traccar/events/MotionEventHandler.java b/src/org/traccar/events/MotionEventHandler.java
index ddb99185f..7178f7036 100644
--- a/src/org/traccar/events/MotionEventHandler.java
+++ b/src/org/traccar/events/MotionEventHandler.java
@@ -35,14 +35,14 @@ public class MotionEventHandler extends BaseEventHandler {
if (device == null) {
return null;
}
- if (!Context.getDeviceManager().isLatestPosition(position) || !position.getValid()) {
+ if (!Context.getIdentityManager().isLatestPosition(position) || !position.getValid()) {
return null;
}
Collection<Event> result = null;
double speed = position.getSpeed();
double oldSpeed = 0;
- Position lastPosition = Context.getDeviceManager().getLastPosition(position.getDeviceId());
+ Position lastPosition = Context.getIdentityManager().getLastPosition(position.getDeviceId());
if (lastPosition != null) {
oldSpeed = lastPosition.getSpeed();
}
diff --git a/src/org/traccar/events/OverspeedEventHandler.java b/src/org/traccar/events/OverspeedEventHandler.java
index dbdb01ffb..c739348eb 100644
--- a/src/org/traccar/events/OverspeedEventHandler.java
+++ b/src/org/traccar/events/OverspeedEventHandler.java
@@ -42,7 +42,7 @@ public class OverspeedEventHandler extends BaseEventHandler {
if (device == null) {
return null;
}
- if (!Context.getDeviceManager().isLatestPosition(position) || !position.getValid()) {
+ if (!Context.getIdentityManager().isLatestPosition(position) || !position.getValid()) {
return null;
}
@@ -58,7 +58,7 @@ public class OverspeedEventHandler extends BaseEventHandler {
}
double oldSpeed = 0;
if (notRepeat) {
- Position lastPosition = Context.getDeviceManager().getLastPosition(position.getDeviceId());
+ Position lastPosition = Context.getIdentityManager().getLastPosition(position.getDeviceId());
if (lastPosition != null) {
oldSpeed = lastPosition.getSpeed();
}
diff --git a/src/org/traccar/model/Event.java b/src/org/traccar/model/Event.java
index a2c346688..c3c8b5320 100644
--- a/src/org/traccar/model/Event.java
+++ b/src/org/traccar/model/Event.java
@@ -50,6 +50,9 @@ public class Event extends Message {
public static final String TYPE_ALARM = "alarm";
+ public static final String TYPE_IGNITION_ON = "ignitionOn";
+ public static final String TYPE_IGNITION_OFF = "ignitionOff";
+
private Date serverTime;
public Date getServerTime() {
diff --git a/src/org/traccar/notification/NotificationFormatter.java b/src/org/traccar/notification/NotificationFormatter.java
index 449426df0..1d5257b4f 100644
--- a/src/org/traccar/notification/NotificationFormatter.java
+++ b/src/org/traccar/notification/NotificationFormatter.java
@@ -70,6 +70,23 @@ public final class NotificationFormatter {
+ "Point: http://www.openstreetmap.org/?mlat=%3$f&mlon=%4$f#map=16/%3$f/%4$f%n"
+ "Time: %2$tc%n";
+ public static final String TITLE_TEMPLATE_TYPE_ALARM = "%1$s: alarm!";
+ public static final String MESSAGE_TEMPLATE_TYPE_ALARM = "Device: %1$s%n"
+ + "Alarm: %5$s%n"
+ + "Point: http://www.openstreetmap.org/?mlat=%3$f&mlon=%4$f#map=16/%3$f/%4$f%n"
+ + "Time: %2$tc%n";
+
+ public static final String TITLE_TEMPLATE_TYPE_IGNITION_ON = "%1$s: ignition ON";
+ public static final String MESSAGE_TEMPLATE_TYPE_IGNITION_ON = "Device: %1$s%n"
+ + "Ignition ON%n"
+ + "Point: http://www.openstreetmap.org/?mlat=%3$f&mlon=%4$f#map=16/%3$f/%4$f%n"
+ + "Time: %2$tc%n";
+ public static final String TITLE_TEMPLATE_TYPE_IGNITION_OFF = "%1$s: ignition OFF";
+ public static final String MESSAGE_TEMPLATE_TYPE_IGNITION_OFF = "Device: %1$s%n"
+ + "Ignition OFF%n"
+ + "Point: http://www.openstreetmap.org/?mlat=%3$f&mlon=%4$f#map=16/%3$f/%4$f%n"
+ + "Time: %2$tc%n";
+
public static String formatTitle(long userId, Event event, Position position) {
Device device = Context.getIdentityManager().getDeviceById(event.getDeviceId());
StringBuilder stringBuilder = new StringBuilder();
@@ -100,6 +117,15 @@ public final class NotificationFormatter {
case Event.TYPE_GEOFENCE_EXIT:
formatter.format(TITLE_TEMPLATE_TYPE_GEOFENCE_EXIT, device.getName());
break;
+ case Event.TYPE_ALARM:
+ formatter.format(TITLE_TEMPLATE_TYPE_ALARM, device.getName());
+ break;
+ case Event.TYPE_IGNITION_ON:
+ formatter.format(TITLE_TEMPLATE_TYPE_IGNITION_ON, device.getName());
+ break;
+ case Event.TYPE_IGNITION_OFF:
+ formatter.format(TITLE_TEMPLATE_TYPE_IGNITION_OFF, device.getName());
+ break;
default:
formatter.format("Unknown type");
break;
@@ -117,7 +143,7 @@ public final class NotificationFormatter {
switch (event.getType()) {
case Event.TYPE_COMMAND_RESULT:
formatter.format(MESSAGE_TEMPLATE_TYPE_COMMAND_RESULT, device.getName(), event.getServerTime(),
- position.getAttributes().get("result"));
+ position.getAttributes().get(Position.KEY_RESULT));
break;
case Event.TYPE_DEVICE_ONLINE:
formatter.format(MESSAGE_TEMPLATE_TYPE_DEVICE_ONLINE, device.getName(), event.getServerTime());
@@ -147,6 +173,19 @@ public final class NotificationFormatter {
position.getLatitude(), position.getLongitude(),
Context.getGeofenceManager().getGeofence(event.getGeofenceId()).getName());
break;
+ case Event.TYPE_ALARM:
+ formatter.format(MESSAGE_TEMPLATE_TYPE_ALARM, device.getName(), event.getServerTime(),
+ position.getLatitude(), position.getLongitude(),
+ position.getAttributes().get(Position.KEY_ALARM));
+ break;
+ case Event.TYPE_IGNITION_ON:
+ formatter.format(MESSAGE_TEMPLATE_TYPE_IGNITION_ON, device.getName(), position.getFixTime(),
+ position.getLatitude(), position.getLongitude());
+ break;
+ case Event.TYPE_IGNITION_OFF:
+ formatter.format(MESSAGE_TEMPLATE_TYPE_IGNITION_OFF, device.getName(), position.getFixTime(),
+ position.getLatitude(), position.getLongitude());
+ break;
default:
formatter.format("Unknown type");
break;
diff --git a/src/org/traccar/protocol/IdplProtocolDecoder.java b/src/org/traccar/protocol/IdplProtocolDecoder.java
index b0d331e3e..5b8ec7897 100644
--- a/src/org/traccar/protocol/IdplProtocolDecoder.java
+++ b/src/org/traccar/protocol/IdplProtocolDecoder.java
@@ -100,7 +100,7 @@ public class IdplProtocolDecoder extends BaseProtocolDecoder {
position.set(Position.KEY_ALARM, parser.nextInt());
parser.nextInt(); // body tamper
parser.nextInt(); // ac status
- position.set(Position.KEY_IGNITION, parser.nextInt());
+ position.set(Position.KEY_IGNITION, parser.nextInt() == 1);
position.set(Position.KEY_OUTPUT, parser.nextInt());
position.set(Position.PREFIX_ADC + 1, parser.nextInt());
position.set(Position.PREFIX_ADC + 2, parser.nextInt());
diff --git a/src/org/traccar/protocol/Stl060ProtocolDecoder.java b/src/org/traccar/protocol/Stl060ProtocolDecoder.java
index b8eb5ed3d..86b097f77 100644
--- a/src/org/traccar/protocol/Stl060ProtocolDecoder.java
+++ b/src/org/traccar/protocol/Stl060ProtocolDecoder.java
@@ -98,7 +98,7 @@ public class Stl060ProtocolDecoder extends BaseProtocolDecoder {
// Old format
if (parser.hasNext(5)) {
position.set(Position.KEY_ODOMETER, parser.nextInt());
- position.set(Position.KEY_IGNITION, parser.nextInt());
+ position.set(Position.KEY_IGNITION, parser.nextInt() == 1);
position.set(Position.KEY_INPUT, parser.nextInt() + parser.nextInt() << 1);
position.set(Position.KEY_FUEL, parser.nextInt());
}
@@ -106,7 +106,7 @@ public class Stl060ProtocolDecoder extends BaseProtocolDecoder {
// New format
if (parser.hasNext(10)) {
position.set(Position.KEY_CHARGE, parser.nextInt() == 1);
- position.set(Position.KEY_IGNITION, parser.nextInt());
+ position.set(Position.KEY_IGNITION, parser.nextInt() == 1);
position.set(Position.KEY_INPUT, parser.nextInt());
position.set(Position.KEY_RFID, parser.next());
position.set(Position.KEY_ODOMETER, parser.nextInt());
diff --git a/src/org/traccar/reports/Events.java b/src/org/traccar/reports/Events.java
index fbbd3131b..ed7e9e411 100644
--- a/src/org/traccar/reports/Events.java
+++ b/src/org/traccar/reports/Events.java
@@ -1,3 +1,19 @@
+/*
+ * Copyright 2016 Anton Tananaev (anton.tananaev@gmail.com)
+ * Copyright 2016 Andrey Kunitsyn (abyss@fox5.ru)
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
package org.traccar.reports;
import java.sql.SQLException;
diff --git a/src/org/traccar/reports/ReportUtils.java b/src/org/traccar/reports/ReportUtils.java
index 5041871f7..9f6d34860 100644
--- a/src/org/traccar/reports/ReportUtils.java
+++ b/src/org/traccar/reports/ReportUtils.java
@@ -1,3 +1,19 @@
+/*
+ * Copyright 2016 Anton Tananaev (anton.tananaev@gmail.com)
+ * Copyright 2016 Andrey Kunitsyn (abyss@fox5.ru)
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
package org.traccar.reports;
import java.util.ArrayList;
diff --git a/src/org/traccar/reports/Route.java b/src/org/traccar/reports/Route.java
index 9622151e7..45b81cd8c 100644
--- a/src/org/traccar/reports/Route.java
+++ b/src/org/traccar/reports/Route.java
@@ -1,3 +1,19 @@
+/*
+ * Copyright 2016 Anton Tananaev (anton.tananaev@gmail.com)
+ * Copyright 2016 Andrey Kunitsyn (abyss@fox5.ru)
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
package org.traccar.reports;
import java.sql.SQLException;
diff --git a/src/org/traccar/reports/Summary.java b/src/org/traccar/reports/Summary.java
index e0da1c87e..68733ded6 100644
--- a/src/org/traccar/reports/Summary.java
+++ b/src/org/traccar/reports/Summary.java
@@ -1,3 +1,19 @@
+/*
+ * Copyright 2016 Anton Tananaev (anton.tananaev@gmail.com)
+ * Copyright 2016 Andrey Kunitsyn (abyss@fox5.ru)
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
package org.traccar.reports;
import java.math.BigDecimal;
@@ -33,6 +49,14 @@ public final class Summary {
if (previousPosition != null) {
result.addDistance(DistanceCalculator.distance(previousPosition.getLatitude(),
previousPosition.getLongitude(), position.getLatitude(), position.getLongitude()));
+ if (position.getAttributes().get(Position.KEY_IGNITION) != null
+ && Boolean.parseBoolean(position.getAttributes().get(Position.KEY_IGNITION).toString())
+ && previousPosition.getAttributes().get(Position.KEY_IGNITION) != null
+ && Boolean.parseBoolean(previousPosition.getAttributes()
+ .get(Position.KEY_IGNITION).toString())) {
+ result.addEngineHours(position.getFixTime().getTime()
+ - previousPosition.getFixTime().getTime());
+ }
}
previousPosition = position;
speedSum += position.getSpeed();
diff --git a/src/org/traccar/reports/model/SummaryReport.java b/src/org/traccar/reports/model/SummaryReport.java
index e42727eaf..271d0c7c2 100644
--- a/src/org/traccar/reports/model/SummaryReport.java
+++ b/src/org/traccar/reports/model/SummaryReport.java
@@ -1,3 +1,19 @@
+/*
+ * Copyright 2016 Anton Tananaev (anton.tananaev@gmail.com)
+ * Copyright 2016 Andrey Kunitsyn (abyss@fox5.ru)
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
package org.traccar.reports.model;
public class SummaryReport {
@@ -47,4 +63,15 @@ public class SummaryReport {
this.maxSpeed = maxSpeed;
}
}
+
+ private long engineHours;
+ public long getEngineHours() {
+ return engineHours;
+ }
+ public void setEngineHours(long engineHours) {
+ this.engineHours = engineHours;
+ }
+ public void addEngineHours(long engineHours) {
+ this.engineHours += engineHours;
+ }
}
diff --git a/test/org/traccar/EventHandlerTest.java b/test/org/traccar/EventHandlerTest.java
new file mode 100644
index 000000000..423a5084f
--- /dev/null
+++ b/test/org/traccar/EventHandlerTest.java
@@ -0,0 +1,43 @@
+package org.traccar;
+
+import org.traccar.database.IdentityManager;
+import org.traccar.model.Device;
+import org.traccar.model.Position;
+
+public class EventHandlerTest {
+
+ static {
+ Context.init(new IdentityManager() {
+
+ private Device createDevice() {
+ Device device = new Device();
+ device.setId(1);
+ device.setName("test");
+ device.setUniqueId("123456789012345");
+ return device;
+ }
+
+ @Override
+ public Device getDeviceById(long id) {
+ return createDevice();
+ }
+
+ @Override
+ public Device getDeviceByUniqueId(String uniqueId) {
+ return createDevice();
+ }
+
+ @Override
+ public Position getLastPosition(long deviceId) {
+ return null;
+ }
+
+ @Override
+ public boolean isLatestPosition(Position position) {
+ return true;
+ }
+
+ });
+ }
+
+}
diff --git a/test/org/traccar/ProtocolTest.java b/test/org/traccar/ProtocolTest.java
index 07a19b691..c6c957679 100644
--- a/test/org/traccar/ProtocolTest.java
+++ b/test/org/traccar/ProtocolTest.java
@@ -49,6 +49,11 @@ public class ProtocolTest {
public Position getLastPosition(long deviceId) {
return null;
}
+
+ @Override
+ public boolean isLatestPosition(Position position) {
+ return true;
+ }
});
}
diff --git a/test/org/traccar/events/AlertEventHandlerTest.java b/test/org/traccar/events/AlertEventHandlerTest.java
new file mode 100644
index 000000000..c6d5e07d9
--- /dev/null
+++ b/test/org/traccar/events/AlertEventHandlerTest.java
@@ -0,0 +1,28 @@
+package org.traccar.events;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+import java.util.Collection;
+
+import org.junit.Test;
+import org.traccar.EventHandlerTest;
+import org.traccar.model.Event;
+import org.traccar.model.Position;
+
+public class AlertEventHandlerTest extends EventHandlerTest {
+
+ @Test
+ public void testAlertEventHandler() throws Exception {
+
+ AlertEventHandler alertEventHandler = new AlertEventHandler();
+
+ Position position = new Position();
+ position.set(Position.KEY_ALARM, Position.ALARM_GENERAL);
+ Collection<Event> events = alertEventHandler.analyzePosition(position);
+ assertNotNull(events);
+ Event event = (Event) events.toArray()[0];
+ assertEquals(Event.TYPE_ALARM, event.getType());
+ }
+
+}
diff --git a/test/org/traccar/events/CommandResultEventHandlerTest.java b/test/org/traccar/events/CommandResultEventHandlerTest.java
new file mode 100644
index 000000000..b09898b4a
--- /dev/null
+++ b/test/org/traccar/events/CommandResultEventHandlerTest.java
@@ -0,0 +1,28 @@
+package org.traccar.events;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+import java.util.Collection;
+
+import org.junit.Test;
+import org.traccar.EventHandlerTest;
+import org.traccar.model.Event;
+import org.traccar.model.Position;
+
+public class CommandResultEventHandlerTest extends EventHandlerTest {
+
+ @Test
+ public void testCommandResultEventHandler() throws Exception {
+
+ CommandResultEventHandler commandResultEventHandler = new CommandResultEventHandler();
+
+ Position position = new Position();
+ position.set(Position.KEY_RESULT, "Test Result");
+ Collection<Event> events = commandResultEventHandler.analyzePosition(position);
+ assertNotNull(events);
+ Event event = (Event) events.toArray()[0];
+ assertEquals(Event.TYPE_COMMAND_RESULT, event.getType());
+ }
+
+}
diff --git a/test/org/traccar/events/IgnitionEventHandlerTest.java b/test/org/traccar/events/IgnitionEventHandlerTest.java
new file mode 100644
index 000000000..96df6e1ed
--- /dev/null
+++ b/test/org/traccar/events/IgnitionEventHandlerTest.java
@@ -0,0 +1,29 @@
+package org.traccar.events;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+import java.util.Collection;
+
+import org.junit.Test;
+import org.traccar.EventHandlerTest;
+import org.traccar.model.Event;
+import org.traccar.model.Position;
+
+public class IgnitionEventHandlerTest extends EventHandlerTest{
+
+ @Test
+ public void testIgnitionEventHandler() throws Exception {
+
+ IgnitionEventHandler ignitionEventHandler = new IgnitionEventHandler();
+
+ Position position = new Position();
+ position.set(Position.KEY_IGNITION, true);
+ position.setValid(true);
+ Collection<Event> events = ignitionEventHandler.analyzePosition(position);
+ assertNotNull(events);
+ Event event = (Event) events.toArray()[0];
+ assertEquals(Event.TYPE_IGNITION_ON, event.getType());
+ }
+
+}
diff --git a/test/org/traccar/events/MotionEventHandlerTest.java b/test/org/traccar/events/MotionEventHandlerTest.java
new file mode 100644
index 000000000..34b2c481d
--- /dev/null
+++ b/test/org/traccar/events/MotionEventHandlerTest.java
@@ -0,0 +1,29 @@
+package org.traccar.events;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+import java.util.Collection;
+
+import org.junit.Test;
+import org.traccar.EventHandlerTest;
+import org.traccar.model.Event;
+import org.traccar.model.Position;
+
+public class MotionEventHandlerTest extends EventHandlerTest {
+
+ @Test
+ public void testMotionEventHandler() throws Exception {
+
+ MotionEventHandler motionEventHandler = new MotionEventHandler();
+
+ Position position = new Position();
+ position.setSpeed(10.0);
+ position.setValid(true);
+ Collection<Event> events = motionEventHandler.analyzePosition(position);
+ assertNotNull(events);
+ Event event = (Event) events.toArray()[0];
+ assertEquals(Event.TYPE_DEVICE_MOVING, event.getType());
+ }
+
+}
diff --git a/tools/test-generator.py b/tools/test-generator.py
index 41a32a565..0b8e4113c 100755
--- a/tools/test-generator.py
+++ b/tools/test-generator.py
@@ -32,10 +32,12 @@ for i in range(0, len(waypoints)):
lon = lon1 + (lon2 - lon1) * j / count
points.append((lat, lon))
-def send(conn, lat, lon, course, alarm):
+def send(conn, lat, lon, course, alarm, ignition):
params = (('id', id), ('timestamp', int(time.time())), ('lat', lat), ('lon', lon), ('bearing', course))
if alarm:
params = params + (('alarm', 'sos'),)
+ if ignition:
+ params = params + (('ignition', 'true'),)
conn.request('GET', '?' + urllib.urlencode(params))
conn.getresponse().read()
@@ -56,6 +58,7 @@ while True:
(lat1, lon1) = points[index % len(points)]
(lat2, lon2) = points[(index + 1) % len(points)]
alarm = ((index % 10) == 0)
- send(conn, lat1, lon1, course(lat1, lon1, lat2, lon2), alarm)
+ ignition = ((index % len(points)) != 0)
+ send(conn, lat1, lon1, course(lat1, lon1, lat2, lon2), alarm, ignition)
time.sleep(period)
index += 1
diff --git a/web/app/AttributeFormatter.js b/web/app/AttributeFormatter.js
index 3432ca1e0..274b8d028 100644
--- a/web/app/AttributeFormatter.js
+++ b/web/app/AttributeFormatter.js
@@ -34,6 +34,11 @@ Ext.define('Traccar.AttributeFormatter', {
return Ext.getStore('DistanceUnits').formatValue(value, Traccar.app.getPreference('distanceUnit'));
},
+ hoursFormatter: function (value) {
+ var hours = Math.round(value / 3600000);
+ return (hours + ' ' + Strings.sharedHourAbbreviation);
+ },
+
defaultFormatter: function (value) {
if (typeof value === 'number') {
return Number(value.toFixed(Traccar.Style.numberPrecision));
@@ -58,6 +63,8 @@ Ext.define('Traccar.AttributeFormatter', {
return this.courseFormatter;
} else if (key === 'distance' || key === 'odometer') {
return this.distanceFormatter;
+ } else if (key === 'hours') {
+ return this.hoursFormatter;
} else {
return this.defaultFormatter;
}
diff --git a/web/app/model/ReportSummary.js b/web/app/model/ReportSummary.js
index 7821e1c00..39f0c498c 100644
--- a/web/app/model/ReportSummary.js
+++ b/web/app/model/ReportSummary.js
@@ -33,5 +33,8 @@ Ext.define('Traccar.model.ReportSummary', {
}, {
name: 'distance',
type: 'float'
+ }, {
+ name: 'engineHours',
+ type: 'int'
}]
});
diff --git a/web/app/view/ReportController.js b/web/app/view/ReportController.js
index ecc7b0f91..61e278993 100644
--- a/web/app/view/ReportController.js
+++ b/web/app/view/ReportController.js
@@ -227,6 +227,11 @@ Ext.define('Traccar.view.ReportController', {
dataIndex: 'maxSpeed',
flex: 1,
renderer: Traccar.AttributeFormatter.getFormatter('speed')
+ }, {
+ text: Strings.reportEngineHours,
+ dataIndex: 'engineHours',
+ flex: 1,
+ renderer: Traccar.AttributeFormatter.getFormatter('hours')
}];
if (newValue === 'route') {
diff --git a/web/l10n/en.json b/web/l10n/en.json
index b98e6d127..af4f2363e 100644
--- a/web/l10n/en.json
+++ b/web/l10n/en.json
@@ -26,6 +26,7 @@
"sharedMute": "Mute",
"sharedType": "Type",
"sharedDistance": "Distance",
+ "sharedHourAbbreviation": "h",
"errorTitle": "Error",
"errorUnknown": "Unknown error",
"errorConnection": "Connection error",
@@ -121,6 +122,8 @@
"eventGeofenceEnter": "Device has entered geofence",
"eventGeofenceExit": "Device has exited geofence",
"eventAlarm": "Alarms",
+ "eventIgnitionOn": "Ignition is ON",
+ "eventIgnitionOff": "Ignition is OFF",
"alarm": "Alarm",
"alarmSos": "SOS Alarm",
"alarmVibration": "Vibration Alarm",
@@ -139,5 +142,6 @@
"reportCsv": "CSV",
"reportDeviceName": "Device Name",
"reportAverageSpeed": "Average Speed",
- "reportMaximumSpeed": "Maximum Speed"
+ "reportMaximumSpeed": "Maximum Speed",
+ "reportEngineHours": "Engine Hours"
} \ No newline at end of file