aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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');