aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--debug.xml6
-rw-r--r--src/org/traccar/BasePipelineFactory.java5
-rw-r--r--src/org/traccar/Context.java7
-rw-r--r--src/org/traccar/WebDataHandler.java19
-rw-r--r--src/org/traccar/model/Server.java8
-rw-r--r--src/org/traccar/protocol/Gl200ProtocolDecoder.java31
-rw-r--r--src/org/traccar/protocol/MegastekProtocolDecoder.java119
-rw-r--r--src/org/traccar/protocol/MeiligaoProtocol.java5
-rw-r--r--src/org/traccar/protocol/MeitrackProtocol.java11
-rw-r--r--src/org/traccar/protocol/MeitrackProtocolEncoder.java40
-rw-r--r--src/org/traccar/protocol/TotemProtocolDecoder.java9
-rw-r--r--test/org/traccar/protocol/Gl200ProtocolDecoderTest.java6
-rw-r--r--test/org/traccar/protocol/GoSafeProtocolDecoderTest.java6
-rw-r--r--test/org/traccar/protocol/KhdProtocolDecoderTest.java3
-rw-r--r--test/org/traccar/protocol/MegastekProtocolDecoderTest.java3
-rw-r--r--test/org/traccar/protocol/TotemProtocolDecoderTest.java5
-rw-r--r--web/app/model/Server.js2
-rw-r--r--web/app/store/MapTypes.js3
-rw-r--r--web/app/view/admin/ServerDialog.js8
-rw-r--r--web/app/view/map/Map.js12
-rw-r--r--web/app/view/map/MapController.js5
-rw-r--r--web/app/view/state/StateController.js12
-rw-r--r--web/l10n/en.js2
-rw-r--r--web/l10n/sk.js86
-rw-r--r--web/l10n/sr.js86
-rw-r--r--web/locale.js2
26 files changed, 404 insertions, 97 deletions
diff --git a/debug.xml b/debug.xml
index ceee553ce..ecbfe6857 100644
--- a/debug.xml
+++ b/debug.xml
@@ -124,6 +124,8 @@
id INT PRIMARY KEY AUTO_INCREMENT,
registration BIT NOT NULL,
map VARCHAR(128),
+ bingKey VARCHAR(128),
+ mapUrl VARCHAR(128),
language VARCHAR(128),
distanceUnit VARCHAR(128),
speedUnit VARCHAR(128),
@@ -150,6 +152,8 @@
UPDATE server SET
registration = :registration,
map = :map,
+ bingKey = :bingKey,
+ mapUrl = :mapUrl,
language = :language,
distanceUnit = :distanceUnit,
speedUnit = :speedUnit,
@@ -230,7 +234,7 @@
</entry>
<entry key='database.selectPositions'>
- SELECT * FROM position WHERE deviceId = :deviceId AND fixTime BETWEEN :from AND :to;
+ SELECT * FROM position WHERE deviceId = :deviceId AND fixTime BETWEEN :from AND :to ORDER BY fixTime;
</entry>
<entry key='database.insertPosition'>
diff --git a/src/org/traccar/BasePipelineFactory.java b/src/org/traccar/BasePipelineFactory.java
index 216e48709..0dc0bbb47 100644
--- a/src/org/traccar/BasePipelineFactory.java
+++ b/src/org/traccar/BasePipelineFactory.java
@@ -34,7 +34,7 @@ import org.traccar.helper.Log;
public abstract class BasePipelineFactory implements ChannelPipelineFactory {
private final TrackerServer server;
- private int resetDelay;
+ private final int resetDelay;
private FilterHandler filterHandler;
private DistanceHandler distanceHandler;
@@ -54,9 +54,6 @@ public abstract class BasePipelineFactory implements ChannelPipelineFactory {
}
}
- /**
- * Logging using global logger
- */
protected class StandardLoggingHandler extends LoggingHandler {
@Override
diff --git a/src/org/traccar/Context.java b/src/org/traccar/Context.java
index d50a0c626..f818368d0 100644
--- a/src/org/traccar/Context.java
+++ b/src/org/traccar/Context.java
@@ -15,6 +15,7 @@
*/
package org.traccar;
+import com.ning.http.client.AsyncHttpClient;
import org.traccar.database.ConnectionManager;
import org.traccar.database.DataManager;
import org.traccar.database.IdentityManager;
@@ -81,6 +82,12 @@ public class Context {
public static ServerManager getServerManager() {
return serverManager;
}
+
+ private static final AsyncHttpClient asyncHttpClient = new AsyncHttpClient();
+
+ public static AsyncHttpClient getAsyncHttpClient() {
+ return asyncHttpClient;
+ }
public static void init(String[] arguments) throws Exception {
diff --git a/src/org/traccar/WebDataHandler.java b/src/org/traccar/WebDataHandler.java
index 5e3626022..5f12b9c93 100644
--- a/src/org/traccar/WebDataHandler.java
+++ b/src/org/traccar/WebDataHandler.java
@@ -15,7 +15,6 @@
*/
package org.traccar;
-import com.ning.http.client.AsyncHttpClient;
import java.util.Calendar;
import java.util.Formatter;
import java.util.Locale;
@@ -62,16 +61,16 @@ public class WebDataHandler extends BaseDataHandler {
Device device = Context.getIdentityManager().getDeviceById(position.getDeviceId());
- String request = url.
- replace("{uniqueId}", device.getUniqueId()).
- replace("{deviceId}", String.valueOf(device.getId())).
- replace("{fixTime}", String.valueOf(position.getFixTime().getTime())).
- replace("{latitude}", String.valueOf(position.getLatitude())).
- replace("{longitude}", String.valueOf(position.getLongitude())).
- replace("{gprmc}", formatSentence(position));
+ String request = url
+ .replace("{uniqueId}", device.getUniqueId())
+ .replace("{deviceId}", String.valueOf(device.getId()))
+ .replace("{fixTime}", String.valueOf(position.getFixTime().getTime()))
+ .replace("{latitude}", String.valueOf(position.getLatitude()))
+ .replace("{longitude}", String.valueOf(position.getLongitude()))
+ .replace("{gprmc}", formatSentence(position))
+ .replace("{statusCode}", position.getSpeed() < 1.0 ? "0xF020" : "0xF11C");
- AsyncHttpClient asyncHttpClient = new AsyncHttpClient();
- asyncHttpClient.prepareGet(request).execute();
+ Context.getAsyncHttpClient().prepareGet(request).execute();
return position;
}
diff --git a/src/org/traccar/model/Server.java b/src/org/traccar/model/Server.java
index f5ad4887c..b910e30ec 100644
--- a/src/org/traccar/model/Server.java
+++ b/src/org/traccar/model/Server.java
@@ -34,6 +34,14 @@ public class Server implements Factory {
public String getMap() { return map; }
public void setMap(String map) { this.map = map; }
+ private String bingKey;
+ public String getBingKey() { return bingKey; }
+ public void setBingKey(String bingKey) { this.bingKey = bingKey; }
+
+ private String mapUrl;
+ public String getMapUrl() { return mapUrl; }
+ public void setMapUrl(String mapUrl) { this.mapUrl = mapUrl; }
+
private String language;
public String getLanguage() { return language; }
public void setLanguage(String language) { this.language = language; }
diff --git a/src/org/traccar/protocol/Gl200ProtocolDecoder.java b/src/org/traccar/protocol/Gl200ProtocolDecoder.java
index 3628730e3..38b1df1a6 100644
--- a/src/org/traccar/protocol/Gl200ProtocolDecoder.java
+++ b/src/org/traccar/protocol/Gl200ProtocolDecoder.java
@@ -44,7 +44,30 @@ public class Gl200ProtocolDecoder extends BaseProtocolDecoder {
"(?:\\x00?\\x04,\\p{XDigit}{4},[01],))" +
"GT...," +
"(?:[0-9A-Z]{2}\\p{XDigit}{4})?," + // Protocol version
- "([^,]+),.*," + // IMEI
+ "([^,]+)," + // IMEI
+
+ "(?:[0-9A-Z]{17}," + // VIN
+ "[^,]{0,20}," + // Device name
+ "[01]," + // Report type
+ "\\p{XDigit}{1,8}," + // Report mask
+ "[0-9A-Z]{17}," + // VIN
+ "[01]," + // ODB connect
+ "\\d{1,5}," + // ODB voltage
+ "\\p{XDigit}{8}," + // Support PIDs
+ "\\d{1,5}," + // Engine RPM
+ "\\d{1,3}," + // Speed
+ "-?\\d{1,3}," + // Coolant temp
+ "(\\d+\\.?\\d*|Inf|NaN)?," + // Fuel consumption
+ "\\d{1,5}," + // Odometer
+ "\\d{1,5}," +
+ "[01]," + // ODB connect
+ "\\d{1,3}," + // Number of DTCs
+ "\\p{XDigit}*," + // DTCs
+ "\\d{1,3}," + // Throttle
+ "\\d{1,3}," + // Engine load
+ "(\\d{1,3})?,"+ // Fuel level
+ "\\d+|.*)," + // Odometer
+
"(\\d*)," + // GPS accuracy
"(\\d+.\\d)?," + // Speed
"(\\d+)?," + // Course
@@ -58,7 +81,7 @@ public class Gl200ProtocolDecoder extends BaseProtocolDecoder {
"(\\p{XDigit}{4}|\\p{XDigit}{8})?," + // LAC
"(\\p{XDigit}{4})?," + // Cell
"(?:(\\d+\\.\\d)?," + // Odometer
- "(\\d{1,3})?,)?" + // Battery
+ "(\\d{1,3})?,)?" + // Battery*/
".*," +
"(\\p{XDigit}{4})\\$?");
@@ -96,6 +119,10 @@ public class Gl200ProtocolDecoder extends BaseProtocolDecoder {
}
position.setDeviceId(getDeviceId());
+ // Fuel
+ position.set("fuel-consumption", parser.group(index++));
+ position.set(Event.KEY_FUEL, parser.group(index++));
+
// Validity
position.setValid(Integer.valueOf(parser.group(index++)) < 20);
diff --git a/src/org/traccar/protocol/MegastekProtocolDecoder.java b/src/org/traccar/protocol/MegastekProtocolDecoder.java
index 019bb69de..c07e73533 100644
--- a/src/org/traccar/protocol/MegastekProtocolDecoder.java
+++ b/src/org/traccar/protocol/MegastekProtocolDecoder.java
@@ -20,9 +20,7 @@ import java.util.Calendar;
import java.util.TimeZone;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
-
import org.jboss.netty.channel.Channel;
-
import org.traccar.BaseProtocolDecoder;
import org.traccar.model.Event;
import org.traccar.model.Position;
@@ -44,7 +42,7 @@ public class MegastekProtocolDecoder extends BaseProtocolDecoder {
"(\\d+\\.\\d+)?," + // Speed
"(\\d+\\.\\d+)?," + // Course
"(\\d{2})(\\d{2})(\\d{2})" + // Date (DDMMYY)
- "[^\\*]+\\*[0-9a-fA-F]{2}"); // Checksum
+ ".*"); // Checksum
private static final Pattern patternSimple = Pattern.compile(
"[FL]," + // Flag
@@ -143,10 +141,18 @@ public class MegastekProtocolDecoder extends BaseProtocolDecoder {
id = sentence.substring(beginIndex, endIndex);
beginIndex = endIndex + 1;
- endIndex = sentence.indexOf('*', beginIndex) + 3;
+ endIndex = sentence.indexOf('*', beginIndex);
+ if (endIndex != -1) {
+ endIndex += 3;
+ } else {
+ endIndex = sentence.length();
+ }
gprmc = sentence.substring(beginIndex, endIndex);
beginIndex = endIndex + 1;
+ if (beginIndex > sentence.length()) {
+ beginIndex = endIndex;
+ }
status = sentence.substring(beginIndex);
} else {
@@ -175,78 +181,75 @@ public class MegastekProtocolDecoder extends BaseProtocolDecoder {
if (simple) {
- // Parse status
Matcher parser = patternSimple.matcher(status);
- if (!parser.matches()) {
- return null;
- }
+ if (parser.matches()) {
- int index = 1;
+ int index = 1;
- // Alarm
- position.set(Event.KEY_ALARM, parser.group(index++));
+ position.set(Event.KEY_ALARM, parser.group(index++));
- // IMEI
- if (!identify(parser.group(index++), channel, null, false)) {
- if (!identify(id, channel)) {
- return null;
+ // IMEI
+ if (!identify(parser.group(index++), channel, null, false)) {
+ if (!identify(id, channel)) {
+ return null;
+ }
}
- }
- position.setDeviceId(getDeviceId());
+ position.setDeviceId(getDeviceId());
- // Satellites
- position.set(Event.KEY_SATELLITES, parser.group(index++));
+ position.set(Event.KEY_SATELLITES, parser.group(index++));
- // Altitude
- String altitude = parser.group(index++);
- if (altitude != null) {
- position.setAltitude(Double.valueOf(altitude));
- }
+ String altitude = parser.group(index++);
+ if (altitude != null) {
+ position.setAltitude(Double.valueOf(altitude));
+ }
- // Battery
- position.set(Event.KEY_POWER, Double.valueOf(parser.group(index++)));
+ position.set(Event.KEY_POWER, Double.valueOf(parser.group(index++)));
- // Charger
- String charger = parser.group(index++);
- if (charger != null) {
- position.set(Event.KEY_CHARGE, Integer.valueOf(charger) == 1);
- }
+ String charger = parser.group(index++);
+ if (charger != null) {
+ position.set(Event.KEY_CHARGE, Integer.valueOf(charger) == 1);
+ }
- position.set(Event.KEY_MCC, parser.group(index++));
- position.set(Event.KEY_MNC, parser.group(index++));
- position.set(Event.KEY_LAC, parser.group(index++));
+ position.set(Event.KEY_MCC, parser.group(index++));
+ position.set(Event.KEY_MNC, parser.group(index++));
+ position.set(Event.KEY_LAC, parser.group(index++));
+
+ } else {
+
+ if (!identify(id, channel)) {
+ return null;
+ }
+ position.setDeviceId(getDeviceId());
+
+ }
} else {
- // Parse status
Matcher parser = patternAlternative.matcher(status);
if (!parser.matches()) {
- return null;
- }
- int index = 1;
+ int index = 1;
- if (!identify(id, channel)) {
- return null;
+ if (!identify(id, channel)) {
+ return null;
+ }
+ position.setDeviceId(getDeviceId());
+
+ position.set(Event.KEY_MCC, parser.group(index++));
+ position.set(Event.KEY_MNC, parser.group(index++));
+ position.set(Event.KEY_LAC, parser.group(index++));
+ position.set(Event.KEY_GSM, parser.group(index++));
+
+ position.set(Event.KEY_BATTERY, Double.valueOf(parser.group(index++)));
+
+ position.set(Event.KEY_FLAGS, parser.group(index++));
+ position.set(Event.KEY_INPUT, parser.group(index++));
+ position.set(Event.KEY_OUTPUT, parser.group(index++));
+ position.set(Event.PREFIX_ADC + 1, parser.group(index++));
+ position.set(Event.PREFIX_ADC + 2, parser.group(index++));
+ position.set(Event.PREFIX_ADC + 3, parser.group(index++));
+ position.set(Event.KEY_ALARM, parser.group(index++));
}
- position.setDeviceId(getDeviceId());
-
- position.set(Event.KEY_MCC, parser.group(index++));
- position.set(Event.KEY_MNC, parser.group(index++));
- position.set(Event.KEY_LAC, parser.group(index++));
- position.set(Event.KEY_GSM, parser.group(index++));
-
- // Battery
- position.set(Event.KEY_BATTERY, Double.valueOf(parser.group(index++)));
-
- position.set(Event.KEY_FLAGS, parser.group(index++));
- position.set(Event.KEY_INPUT, parser.group(index++));
- position.set(Event.KEY_OUTPUT, parser.group(index++));
- position.set(Event.PREFIX_ADC + 1, parser.group(index++));
- position.set(Event.PREFIX_ADC + 2, parser.group(index++));
- position.set(Event.PREFIX_ADC + 3, parser.group(index++));
- position.set(Event.KEY_ALARM, parser.group(index++));
-
}
return position;
diff --git a/src/org/traccar/protocol/MeiligaoProtocol.java b/src/org/traccar/protocol/MeiligaoProtocol.java
index 70c9a87ec..9e8da7dc2 100644
--- a/src/org/traccar/protocol/MeiligaoProtocol.java
+++ b/src/org/traccar/protocol/MeiligaoProtocol.java
@@ -15,16 +15,13 @@
*/
package org.traccar.protocol;
+import java.util.List;
import org.jboss.netty.bootstrap.ConnectionlessBootstrap;
import org.jboss.netty.bootstrap.ServerBootstrap;
import org.jboss.netty.channel.ChannelPipeline;
-import org.jboss.netty.handler.codec.string.StringDecoder;
-import org.jboss.netty.handler.codec.string.StringEncoder;
import org.traccar.BaseProtocol;
import org.traccar.TrackerServer;
-import java.util.List;
-
public class MeiligaoProtocol extends BaseProtocol {
public MeiligaoProtocol() {
diff --git a/src/org/traccar/protocol/MeitrackProtocol.java b/src/org/traccar/protocol/MeitrackProtocol.java
index bcc224a94..6f452aa33 100644
--- a/src/org/traccar/protocol/MeitrackProtocol.java
+++ b/src/org/traccar/protocol/MeitrackProtocol.java
@@ -15,19 +15,24 @@
*/
package org.traccar.protocol;
+import java.nio.ByteOrder;
+import java.util.List;
import org.jboss.netty.bootstrap.ServerBootstrap;
import org.jboss.netty.channel.ChannelPipeline;
import org.jboss.netty.handler.codec.string.StringEncoder;
import org.traccar.BaseProtocol;
import org.traccar.TrackerServer;
-
-import java.nio.ByteOrder;
-import java.util.List;
+import org.traccar.model.Command;
public class MeitrackProtocol extends BaseProtocol {
public MeitrackProtocol() {
super("meitrack");
+ setSupportedCommands(
+ Command.TYPE_ENGINE_STOP,
+ Command.TYPE_ENGINE_RESUME,
+ Command.TYPE_ALARM_ARM,
+ Command.TYPE_ALARM_DISARM);
}
@Override
diff --git a/src/org/traccar/protocol/MeitrackProtocolEncoder.java b/src/org/traccar/protocol/MeitrackProtocolEncoder.java
new file mode 100644
index 000000000..73f3d01e4
--- /dev/null
+++ b/src/org/traccar/protocol/MeitrackProtocolEncoder.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2015 Anton Tananaev (anton.tananaev@gmail.com)
+ *
+ * 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.protocol;
+
+import org.traccar.StringProtocolEncoder;
+import org.traccar.model.Command;
+
+public class MeitrackProtocolEncoder extends StringProtocolEncoder {
+
+ @Override
+ protected Object encodeCommand(Command command) {
+
+ switch (command.getType()) {
+ case Command.TYPE_ENGINE_STOP:
+ return formatCommand(command, "@@M33,{%s},C01,0,12222*18\r\n", Command.KEY_UNIQUE_ID);
+ case Command.TYPE_ENGINE_RESUME:
+ return formatCommand(command, "@@M33,{%s},C01,0,02222*18\r\n", Command.KEY_UNIQUE_ID);
+ case Command.TYPE_ALARM_ARM:
+ return formatCommand(command, "@@M33,{%s},C01,0,22122*18\r\n", Command.KEY_UNIQUE_ID);
+ case Command.TYPE_ALARM_DISARM:
+ return formatCommand(command, "@@M33,{%s},C01,0,22022*18\r\n", Command.KEY_UNIQUE_ID);
+ }
+
+ return null;
+ }
+
+}
diff --git a/src/org/traccar/protocol/TotemProtocolDecoder.java b/src/org/traccar/protocol/TotemProtocolDecoder.java
index a22bbf71e..358c5cb67 100644
--- a/src/org/traccar/protocol/TotemProtocolDecoder.java
+++ b/src/org/traccar/protocol/TotemProtocolDecoder.java
@@ -20,10 +20,7 @@ import java.util.Calendar;
import java.util.TimeZone;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
-
import org.jboss.netty.channel.Channel;
-import org.jboss.netty.channel.ChannelHandlerContext;
-
import org.traccar.BaseProtocolDecoder;
import org.traccar.model.Event;
import org.traccar.model.Position;
@@ -59,7 +56,7 @@ public class TotemProtocolDecoder extends BaseProtocolDecoder {
"(\\d{3})" + // Battery
"(\\d{4})\\|" + // External Power
"(?:(\\d+)\\|)?" + // ADC
- "(\\p{XDigit}{8})\\|" + // Location Code
+ "(\\p{XDigit}+)\\|" + // Location Code
"(\\d+)\\|" + // Temperature
"(\\d+.\\d+)\\|" + // Odometer
"\\d+\\|" + // Serial Number
@@ -315,6 +312,10 @@ public class TotemProtocolDecoder extends BaseProtocolDecoder {
position.setLongitude(longitude);
}
+
+ if (channel != null) {
+ channel.write("ACK OK\r\n");
+ }
return position;
}
diff --git a/test/org/traccar/protocol/Gl200ProtocolDecoderTest.java b/test/org/traccar/protocol/Gl200ProtocolDecoderTest.java
index 6eeb9c13b..1a816554f 100644
--- a/test/org/traccar/protocol/Gl200ProtocolDecoderTest.java
+++ b/test/org/traccar/protocol/Gl200ProtocolDecoderTest.java
@@ -12,6 +12,12 @@ public class Gl200ProtocolDecoderTest extends ProtocolDecoderTest {
Gl200ProtocolDecoder decoder = new Gl200ProtocolDecoder(new Gl200Protocol());
verify(decoder.decode(null, null,
+ "+RESP:GTOBD,1F0109,864251020135483,,gv500,0,78FFFF,,1,12613,,,,,,,,,,,,,,1286,0,0.0,0,17.1,3.379630,6.529701,20150813074639,0621,0030,51C0,A2B3,00,0.0,20150813074641,A7E6$"));
+
+ verify(decoder.decode(null, null,
+ "+RESP:GTOBD,1F0109,864251020135483,4T1BE46KX7U018210,gv500,0,78FFFF,4T1BE46KX7U018210,1,13411,981B81C0,787,3,43,,921,463,1,10,0300030103030304001200310351035203530354,20,55,,1286,0,6.5,74,21.6,3.379710,6.529714,20150813074824,0621,0030,51C0,A2B3,00,0.0,20150813074828,A7E9$"));
+
+ verify(decoder.decode(null, null,
"+RESP:GTSTT,1A0401,860599000508846,,41,0,0.0,84,107.5,-76.657998,39.497203,20150623160622,0310,0260,B435,3B81,,20150623160622,0F54$"));
verify(decoder.decode(null, null,
diff --git a/test/org/traccar/protocol/GoSafeProtocolDecoderTest.java b/test/org/traccar/protocol/GoSafeProtocolDecoderTest.java
index c1a204b3c..7148a0ab3 100644
--- a/test/org/traccar/protocol/GoSafeProtocolDecoderTest.java
+++ b/test/org/traccar/protocol/GoSafeProtocolDecoderTest.java
@@ -16,6 +16,12 @@ public class GoSafeProtocolDecoderTest extends ProtocolDecoderTest {
verify(decoder.decode(null, null,
"*GS16,351535058709775,100356130215,,SYS:G79W;V1.06;V1.0.2,GPS:A;6;N24.802700;E46.616828;0;0;684;1.35,COT:60,ADC:4.31;0.10,DTT:20000;;0;0;0;1"));
+
+ verify(decoder.decode(null, null,
+ "*GS16,351535059439208,155750220815,,SYS:G79;V1.10;V1.0.2,GPS:A;4;N31.944198;E35.846644;0;0;923;9.47;1.00,COT:155133,ADC:12.21;0.10,DTT:20002;;0;0;0;1#"));
+
+ verify(decoder.decode(null, null,
+ "*GS16,351535059439208,070034220815,,SYS:G79;V1.10;V1.0.2,GPS:A;8;N31.945970;E35.859848;29;65;922;1.14;1.68,COT:147528,ADC:14.07;0.11,DTT:27006;;0;0;0;3,OBD:04410C1ECD03410D2D03411C010341057A037F011203411107$070035220815,,SYS:G79;V1.10;V1.0.2,GPS:A;8;N31.945934;E35.859908;29;86;922;1.14;1.68,COT:147528,ADC:13.94;0.15,DTT:27006;;0;0;0;3,OBD:04410C1ECD03410D2D03411C010341057A037F011203411107$070037220815,,SYS:G79;V1.10;V1.0.2,GPS:A;8;N31.945844;E35.859952;29;123;922;1.14;1.68,COT:147625,ADC:13.75;0.11,DTT:27006;;0;0;0;3,OBD:04410C0FE803410D1803411C010341057C037F011203411100$070038220815,,SYS:G79;V1.10;V1.0.2,GPS:A;8;N31.945808;E35.859940;29;145;923;1.14;1.68,COT:147625,ADC:14.00;0.11,DTT:27006;;0;0;0;3,OBD:04410C0FE803410D1803411C010341057C037F011203411100#"));
}
diff --git a/test/org/traccar/protocol/KhdProtocolDecoderTest.java b/test/org/traccar/protocol/KhdProtocolDecoderTest.java
index 2a92e3f6c..7bab7b2e8 100644
--- a/test/org/traccar/protocol/KhdProtocolDecoderTest.java
+++ b/test/org/traccar/protocol/KhdProtocolDecoderTest.java
@@ -38,6 +38,9 @@ public class KhdProtocolDecoderTest extends ProtocolDecoderTest {
verify(decoder.decode(null, null, ChannelBuffers.wrappedBuffer(ChannelBufferTools.convertHexString(
"292980002822836665140825142037045343770193879200000050ffff000082fc000004b0780b170000002a0d"))));
+ verify(decoder.decode(null, null, ChannelBuffers.wrappedBuffer(ChannelBufferTools.convertHexString(
+ "292980002802425349120811032137022373011140211100000334FFFF000082FC0000001E780913000034DF0D"))));
+
}
}
diff --git a/test/org/traccar/protocol/MegastekProtocolDecoderTest.java b/test/org/traccar/protocol/MegastekProtocolDecoderTest.java
index a9b7c4f0a..21a2d46b4 100644
--- a/test/org/traccar/protocol/MegastekProtocolDecoderTest.java
+++ b/test/org/traccar/protocol/MegastekProtocolDecoderTest.java
@@ -12,6 +12,9 @@ public class MegastekProtocolDecoderTest extends ProtocolDecoderTest {
MegastekProtocolDecoder decoder = new MegastekProtocolDecoder(new MegastekProtocol());
verify(decoder.decode(null, null,
+ "STX,865067020439090,$GPRMC,171013.000,A,5919.1411,N,01804.1681,E,0.000,294.41,140815,,,A"));
+
+ verify(decoder.decode(null, null,
"$MGV002,013777007536434,,R,010114,000057,V,0000.0000,N,00000.0000,E,00,00,00,99.9,0.000,0.00,0.0,80.263,510,89,2342,030B,,0000,0000,200,96,0, , ,,,,Timer;!"));
verify(decoder.decode(null, null,
diff --git a/test/org/traccar/protocol/TotemProtocolDecoderTest.java b/test/org/traccar/protocol/TotemProtocolDecoderTest.java
index cdb6be355..c01640241 100644
--- a/test/org/traccar/protocol/TotemProtocolDecoderTest.java
+++ b/test/org/traccar/protocol/TotemProtocolDecoderTest.java
@@ -11,7 +11,10 @@ public class TotemProtocolDecoderTest extends ProtocolDecoderTest {
public void testDecode() throws Exception {
TotemProtocolDecoder decoder = new TotemProtocolDecoder(new TotemProtocol());
-
+
+ verify(decoder.decode(null, null,
+ "$$BE863771024392112|AA$GPRMC,044704.000,A,1439.3334,N,12059.1417,E,0.00,0.00,200815,,,A*67|01.7|00.8|01.4|000000000000|20150820044704|14291265|00000000|4EECBF8B31|0000|0.0000|0002|00000|56E7"));
+
verify(decoder.decode(null, null,
"$$AE860990002922822|AA$GPRMC,051002.00,A,0439.26245,N,10108.94448,E,0.023,,140315,,,A*71|02.98|01.95|02.26|000000000000|20150314051003|13841157|105A3B1C|0000|0.0000|0005|5324"));
diff --git a/web/app/model/Server.js b/web/app/model/Server.js
index 9e4ab1eec..b21f28299 100644
--- a/web/app/model/Server.js
+++ b/web/app/model/Server.js
@@ -22,6 +22,8 @@ Ext.define('Traccar.model.Server', {
{ name: 'id', type: 'int' },
{ name: 'registration', type: 'boolean' },
{ name: 'map', type: 'string' },
+ { name: 'bingKey', type: 'string' },
+ { name: 'mapUrl', type: 'string' },
{ name: 'language', type: 'string' },
{ name: 'distanceUnit', type: 'string' },
{ name: 'speedUnit', type: 'string' },
diff --git a/web/app/store/MapTypes.js b/web/app/store/MapTypes.js
index ebc45cc8d..fbdc49acc 100644
--- a/web/app/store/MapTypes.js
+++ b/web/app/store/MapTypes.js
@@ -20,6 +20,7 @@ Ext.define('Traccar.store.MapTypes', {
data: [
{'key': 'osm', 'name': strings.mapOsm},
{'key': 'bingRoad', 'name': strings.mapBingRoad},
- {'key': 'bingAerial', 'name': strings.mapBingAerial}
+ {'key': 'bingAerial', 'name': strings.mapBingAerial},
+ {'key': 'custom', 'name': strings.mapCustom},
]
});
diff --git a/web/app/view/admin/ServerDialog.js b/web/app/view/admin/ServerDialog.js
index 37bb498a0..080e2fcc4 100644
--- a/web/app/view/admin/ServerDialog.js
+++ b/web/app/view/admin/ServerDialog.js
@@ -43,6 +43,14 @@ Ext.define('Traccar.view.admin.ServerDialog', {
displayField: 'name',
valueField: 'key'
}, {
+ xtype: 'textfield',
+ name: 'bingKey',
+ fieldLabel: strings.mapBingKey
+ }, {
+ xtype: 'textfield',
+ name: 'mapUrl',
+ fieldLabel: strings.mapCustom
+ }, {
xtype: 'combobox',
name: 'distanceUnit',
fieldLabel: strings.settingsDistanceUnit,
diff --git a/web/app/view/map/Map.js b/web/app/view/map/Map.js
index 9d9a92886..cdb46342b 100644
--- a/web/app/view/map/Map.js
+++ b/web/app/view/map/Map.js
@@ -36,16 +36,20 @@ Ext.define('Traccar.view.map.Map', {
var layer;
var mapLayer = user.get('map') || server.get('map');
- var bindKey = 'AseEs0DLJhLlTNoxbNXu7DGsnnH4UoWuGue7-irwKkE3fffaClwc9q_Mr6AyHY8F';
+ var bingKey = server.get('bingKey');
- if (mapLayer === 'bingRoad') {
+ if (mapLayer === 'custom') {
+ layer = new ol.layer.Tile({ source: new ol.source.XYZ({
+ url: server.get('mapUrl')
+ })});
+ } else if (mapLayer === 'bingRoad') {
layer = new ol.layer.Tile({ source: new ol.source.BingMaps({
- key: bindKey,
+ key: bingKey,
imagerySet: 'Road'
})});
} else if (mapLayer === 'bingAerial') {
layer = new ol.layer.Tile({ source: new ol.source.BingMaps({
- key: bindKey,
+ key: bingKey,
imagerySet: 'Aerial'
})});
} else {
diff --git a/web/app/view/map/MapController.js b/web/app/view/map/MapController.js
index 98922a307..0aab71725 100644
--- a/web/app/view/map/MapController.js
+++ b/web/app/view/map/MapController.js
@@ -128,9 +128,8 @@ Ext.define('Traccar.view.map.MapController', {
var vectorSource = this.getView().vectorSource;
- var data = Ext.getStore('Positions').getData().clone();
- data.sort('fixTime');
-
+ var data = Ext.getStore('Positions').getData();
+
var index;
var positions = [];
this.reportRoutePoints = {};
diff --git a/web/app/view/state/StateController.js b/web/app/view/state/StateController.js
index 58bc5c55c..73dc28b50 100644
--- a/web/app/view/state/StateController.js
+++ b/web/app/view/state/StateController.js
@@ -73,6 +73,14 @@ Ext.define('Traccar.view.state.StateController', {
}
},
+ formatValue: function(value) {
+ if (typeof(id) === 'number') {
+ return +value.toFixed(2);
+ } else {
+ return value;
+ }
+ },
+
updatePosition: function(position) {
var other;
@@ -93,7 +101,7 @@ Ext.define('Traccar.view.state.StateController', {
store.add(Ext.create('Traccar.model.Parameter', {
priority: this.keys[key].priority,
name: this.keys[key].name,
- value: value
+ value: this.formatValue(value)
}));
}
}
@@ -119,7 +127,7 @@ Ext.define('Traccar.view.state.StateController', {
name: key.replace(/^./, function (match) {
return match.toUpperCase();
}),
- value: value
+ value: this.formatValue(value)
}));
}
}
diff --git a/web/l10n/en.js b/web/l10n/en.js
index 33c494a54..4c1e0f233 100644
--- a/web/l10n/en.js
+++ b/web/l10n/en.js
@@ -66,7 +66,9 @@ var strings = {
mapTitle: 'Map',
mapLayer: 'Map Layer',
+ mapCustom: 'Custom Map',
mapOsm: 'Open Street Map',
+ mapBingKey: 'Bing Maps Key',
mapBingRoad: 'Bing Maps Road',
mapBingAerial: 'Bing Maps Aerial',
diff --git a/web/l10n/sk.js b/web/l10n/sk.js
new file mode 100644
index 000000000..0c0fa77c3
--- /dev/null
+++ b/web/l10n/sk.js
@@ -0,0 +1,86 @@
+var strings = {
+ sharedLoading: 'Načítava...',
+ sharedSave: 'Uloženie',
+ sharedCancel: 'Zrušenie',
+ sharedAdd: 'Pridať',
+ sharedEdit: 'Úprava',
+ sharedRemove: 'Odstrániť',
+ sharedRemoveConfirm: 'Odstrániť položku?',
+ sharedKm: 'Km',
+ sharedMi: 'mi',
+ sharedKmh: 'Km/h',
+ sharedMph: 'mph',
+ sharedHour: 'Hodina',
+ sharedMinute: 'Minúta',
+ sharedSecond: 'Druhý',
+
+ errorTitle: 'Chyba',
+ errorUnknown: 'Neznáma chyba',
+
+ userName: 'Meno',
+ userEmail: 'E-mail',
+ userPassword: 'Heslo',
+ userAdmin: 'Admin',
+
+ loginTitle: 'Prihlásenie',
+ loginLanguage: 'Jazyk',
+ loginRegister: 'Registrovať',
+ loginLogin: 'Prihlásenie',
+ loginFailed: 'Nesprávna e-mailová adresa alebo heslo',
+ loginCreated: 'Nový užívateľ sa zaregistroval',
+ loginLogout: 'Odhlásiť',
+
+ deviceDialog: 'Zariadenie',
+ deviceTitle: 'Zariadena',
+ deviceName: 'Meno',
+ deviceIdentifier: 'Identifikátor',
+ deviceCommand: 'Príkaz',
+
+ settingsTitle: 'Nastavenia',
+ settingsUser: 'Účet',
+ settingsServer: 'Server',
+ settingsUsers: 'Užívatelia',
+ settingsDistanceUnit: 'Vzdialenosť',
+ settingsSpeedUnit: 'Rýchlosť jazdy',
+
+ reportTitle: 'Správy',
+ reportDevice: 'Zariadenie',
+ reportFrom: 'Z',
+ reportTo: 'do',
+ reportShow: 'Zobraziť',
+ reportClear: 'Vyčistiť',
+
+ positionTime: 'Čas',
+ positionValid: 'Platný',
+ positionLatitude: 'Šírka',
+ positionLongitude: 'Dĺžka',
+ positionAltitude: 'Výška',
+ positionSpeed: 'Rýchlosť jazdy',
+ positionCourse: 'Kurz',
+ positionAddress: 'Adresa',
+ positionProtocol: 'Protokol',
+
+ serverTitle: 'Nastavenie servera',
+ serverZoom: 'Zoom',
+ serverRegistration: 'Registrácia',
+
+ mapTitle: 'Mapa',
+ mapLayer: 'Mapové vrstvy',
+ mapOsm: 'Open Street Map',
+ mapBingRoad: 'Bing Maps Road',
+ mapBingAerial: 'Bing Maps Arial',
+
+ stateTitle: 'Štát',
+ stateName: 'Parameter',
+ stateValue: 'Hodnota',
+
+ commandTitle: 'Príkaz',
+ commandSend: 'Odoslať',
+ commandType: 'Typ',
+ commandPositionPeriodic: 'Pravidelné podávanie správ',
+ commandPositionStop: 'Zastavte podávanie správ',
+ commandEngineStop: 'Zastavenie motora',
+ commandEngineResume: 'Spustenie motora',
+ commandFrequency: 'Frekvencia',
+ commandUnit: 'Unit'
+};
diff --git a/web/l10n/sr.js b/web/l10n/sr.js
new file mode 100644
index 000000000..8bfe6f104
--- /dev/null
+++ b/web/l10n/sr.js
@@ -0,0 +1,86 @@
+var strings = {
+ sharedLoading: 'Učitava...',
+ sharedSave: 'Sačuvaj',
+ sharedCancel: 'Odustani',
+ sharedAdd: 'Dodaj',
+ sharedEdit: 'Podesi',
+ sharedRemove: 'Ukloni',
+ sharedRemoveConfirm: 'Ukloniti jedinicu?',
+ sharedKm: 'km',
+ sharedMi: 'mi',
+ sharedKmh: 'km/h',
+ sharedMph: 'mph',
+ sharedHour: 'Čas',
+ sharedMinute: 'Minut',
+ sharedSecond: 'Sekunda',
+
+ errorTitle: 'Greška',
+ errorUnknown: 'Nepoznata greška',
+
+ userName: 'Ime',
+ userEmail: 'Email',
+ userPassword: 'Lozinka',
+ userAdmin: 'Admin',
+
+ loginTitle: 'Prijava',
+ loginLanguage: 'Jezik',
+ loginRegister: 'Registruj se',
+ loginLogin: 'Prijava',
+ loginFailed: 'Neispravna email adresa ili lozinka',
+ loginCreated: 'Novi korisnik je registrovan',
+ loginLogout: 'Odjava',
+
+ deviceDialog: 'Uređaj',
+ deviceTitle: 'Uređaji',
+ deviceName: 'Ime',
+ deviceIdentifier: 'Identifikator',
+ deviceCommand: 'Komanda',
+
+ settingsTitle: 'Podešavanja',
+ settingsUser: 'Nalog',
+ settingsServer: 'Server',
+ settingsUsers: 'Korisnici',
+ settingsDistanceUnit: 'Udaljenost',
+ settingsSpeedUnit: 'Brzina',
+
+ reportTitle: 'Izveštaji',
+ reportDevice: 'Uređaj',
+ reportFrom: 'Od',
+ reportTo: 'Do',
+ reportShow: 'Prikaži',
+ reportClear: 'Izbriši',
+
+ positionTime: 'Vreme',
+ positionValid: 'Ispravno',
+ positionLatitude: 'Geografska širina',
+ positionLongitude: 'Geografska dužina',
+ positionAltitude: 'Visina',
+ positionSpeed: 'Brzina',
+ positionCourse: 'Pravac',
+ positionAddress: 'Adresa',
+ positionProtocol: 'Protokol',
+
+ serverTitle: 'Podešavanja Servera',
+ serverZoom: 'Zumiranje',
+ serverRegistration: 'Registracija',
+
+ mapTitle: 'Mapa',
+ mapLayer: 'Vrsta Mape',
+ mapOsm: 'Open Street Map',
+ mapBingRoad: 'Bing Maps Road',
+ mapBingAerial: 'Bing Maps Aerial',
+
+ stateTitle: 'Stanje',
+ stateName: 'Parametar',
+ stateValue: 'Vrednost',
+
+ commandTitle: 'Komanda',
+ commandSend: 'Pošalji',
+ commandType: 'Tip',
+ commandPositionPeriodic: 'Periodično izveštavanje',
+ commandPositionStop: 'Prekini izveštavanja',
+ commandEngineStop: 'Zaustavi motor',
+ commandEngineResume: 'Pokreni motor',
+ commandFrequency: 'Frekvencija',
+ commandUnit: 'Jedinica'
+};
diff --git a/web/locale.js b/web/locale.js
index 497b6ab2e..c5aca40cd 100644
--- a/web/locale.js
+++ b/web/locale.js
@@ -28,6 +28,8 @@ var availableLanguages = {
'pl': { name: 'Polski', code: 'pl' },
'pt': { name: 'Português', code: 'pt' },
'ru': { name: 'Русский', code: 'ru' },
+ 'sk': { name: 'Slovenčina', code: 'sk' },
+ 'sr': { name: 'Srpski', code: 'sr' },
'th': { name: 'ไทย', code: 'th' },
'zh': { name: '中文', code: 'zh_CN' },
'lt': { name: 'Lietuvių', code: 'lt' }