aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorninioe <ninioe@gmail.com>2016-07-12 16:04:40 +0300
committerninioe <ninioe@gmail.com>2016-07-12 16:04:40 +0300
commitd045c1e2174146ddc8ad8b2ef4442863f3d84a11 (patch)
tree458ac9a09ef9df6426a34067072164c44ac18020
parent8d5b4ec5ec8e4aaa2c34793e3100a7782551afbd (diff)
downloadtraccar-server-d045c1e2174146ddc8ad8b2ef4442863f3d84a11.tar.gz
traccar-server-d045c1e2174146ddc8ad8b2ef4442863f3d84a11.tar.bz2
traccar-server-d045c1e2174146ddc8ad8b2ef4442863f3d84a11.zip
Added support for Alarm popup & positions history cleaner
1. added support for Alarm and Alarm Type in popup and also in history records. can be muted with a toggle button in the UI 2. added a timer to clear positions history once a day. the default is to save positions history for 7 days if not defined in the configuration file. 3. prevent the lock of the UI files (js, html, css, etc..) for wondows developers in debug mode. It's easier to do changes to the UI without stopping the app each time. 4. tools: added support in test-generator.py to simulate Alert, also added minify.bat file to compile new js files for the UI using sencha SDK for windows developers
-rw-r--r--debug.xml11
-rw-r--r--src/org/traccar/Main.java17
-rw-r--r--src/org/traccar/database/DataManager.java25
-rw-r--r--src/org/traccar/model/Position.java1
-rw-r--r--src/org/traccar/protocol/H02ProtocolDecoder.java15
-rw-r--r--src/org/traccar/web/WebServer.java7
-rw-r--r--tools/minify.bat5
-rwxr-xr-xtools/test-generator.py8
-rw-r--r--web/app/AttributeFormatter.js32
-rw-r--r--web/app/view/Devices.js20
-rw-r--r--web/app/view/Report.js10
-rw-r--r--web/app/view/StateController.js49
12 files changed, 194 insertions, 6 deletions
diff --git a/debug.xml b/debug.xml
index 227ba7b73..20287587b 100644
--- a/debug.xml
+++ b/debug.xml
@@ -65,10 +65,15 @@
<!-- DATABASE CONFIG -->
<!--<entry key='database.driverFile'>hsqldb.jar</entry>-->
- <entry key='database.driver'>org.h2.Driver</entry>
+ <!--<entry key='database.driver'>org.h2.Driver</entry>
<entry key='database.url'>jdbc:h2:./target/database</entry>
<entry key='database.user'>sa</entry>
- <entry key='database.password'></entry>
+ <entry key='database.password'></entry>-->
+
+ <entry key='database.driver'>com.mysql.jdbc.Driver</entry>
+ <entry key='database.url'>jdbc:mysql://127.0.0.1:3306/traccar?allowMultiQueries=true&amp;autoReconnect=true&amp;useUnicode=yes&amp;characterEncoding=UTF-8&amp;sessionVariables=sql_mode=ANSI_QUOTES</entry>
+ <entry key='database.user'>traccar</entry>
+ <entry key='database.password'>###########</entry>
<entry key='database.ignoreUnknown'>true</entry>
@@ -77,6 +82,8 @@
<entry key='database.changelog'>./schema/changelog-master.xml</entry>
+ <entry key='database.positionsHistoryDays'>7</entry>
+
<entry key='database.selectServers'>
SELECT * FROM server;
</entry>
diff --git a/src/org/traccar/Main.java b/src/org/traccar/Main.java
index 1b8d93e34..eb3114210 100644
--- a/src/org/traccar/Main.java
+++ b/src/org/traccar/Main.java
@@ -16,7 +16,8 @@
package org.traccar;
import org.traccar.helper.Log;
-
+import java.util.Timer;
+import java.util.TimerTask;
import java.util.Locale;
public final class Main {
@@ -35,6 +36,20 @@ public final class Main {
Context.getWebServer().start();
}
+ //added by Erez
+ Timer timer = new Timer();
+ timer.scheduleAtFixedRate(new TimerTask() {
+ @Override
+ public void run() {
+ // Clean positions history every day
+ try {
+ Context.getDataManager().clearPositionsHistory();
+ } catch (Exception error) {
+ Log.warning(error);
+ }
+ }
+ }, 10*1000, 24*60*60*1000);
+
Runtime.getRuntime().addShutdownHook(new Thread() {
@Override
public void run() {
diff --git a/src/org/traccar/database/DataManager.java b/src/org/traccar/database/DataManager.java
index b3f24383f..7fd672849 100644
--- a/src/org/traccar/database/DataManager.java
+++ b/src/org/traccar/database/DataManager.java
@@ -521,6 +521,31 @@ public class DataManager implements IdentityManager {
.executeQuery(Position.class);
}
+ //added by Erez
+ public void clearPositionsHistory() throws SQLException {
+ //SimpleDateFormat s = new SimpleDateFormat("yyyy-MM-dd");
+ String histDays = config.getString("database.positionsHistoryDays");
+ if (histDays == null) {
+ histDays = "7";
+ }
+ int n = Integer.parseInt(histDays);
+
+ for (Device device : getAllDevices()) {
+ Date lastUpdate = device.getLastUpdate();
+ if(lastUpdate != null){
+
+ Date dateBefore = new Date(lastUpdate.getTime() - n * 24 * 3600 * 1000 ); //Subtract n days
+ //String dt = s.format(dateBefore);
+ String sql = "DELETE FROM positions WHERE deviceid=:deviceId and servertime<:serverTime";
+
+ QueryBuilder.create(dataSource, sql)
+ .setLong("deviceId", device.getId())
+ .setDate("serverTime", dateBefore)
+ .executeUpdate();
+ }
+ }
+ }
+
public Server getServer() throws SQLException {
return QueryBuilder.create(dataSource, getQuery("database.selectServers"))
.executeQuerySingle(Server.class);
diff --git a/src/org/traccar/model/Position.java b/src/org/traccar/model/Position.java
index 4e03b2097..c548c542f 100644
--- a/src/org/traccar/model/Position.java
+++ b/src/org/traccar/model/Position.java
@@ -28,6 +28,7 @@ public class Position extends Message {
public static final String KEY_GPS = "gps";
public static final String KEY_EVENT = "event";
public static final String KEY_ALARM = "alarm";
+ public static final String KEY_ALARM_TYPE = "alarm-type"; //added by Erez
public static final String KEY_STATUS = "status";
public static final String KEY_ODOMETER = "odometer";
public static final String KEY_HOURS = "hours";
diff --git a/src/org/traccar/protocol/H02ProtocolDecoder.java b/src/org/traccar/protocol/H02ProtocolDecoder.java
index ec5d3adef..6e1bb2d9d 100644
--- a/src/org/traccar/protocol/H02ProtocolDecoder.java
+++ b/src/org/traccar/protocol/H02ProtocolDecoder.java
@@ -64,8 +64,21 @@ public class H02ProtocolDecoder extends BaseProtocolDecoder {
private void processStatus(Position position, long status) {
if (!BitUtil.check(status, 0) || !BitUtil.check(status, 1)
- || !BitUtil.check(status, 3) || !BitUtil.check(status, 4)) {
+ || !BitUtil.check(status, 3) || !BitUtil.check(status, 4) || !BitUtil.check(status, 7)) {//added by Erez
position.set(Position.KEY_ALARM, true);
+
+ if (!BitUtil.check(status, 0)){//added by Erez
+ position.set(Position.KEY_ALARM_TYPE, "theft alarm");
+ } else if (!BitUtil.check(status, 1)){
+ position.set(Position.KEY_ALARM_TYPE, "robbery alarm");
+ } else if (!BitUtil.check(status, 3)){
+ position.set(Position.KEY_ALARM_TYPE, "illegal ignition alarm");
+ } else if (!BitUtil.check(status, 4)){
+ position.set(Position.KEY_ALARM_TYPE, "entering alarm");
+ } else if (!BitUtil.check(status, 7)){
+ position.set(Position.KEY_ALARM_TYPE, "out alarm");
+ }
+
}
position.set(Position.KEY_IGNITION, !BitUtil.check(status, 10));
position.set(Position.KEY_STATUS, status);
diff --git a/src/org/traccar/web/WebServer.java b/src/org/traccar/web/WebServer.java
index 5527e80f3..73702cc3d 100644
--- a/src/org/traccar/web/WebServer.java
+++ b/src/org/traccar/web/WebServer.java
@@ -118,6 +118,13 @@ public class WebServer {
resourceHandler.setResourceBase(config.getString("web.path"));
if (config.getBoolean("web.debug")) {
resourceHandler.setWelcomeFiles(new String[] {"debug.html"});
+ //Troubleshooting Locked Files on Windows (changed by Erez)
+ resourceHandler.setMinMemoryMappedContentLength(-1);
+
+ /*DefaultServlet defaultServlet = new DefaultServlet();
+ ServletHolder holder = new ServletHolder(defaultServlet);
+ holder.setInitParameter("useFileMappedBuffer", "false");
+ handler.addServlet(holder, "/");*/
} else {
resourceHandler.setWelcomeFiles(new String[] {"release.html", "index.html"});
}
diff --git a/tools/minify.bat b/tools/minify.bat
new file mode 100644
index 000000000..dfa9c5895
--- /dev/null
+++ b/tools/minify.bat
@@ -0,0 +1,5 @@
+@echo off
+cd C:\Users\Erez\Documents\traccar\web
+set SDK=C:\inetpub\wwwroot\ext-6.0.0
+
+sencha -sdk %SDK% compile -classpath=app.js,app,%SDK%\packages\core\src,%SDK%\packages\core\overrides,%SDK%\classic\classic\src,%SDK%\classic\classic\overrides exclude -all and include -recursive -file app.js and exclude -namespace=Ext and concatenate -closure app.min.js
diff --git a/tools/test-generator.py b/tools/test-generator.py
index 681d1755d..4beadc375 100755
--- a/tools/test-generator.py
+++ b/tools/test-generator.py
@@ -32,8 +32,11 @@ for i in range(0, len(waypoints)):
lon = lon1 + (lon2 - lon1) * j / count
points.append((lat, lon))
-def send(lat, lon, course):
+#changed by Erez
+def send(lat, lon, course, alarm):
params = (('id', id), ('timestamp', int(time.time())), ('lat', lat), ('lon', lon), ('bearing', course))
+ if alarm:
+ params = params + (('alarm', 'true'),)
urllib2.urlopen(server + '?' + urllib.urlencode(params)).read()
def course(lat1, lon1, lat2, lon2):
@@ -50,6 +53,7 @@ index = 0
while True:
(lat1, lon1) = points[index % len(points)]
(lat2, lon2) = points[(index + 1) % len(points)]
- send(lat1, lon1, course(lat1, lon1, lat2, lon2))
+ alarm = ((index % 10) == 0)#added by Erez
+ send(lat1, lon1, course(lat1, lon1, lat2, lon2), alarm)
time.sleep(period)
index += 1
diff --git a/web/app/AttributeFormatter.js b/web/app/AttributeFormatter.js
index 3432ca1e0..51b479b9a 100644
--- a/web/app/AttributeFormatter.js
+++ b/web/app/AttributeFormatter.js
@@ -34,6 +34,34 @@ Ext.define('Traccar.AttributeFormatter', {
return Ext.getStore('DistanceUnits').formatValue(value, Traccar.app.getPreference('distanceUnit'));
},
+ //added by Erez
+ alarmFormatter: function (attributes) {
+ if (attributes instanceof Object) {
+ if (attributes.hasOwnProperty('alarm')){
+ var value = attributes.alarm;
+ if (typeof value === 'boolean') {
+ value = (value ? Ext.Msg.buttonText.yes : Ext.Msg.buttonText.no);
+ }
+ return '<span style="color:red;">' + value + '</span>';
+ }
+ }
+ return '';
+ },
+
+ //added by Erez
+ alarmTypeFormatter: function (attributes) {
+ var alatmType = '';
+ if (attributes instanceof Object) {
+ for (key in attributes) {
+ if (attributes.hasOwnProperty(key) && key.toLowerCase()=='alarm-type') {
+ alatmType = attributes[key];
+ break;
+ }
+ }
+ }
+ return '<span style="color:red;">' + alatmType + '</span>';
+ },
+
defaultFormatter: function (value) {
if (typeof value === 'number') {
return Number(value.toFixed(Traccar.Style.numberPrecision));
@@ -58,6 +86,10 @@ Ext.define('Traccar.AttributeFormatter', {
return this.courseFormatter;
} else if (key === 'distance' || key === 'odometer') {
return this.distanceFormatter;
+ } else if (key === 'alarm') {//added by Erez
+ return this.alarmFormatter;
+ } else if (key === 'alarm-type') {//added by Erez
+ return this.alarmTypeFormatter;
} else {
return this.defaultFormatter;
}
diff --git a/web/app/view/Devices.js b/web/app/view/Devices.js
index 1a70dfef8..4227fd1fb 100644
--- a/web/app/view/Devices.js
+++ b/web/app/view/Devices.js
@@ -57,6 +57,26 @@ Ext.define('Traccar.view.Devices', {
tooltipType: 'title'
}, {
xtype: 'tbfill'
+ },{
+ id: 'showAlarmButton',//added by Erez
+ glyph: 'xf0a2@FontAwesome',
+ tooltip: 'Show Alarms',
+ tooltipType: 'title',
+ pressed : true,
+ enableToggle: true,
+ listeners:{
+ toggle: function(button, pressed){
+ if(pressed){
+ button.setGlyph('xf0a2@FontAwesome');
+ //Ext.getCmp('useAlarmSoundButton').enable();
+ }
+ else {
+ button.setGlyph('xf1f7@FontAwesome');
+ //Ext.getCmp('useAlarmSoundButton').disable();
+ }
+ },
+ scope:this
+ }
}, {
id: 'deviceFollowButton',
glyph: 'xf05b@FontAwesome',
diff --git a/web/app/view/Report.js b/web/app/view/Report.js
index 4261b9040..fcbd5c028 100644
--- a/web/app/view/Report.js
+++ b/web/app/view/Report.js
@@ -115,5 +115,15 @@ Ext.define('Traccar.view.Report', {
dataIndex: 'address',
flex: 1,
renderer: Traccar.AttributeFormatter.getFormatter('address')
+ }, {
+ text: 'Alarm',//added by Erez
+ dataIndex: 'attributes',
+ flex: 1,
+ renderer: Traccar.AttributeFormatter.getFormatter('alarm')
+ }, {
+ text: 'Alarm Type',//added by Erez
+ dataIndex: 'attributes',
+ flex: 1,
+ renderer: Traccar.AttributeFormatter.getFormatter('alarm-type')
}]
});
diff --git a/web/app/view/StateController.js b/web/app/view/StateController.js
index 01df6645d..20b6145ec 100644
--- a/web/app/view/StateController.js
+++ b/web/app/view/StateController.js
@@ -62,6 +62,11 @@ Ext.define('Traccar.view.StateController', {
if (this.deviceId === data[i].get('deviceId')) {
this.updatePosition(data[i]);
}
+ var position = data[i]; //added by Erez
+ var attributes = position.get('attributes');
+ if (attributes instanceof Object){
+ if (attributes.hasOwnProperty('alarm') && this.showAlarmSelected()) this.onAlarm(position.get('deviceId'), attributes);
+ }
}
},
@@ -104,6 +109,50 @@ Ext.define('Traccar.view.StateController', {
}
},
+ showAlarmSelected: function () {//added by Erez
+ return Ext.getCmp('showAlarmButton') && Ext.getCmp('showAlarmButton').pressed;
+ },
+
+ onAlarm: function(deviceId, attributes){//added by Erez
+ var alatmType = '';
+ for (key in attributes) {
+ if (attributes.hasOwnProperty(key) && key.toLowerCase()=='alarm-type') {
+ alatmType = ' of type ' + attributes[key];
+ break;
+ }
+ }
+
+ var device = Ext.getStore('Devices').findRecord('id', deviceId, 0, false, false, true);
+ if(device){
+ var deviceName = device.get('name');
+ var msg = 'Alarm'+alatmType+' on device '+deviceName+'!';
+ this.showAlarmMsg(msg);
+ }
+ },
+
+ showAlarmMsg: function(msg){//added by Erez
+ this.beep();
+ var alarmMsg = Ext.Msg.show({
+ title:'Alarm',
+ message: msg,
+ modal: false,
+ buttons: Ext.Msg.YES,
+ icon: Ext.Msg.WARNING
+ });
+
+ window.setTimeout(function(){
+ alarmMsg.close();
+ }, 10000)
+
+ },
+
+ beep: function() {//added by Erez
+ if(this.snd == null){
+ this.snd = new Audio("data:audio/wav;base64,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qJrx4KOQjahZxWbcZgztj2c49nKmkId44S71j0c8eV9yDK6uPRzx5X18eDvjvQ6yKo9ZSS6l//8elePK/Lf//IInrOF/FvDoADYAGBMGb7FtErm5MXMlmPAJQVgWta7Zx2go+8xJ0UiCb8LHHdftWyLJE0QIAIsI+UbXu67dZMjmgDGCGl1H+vpF4NSDckSIkk7Vd+sxEhBQMRU8j/12UIRhzSaUdQ+rQU5kGeFxm+hb1oh6pWWmv3uvmReDl0UnvtapVaIzo1jZbf/pD6ElLqSX+rUmOQNpJFa/r+sa4e/pBlAABoAAAAA3CUgShLdGIxsY7AUABPRrgCABdDuQ5GC7DqPQCgbbJUAoRSUj+NIEig0YfyWUho1VBBBA//uQZB4ABZx5zfMakeAAAAmwAAAAF5F3P0w9GtAAACfAAAAAwLhMDmAYWMgVEG1U0FIGCBgXBXAtfMH10000EEEEEECUBYln03TTTdNBDZopopYvrTTdNa325mImNg3TTPV9q3pmY0xoO6bv3r00y+IDGid/9aaaZTGMuj9mpu9Mpio1dXrr5HERTZSmqU36A3CumzN/9Robv/Xx4v9ijkSRSNLQhAWumap82WRSBUqXStV/YcS+XVLnSS+WLDroqArFkMEsAS+eWmrUzrO0oEmE40RlMZ5+ODIkAyKAGUwZ3mVKmcamcJnMW26MRPgUw6j+LkhyHGVGYjSUUKNpuJUQoOIAyDvEyG8S5yfK6dhZc0Tx1KI/gviKL6qvvFs1+bWtaz58uUNnryq6kt5RzOCkPWlVqVX2a/EEBUdU1KrXLf40GoiiFXK///qpoiDXrOgqDR38JB0bw7SoL+ZB9o1RCkQjQ2CBYZKd/+VJxZRRZlqSkKiws0WFxUyCwsKiMy7hUVFhIaCrNQsKkTIsLivwKKigsj8XYlwt/WKi2N4d//uQRCSAAjURNIHpMZBGYiaQPSYyAAABLAAAAAAAACWAAAAApUF/Mg+0aohSIRobBAsMlO//Kk4soosy1JSFRYWaLC4qZBYWFRGZdwqKiwkNBVmoWFSJkWFxX4FFRQWR+LsS4W/rFRb/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////VEFHAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAU291bmRib3kuZGUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMjAwNGh0dHA6Ly93d3cuc291bmRib3kuZGUAAAAAAAAAACU=");
+ }
+ this.snd.play();
+ },
+
selectDevice: function (device) {
var position;
this.deviceId = device.get('id');