aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/org/traccar/database/ConnectionManager.java35
-rw-r--r--web/app.css10
-rw-r--r--web/app/Style.js6
-rw-r--r--web/app/controller/Root.js21
-rw-r--r--web/app/model/Device.js6
-rw-r--r--web/app/view/Devices.js23
-rw-r--r--web/app/view/MapController.js55
-rw-r--r--web/l10n/en.json1
-rw-r--r--web/l10n/no.json79
-rw-r--r--web/l10n/si.json16
-rw-r--r--web/locale.js1
11 files changed, 229 insertions, 24 deletions
diff --git a/src/org/traccar/database/ConnectionManager.java b/src/org/traccar/database/ConnectionManager.java
index 345bb4577..ae931151d 100644
--- a/src/org/traccar/database/ConnectionManager.java
+++ b/src/org/traccar/database/ConnectionManager.java
@@ -25,8 +25,13 @@ import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
+import java.util.concurrent.TimeUnit;
+
import org.jboss.netty.channel.Channel;
+import org.jboss.netty.util.Timeout;
+import org.jboss.netty.util.TimerTask;
import org.traccar.Context;
+import org.traccar.GlobalTimer;
import org.traccar.Protocol;
import org.traccar.helper.Log;
import org.traccar.model.Device;
@@ -34,11 +39,17 @@ import org.traccar.model.Position;
public class ConnectionManager {
+ private static final long DEFAULT_TIMEOUT = 600;
+
+ private final long deviceTimeout;
+
private final Map<Long, ActiveDevice> activeDevices = new HashMap<>();
private final Map<Long, Position> positions = new HashMap<>();
private final Map<Long, Set<UpdateListener>> listeners = new HashMap<>();
+ private final Map<Long, Timeout> timeouts = new HashMap<>();
public ConnectionManager(DataManager dataManager) {
+ deviceTimeout = Context.getConfig().getLong("status.timeout", DEFAULT_TIMEOUT) * 1000;
if (dataManager != null) {
try {
for (Position position : dataManager.getLatestPositions()) {
@@ -57,7 +68,7 @@ public class ConnectionManager {
public void removeActiveDevice(Channel channel) {
for (ActiveDevice activeDevice : activeDevices.values()) {
if (activeDevice.getChannel() == channel) {
- updateDevice(activeDevice.getDeviceId(), Device.STATUS_OFFLINE, new Date());
+ updateDevice(activeDevice.getDeviceId(), Device.STATUS_OFFLINE, null);
activeDevices.remove(activeDevice.getDeviceId());
break;
}
@@ -68,10 +79,28 @@ public class ConnectionManager {
return activeDevices.get(deviceId);
}
- public synchronized void updateDevice(long deviceId, String status, Date time) {
+ public synchronized void updateDevice(final long deviceId, String status, Date time) {
Device device = Context.getIdentityManager().getDeviceById(deviceId);
device.setStatus(status);
- device.setLastUpdate(time);
+ if (time != null) {
+ device.setLastUpdate(time);
+ }
+
+ Timeout timeout = timeouts.remove(deviceId);
+ if (timeout != null) {
+ timeout.cancel();
+ }
+
+ if (status.equals(Device.STATUS_ONLINE)) {
+ timeouts.put(deviceId, GlobalTimer.getTimer().newTimeout(new TimerTask() {
+ @Override
+ public void run(Timeout timeout) throws Exception {
+ if (!timeout.isCancelled()) {
+ updateDevice(deviceId, Device.STATUS_UNKNOWN, null);
+ }
+ }
+ }, deviceTimeout, TimeUnit.MILLISECONDS));
+ }
try {
Context.getDataManager().updateDeviceStatus(device);
diff --git a/web/app.css b/web/app.css
index 3c4507e38..eb0fdf136 100644
--- a/web/app.css
+++ b/web/app.css
@@ -1,3 +1,13 @@
+.status-color-online {
+ background-color: rgba(77, 250, 144, 0.3);
+}
+.status-color-unknown {
+ background-color: rgba(250, 190, 77, 0.3);
+}
+.status-color-offline {
+ background-color: rgba(255, 84, 104, 0.3);
+}
+
.state-indicator {
position: absolute;
top: -999em;
diff --git a/web/app/Style.js b/web/app/Style.js
index 58ab059ad..b75503c32 100644
--- a/web/app/Style.js
+++ b/web/app/Style.js
@@ -48,9 +48,9 @@ Ext.define('Traccar.Style', {
mapTextOffset: 10,
mapTextFont: 'bold 12px sans-serif',
- mapColorOnline: '#4DFA90',
- mapColorUnknown: '#FABE4D',
- mapColorOffline: '#FF5468',
+ mapColorOnline: 'rgba(77, 250, 144, 1.0)',
+ mapColorUnknown: 'rgba(250, 190, 77, 1.0)',
+ mapColorOffline: 'rgba(255, 84, 104, 1.0)',
mapColorReport: 'rgba(21, 127, 204, 1.0)',
mapRadiusNormal: 10,
diff --git a/web/app/controller/Root.js b/web/app/controller/Root.js
index 041e0b902..733055cdf 100644
--- a/web/app/controller/Root.js
+++ b/web/app/controller/Root.js
@@ -97,19 +97,32 @@ Ext.define('Traccar.controller.Root', {
first: first
},
callback: Traccar.app.getErrorHandler(this, function (options, success, response) {
- var i, store, data, devices, positions, position;
+ var i, deviceStore, positionStore, data, devices, positions, device, position;
if (success) {
- store = Ext.getStore('LatestPositions');
+ deviceStore = Ext.getStore('Devices');
+ positionStore = Ext.getStore('LatestPositions');
data = Ext.decode(response.responseText).data;
devices = data.devices;
positions = data.positions;
+ for (i = 0; i < devices.length; i++) {
+ device = deviceStore.findRecord('id', devices[i].id, 0, false, false, true);
+ if (device) {
+ device.set({
+ status: devices[i].status,
+ lastUpdate: devices[i].lastUpdate
+ }, {
+ dirty: false
+ });
+ }
+ }
+
for (i = 0; i < positions.length; i++) {
- position = store.findRecord('deviceId', positions[i].deviceId, 0, false, false, true);
+ position = positionStore.findRecord('deviceId', positions[i].deviceId, 0, false, false, true);
if (position) {
position.set(positions[i]);
} else {
- store.add(Ext.create('Traccar.model.Position', positions[i]));
+ positionStore.add(Ext.create('Traccar.model.Position', positions[i]));
}
}
diff --git a/web/app/model/Device.js b/web/app/model/Device.js
index e9ed1f680..983e3e62e 100644
--- a/web/app/model/Device.js
+++ b/web/app/model/Device.js
@@ -27,5 +27,11 @@ Ext.define('Traccar.model.Device', {
}, {
name: 'uniqueId',
type: 'string'
+ }, {
+ name: 'status',
+ type: 'string'
+ }, {
+ name: 'lastUpdate',
+ type: 'date'
}]
});
diff --git a/web/app/view/Devices.js b/web/app/view/Devices.js
index 9dcd76a55..128cd3be1 100644
--- a/web/app/view/Devices.js
+++ b/web/app/view/Devices.js
@@ -52,10 +52,27 @@ Ext.define('Traccar.view.Devices', {
columns: [{
text: Strings.deviceName,
- dataIndex: 'name', flex: 1
+ dataIndex: 'name',
+ flex: 1
}, {
- text: Strings.deviceIdentifier,
- dataIndex: 'uniqueId', flex: 1
+ text: Strings.deviceLastUpdate,
+ dataIndex: 'lastUpdate',
+ flex: 1,
+ renderer: function (value, metaData, record) {
+ var status = record.get('status');
+ switch (status) {
+ case 'online':
+ metaData.tdCls = 'status-color-online';
+ break;
+ case 'offline':
+ metaData.tdCls = 'status-color-offline';
+ break;
+ default:
+ metaData.tdCls = 'status-color-unknown';
+ break;
+ }
+ return Ext.Date.format(value, Traccar.Style.dateTimeFormat);
+ }
}]
});
diff --git a/web/app/view/MapController.js b/web/app/view/MapController.js
index c153ebd45..95ceb51c3 100644
--- a/web/app/view/MapController.js
+++ b/web/app/view/MapController.js
@@ -27,6 +27,10 @@ Ext.define('Traccar.view.MapController', {
}
},
store: {
+ '#Devices': {
+ add: 'updateDevice',
+ update: 'updateDevice'
+ },
'#LatestPositions': {
add: 'updateLatest',
update: 'updateLatest'
@@ -49,6 +53,51 @@ Ext.define('Traccar.view.MapController', {
this.reportMarkers = {};
},
+ getDeviceColor: function (device) {
+ console.log(device.get('status'));
+ switch (device.get('status')) {
+ case 'online':
+ return Traccar.Style.mapColorOnline;
+ case 'offline':
+ return Traccar.Style.mapColorOffline;
+ default:
+ return Traccar.Style.mapColorUnknown;
+ }
+ },
+
+ changeMarkerColor: function (style, color) {
+ return new ol.style.Style({
+ image: new ol.style.Arrow({
+ radius: style.getImage().getRadius(),
+ fill: new ol.style.Fill({
+ color: color
+ }),
+ stroke: style.getImage().getStroke(),
+ rotation: style.getImage().getRotation()
+ }),
+ text: style.getText()
+ });
+ },
+
+ updateDevice: function (store, data) {
+ var i, device, deviceId;
+
+ if (!Ext.isArray(data)) {
+ data = [data];
+ }
+
+ for (i = 0; i < data.length; i++) {
+ device = data[i];
+ deviceId = device.get('id');
+
+ if (deviceId in this.latestMarkers) {
+ marker = this.latestMarkers[deviceId];
+ marker.setStyle(
+ this.changeMarkerColor(marker.getStyle(), this.getDeviceColor(device)));
+ }
+ }
+ },
+
updateLatest: function (store, data) {
var i, position, geometry, device, deviceId, marker, style;
@@ -75,7 +124,7 @@ Ext.define('Traccar.view.MapController', {
this.latestMarkers[deviceId] = marker;
this.getView().getVectorSource().addFeature(marker);
- style = this.getLatestMarker();
+ style = this.getLatestMarker(this.getDeviceColor(device));
style.getText().setText(device.get('name'));
marker.setStyle(style);
}
@@ -175,9 +224,9 @@ Ext.define('Traccar.view.MapController', {
});
},
- getLatestMarker: function () {
+ getLatestMarker: function (color) {
return this.getMarkerStyle(
- Traccar.Style.mapRadiusNormal, Traccar.Style.mapColorUnknown);
+ Traccar.Style.mapRadiusNormal, color);
},
getReportMarker: function () {
diff --git a/web/l10n/en.json b/web/l10n/en.json
index a3489fbe1..b18c85afd 100644
--- a/web/l10n/en.json
+++ b/web/l10n/en.json
@@ -31,6 +31,7 @@
"deviceTitle": "Devices",
"deviceName": "Name",
"deviceIdentifier": "Identifier",
+ "deviceLastUpdate": "Last Update",
"deviceCommand": "Command",
"settingsTitle": "Settings",
"settingsUser": "Account",
diff --git a/web/l10n/no.json b/web/l10n/no.json
new file mode 100644
index 000000000..8a53e1213
--- /dev/null
+++ b/web/l10n/no.json
@@ -0,0 +1,79 @@
+{
+ "sharedLoading": "Laster...",
+ "sharedSave": "Lagre",
+ "sharedCancel": "Avbryte",
+ "sharedAdd": "Legg til",
+ "sharedEdit": "Endre",
+ "sharedRemove": "Fjerne",
+ "sharedRemoveConfirm": "Fjerne element?",
+ "sharedKm": "km",
+ "sharedMi": "mi",
+ "sharedKmh": "km/t",
+ "sharedMph": "mph",
+ "sharedHour": "Time",
+ "sharedMinute": "Minutt",
+ "sharedSecond": "Sekund",
+ "errorTitle": "Feil",
+ "errorUnknown": "Ukjent feil",
+ "errorConnection": "Forbindelse feilet",
+ "userName": "Navn",
+ "userEmail": "Epost",
+ "userPassword": "Passord",
+ "userAdmin": "Admin",
+ "loginTitle": "Logg inn",
+ "loginLanguage": "Språk",
+ "loginRegister": "Registrere",
+ "loginLogin": "Logg inn",
+ "loginFailed": "Feil epost eller passord",
+ "loginCreated": "Ny bruker har blitt registrert",
+ "loginLogout": "Logg ut",
+ "deviceDialog": "Enhet",
+ "deviceTitle": "Enheter",
+ "deviceName": "Navn",
+ "deviceIdentifier": "Identitet",
+ "deviceCommand": "Kommando",
+ "settingsTitle": "Innstillinger",
+ "settingsUser": "Konto",
+ "settingsServer": "Server",
+ "settingsUsers": "Brukere",
+ "settingsDistanceUnit": "Avstand",
+ "settingsSpeedUnit": "Hastighet",
+ "reportTitle": "Rapporter",
+ "reportDevice": "Enhet",
+ "reportFrom": "Fra",
+ "reportTo": "Til",
+ "reportShow": "Vis",
+ "reportClear": "Nullstille",
+ "positionFixTime": "Tid",
+ "positionValid": "Gyldig",
+ "positionLatitude": "Latitude",
+ "positionLongitude": "Longitude",
+ "positionAltitude": "Altitude",
+ "positionSpeed": "Hastighet",
+ "positionCourse": "Retning",
+ "positionAddress": "Adresse",
+ "positionProtocol": "Protokoll",
+ "serverTitle": "Server Instillinger",
+ "serverZoom": "Zoom",
+ "serverRegistration": "Registere",
+ "mapTitle": "Kart",
+ "mapLayer": "Kart Lag",
+ "mapCustom": "Egendefinert Kart",
+ "mapOsm": "Open Street Kart",
+ "mapBingKey": "Bing Maps Nøkkel",
+ "mapBingRoad": "Bing Maps Vei",
+ "mapBingAerial": "Bing Maps Fly",
+ "stateTitle": "Stat",
+ "stateName": "Egenskap",
+ "stateValue": "Verdi",
+ "commandTitle": "Kommando",
+ "commandSend": "Sende",
+ "commandType": "Type",
+ "commandSent": "Kommando har blitt sendt",
+ "commandPositionPeriodic": "Periodisk Rapportering",
+ "commandPositionStop": "Stoppe Rapportering",
+ "commandEngineStop": "Motor Stop",
+ "commandEngineResume": "Motor Restarte",
+ "commandFrequency": "Frekvens",
+ "commandUnit": "Enhet"
+} \ No newline at end of file
diff --git a/web/l10n/si.json b/web/l10n/si.json
index 8e565423b..db6381586 100644
--- a/web/l10n/si.json
+++ b/web/l10n/si.json
@@ -1,5 +1,5 @@
{
- "sharedLoading": "පූරණය ...",
+ "sharedLoading": "පූරණය කරමින් ...",
"sharedSave": "සුරකින්න",
"sharedCancel": "අවලංගු කරන්න",
"sharedAdd": "එක් කරන්න",
@@ -13,19 +13,19 @@
"sharedHour": "පැය",
"sharedMinute": "මිනිත්තු",
"sharedSecond": "තත්පර",
- "errorTitle": "දෝෂයක්",
- "errorUnknown": "නොදන්නා දෝෂයක්",
- "errorConnection": "සම්බන්ධතා දෝෂයක්",
+ "errorTitle": "දෝෂයක් ",
+ "errorUnknown": "නොදන්නා දෝෂයක් !",
+ "errorConnection": "සම්බන්ධතා දෝෂයක් !",
"userName": "නම",
"userEmail": "විද්යුත් තැපෑල",
"userPassword": "මුරපදය",
"userAdmin": "පරිපාලක",
- "loginTitle": "පිවිසුම",
+ "loginTitle": "පිවිසුම් ගිණුම",
"loginLanguage": "භාෂාව",
"loginRegister": "ලියාපදිංචි කරන්න",
"loginLogin": "පිවිසුම",
- "loginFailed": "ඊ-මේල් ලිපිනය හෝ මුරපදය වැරදිය",
- "loginCreated": "නව පරිශීලක ලියාපදිංචි කරන ලදි",
+ "loginFailed": "ඊ-මේල් ලිපිනය හෝ මුරපදය වැරදිය !",
+ "loginCreated": "නව පරිශීලක ලියාපදිංචි කරන ලදි !",
"loginLogout": "ඉවත්වන්න",
"deviceDialog": "උපාංගය",
"deviceTitle": "උපාංග",
@@ -69,7 +69,7 @@
"commandTitle": "විධානය",
"commandSend": "යවන්න",
"commandType": "වර්ගය",
- "commandSent": "අණ යවා ඇත",
+ "commandSent": "විධානය යවා ඇත",
"commandPositionPeriodic": "ආවර්තිතව වාර්තා කරන්න",
"commandPositionStop": "වාර්තා කිරීම නවත්වන්න",
"commandEngineStop": "එන්ජිම නවත්වන්න",
diff --git a/web/locale.js b/web/locale.js
index a5acb0ad3..8b050c6f8 100644
--- a/web/locale.js
+++ b/web/locale.js
@@ -33,6 +33,7 @@ Locale.languages = {
'hu': { name: 'Magyar', code: 'hu' },
'lt': { name: 'Lietuvių', code: 'lt' },
'nl': { name: 'Nederlands', code: 'nl' },
+ 'no': { name: 'Norsk', code: 'no_NB' },
'pl': { name: 'Polski', code: 'pl' },
'pt': { name: 'Português', code: 'pt' },
'pt_BR': { name: 'Português (Brasil)', code: 'pt_BR' },