aboutsummaryrefslogtreecommitdiff
path: root/src/main
diff options
context:
space:
mode:
Diffstat (limited to 'src/main')
-rw-r--r--src/main/java/org/traccar/MainModule.java2
-rw-r--r--src/main/java/org/traccar/StringProtocolEncoder.java30
-rw-r--r--src/main/java/org/traccar/geolocation/OpenCellIdGeolocationProvider.java7
-rw-r--r--src/main/java/org/traccar/model/Command.java1
-rw-r--r--src/main/java/org/traccar/protocol/AdmProtocolEncoder.java2
-rw-r--r--src/main/java/org/traccar/protocol/CarcellProtocolEncoder.java4
-rw-r--r--src/main/java/org/traccar/protocol/DmtProtocolDecoder.java10
-rw-r--r--src/main/java/org/traccar/protocol/EsealProtocolEncoder.java6
-rw-r--r--src/main/java/org/traccar/protocol/Gl200ProtocolEncoder.java10
-rw-r--r--src/main/java/org/traccar/protocol/Gps103ProtocolEncoder.java18
-rw-r--r--src/main/java/org/traccar/protocol/GranitProtocolSmsEncoder.java2
-rw-r--r--src/main/java/org/traccar/protocol/Gt06ProtocolDecoder.java37
-rw-r--r--src/main/java/org/traccar/protocol/H02ProtocolDecoder.java2
-rw-r--r--src/main/java/org/traccar/protocol/HuabaoProtocolDecoder.java32
-rw-r--r--src/main/java/org/traccar/protocol/LaipacProtocolEncoder.java6
-rw-r--r--src/main/java/org/traccar/protocol/MiniFinderProtocolEncoder.java22
-rw-r--r--src/main/java/org/traccar/protocol/Minifinder2ProtocolDecoder.java8
-rw-r--r--src/main/java/org/traccar/protocol/OutsafeProtocol.java39
-rw-r--r--src/main/java/org/traccar/protocol/OutsafeProtocolDecoder.java69
-rw-r--r--src/main/java/org/traccar/protocol/PluginProtocolDecoder.java62
-rw-r--r--src/main/java/org/traccar/protocol/Pt215FrameDecoder.java55
-rw-r--r--src/main/java/org/traccar/protocol/Pt215Protocol.java3
-rw-r--r--src/main/java/org/traccar/protocol/Pt502ProtocolEncoder.java8
-rw-r--r--src/main/java/org/traccar/protocol/RstProtocolDecoder.java10
-rw-r--r--src/main/java/org/traccar/protocol/SigfoxProtocolDecoder.java68
-rw-r--r--src/main/java/org/traccar/protocol/SolarPoweredProtocol.java34
-rw-r--r--src/main/java/org/traccar/protocol/SolarPoweredProtocolDecoder.java97
-rw-r--r--src/main/java/org/traccar/protocol/StarcomProtocolDecoder.java7
-rw-r--r--src/main/java/org/traccar/protocol/SuntechFrameDecoder.java23
-rw-r--r--src/main/java/org/traccar/protocol/SuntechProtocol.java2
-rw-r--r--src/main/java/org/traccar/protocol/SuntechProtocolDecoder.java148
-rw-r--r--src/main/java/org/traccar/protocol/SuntechProtocolEncoder.java37
-rw-r--r--src/main/java/org/traccar/protocol/SviasProtocolEncoder.java4
-rw-r--r--src/main/java/org/traccar/protocol/TeltonikaProtocolDecoder.java3
-rw-r--r--src/main/java/org/traccar/protocol/Tk103ProtocolEncoder.java30
-rw-r--r--src/main/java/org/traccar/protocol/TopinProtocol.java33
-rw-r--r--src/main/java/org/traccar/protocol/TopinProtocolDecoder.java172
-rw-r--r--src/main/java/org/traccar/protocol/TotemProtocolEncoder.java4
-rw-r--r--src/main/java/org/traccar/protocol/UproProtocolDecoder.java23
-rw-r--r--src/main/java/org/traccar/protocol/WatchProtocolEncoder.java22
-rw-r--r--src/main/java/org/traccar/protocol/WialonProtocolEncoder.java4
-rw-r--r--src/main/java/org/traccar/protocol/WondexProtocolEncoder.java12
-rw-r--r--src/main/java/org/traccar/protocol/XexunProtocolEncoder.java4
43 files changed, 959 insertions, 213 deletions
diff --git a/src/main/java/org/traccar/MainModule.java b/src/main/java/org/traccar/MainModule.java
index 3acd19b6a..9adea61b0 100644
--- a/src/main/java/org/traccar/MainModule.java
+++ b/src/main/java/org/traccar/MainModule.java
@@ -191,7 +191,7 @@ public class MainModule extends AbstractModule {
case "google":
return new GoogleGeolocationProvider(key);
case "opencellid":
- return new OpenCellIdGeolocationProvider(key);
+ return new OpenCellIdGeolocationProvider(url, key);
case "unwired":
return new UnwiredGeolocationProvider(url, key);
default:
diff --git a/src/main/java/org/traccar/StringProtocolEncoder.java b/src/main/java/org/traccar/StringProtocolEncoder.java
index d9acce7f0..e9fb65500 100644
--- a/src/main/java/org/traccar/StringProtocolEncoder.java
+++ b/src/main/java/org/traccar/StringProtocolEncoder.java
@@ -17,8 +17,6 @@ package org.traccar;
import org.traccar.model.Command;
-import java.util.Map;
-
public abstract class StringProtocolEncoder extends BaseProtocolEncoder {
public StringProtocolEncoder(Protocol protocol) {
@@ -31,21 +29,27 @@ public abstract class StringProtocolEncoder extends BaseProtocolEncoder {
protected String formatCommand(Command command, String format, ValueFormatter valueFormatter, String... keys) {
- String result = String.format(format, (Object[]) keys);
-
- result = result.replaceAll("\\{" + Command.KEY_UNIQUE_ID + "}", getUniqueId(command.getDeviceId()));
- for (Map.Entry<String, Object> entry : command.getAttributes().entrySet()) {
+ Object[] values = new String[keys.length];
+ for (int i = 0; i < keys.length; i++) {
String value = null;
- if (valueFormatter != null) {
- value = valueFormatter.formatValue(entry.getKey(), entry.getValue());
- }
- if (value == null) {
- value = entry.getValue().toString();
+ if (keys[i].equals(Command.KEY_UNIQUE_ID)) {
+ value = getUniqueId(command.getDeviceId());
+ } else {
+ Object object = command.getAttributes().get(keys[i]);
+ if (valueFormatter != null) {
+ value = valueFormatter.formatValue(keys[i], object);
+ }
+ if (value == null && object != null) {
+ value = object.toString();
+ }
+ if (value == null) {
+ value = "";
+ }
}
- result = result.replaceAll("\\{" + entry.getKey() + "}", value);
+ values[i] = value;
}
- return result;
+ return String.format(format, values);
}
protected String formatCommand(Command command, String format, String... keys) {
diff --git a/src/main/java/org/traccar/geolocation/OpenCellIdGeolocationProvider.java b/src/main/java/org/traccar/geolocation/OpenCellIdGeolocationProvider.java
index 768aaf6a2..cb3094e16 100644
--- a/src/main/java/org/traccar/geolocation/OpenCellIdGeolocationProvider.java
+++ b/src/main/java/org/traccar/geolocation/OpenCellIdGeolocationProvider.java
@@ -26,11 +26,10 @@ public class OpenCellIdGeolocationProvider implements GeolocationProvider {
private String url;
- public OpenCellIdGeolocationProvider(String key) {
- this("http://opencellid.org/cell/get", key);
- }
-
public OpenCellIdGeolocationProvider(String url, String key) {
+ if (url == null) {
+ url = "http://opencellid.org/cell/get";
+ }
this.url = url + "?format=json&mcc=%d&mnc=%d&lac=%d&cellid=%d&key=" + key;
}
diff --git a/src/main/java/org/traccar/model/Command.java b/src/main/java/org/traccar/model/Command.java
index 336fc61f4..abe538a10 100644
--- a/src/main/java/org/traccar/model/Command.java
+++ b/src/main/java/org/traccar/model/Command.java
@@ -68,6 +68,7 @@ public class Command extends Message implements Cloneable {
public static final String KEY_UNIQUE_ID = "uniqueId";
public static final String KEY_FREQUENCY = "frequency";
+ public static final String KEY_LANGUAGE = "language";
public static final String KEY_TIMEZONE = "timezone";
public static final String KEY_DEVICE_PASSWORD = "devicePassword";
public static final String KEY_RADIUS = "radius";
diff --git a/src/main/java/org/traccar/protocol/AdmProtocolEncoder.java b/src/main/java/org/traccar/protocol/AdmProtocolEncoder.java
index 1c3dfc156..c02fa4112 100644
--- a/src/main/java/org/traccar/protocol/AdmProtocolEncoder.java
+++ b/src/main/java/org/traccar/protocol/AdmProtocolEncoder.java
@@ -34,7 +34,7 @@ public class AdmProtocolEncoder extends StringProtocolEncoder {
return formatCommand(command, "STATUS\r\n");
case Command.TYPE_CUSTOM:
- return formatCommand(command, "{%s}\r\n", Command.KEY_DATA);
+ return formatCommand(command, "%s\r\n", Command.KEY_DATA);
default:
return null;
diff --git a/src/main/java/org/traccar/protocol/CarcellProtocolEncoder.java b/src/main/java/org/traccar/protocol/CarcellProtocolEncoder.java
index 083fe9a9e..78dbe7e91 100644
--- a/src/main/java/org/traccar/protocol/CarcellProtocolEncoder.java
+++ b/src/main/java/org/traccar/protocol/CarcellProtocolEncoder.java
@@ -30,9 +30,9 @@ public class CarcellProtocolEncoder extends StringProtocolEncoder {
switch (command.getType()) {
case Command.TYPE_ENGINE_STOP:
- return formatCommand(command, "$SRVCMD,{%s},BA#\r\n", Command.KEY_UNIQUE_ID);
+ return formatCommand(command, "$SRVCMD,%s,BA#\r\n", Command.KEY_UNIQUE_ID);
case Command.TYPE_ENGINE_RESUME:
- return formatCommand(command, "$SRVCMD,{%s},BD#\r\n", Command.KEY_UNIQUE_ID);
+ return formatCommand(command, "$SRVCMD,%s,BD#\r\n", Command.KEY_UNIQUE_ID);
default:
return null;
}
diff --git a/src/main/java/org/traccar/protocol/DmtProtocolDecoder.java b/src/main/java/org/traccar/protocol/DmtProtocolDecoder.java
index fabcae002..58a5a88e3 100644
--- a/src/main/java/org/traccar/protocol/DmtProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/DmtProtocolDecoder.java
@@ -213,6 +213,16 @@ public class DmtProtocolDecoder extends BaseProtocolDecoder {
}
}
+ } else if (fieldId == 26) {
+
+ position.set(Position.KEY_ODOMETER_TRIP, buf.readUnsignedIntLE());
+ position.set("tripHours", buf.readUnsignedIntLE() * 1000);
+
+ } else if (fieldId == 27) {
+
+ position.set(Position.KEY_ODOMETER, buf.readUnsignedIntLE());
+ position.set(Position.KEY_HOURS, buf.readUnsignedIntLE() * 1000);
+
}
buf.readerIndex(fieldEnd);
diff --git a/src/main/java/org/traccar/protocol/EsealProtocolEncoder.java b/src/main/java/org/traccar/protocol/EsealProtocolEncoder.java
index 6ee305ed8..74f9e22ab 100644
--- a/src/main/java/org/traccar/protocol/EsealProtocolEncoder.java
+++ b/src/main/java/org/traccar/protocol/EsealProtocolEncoder.java
@@ -31,13 +31,13 @@ public class EsealProtocolEncoder extends StringProtocolEncoder {
switch (command.getType()) {
case Command.TYPE_CUSTOM:
return formatCommand(
- command, "##S,eSeal,{%s},256,3.0.8,{%s},E##", Command.KEY_UNIQUE_ID, Command.KEY_DATA);
+ command, "##S,eSeal,%s,256,3.0.8,%s,E##", Command.KEY_UNIQUE_ID, Command.KEY_DATA);
case Command.TYPE_ALARM_ARM:
return formatCommand(
- command, "##S,eSeal,{%s},256,3.0.8,RC-Power Control,Power OFF,E##", Command.KEY_UNIQUE_ID);
+ command, "##S,eSeal,%s,256,3.0.8,RC-Power Control,Power OFF,E##", Command.KEY_UNIQUE_ID);
case Command.TYPE_ALARM_DISARM:
return formatCommand(
- command, "##S,eSeal,{%s},256,3.0.8,RC-Unlock,E##", Command.KEY_UNIQUE_ID);
+ command, "##S,eSeal,%s,256,3.0.8,RC-Unlock,E##", Command.KEY_UNIQUE_ID);
default:
return null;
}
diff --git a/src/main/java/org/traccar/protocol/Gl200ProtocolEncoder.java b/src/main/java/org/traccar/protocol/Gl200ProtocolEncoder.java
index 32307446b..dd0672c23 100644
--- a/src/main/java/org/traccar/protocol/Gl200ProtocolEncoder.java
+++ b/src/main/java/org/traccar/protocol/Gl200ProtocolEncoder.java
@@ -32,17 +32,17 @@ public class Gl200ProtocolEncoder extends StringProtocolEncoder {
switch (command.getType()) {
case Command.TYPE_POSITION_SINGLE:
- return formatCommand(command, "AT+GTRTO={%s},1,,,,,,FFFF$", Command.KEY_DEVICE_PASSWORD);
+ return formatCommand(command, "AT+GTRTO=%s,1,,,,,,FFFF$", Command.KEY_DEVICE_PASSWORD);
case Command.TYPE_ENGINE_STOP:
- return formatCommand(command, "AT+GTOUT={%s},1,,,0,0,0,0,0,0,0,,,,,,,FFFF$",
+ return formatCommand(command, "AT+GTOUT=%s,1,,,0,0,0,0,0,0,0,,,,,,,FFFF$",
Command.KEY_DEVICE_PASSWORD);
case Command.TYPE_ENGINE_RESUME:
- return formatCommand(command, "AT+GTOUT={%s},0,,,0,0,0,0,0,0,0,,,,,,,FFFF$",
+ return formatCommand(command, "AT+GTOUT=%s,0,,,0,0,0,0,0,0,0,,,,,,,FFFF$",
Command.KEY_DEVICE_PASSWORD);
case Command.TYPE_IDENTIFICATION:
- return formatCommand(command, "AT+GTRTO={%s},8,,,,,,FFFF$", Command.KEY_DEVICE_PASSWORD);
+ return formatCommand(command, "AT+GTRTO=%s,8,,,,,,FFFF$", Command.KEY_DEVICE_PASSWORD);
case Command.TYPE_REBOOT_DEVICE:
- return formatCommand(command, "AT+GTRTO={%s},3,,,,,,FFFF$", Command.KEY_DEVICE_PASSWORD);
+ return formatCommand(command, "AT+GTRTO=%s,3,,,,,,FFFF$", Command.KEY_DEVICE_PASSWORD);
default:
return null;
}
diff --git a/src/main/java/org/traccar/protocol/Gps103ProtocolEncoder.java b/src/main/java/org/traccar/protocol/Gps103ProtocolEncoder.java
index 7128823ed..e662e9b04 100644
--- a/src/main/java/org/traccar/protocol/Gps103ProtocolEncoder.java
+++ b/src/main/java/org/traccar/protocol/Gps103ProtocolEncoder.java
@@ -47,24 +47,24 @@ public class Gps103ProtocolEncoder extends StringProtocolEncoder implements Stri
switch (command.getType()) {
case Command.TYPE_CUSTOM:
- return formatCommand(command, "**,imei:{%s},{%s}", Command.KEY_UNIQUE_ID, Command.KEY_DATA);
+ return formatCommand(command, "**,imei:%s,%s", Command.KEY_UNIQUE_ID, Command.KEY_DATA);
case Command.TYPE_POSITION_STOP:
- return formatCommand(command, "**,imei:{%s},A", Command.KEY_UNIQUE_ID);
+ return formatCommand(command, "**,imei:%s,A", Command.KEY_UNIQUE_ID);
case Command.TYPE_POSITION_SINGLE:
- return formatCommand(command, "**,imei:{%s},B", Command.KEY_UNIQUE_ID);
+ return formatCommand(command, "**,imei:%s,B", Command.KEY_UNIQUE_ID);
case Command.TYPE_POSITION_PERIODIC:
return formatCommand(
- command, "**,imei:{%s},C,{%s}", this, Command.KEY_UNIQUE_ID, Command.KEY_FREQUENCY);
+ command, "**,imei:%s,C,%s", this, Command.KEY_UNIQUE_ID, Command.KEY_FREQUENCY);
case Command.TYPE_ENGINE_STOP:
- return formatCommand(command, "**,imei:{%s},J", Command.KEY_UNIQUE_ID);
+ return formatCommand(command, "**,imei:%s,J", Command.KEY_UNIQUE_ID);
case Command.TYPE_ENGINE_RESUME:
- return formatCommand(command, "**,imei:{%s},K", Command.KEY_UNIQUE_ID);
+ return formatCommand(command, "**,imei:%s,K", Command.KEY_UNIQUE_ID);
case Command.TYPE_ALARM_ARM:
- return formatCommand(command, "**,imei:{%s},L", Command.KEY_UNIQUE_ID);
+ return formatCommand(command, "**,imei:%s,L", Command.KEY_UNIQUE_ID);
case Command.TYPE_ALARM_DISARM:
- return formatCommand(command, "**,imei:{%s},M", Command.KEY_UNIQUE_ID);
+ return formatCommand(command, "**,imei:%s,M", Command.KEY_UNIQUE_ID);
case Command.TYPE_REQUEST_PHOTO:
- return formatCommand(command, "**,imei:{%s},160", Command.KEY_UNIQUE_ID);
+ return formatCommand(command, "**,imei:%s,160", Command.KEY_UNIQUE_ID);
default:
return null;
}
diff --git a/src/main/java/org/traccar/protocol/GranitProtocolSmsEncoder.java b/src/main/java/org/traccar/protocol/GranitProtocolSmsEncoder.java
index 7dd4b2d77..be0ab5130 100644
--- a/src/main/java/org/traccar/protocol/GranitProtocolSmsEncoder.java
+++ b/src/main/java/org/traccar/protocol/GranitProtocolSmsEncoder.java
@@ -32,7 +32,7 @@ public class GranitProtocolSmsEncoder extends StringProtocolEncoder {
case Command.TYPE_REBOOT_DEVICE:
return "BB+RESET";
case Command.TYPE_POSITION_PERIODIC:
- return formatCommand(command, "BB+BBMD={%s}", Command.KEY_FREQUENCY);
+ return formatCommand(command, "BB+BBMD=%s", Command.KEY_FREQUENCY);
default:
return null;
}
diff --git a/src/main/java/org/traccar/protocol/Gt06ProtocolDecoder.java b/src/main/java/org/traccar/protocol/Gt06ProtocolDecoder.java
index e1ff0b6b6..b51da00d7 100644
--- a/src/main/java/org/traccar/protocol/Gt06ProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/Gt06ProtocolDecoder.java
@@ -209,7 +209,7 @@ public class Gt06ProtocolDecoder extends BaseProtocolDecoder {
sendResponse(channel, false, MSG_X1_PHOTO_DATA, 0, content);
}
- private boolean decodeGps(Position position, ByteBuf buf, boolean hasLength, TimeZone timezone) {
+ public static boolean decodeGps(Position position, ByteBuf buf, boolean hasLength, TimeZone timezone) {
DateBuilder dateBuilder = new DateBuilder(timezone)
.setDate(buf.readUnsignedByte(), buf.readUnsignedByte(), buf.readUnsignedByte())
@@ -548,6 +548,15 @@ public class Gt06ProtocolDecoder extends BaseProtocolDecoder {
position.set(Position.KEY_BATTERY, buf.readUnsignedShort() * 0.01);
position.set(Position.KEY_POWER, buf.readUnsignedShort() * 0.01);
+ long portInfo = buf.readUnsignedInt();
+
+ position.set(Position.KEY_INPUT, buf.readUnsignedByte());
+ position.set(Position.KEY_OUTPUT, buf.readUnsignedByte());
+
+ for (int i = 1; i <= BitUtil.between(portInfo, 20, 24); i++) {
+ position.set(Position.PREFIX_ADC + i, buf.readUnsignedShort() * 0.01);
+ }
+
return position;
} else if (type == MSG_X1_PHOTO_INFO) {
@@ -1011,7 +1020,28 @@ public class Gt06ProtocolDecoder extends BaseProtocolDecoder {
while (buf.readableBytes() > 6) {
int moduleType = buf.readUnsignedShort();
int moduleLength = buf.readUnsignedShort();
+
switch (moduleType) {
+ case 0x03:
+ position.set(Position.KEY_ICCID, ByteBufUtil.hexDump(buf.readSlice(10)));
+ break;
+ case 0x09:
+ position.set(Position.KEY_SATELLITES, buf.readUnsignedByte());
+ break;
+ case 0x0a:
+ position.set(Position.KEY_SATELLITES_VISIBLE, buf.readUnsignedByte());
+ break;
+ case 0x11:
+ CellTower cellTower = CellTower.from(
+ buf.readUnsignedShort(),
+ buf.readUnsignedShort(),
+ buf.readUnsignedShort(),
+ buf.readUnsignedMedium(),
+ buf.readUnsignedByte());
+ if (cellTower.getCellId() > 0) {
+ position.setNetwork(new Network(cellTower));
+ }
+ break;
case 0x18:
position.set(Position.KEY_BATTERY, buf.readUnsignedShort() * 0.01);
break;
@@ -1072,6 +1102,11 @@ public class Gt06ProtocolDecoder extends BaseProtocolDecoder {
position.setLatitude(latitude);
position.setLongitude(longitude);
break;
+ case 0x34:
+ position.set(Position.KEY_EVENT, buf.readUnsignedByte());
+ buf.readUnsignedIntLE(); // time
+ buf.skipBytes(buf.readUnsignedByte()); // content
+ break;
default:
buf.skipBytes(moduleLength);
break;
diff --git a/src/main/java/org/traccar/protocol/H02ProtocolDecoder.java b/src/main/java/org/traccar/protocol/H02ProtocolDecoder.java
index 137689a67..47e5aede0 100644
--- a/src/main/java/org/traccar/protocol/H02ProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/H02ProtocolDecoder.java
@@ -185,7 +185,7 @@ public class H02ProtocolDecoder extends BaseProtocolDecoder {
.number("(d+)(dd.d+),") // longitude
.groupEnd()
.expression("([EW]),")
- .number("(d+.?d*),") // speed
+ .number(" *(d+.?d*),") // speed
.number("(d+.?d*)?,") // course
.number("(?:d+,)?") // battery
.number("(?:(dd)(dd)(dd))?") // date (ddmmyy)
diff --git a/src/main/java/org/traccar/protocol/HuabaoProtocolDecoder.java b/src/main/java/org/traccar/protocol/HuabaoProtocolDecoder.java
index fceefa73a..342edb22b 100644
--- a/src/main/java/org/traccar/protocol/HuabaoProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/HuabaoProtocolDecoder.java
@@ -98,6 +98,9 @@ public class HuabaoProtocolDecoder extends BaseProtocolDecoder {
if (BitUtil.check(value, 20)) {
return Position.ALARM_GEOFENCE;
}
+ if (BitUtil.check(value, 28)) {
+ return Position.ALARM_MOVEMENT;
+ }
if (BitUtil.check(value, 29)) {
return Position.ALARM_ACCIDENT;
}
@@ -160,22 +163,23 @@ public class HuabaoProtocolDecoder extends BaseProtocolDecoder {
position.set(Position.KEY_ALARM, decodeAlarm(buf.readUnsignedInt()));
- int flags = buf.readInt();
+ int status = buf.readInt();
- position.set(Position.KEY_IGNITION, BitUtil.check(flags, 0));
+ position.set(Position.KEY_IGNITION, BitUtil.check(status, 0));
+ position.set(Position.KEY_BLOCKED, BitUtil.check(status, 10));
- position.setValid(BitUtil.check(flags, 1));
+ position.setValid(BitUtil.check(status, 1));
double lat = buf.readUnsignedInt() * 0.000001;
double lon = buf.readUnsignedInt() * 0.000001;
- if (BitUtil.check(flags, 2)) {
+ if (BitUtil.check(status, 2)) {
position.setLatitude(-lat);
} else {
position.setLatitude(lat);
}
- if (BitUtil.check(flags, 3)) {
+ if (BitUtil.check(status, 3)) {
position.setLongitude(-lon);
} else {
position.setLongitude(lon);
@@ -211,6 +215,13 @@ public class HuabaoProtocolDecoder extends BaseProtocolDecoder {
case 0x31:
position.set(Position.KEY_SATELLITES, buf.readUnsignedByte());
break;
+ case 0x33:
+ String sentence = buf.readCharSequence(length, StandardCharsets.US_ASCII).toString();
+ if (sentence.startsWith("*M00")) {
+ String lockStatus = sentence.substring(8, 8 + 7);
+ position.set(Position.KEY_BATTERY, Integer.parseInt(lockStatus.substring(2, 5)) * 0.01);
+ }
+ break;
case 0x91:
position.set(Position.KEY_BATTERY, buf.readUnsignedShort() * 0.1);
position.set(Position.KEY_RPM, buf.readUnsignedShort());
@@ -231,7 +242,17 @@ public class HuabaoProtocolDecoder extends BaseProtocolDecoder {
Position.KEY_VIN, buf.readCharSequence(length, StandardCharsets.US_ASCII).toString());
}
break;
+ case 0xD0:
+ long userStatus = buf.readUnsignedInt();
+ if (BitUtil.check(userStatus, 3)) {
+ position.set(Position.KEY_ALARM, Position.ALARM_VIBRATION);
+ }
+ break;
+ case 0xD3:
+ position.set(Position.KEY_POWER, buf.readUnsignedShort() * 0.1);
+ break;
default:
+ System.out.print(String.format("%02x ", subtype));
break;
}
buf.readerIndex(endIndex);
@@ -257,4 +278,3 @@ public class HuabaoProtocolDecoder extends BaseProtocolDecoder {
}
}
-
diff --git a/src/main/java/org/traccar/protocol/LaipacProtocolEncoder.java b/src/main/java/org/traccar/protocol/LaipacProtocolEncoder.java
index 343ac9431..0c9f8ebb8 100644
--- a/src/main/java/org/traccar/protocol/LaipacProtocolEncoder.java
+++ b/src/main/java/org/traccar/protocol/LaipacProtocolEncoder.java
@@ -40,13 +40,13 @@ public class LaipacProtocolEncoder extends StringProtocolEncoder {
switch (command.getType()) {
case Command.TYPE_CUSTOM:
- return formatCommand(command, "{%s}",
+ return formatCommand(command, "%s",
Command.KEY_DATA);
case Command.TYPE_POSITION_SINGLE:
- return formatCommand(command, "AVREQ,{%s},1",
+ return formatCommand(command, "AVREQ,%s,1",
Command.KEY_DEVICE_PASSWORD);
case Command.TYPE_REBOOT_DEVICE:
- return formatCommand(command, "AVRESET,{%s},{%s}",
+ return formatCommand(command, "AVRESET,%s,%s",
Command.KEY_UNIQUE_ID, Command.KEY_DEVICE_PASSWORD);
default:
return null;
diff --git a/src/main/java/org/traccar/protocol/MiniFinderProtocolEncoder.java b/src/main/java/org/traccar/protocol/MiniFinderProtocolEncoder.java
index 36fb9fc2f..059f688f7 100644
--- a/src/main/java/org/traccar/protocol/MiniFinderProtocolEncoder.java
+++ b/src/main/java/org/traccar/protocol/MiniFinderProtocolEncoder.java
@@ -57,28 +57,28 @@ public class MiniFinderProtocolEncoder extends StringProtocolEncoder implements
switch (command.getType()) {
case Command.TYPE_SET_TIMEZONE:
- return formatCommand(command, "{%s}L{%s}", this, Command.KEY_DEVICE_PASSWORD, Command.KEY_TIMEZONE);
+ return formatCommand(command, "%sL%s", this, Command.KEY_DEVICE_PASSWORD, Command.KEY_TIMEZONE);
case Command.TYPE_VOICE_MONITORING:
- return formatCommand(command, "{%s}P{%s}", this, Command.KEY_DEVICE_PASSWORD, Command.KEY_ENABLE);
+ return formatCommand(command, "%sP%s", this, Command.KEY_DEVICE_PASSWORD, Command.KEY_ENABLE);
case Command.TYPE_ALARM_SPEED:
- return formatCommand(command, "{%s}J1{%s}", Command.KEY_DEVICE_PASSWORD, Command.KEY_DATA);
+ return formatCommand(command, "%sJ1%s", Command.KEY_DEVICE_PASSWORD, Command.KEY_DATA);
case Command.TYPE_ALARM_GEOFENCE:
- return formatCommand(command, "{%s}R1{%s}", Command.KEY_DEVICE_PASSWORD, Command.KEY_RADIUS);
+ return formatCommand(command, "%sR1%s", Command.KEY_DEVICE_PASSWORD, Command.KEY_RADIUS);
case Command.TYPE_ALARM_VIBRATION:
- return formatCommand(command, "{%s}W1,{%s}", Command.KEY_DEVICE_PASSWORD, Command.KEY_DATA);
+ return formatCommand(command, "%sW1,%s", Command.KEY_DEVICE_PASSWORD, Command.KEY_DATA);
case Command.TYPE_SET_AGPS:
- return formatCommand(command, "{%s}AGPS{%s}", this, Command.KEY_DEVICE_PASSWORD, Command.KEY_ENABLE);
+ return formatCommand(command, "%sAGPS%s", this, Command.KEY_DEVICE_PASSWORD, Command.KEY_ENABLE);
case Command.TYPE_ALARM_FALL:
- return formatCommand(command, "{%s}F{%s}", this, Command.KEY_DEVICE_PASSWORD, Command.KEY_ENABLE);
+ return formatCommand(command, "%sF%s", this, Command.KEY_DEVICE_PASSWORD, Command.KEY_ENABLE);
case Command.TYPE_MODE_POWER_SAVING:
- return formatCommand(command, "{%s}SP{%s}", this, Command.KEY_DEVICE_PASSWORD, Command.KEY_ENABLE);
+ return formatCommand(command, "%sSP%s", this, Command.KEY_DEVICE_PASSWORD, Command.KEY_ENABLE);
case Command.TYPE_MODE_DEEP_SLEEP:
- return formatCommand(command, "{%s}DS{%s}", this, Command.KEY_DEVICE_PASSWORD, Command.KEY_ENABLE);
+ return formatCommand(command, "%sDS%s", this, Command.KEY_DEVICE_PASSWORD, Command.KEY_ENABLE);
case Command.TYPE_SOS_NUMBER:
- return formatCommand(command, "{%s}{%s}1,{%s}", this,
+ return formatCommand(command, "%s%s1,%s", this,
Command.KEY_DEVICE_PASSWORD, Command.KEY_INDEX, Command.KEY_PHONE);
case Command.TYPE_SET_INDICATOR:
- return formatCommand(command, "{%s}LED{%s}", Command.KEY_DEVICE_PASSWORD, Command.KEY_DATA);
+ return formatCommand(command, "%sLED%s", Command.KEY_DEVICE_PASSWORD, Command.KEY_DATA);
default:
return null;
}
diff --git a/src/main/java/org/traccar/protocol/Minifinder2ProtocolDecoder.java b/src/main/java/org/traccar/protocol/Minifinder2ProtocolDecoder.java
index 75c8b11d3..b6f257d2c 100644
--- a/src/main/java/org/traccar/protocol/Minifinder2ProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/Minifinder2ProtocolDecoder.java
@@ -117,6 +117,10 @@ public class Minifinder2ProtocolDecoder extends BaseProtocolDecoder {
case 0x02:
position.set(Position.KEY_ALARM, decodeAlarm(buf.readIntLE()));
break;
+ case 0x14:
+ position.set(Position.KEY_BATTERY_LEVEL, buf.readUnsignedByte());
+ position.set(Position.KEY_BATTERY, buf.readUnsignedShortLE() * 0.001);
+ break;
case 0x20:
position.setLatitude(buf.readIntLE() * 0.0000001);
position.setLongitude(buf.readIntLE() * 0.0000001);
@@ -152,7 +156,9 @@ public class Minifinder2ProtocolDecoder extends BaseProtocolDecoder {
break;
case 0x24:
position.setTime(new Date(buf.readUnsignedIntLE() * 1000));
- position.set(Position.KEY_STATUS, buf.readUnsignedIntLE());
+ long status = buf.readUnsignedIntLE();
+ position.set(Position.KEY_BATTERY_LEVEL, BitUtil.from(status, 24));
+ position.set(Position.KEY_STATUS, status);
break;
case 0x40:
buf.readUnsignedIntLE(); // timestamp
diff --git a/src/main/java/org/traccar/protocol/OutsafeProtocol.java b/src/main/java/org/traccar/protocol/OutsafeProtocol.java
new file mode 100644
index 000000000..c728a404d
--- /dev/null
+++ b/src/main/java/org/traccar/protocol/OutsafeProtocol.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2019 Anton Tananaev (anton@traccar.org)
+ *
+ * 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 io.netty.handler.codec.http.HttpObjectAggregator;
+import io.netty.handler.codec.http.HttpRequestDecoder;
+import io.netty.handler.codec.http.HttpResponseEncoder;
+import org.traccar.BaseProtocol;
+import org.traccar.PipelineBuilder;
+import org.traccar.TrackerServer;
+
+public class OutsafeProtocol extends BaseProtocol {
+
+ public OutsafeProtocol() {
+ addServer(new TrackerServer(false, getName()) {
+ @Override
+ protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ pipeline.addLast(new HttpResponseEncoder());
+ pipeline.addLast(new HttpRequestDecoder());
+ pipeline.addLast(new HttpObjectAggregator(65535));
+ pipeline.addLast(new OutsafeProtocolDecoder(OutsafeProtocol.this));
+ }
+ });
+ }
+
+}
diff --git a/src/main/java/org/traccar/protocol/OutsafeProtocolDecoder.java b/src/main/java/org/traccar/protocol/OutsafeProtocolDecoder.java
new file mode 100644
index 000000000..5e95270e8
--- /dev/null
+++ b/src/main/java/org/traccar/protocol/OutsafeProtocolDecoder.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright 2019 Anton Tananaev (anton@traccar.org)
+ *
+ * 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 io.netty.channel.Channel;
+import io.netty.handler.codec.http.FullHttpRequest;
+import io.netty.handler.codec.http.HttpResponseStatus;
+import org.traccar.BaseHttpProtocolDecoder;
+import org.traccar.DeviceSession;
+import org.traccar.Protocol;
+import org.traccar.model.Position;
+
+import javax.json.Json;
+import javax.json.JsonObject;
+import java.io.StringReader;
+import java.net.SocketAddress;
+import java.nio.charset.StandardCharsets;
+import java.util.Date;
+
+public class OutsafeProtocolDecoder extends BaseHttpProtocolDecoder {
+
+ public OutsafeProtocolDecoder(Protocol protocol) {
+ super(protocol);
+ }
+
+ @Override
+ protected Object decode(
+ Channel channel, SocketAddress remoteAddress, Object msg) throws Exception {
+
+ FullHttpRequest request = (FullHttpRequest) msg;
+ String content = request.content().toString(StandardCharsets.UTF_8);
+ JsonObject json = Json.createReader(new StringReader(content)).readObject();
+
+ DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, json.getString("device"));
+ if (deviceSession == null) {
+ sendResponse(channel, HttpResponseStatus.BAD_REQUEST);
+ return null;
+ }
+
+ Position position = new Position(getProtocolName());
+ position.setDeviceId(deviceSession.getDeviceId());
+
+ position.setTime(new Date());
+ position.setValid(true);
+ position.setLatitude(json.getJsonNumber("latitude").doubleValue());
+ position.setLongitude(json.getJsonNumber("longitude").doubleValue());
+ position.setAltitude(json.getJsonNumber("altitude").doubleValue());
+ position.setCourse(json.getJsonNumber("heading").intValue());
+
+ position.set(Position.KEY_RSSI, json.getJsonNumber("rssi").intValue());
+
+ sendResponse(channel, HttpResponseStatus.OK);
+ return position;
+ }
+
+}
diff --git a/src/main/java/org/traccar/protocol/PluginProtocolDecoder.java b/src/main/java/org/traccar/protocol/PluginProtocolDecoder.java
index 106889ee0..949c994ee 100644
--- a/src/main/java/org/traccar/protocol/PluginProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/PluginProtocolDecoder.java
@@ -19,6 +19,7 @@ import io.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
import org.traccar.DeviceSession;
import org.traccar.Protocol;
+import org.traccar.helper.BitUtil;
import org.traccar.helper.Parser;
import org.traccar.helper.PatternBuilder;
import org.traccar.helper.UnitsConverter;
@@ -40,17 +41,30 @@ public class PluginProtocolDecoder extends BaseProtocolDecoder {
.number("(dd)(dd)(dd),") // time (hhmmss)
.number("(-?d+.d+),") // longitude
.number("(-?d+.d+),") // latitude
- .number("(d+),") // speed
+ .number("(d+.?d*),") // speed
.number("(d+),") // course
.number("(-?d+),") // altitude
.number("(-?d+),") // satellites
.number("d+,") // type
- .number("(d+),") // odometer
+ .number("(d+.?d*),") // odometer
.number("(d+),") // status
- .expression("[^,]*,")
+ .number("(d+.?d*),") // fuel
.expression("[^,]*,")
.text("0")
.groupBegin()
+ .number(",(-?d+.?d*)") // temperature 1
+ .number(",(-?d+.?d*)") // temperature 2
+ .number(",d+") // oil level
+ .number(",(d+)") // rpm
+ .number(",(d+)") // obd speed
+ .number(",d+") // people up
+ .number(",d+") // people down
+ .number(",d+") // obd status
+ .number(",d+") // fuel intake air temperature
+ .number(",(d+)") // throttle
+ .number(",(d+)") // battery
+ .groupEnd("?")
+ .groupBegin()
.text(",+,")
.number("(d+),") // event
.groupEnd("?")
@@ -74,18 +88,50 @@ public class PluginProtocolDecoder extends BaseProtocolDecoder {
Position position = new Position(getProtocolName());
position.setDeviceId(deviceSession.getDeviceId());
- position.setValid(true);
position.setTime(parser.nextDateTime());
position.setLongitude(parser.nextDouble());
position.setLatitude(parser.nextDouble());
- position.setSpeed(UnitsConverter.knotsFromKph(parser.nextInt()));
+ position.setSpeed(UnitsConverter.knotsFromKph(parser.nextDouble()));
position.setCourse(parser.nextInt());
position.setAltitude(parser.nextInt());
position.set(Position.KEY_SATELLITES, parser.nextInt());
- position.set(Position.KEY_ODOMETER, parser.nextInt());
- position.set(Position.KEY_STATUS, parser.nextInt());
- position.set(Position.KEY_EVENT, parser.nextInt());
+ position.set(Position.KEY_ODOMETER, (long) (parser.nextDouble() * 1000));
+
+ int status = parser.nextInt();
+ position.setValid(BitUtil.check(status, 0));
+ position.set(Position.KEY_IGNITION, BitUtil.check(status, 1));
+ for (int i = 0; i < 4; i++) {
+ position.set(Position.PREFIX_IN + (i + 1), BitUtil.check(status, 20 + i));
+ }
+ position.set(Position.KEY_STATUS, status);
+
+ position.set(Position.KEY_FUEL_LEVEL, parser.nextDouble());
+
+ if (parser.hasNext(6)) {
+ position.set(Position.PREFIX_TEMP + 1, parser.nextDouble());
+ position.set(Position.PREFIX_TEMP + 2, parser.nextDouble());
+ position.set(Position.KEY_RPM, parser.nextInt());
+ position.set(Position.KEY_OBD_SPEED, parser.nextInt());
+ position.set(Position.KEY_THROTTLE, parser.nextInt() * 0.1);
+ position.set(Position.KEY_POWER, parser.nextInt() * 0.1);
+ }
+
+ if (parser.hasNext()) {
+ int event = parser.nextInt();
+ switch (event) {
+ case 11317:
+ position.set(Position.KEY_ALARM, Position.ALARM_ACCELERATION);
+ break;
+ case 11319:
+ position.set(Position.KEY_ALARM, Position.ALARM_BRAKING);
+ break;
+ default:
+ break;
+
+ }
+ position.set(Position.KEY_EVENT, event);
+ }
return position;
}
diff --git a/src/main/java/org/traccar/protocol/Pt215FrameDecoder.java b/src/main/java/org/traccar/protocol/Pt215FrameDecoder.java
deleted file mode 100644
index 0b3bae914..000000000
--- a/src/main/java/org/traccar/protocol/Pt215FrameDecoder.java
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * Copyright 2019 Anton Tananaev (anton@traccar.org)
- *
- * 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 io.netty.buffer.ByteBuf;
-import io.netty.channel.Channel;
-import io.netty.channel.ChannelHandlerContext;
-import org.traccar.BaseFrameDecoder;
-
-public class Pt215FrameDecoder extends BaseFrameDecoder {
-
- private ByteBuf decodeFrame(ByteBuf buf, int length) {
- if (buf.readableBytes() >= length) {
- return buf.readRetainedSlice(length);
- }
- return null;
- }
-
- @Override
- protected Object decode(
- ChannelHandlerContext ctx, Channel channel, ByteBuf buf) throws Exception {
-
- if (buf.readableBytes() < 5) {
- return null;
- }
-
- int type = buf.getUnsignedByte(buf.readerIndex() + 2 + 1);
- switch (type) {
- case Pt215ProtocolDecoder.MSG_LOGIN:
- return decodeFrame(buf, 15);
- case Pt215ProtocolDecoder.MSG_GPS_REALTIME:
- case Pt215ProtocolDecoder.MSG_GPS_OFFLINE:
- return decodeFrame(buf, 27);
- case Pt215ProtocolDecoder.MSG_STATUS:
- return decodeFrame(buf, 11);
- default:
- return null;
-
- }
- }
-
-}
diff --git a/src/main/java/org/traccar/protocol/Pt215Protocol.java b/src/main/java/org/traccar/protocol/Pt215Protocol.java
index 31ddc2c7a..09bd9b121 100644
--- a/src/main/java/org/traccar/protocol/Pt215Protocol.java
+++ b/src/main/java/org/traccar/protocol/Pt215Protocol.java
@@ -15,6 +15,7 @@
*/
package org.traccar.protocol;
+import io.netty.handler.codec.LengthFieldBasedFrameDecoder;
import org.traccar.BaseProtocol;
import org.traccar.PipelineBuilder;
import org.traccar.TrackerServer;
@@ -25,7 +26,7 @@ public class Pt215Protocol extends BaseProtocol {
addServer(new TrackerServer(false, getName()) {
@Override
protected void addProtocolHandlers(PipelineBuilder pipeline) {
- pipeline.addLast(new Pt215FrameDecoder());
+ pipeline.addLast(new LengthFieldBasedFrameDecoder(1024, 2, 1, -1, 0));
pipeline.addLast(new Pt215ProtocolDecoder(Pt215Protocol.this));
}
});
diff --git a/src/main/java/org/traccar/protocol/Pt502ProtocolEncoder.java b/src/main/java/org/traccar/protocol/Pt502ProtocolEncoder.java
index ba08b16ae..364ecae86 100644
--- a/src/main/java/org/traccar/protocol/Pt502ProtocolEncoder.java
+++ b/src/main/java/org/traccar/protocol/Pt502ProtocolEncoder.java
@@ -46,13 +46,13 @@ public class Pt502ProtocolEncoder extends StringProtocolEncoder implements Strin
switch (command.getType()) {
case Command.TYPE_CUSTOM:
- return formatCommand(command, "{%s}\r\n", Command.KEY_DATA);
+ return formatCommand(command, "%s\r\n", Command.KEY_DATA);
case Command.TYPE_OUTPUT_CONTROL:
- return formatCommand(command, "#OPC{%s},{%s}\r\n", Command.KEY_INDEX, Command.KEY_DATA);
+ return formatCommand(command, "#OPC%s,%s\r\n", Command.KEY_INDEX, Command.KEY_DATA);
case Command.TYPE_SET_TIMEZONE:
- return formatCommand(command, "#TMZ{%s}\r\n", Command.KEY_TIMEZONE);
+ return formatCommand(command, "#TMZ%s\r\n", Command.KEY_TIMEZONE);
case Command.TYPE_ALARM_SPEED:
- return formatCommand(command, "#SPD{%s}\r\n", Command.KEY_DATA);
+ return formatCommand(command, "#SPD%s\r\n", Command.KEY_DATA);
case Command.TYPE_REQUEST_PHOTO:
return formatCommand(command, "#PHO\r\n");
default:
diff --git a/src/main/java/org/traccar/protocol/RstProtocolDecoder.java b/src/main/java/org/traccar/protocol/RstProtocolDecoder.java
index 071200d6d..f9c8d9df8 100644
--- a/src/main/java/org/traccar/protocol/RstProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/RstProtocolDecoder.java
@@ -20,6 +20,7 @@ import org.traccar.BaseProtocolDecoder;
import org.traccar.DeviceSession;
import org.traccar.NetworkMessage;
import org.traccar.Protocol;
+import org.traccar.helper.BitUtil;
import org.traccar.helper.Parser;
import org.traccar.helper.PatternBuilder;
import org.traccar.helper.UnitsConverter;
@@ -84,10 +85,10 @@ public class RstProtocolDecoder extends BaseProtocolDecoder {
String firmware = parser.next();
String serial = parser.next();
int index = parser.nextInt();
- int type = parser.nextInt();
+ parser.nextInt(); // type
if (channel != null && archive.equals("A")) {
- String response = "RST;A;" + model + ";" + firmware + ";" + serial + ";" + index + ";" + type + ";FIM;";
+ String response = "RST;A;" + model + ";" + firmware + ";" + serial + ";" + index + ";6;FIM;";
channel.writeAndFlush(new NetworkMessage(response, remoteAddress));
}
@@ -120,7 +121,10 @@ public class RstProtocolDecoder extends BaseProtocolDecoder {
position.set(Position.KEY_ODOMETER, parser.nextInt());
position.set(Position.KEY_RSSI, parser.nextInt());
position.set(Position.PREFIX_TEMP + 1, (int) parser.nextHexInt().byteValue());
- position.set(Position.KEY_STATUS, parser.nextHexInt() << 8 + parser.nextHexInt());
+
+ int status = parser.nextHexInt() << 8 + parser.nextHexInt();
+ position.set(Position.KEY_IGNITION, BitUtil.check(status, 7));
+ position.set(Position.KEY_STATUS, status);
return position;
}
diff --git a/src/main/java/org/traccar/protocol/SigfoxProtocolDecoder.java b/src/main/java/org/traccar/protocol/SigfoxProtocolDecoder.java
index f9c79fb5b..304f61836 100644
--- a/src/main/java/org/traccar/protocol/SigfoxProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/SigfoxProtocolDecoder.java
@@ -24,6 +24,7 @@ import io.netty.handler.codec.http.HttpResponseStatus;
import org.traccar.BaseHttpProtocolDecoder;
import org.traccar.DeviceSession;
import org.traccar.Protocol;
+import org.traccar.helper.BitUtil;
import org.traccar.helper.DataConverter;
import org.traccar.helper.UnitsConverter;
import org.traccar.model.Network;
@@ -31,7 +32,10 @@ import org.traccar.model.Position;
import org.traccar.model.WifiAccessPoint;
import javax.json.Json;
+import javax.json.JsonNumber;
import javax.json.JsonObject;
+import javax.json.JsonString;
+import javax.json.JsonValue;
import java.io.StringReader;
import java.net.SocketAddress;
import java.net.URLDecoder;
@@ -44,6 +48,30 @@ public class SigfoxProtocolDecoder extends BaseHttpProtocolDecoder {
super(protocol);
}
+ private int getJsonInt(JsonObject json, String key) {
+ JsonValue value = json.get(key);
+ if (value != null) {
+ if (value.getValueType() == JsonValue.ValueType.NUMBER) {
+ return ((JsonNumber) value).intValue();
+ } else if (value.getValueType() == JsonValue.ValueType.STRING) {
+ return Integer.parseInt(((JsonString) value).getString());
+ }
+ }
+ return 0;
+ }
+
+ private double getJsonDouble(JsonObject json, String key) {
+ JsonValue value = json.get(key);
+ if (value != null) {
+ if (value.getValueType() == JsonValue.ValueType.NUMBER) {
+ return ((JsonNumber) value).doubleValue();
+ } else if (value.getValueType() == JsonValue.ValueType.STRING) {
+ return Double.parseDouble(((JsonString) value).getString());
+ }
+ }
+ return 0;
+ }
+
@Override
protected Object decode(
Channel channel, SocketAddress remoteAddress, Object msg) throws Exception {
@@ -65,18 +93,24 @@ public class SigfoxProtocolDecoder extends BaseHttpProtocolDecoder {
position.setDeviceId(deviceSession.getDeviceId());
if (json.containsKey("time")) {
- position.setTime(new Date(json.getInt("time") * 1000L));
+ position.setTime(new Date(getJsonInt(json, "time") * 1000L));
} else {
position.setTime(new Date());
}
- if (json.containsKey("location")) {
+ if (json.containsKey("location")
+ || json.containsKey("lat") && json.containsKey("lng") && !json.containsKey("data")) {
- JsonObject location = json.getJsonObject("location");
+ JsonObject location;
+ if (json.containsKey("location")) {
+ location = json.getJsonObject("location");
+ } else {
+ location = json;
+ }
position.setValid(true);
- position.setLatitude(location.getJsonNumber("lat").doubleValue());
- position.setLongitude(location.getJsonNumber("lng").doubleValue());
+ position.setLatitude(getJsonDouble(location, "lat"));
+ position.setLongitude(getJsonDouble(location, "lng"));
} else {
@@ -84,7 +118,25 @@ public class SigfoxProtocolDecoder extends BaseHttpProtocolDecoder {
ByteBuf buf = Unpooled.wrappedBuffer(DataConverter.parseHex(data));
try {
int event = buf.readUnsignedByte();
- if (event >> 4 == 0) {
+ if (event == 0x0f || event == 0x1f) {
+
+ position.setValid(event >> 4 > 0);
+
+ long value;
+ value = buf.readUnsignedInt();
+ position.setLatitude(BitUtil.to(value, 31) * 0.000001);
+ if (BitUtil.check(value, 31)) {
+ position.setLatitude(-position.getLatitude());
+ }
+ value = buf.readUnsignedInt();
+ position.setLongitude(BitUtil.to(value, 31) * 0.000001);
+ if (BitUtil.check(value, 31)) {
+ position.setLongitude(-position.getLongitude());
+ }
+
+ position.set(Position.KEY_BATTERY, (int) buf.readUnsignedByte());
+
+ } else if (event >> 4 == 0) {
position.setValid(true);
position.setLatitude(buf.readIntLE() * 0.0000001);
@@ -154,10 +206,10 @@ public class SigfoxProtocolDecoder extends BaseHttpProtocolDecoder {
}
if (json.containsKey("rssi")) {
- position.set(Position.KEY_RSSI, json.getJsonNumber("rssi").doubleValue());
+ position.set(Position.KEY_RSSI, getJsonDouble(json, "rssi"));
}
if (json.containsKey("seqNumber")) {
- position.set(Position.KEY_INDEX, json.getInt("seqNumber"));
+ position.set(Position.KEY_INDEX, getJsonInt(json, "seqNumber"));
}
sendResponse(channel, HttpResponseStatus.OK);
diff --git a/src/main/java/org/traccar/protocol/SolarPoweredProtocol.java b/src/main/java/org/traccar/protocol/SolarPoweredProtocol.java
new file mode 100644
index 000000000..53a948cdc
--- /dev/null
+++ b/src/main/java/org/traccar/protocol/SolarPoweredProtocol.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2019 Anton Tananaev (anton@traccar.org)
+ *
+ * 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.BaseProtocol;
+import org.traccar.PipelineBuilder;
+import org.traccar.TrackerServer;
+
+public class SolarPoweredProtocol extends BaseProtocol {
+
+ public SolarPoweredProtocol() {
+ addServer(new TrackerServer(false, getName()) {
+ @Override
+ protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ pipeline.addLast(new HuabaoFrameDecoder());
+ pipeline.addLast(new SolarPoweredProtocolDecoder(SolarPoweredProtocol.this));
+ }
+ });
+ }
+
+}
diff --git a/src/main/java/org/traccar/protocol/SolarPoweredProtocolDecoder.java b/src/main/java/org/traccar/protocol/SolarPoweredProtocolDecoder.java
new file mode 100644
index 000000000..eae37386a
--- /dev/null
+++ b/src/main/java/org/traccar/protocol/SolarPoweredProtocolDecoder.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright 2019 Anton Tananaev (anton@traccar.org)
+ *
+ * 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 io.netty.buffer.ByteBuf;
+import io.netty.buffer.ByteBufUtil;
+import io.netty.channel.Channel;
+import org.traccar.BaseProtocolDecoder;
+import org.traccar.DeviceSession;
+import org.traccar.Protocol;
+import org.traccar.helper.BitUtil;
+import org.traccar.helper.DateBuilder;
+import org.traccar.helper.UnitsConverter;
+import org.traccar.model.Position;
+
+import java.net.SocketAddress;
+
+public class SolarPoweredProtocolDecoder extends BaseProtocolDecoder {
+
+ public SolarPoweredProtocolDecoder(Protocol protocol) {
+ super(protocol);
+ }
+
+ public static final int MSG_ACTIVE_REPORTING = 0x11;
+
+ @Override
+ protected Object decode(
+ Channel channel, SocketAddress remoteAddress, Object msg) throws Exception {
+
+ ByteBuf buf = (ByteBuf) msg;
+
+ buf.readUnsignedByte(); // start marker
+
+ String imei = ByteBufUtil.hexDump(buf.readSlice(8)).substring(0, 15);
+ DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, imei);
+ if (deviceSession == null) {
+ return null;
+ }
+
+ int type = buf.readUnsignedByte();
+ buf.readUnsignedShort(); // attributes
+
+ if (type == MSG_ACTIVE_REPORTING) {
+
+ Position position = new Position(getProtocolName());
+ position.setDeviceId(deviceSession.getDeviceId());
+
+ while (buf.readableBytes() > 2) {
+ int tag = buf.readUnsignedByte();
+ int length = buf.readUnsignedByte();
+ switch (tag) {
+ case 0x81:
+ int status = buf.readUnsignedByte();
+ DateBuilder dateBuilder = new DateBuilder()
+ .setDate(buf.readUnsignedByte(), buf.readUnsignedByte(), buf.readUnsignedByte())
+ .setTime(buf.readUnsignedByte(), buf.readUnsignedByte(), buf.readUnsignedByte());
+ position.setTime(dateBuilder.getDate());
+ position.setLatitude(buf.readUnsignedInt() * 0.000001);
+ if (BitUtil.check(status, 3)) {
+ position.setLatitude(-position.getLatitude());
+ }
+ position.setLongitude(buf.readUnsignedInt() * 0.000001);
+ if (BitUtil.check(status, 2)) {
+ position.setLongitude(-position.getLongitude());
+ }
+ position.setSpeed(UnitsConverter.knotsFromKph(buf.readUnsignedByte()));
+ position.set(Position.KEY_DEVICE_TEMP, (int) buf.readByte());
+ position.set(Position.KEY_BATTERY, buf.readUnsignedByte() * 0.02);
+ position.setCourse(buf.readUnsignedByte());
+ break;
+ default:
+ buf.skipBytes(length);
+ break;
+ }
+ }
+
+ return position;
+
+ }
+
+ return null;
+ }
+
+}
diff --git a/src/main/java/org/traccar/protocol/StarcomProtocolDecoder.java b/src/main/java/org/traccar/protocol/StarcomProtocolDecoder.java
index 90151d061..5ffddb318 100644
--- a/src/main/java/org/traccar/protocol/StarcomProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/StarcomProtocolDecoder.java
@@ -18,6 +18,7 @@ package org.traccar.protocol;
import io.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
import org.traccar.DeviceSession;
+import org.traccar.helper.UnitsConverter;
import org.traccar.model.Position;
import java.net.SocketAddress;
@@ -66,7 +67,7 @@ public class StarcomProtocolDecoder extends BaseProtocolDecoder {
position.setAltitude(Double.parseDouble(value));
break;
case "velocity":
- position.setSpeed(Integer.parseInt(value));
+ position.setSpeed(UnitsConverter.knotsFromKph(Integer.parseInt(value)));
break;
case "heading":
position.setCourse(Integer.parseInt(value));
@@ -74,8 +75,8 @@ public class StarcomProtocolDecoder extends BaseProtocolDecoder {
case "eventid":
position.set(Position.KEY_EVENT, Integer.parseInt(value));
break;
- case "odometer":
- position.set(Position.KEY_ODOMETER, Long.parseLong(value));
+ case "mileage":
+ position.set(Position.KEY_ODOMETER, (long) (Double.parseDouble(value) * 1000));
break;
case "satellites":
position.set(Position.KEY_SATELLITES, Integer.parseInt(value));
diff --git a/src/main/java/org/traccar/protocol/SuntechFrameDecoder.java b/src/main/java/org/traccar/protocol/SuntechFrameDecoder.java
index de8de17f0..7b8337468 100644
--- a/src/main/java/org/traccar/protocol/SuntechFrameDecoder.java
+++ b/src/main/java/org/traccar/protocol/SuntechFrameDecoder.java
@@ -32,13 +32,24 @@ public class SuntechFrameDecoder extends BaseFrameDecoder {
protected Object decode(
ChannelHandlerContext ctx, Channel channel, ByteBuf buf) throws Exception {
- int delimiterIndex = buf.indexOf(buf.readerIndex(), buf.writerIndex(), (byte) '\r');
- while (delimiterIndex > 0) {
- if (delimiterIndex + 1 < buf.writerIndex() && buf.getByte(delimiterIndex + 1) == '\n') {
- delimiterIndex = buf.indexOf(delimiterIndex + 1, buf.writerIndex(), (byte) '\r');
- } else {
- return readFrame(buf, delimiterIndex);
+ if (buf.getByte(buf.readerIndex()) == (byte) 0x81) {
+
+ int length = 1 + 2 + buf.getShort(buf.readerIndex() + 1);
+ if (buf.readableBytes() >= length) {
+ return buf.readRetainedSlice(length);
}
+
+ } else {
+
+ int delimiterIndex = buf.indexOf(buf.readerIndex(), buf.writerIndex(), (byte) '\r');
+ while (delimiterIndex > 0) {
+ if (delimiterIndex + 1 < buf.writerIndex() && buf.getByte(delimiterIndex + 1) == '\n') {
+ delimiterIndex = buf.indexOf(delimiterIndex + 1, buf.writerIndex(), (byte) '\r');
+ } else {
+ return readFrame(buf, delimiterIndex);
+ }
+ }
+
}
return null;
diff --git a/src/main/java/org/traccar/protocol/SuntechProtocol.java b/src/main/java/org/traccar/protocol/SuntechProtocol.java
index 7e2c20e6f..199885537 100644
--- a/src/main/java/org/traccar/protocol/SuntechProtocol.java
+++ b/src/main/java/org/traccar/protocol/SuntechProtocol.java
@@ -15,7 +15,6 @@
*/
package org.traccar.protocol;
-import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;
import org.traccar.BaseProtocol;
import org.traccar.PipelineBuilder;
@@ -38,7 +37,6 @@ public class SuntechProtocol extends BaseProtocol {
protected void addProtocolHandlers(PipelineBuilder pipeline) {
pipeline.addLast(new SuntechFrameDecoder());
pipeline.addLast(new StringEncoder());
- pipeline.addLast(new StringDecoder());
pipeline.addLast(new SuntechProtocolEncoder(SuntechProtocol.this));
pipeline.addLast(new SuntechProtocolDecoder(SuntechProtocol.this));
}
diff --git a/src/main/java/org/traccar/protocol/SuntechProtocolDecoder.java b/src/main/java/org/traccar/protocol/SuntechProtocolDecoder.java
index e40096a77..601d127f1 100644
--- a/src/main/java/org/traccar/protocol/SuntechProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/SuntechProtocolDecoder.java
@@ -15,18 +15,22 @@
*/
package org.traccar.protocol;
+import io.netty.buffer.ByteBuf;
+import io.netty.buffer.ByteBufUtil;
import io.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
import org.traccar.Context;
import org.traccar.DeviceSession;
import org.traccar.Protocol;
import org.traccar.helper.BitUtil;
+import org.traccar.helper.DateBuilder;
import org.traccar.helper.UnitsConverter;
import org.traccar.model.CellTower;
import org.traccar.model.Network;
import org.traccar.model.Position;
import java.net.SocketAddress;
+import java.nio.charset.StandardCharsets;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
@@ -34,6 +38,8 @@ import java.util.TimeZone;
public class SuntechProtocolDecoder extends BaseProtocolDecoder {
+ private String prefix;
+
private int protocolType;
private boolean hbm;
private boolean includeAdc;
@@ -44,6 +50,10 @@ public class SuntechProtocolDecoder extends BaseProtocolDecoder {
super(protocol);
}
+ public String getPrefix() {
+ return prefix;
+ }
+
public void setProtocolType(int protocolType) {
this.protocolType = protocolType;
}
@@ -268,7 +278,7 @@ public class SuntechProtocolDecoder extends BaseProtocolDecoder {
position.setDeviceId(deviceSession.getDeviceId());
position.set(Position.KEY_TYPE, type);
- if (protocol.equals("ST300") || protocol.equals("ST500") || protocol.equals("ST600")) {
+ if (protocol.startsWith("ST3") || protocol.equals("ST500") || protocol.equals("ST600")) {
index += 1; // model
}
@@ -300,7 +310,7 @@ public class SuntechProtocolDecoder extends BaseProtocolDecoder {
position.set(Position.KEY_POWER, Double.parseDouble(values[index++]));
String io = values[index++];
- if (io.length() == 6) {
+ if (io.length() >= 6) {
position.set(Position.KEY_IGNITION, io.charAt(0) == '1');
position.set(Position.PREFIX_IN + 1, io.charAt(1) == '1');
position.set(Position.PREFIX_IN + 2, io.charAt(2) == '1');
@@ -501,20 +511,138 @@ public class SuntechProtocolDecoder extends BaseProtocolDecoder {
return position;
}
+ private Position decodeBinary(
+ Channel channel, SocketAddress remoteAddress, ByteBuf buf) {
+
+ int type = buf.readUnsignedByte();
+ buf.readUnsignedShort(); // length
+
+ DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, ByteBufUtil.hexDump(buf.readSlice(5)));
+ if (deviceSession == null) {
+ return null;
+ }
+
+ Position position = new Position(getProtocolName());
+ position.setDeviceId(deviceSession.getDeviceId());
+
+ int mask = buf.readUnsignedMedium();
+
+ if (BitUtil.check(mask, 1)) {
+ buf.readUnsignedByte(); // model
+ }
+
+ if (BitUtil.check(mask, 2)) {
+ position.set(Position.KEY_VERSION_FW, String.format("%d.%d.%d",
+ buf.readUnsignedByte(), buf.readUnsignedByte(), buf.readUnsignedByte()));
+ }
+
+ if (BitUtil.check(mask, 3) && buf.readUnsignedByte() == 0) {
+ position.set(Position.KEY_ARCHIVE, true);
+ }
+
+ if (BitUtil.check(mask, 4) && BitUtil.check(mask, 5)) {
+ position.setTime(new DateBuilder()
+ .setDate(buf.readUnsignedByte(), buf.readUnsignedByte(), buf.readUnsignedByte())
+ .setTime(buf.readUnsignedByte(), buf.readUnsignedByte(), buf.readUnsignedByte())
+ .getDate());
+ }
+
+ if (BitUtil.check(mask, 6)) {
+ buf.readUnsignedInt(); // cell
+ }
+
+ if (BitUtil.check(mask, 7)) {
+ buf.readUnsignedShort(); // mcc
+ }
+
+ if (BitUtil.check(mask, 8)) {
+ buf.readUnsignedShort(); // mnc
+ }
+
+ if (BitUtil.check(mask, 9)) {
+ buf.readUnsignedShort(); // lac
+ }
+
+ if (BitUtil.check(mask, 10)) {
+ position.set(Position.KEY_RSSI, buf.readUnsignedByte());
+ }
+
+ if (BitUtil.check(mask, 11)) {
+ long value = buf.readUnsignedInt();
+ if (BitUtil.check(value, 31)) {
+ value = -BitUtil.to(value, 31);
+ }
+ position.setLatitude(value / 1000000.0);
+ }
+
+ if (BitUtil.check(mask, 12)) {
+ long value = buf.readUnsignedInt();
+ if (BitUtil.check(value, 31)) {
+ value = -BitUtil.to(value, 31);
+ }
+ position.setLongitude(value / 1000000.0);
+ }
+
+ if (BitUtil.check(mask, 13)) {
+ position.setSpeed(UnitsConverter.knotsFromKph(buf.readUnsignedShort() / 100.0));
+ }
+
+ if (BitUtil.check(mask, 14)) {
+ position.setCourse(buf.readUnsignedShort() / 100.0);
+ }
+
+ if (BitUtil.check(mask, 15)) {
+ position.set(Position.KEY_SATELLITES, buf.readUnsignedByte());
+ }
+
+ if (BitUtil.check(mask, 16)) {
+ position.setValid(buf.readUnsignedByte() > 0);
+ }
+
+ if (BitUtil.check(mask, 17)) {
+ int input = buf.readUnsignedByte();
+ position.set(Position.KEY_IGNITION, BitUtil.check(input, 0));
+ position.set(Position.KEY_INPUT, input);
+ }
+
+ if (BitUtil.check(mask, 18)) {
+ position.set(Position.KEY_OUTPUT, buf.readUnsignedByte());
+ }
+
+ if (BitUtil.check(mask, 19)) {
+ int value = buf.readUnsignedByte();
+ if (type == 0x82) {
+ position.set(Position.KEY_ALARM, decodeAlert(value));
+ }
+ }
+
+ return position;
+ }
+
@Override
protected Object decode(
Channel channel, SocketAddress remoteAddress, Object msg) throws Exception {
- String[] values = ((String) msg).split(";");
+ ByteBuf buf = (ByteBuf) msg;
+
+ if (buf.getByte(buf.readerIndex()) == (byte) 0x81) {
+
+ return decodeBinary(channel, remoteAddress, buf);
- if (values[0].length() < 5) {
- return decodeUniversal(channel, remoteAddress, values);
- } else if (values[0].startsWith("ST9")) {
- return decode9(channel, remoteAddress, values);
- } else if (values[0].startsWith("ST4")) {
- return decode4(channel, remoteAddress, values);
} else {
- return decode2356(channel, remoteAddress, values[0].substring(0, 5), values);
+
+ String[] values = buf.toString(StandardCharsets.US_ASCII).split(";");
+ prefix = values[0];
+
+ if (prefix.length() < 5) {
+ return decodeUniversal(channel, remoteAddress, values);
+ } else if (prefix.startsWith("ST9")) {
+ return decode9(channel, remoteAddress, values);
+ } else if (prefix.startsWith("ST4")) {
+ return decode4(channel, remoteAddress, values);
+ } else {
+ return decode2356(channel, remoteAddress, prefix.substring(0, 5), values);
+ }
}
}
diff --git a/src/main/java/org/traccar/protocol/SuntechProtocolEncoder.java b/src/main/java/org/traccar/protocol/SuntechProtocolEncoder.java
index 6dae42ad5..3b4995110 100644
--- a/src/main/java/org/traccar/protocol/SuntechProtocolEncoder.java
+++ b/src/main/java/org/traccar/protocol/SuntechProtocolEncoder.java
@@ -15,6 +15,8 @@
*/
package org.traccar.protocol;
+import io.netty.channel.Channel;
+import org.traccar.BasePipelineFactory;
import org.traccar.StringProtocolEncoder;
import org.traccar.model.Command;
import org.traccar.Protocol;
@@ -25,32 +27,49 @@ public class SuntechProtocolEncoder extends StringProtocolEncoder {
super(protocol);
}
+ private String getPrefix(Channel channel) {
+ String prefix = "SA200CMD";
+ if (channel != null) {
+ SuntechProtocolDecoder protocolDecoder =
+ BasePipelineFactory.getHandler(channel.pipeline(), SuntechProtocolDecoder.class);
+ if (protocolDecoder != null) {
+ String decoderPrefix = protocolDecoder.getPrefix();
+ if (decoderPrefix != null && decoderPrefix.length() > 5) {
+ prefix = decoderPrefix.substring(0, decoderPrefix.length() - 3) + "CMD";
+ }
+ }
+ }
+ return prefix;
+ }
+
@Override
- protected Object encodeCommand(Command command) {
+ protected Object encodeCommand(Channel channel, Command command) {
+
+ String prefix = getPrefix(channel);
switch (command.getType()) {
case Command.TYPE_REBOOT_DEVICE:
- return formatCommand(command, "SA200CMD;{%s};02;Reboot\r", Command.KEY_UNIQUE_ID);
+ return formatCommand(command, prefix + ";%s;02;Reboot\r", Command.KEY_UNIQUE_ID);
case Command.TYPE_POSITION_SINGLE:
- return formatCommand(command, "SA200GTR;{%s};02;\r", Command.KEY_UNIQUE_ID);
+ return formatCommand(command, prefix + ";%s;02;\r", Command.KEY_UNIQUE_ID);
case Command.TYPE_OUTPUT_CONTROL:
if (command.getAttributes().containsKey(Command.KEY_DATA)) {
if (command.getAttributes().get(Command.KEY_DATA).equals("1")) {
- return formatCommand(command, "SA200CMD;{%s};02;Enable{%s}\r",
+ return formatCommand(command, prefix + ";%s;02;Enable%s\r",
Command.KEY_UNIQUE_ID, Command.KEY_INDEX);
} else {
- return formatCommand(command, "SA200CMD;{%s};02;Disable{%s}\r",
+ return formatCommand(command, prefix + ";%s;02;Disable%s\r",
Command.KEY_UNIQUE_ID, Command.KEY_INDEX);
}
}
case Command.TYPE_ENGINE_STOP:
- return formatCommand(command, "SA200CMD;{%s};02;Enable1\r", Command.KEY_UNIQUE_ID);
+ return formatCommand(command, prefix + ";%s;02;Enable1\r", Command.KEY_UNIQUE_ID);
case Command.TYPE_ENGINE_RESUME:
- return formatCommand(command, "SA200CMD;{%s};02;Disable1\r", Command.KEY_UNIQUE_ID);
+ return formatCommand(command, prefix + ";%s;02;Disable1\r", Command.KEY_UNIQUE_ID);
case Command.TYPE_ALARM_ARM:
- return formatCommand(command, "SA200CMD;{%s};02;Enable2\r", Command.KEY_UNIQUE_ID);
+ return formatCommand(command, prefix + ";%s;02;Enable2\r", Command.KEY_UNIQUE_ID);
case Command.TYPE_ALARM_DISARM:
- return formatCommand(command, "SA200CMD;{%s};02;Disable2\r", Command.KEY_UNIQUE_ID);
+ return formatCommand(command, prefix + ";%s;02;Disable2\r", Command.KEY_UNIQUE_ID);
default:
return null;
}
diff --git a/src/main/java/org/traccar/protocol/SviasProtocolEncoder.java b/src/main/java/org/traccar/protocol/SviasProtocolEncoder.java
index 2607d7bd1..d218f63ce 100644
--- a/src/main/java/org/traccar/protocol/SviasProtocolEncoder.java
+++ b/src/main/java/org/traccar/protocol/SviasProtocolEncoder.java
@@ -30,11 +30,11 @@ public class SviasProtocolEncoder extends StringProtocolEncoder {
protected Object encodeCommand(Command command) {
switch (command.getType()) {
case Command.TYPE_CUSTOM:
- return formatCommand(command, "{%s}", Command.KEY_DATA);
+ return formatCommand(command, "%s", Command.KEY_DATA);
case Command.TYPE_POSITION_SINGLE:
return formatCommand(command, "AT+STR=1*");
case Command.TYPE_SET_ODOMETER:
- return formatCommand(command, "AT+ODT={%s}*", Command.KEY_DATA);
+ return formatCommand(command, "AT+ODT=%s*", Command.KEY_DATA);
case Command.TYPE_ENGINE_STOP:
return formatCommand(command, "AT+OUT=1,1*");
case Command.TYPE_ENGINE_RESUME:
diff --git a/src/main/java/org/traccar/protocol/TeltonikaProtocolDecoder.java b/src/main/java/org/traccar/protocol/TeltonikaProtocolDecoder.java
index c634d2438..cc2868a20 100644
--- a/src/main/java/org/traccar/protocol/TeltonikaProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/TeltonikaProtocolDecoder.java
@@ -200,6 +200,9 @@ public class TeltonikaProtocolDecoder extends BaseProtocolDecoder {
case 9:
position.set(Position.PREFIX_ADC + 1, readValue(buf, length, false));
break;
+ case 10:
+ position.set(Position.PREFIX_ADC + 2, readValue(buf, length, false));
+ break;
case 17:
position.set("axisX", readValue(buf, length, true));
break;
diff --git a/src/main/java/org/traccar/protocol/Tk103ProtocolEncoder.java b/src/main/java/org/traccar/protocol/Tk103ProtocolEncoder.java
index a8aa84105..5d7e63920 100644
--- a/src/main/java/org/traccar/protocol/Tk103ProtocolEncoder.java
+++ b/src/main/java/org/traccar/protocol/Tk103ProtocolEncoder.java
@@ -50,7 +50,7 @@ public class Tk103ProtocolEncoder extends StringProtocolEncoder {
if (alternative) {
switch (command.getType()) {
case Command.TYPE_CUSTOM:
- return formatAlt(command, "{%s}", Command.KEY_DATA);
+ return formatAlt(command, "%s", Command.KEY_DATA);
case Command.TYPE_GET_VERSION:
return formatAlt(command, "*about*");
case Command.TYPE_POWER_OFF:
@@ -74,36 +74,36 @@ public class Tk103ProtocolEncoder extends StringProtocolEncoder {
case Command.TYPE_ALARM_SOS:
return formatAlt(command, command.getBoolean(Command.KEY_ENABLE) ? "*soson*" : "*sosoff*");
case Command.TYPE_SET_CONNECTION:
- return formatAlt(command, "*setip*%s*{%s}*",
- command.getString(Command.KEY_SERVER).replace(".", "*"), Command.KEY_PORT);
+ String server = command.getString(Command.KEY_SERVER).replace(".", "*");
+ return formatAlt(command, "*setip*" + server + "*%s*", Command.KEY_PORT);
case Command.TYPE_SOS_NUMBER:
- return formatAlt(command, "*master*{%s}*{%s}*", Command.KEY_DEVICE_PASSWORD, Command.KEY_PHONE);
+ return formatAlt(command, "*master*%s*%s*", Command.KEY_DEVICE_PASSWORD, Command.KEY_PHONE);
default:
return null;
}
} else {
switch (command.getType()) {
case Command.TYPE_CUSTOM:
- return formatCommand(command, "({%s}{%s})", Command.KEY_UNIQUE_ID, Command.KEY_DATA);
+ return formatCommand(command, "(%s%s)", Command.KEY_UNIQUE_ID, Command.KEY_DATA);
case Command.TYPE_GET_VERSION:
- return formatCommand(command, "({%s}AP07)", Command.KEY_UNIQUE_ID);
+ return formatCommand(command, "(%sAP07)", Command.KEY_UNIQUE_ID);
case Command.TYPE_REBOOT_DEVICE:
- return formatCommand(command, "({%s}AT00)", Command.KEY_UNIQUE_ID);
+ return formatCommand(command, "(%sAT00)", Command.KEY_UNIQUE_ID);
case Command.TYPE_SET_ODOMETER:
- return formatCommand(command, "({%s}AX01)", Command.KEY_UNIQUE_ID);
+ return formatCommand(command, "(%sAX01)", Command.KEY_UNIQUE_ID);
case Command.TYPE_POSITION_SINGLE:
- return formatCommand(command, "({%s}AP00)", Command.KEY_UNIQUE_ID);
+ return formatCommand(command, "(%sAP00)", Command.KEY_UNIQUE_ID);
case Command.TYPE_POSITION_PERIODIC:
- return formatCommand(command, "({%s}AR00%s0000)", Command.KEY_UNIQUE_ID,
- String.format("%04X", command.getInteger(Command.KEY_FREQUENCY)));
+ String frequency = String.format("%04X", command.getInteger(Command.KEY_FREQUENCY));
+ return formatCommand(command, "(%sAR00" + frequency + "0000)", Command.KEY_UNIQUE_ID);
case Command.TYPE_POSITION_STOP:
- return formatCommand(command, "({%s}AR0000000000)", Command.KEY_UNIQUE_ID);
+ return formatCommand(command, "(%sAR0000000000)", Command.KEY_UNIQUE_ID);
case Command.TYPE_ENGINE_STOP:
- return formatCommand(command, "({%s}AV010)", Command.KEY_UNIQUE_ID);
+ return formatCommand(command, "(%sAV010)", Command.KEY_UNIQUE_ID);
case Command.TYPE_ENGINE_RESUME:
- return formatCommand(command, "({%s}AV011)", Command.KEY_UNIQUE_ID);
+ return formatCommand(command, "(%sAV011)", Command.KEY_UNIQUE_ID);
case Command.TYPE_OUTPUT_CONTROL:
- return formatCommand(command, "({%s}AV00{%s})", Command.KEY_UNIQUE_ID, Command.KEY_DATA);
+ return formatCommand(command, "(%sAV00%s)", Command.KEY_UNIQUE_ID, Command.KEY_DATA);
default:
return null;
}
diff --git a/src/main/java/org/traccar/protocol/TopinProtocol.java b/src/main/java/org/traccar/protocol/TopinProtocol.java
new file mode 100644
index 000000000..844dd7518
--- /dev/null
+++ b/src/main/java/org/traccar/protocol/TopinProtocol.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2019 Anton Tananaev (anton@traccar.org)
+ *
+ * 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.BaseProtocol;
+import org.traccar.PipelineBuilder;
+import org.traccar.TrackerServer;
+
+public class TopinProtocol extends BaseProtocol {
+
+ public TopinProtocol() {
+ addServer(new TrackerServer(false, getName()) {
+ @Override
+ protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ pipeline.addLast(new TopinProtocolDecoder(TopinProtocol.this));
+ }
+ });
+ }
+
+}
diff --git a/src/main/java/org/traccar/protocol/TopinProtocolDecoder.java b/src/main/java/org/traccar/protocol/TopinProtocolDecoder.java
new file mode 100644
index 000000000..ea72b7cb8
--- /dev/null
+++ b/src/main/java/org/traccar/protocol/TopinProtocolDecoder.java
@@ -0,0 +1,172 @@
+/*
+ * Copyright 2019 Anton Tananaev (anton@traccar.org)
+ *
+ * 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 io.netty.buffer.ByteBuf;
+import io.netty.buffer.ByteBufUtil;
+import io.netty.buffer.Unpooled;
+import io.netty.channel.Channel;
+import org.traccar.BaseProtocolDecoder;
+import org.traccar.DeviceSession;
+import org.traccar.NetworkMessage;
+import org.traccar.Protocol;
+import org.traccar.model.CellTower;
+import org.traccar.model.Network;
+import org.traccar.model.Position;
+import org.traccar.model.WifiAccessPoint;
+
+import java.net.SocketAddress;
+import java.util.TimeZone;
+
+public class TopinProtocolDecoder extends BaseProtocolDecoder {
+
+ public TopinProtocolDecoder(Protocol protocol) {
+ super(protocol);
+ }
+
+ public static final int MSG_LOGIN = 0x01;
+ public static final int MSG_GPS = 0x10;
+ public static final int MSG_GPS_OFFLINE = 0x11;
+ public static final int MSG_STATUS = 0x13;
+ public static final int MSG_WIFI_OFFLINE = 0x17;
+ public static final int MSG_WIFI = 0x69;
+
+ private void sendResponse(Channel channel, int type, ByteBuf content) {
+ if (channel != null) {
+ ByteBuf response = Unpooled.buffer();
+ response.writeShort(0x7878);
+ response.writeByte(1 + content.readableBytes());
+ response.writeByte(type);
+ response.writeBytes(content);
+ response.writeByte('\r');
+ response.writeByte('\n');
+ content.release();
+ channel.writeAndFlush(new NetworkMessage(response, channel.remoteAddress()));
+ }
+ }
+
+ @Override
+ protected Object decode(
+ Channel channel, SocketAddress remoteAddress, Object msg) throws Exception {
+
+ ByteBuf buf = (ByteBuf) msg;
+
+ buf.skipBytes(2); // header
+ int length = buf.readUnsignedByte();
+
+ int type = buf.readUnsignedByte();
+
+ DeviceSession deviceSession;
+ if (type == MSG_LOGIN) {
+ String imei = ByteBufUtil.hexDump(buf.readSlice(8)).substring(1);
+ deviceSession = getDeviceSession(channel, remoteAddress, imei);
+ ByteBuf content = Unpooled.buffer();
+ content.writeByte(deviceSession != null ? 0x01 : 0x44);
+ sendResponse(channel, type, content);
+ return null;
+ } else {
+ deviceSession = getDeviceSession(channel, remoteAddress);
+ if (deviceSession == null) {
+ return null;
+ }
+ }
+
+ if (type == MSG_GPS || type == MSG_GPS_OFFLINE) {
+
+ Position position = new Position(getProtocolName());
+ position.setDeviceId(deviceSession.getDeviceId());
+
+ ByteBuf time = buf.slice(buf.readerIndex(), 6);
+
+ Gt06ProtocolDecoder.decodeGps(position, buf, false, TimeZone.getTimeZone("UTC"));
+
+ ByteBuf content = Unpooled.buffer();
+ content.writeBytes(time);
+ sendResponse(channel, type, content);
+
+ return position;
+
+ } else if (type == MSG_STATUS) {
+
+ Position position = new Position(getProtocolName());
+ position.setDeviceId(deviceSession.getDeviceId());
+
+ getLastLocation(position, null);
+
+ int battery = buf.readUnsignedByte();
+ int firmware = buf.readUnsignedByte();
+ int timezone = buf.readUnsignedByte();
+ int interval = buf.readUnsignedByte();
+ int signal = 0;
+ if (length >= 7) {
+ signal = buf.readUnsignedByte();
+ position.set(Position.KEY_RSSI, signal);
+ }
+
+ position.set(Position.KEY_BATTERY_LEVEL, battery);
+ position.set(Position.KEY_VERSION_FW, firmware);
+
+ ByteBuf content = Unpooled.buffer();
+ content.writeByte(battery);
+ content.writeByte(firmware);
+ content.writeByte(timezone);
+ content.writeByte(interval);
+ if (length >= 7) {
+ content.writeByte(signal);
+ }
+ sendResponse(channel, type, content);
+
+ return position;
+
+ } else if (type == MSG_WIFI || type == MSG_WIFI_OFFLINE) {
+
+ Position position = new Position(getProtocolName());
+ position.setDeviceId(deviceSession.getDeviceId());
+
+ getLastLocation(position, null);
+
+ ByteBuf time = buf.readSlice(6);
+
+ Network network = new Network();
+ for (int i = 0; i < length; i++) {
+ String mac = String.format("%02x:%02x:%02x:%02x:%02x:%02x",
+ buf.readUnsignedByte(), buf.readUnsignedByte(), buf.readUnsignedByte(),
+ buf.readUnsignedByte(), buf.readUnsignedByte(), buf.readUnsignedByte());
+ network.addWifiAccessPoint(WifiAccessPoint.from(mac, buf.readUnsignedByte()));
+ }
+
+ int cellCount = buf.readUnsignedByte();
+ int mcc = buf.readUnsignedShort();
+ int mnc = buf.readUnsignedByte();
+ for (int i = 0; i < cellCount; i++) {
+ network.addCellTower(CellTower.from(
+ mcc, mnc, buf.readUnsignedShort(), buf.readUnsignedShort(), buf.readUnsignedByte()));
+ }
+
+ position.setNetwork(network);
+
+ ByteBuf content = Unpooled.buffer();
+ content.writeBytes(time);
+ sendResponse(channel, type, content);
+
+ return position;
+
+ }
+
+ return null;
+ }
+
+}
diff --git a/src/main/java/org/traccar/protocol/TotemProtocolEncoder.java b/src/main/java/org/traccar/protocol/TotemProtocolEncoder.java
index 3bbb92031..a96dd1ee3 100644
--- a/src/main/java/org/traccar/protocol/TotemProtocolEncoder.java
+++ b/src/main/java/org/traccar/protocol/TotemProtocolEncoder.java
@@ -34,9 +34,9 @@ public class TotemProtocolEncoder extends StringProtocolEncoder {
switch (command.getType()) {
// Assuming PIN 8 (Output C) is the power wire, like manual says but it can be PIN 5,7,8
case Command.TYPE_ENGINE_STOP:
- return formatCommand(command, "*{%s},025,C,1#", Command.KEY_DEVICE_PASSWORD);
+ return formatCommand(command, "*%s,025,C,1#", Command.KEY_DEVICE_PASSWORD);
case Command.TYPE_ENGINE_RESUME:
- return formatCommand(command, "*{%s},025,C,0#", Command.KEY_DEVICE_PASSWORD);
+ return formatCommand(command, "*%s,025,C,0#", Command.KEY_DEVICE_PASSWORD);
default:
return null;
}
diff --git a/src/main/java/org/traccar/protocol/UproProtocolDecoder.java b/src/main/java/org/traccar/protocol/UproProtocolDecoder.java
index 873b22006..a17003fc8 100644
--- a/src/main/java/org/traccar/protocol/UproProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/UproProtocolDecoder.java
@@ -171,12 +171,31 @@ public class UproProtocolDecoder extends BaseProtocolDecoder {
position.setAltitude(
Integer.parseInt(data.readSlice(6).toString(StandardCharsets.US_ASCII)) * 0.1);
break;
+ case 'J':
+ if (data.readableBytes() == 6) {
+ char index = (char) data.readUnsignedByte();
+ int status = data.readUnsignedByte();
+ double value = Integer.parseInt(data.readSlice(4).toString(StandardCharsets.US_ASCII)) * 0.1;
+ if (BitUtil.check(status, 0)) {
+ value = -value;
+ }
+ position.set(Position.PREFIX_TEMP + index, value);
+ }
+ break;
case 'K':
position.set("statusExtended", data.toString(StandardCharsets.US_ASCII));
break;
case 'M':
- position.set(Position.KEY_BATTERY_LEVEL,
- Integer.parseInt(data.readSlice(3).toString(StandardCharsets.US_ASCII)) * 0.1);
+ if (data.readableBytes() == 3) {
+ position.set(Position.KEY_BATTERY_LEVEL,
+ Integer.parseInt(data.readSlice(3).toString(StandardCharsets.US_ASCII)) * 0.1);
+ } else if (data.readableBytes() == 4) {
+ char index = (char) data.readUnsignedByte();
+ data.readUnsignedByte(); // status
+ position.set(
+ "humidity" + index,
+ Integer.parseInt(data.readSlice(2).toString(StandardCharsets.US_ASCII)));
+ }
break;
case 'N':
position.set(Position.KEY_RSSI,
diff --git a/src/main/java/org/traccar/protocol/WatchProtocolEncoder.java b/src/main/java/org/traccar/protocol/WatchProtocolEncoder.java
index b433dfd2a..f285267ba 100644
--- a/src/main/java/org/traccar/protocol/WatchProtocolEncoder.java
+++ b/src/main/java/org/traccar/protocol/WatchProtocolEncoder.java
@@ -137,33 +137,33 @@ public class WatchProtocolEncoder extends StringProtocolEncoder implements Strin
case Command.TYPE_POSITION_SINGLE:
return formatTextCommand(channel, command, "RG");
case Command.TYPE_SOS_NUMBER:
- return formatTextCommand(channel, command, "SOS{%s},{%s}", Command.KEY_INDEX, Command.KEY_PHONE);
+ return formatTextCommand(channel, command, "SOS%s,%s", Command.KEY_INDEX, Command.KEY_PHONE);
case Command.TYPE_ALARM_SOS:
- return formatTextCommand(channel, command, "SOSSMS,{%s}", Command.KEY_ENABLE);
+ return formatTextCommand(channel, command, "SOSSMS,%s", Command.KEY_ENABLE);
case Command.TYPE_ALARM_BATTERY:
- return formatTextCommand(channel, command, "LOWBAT,{%s}", Command.KEY_ENABLE);
+ return formatTextCommand(channel, command, "LOWBAT,%s", Command.KEY_ENABLE);
case Command.TYPE_REBOOT_DEVICE:
return formatTextCommand(channel, command, "RESET");
case Command.TYPE_POWER_OFF:
return formatTextCommand(channel, command, "POWEROFF");
case Command.TYPE_ALARM_REMOVE:
- return formatTextCommand(channel, command, "REMOVE,{%s}", Command.KEY_ENABLE);
+ return formatTextCommand(channel, command, "REMOVE,%s", Command.KEY_ENABLE);
case Command.TYPE_SILENCE_TIME:
- return formatTextCommand(channel, command, "SILENCETIME,{%s}", Command.KEY_DATA);
+ return formatTextCommand(channel, command, "SILENCETIME,%s", Command.KEY_DATA);
case Command.TYPE_ALARM_CLOCK:
- return formatTextCommand(channel, command, "REMIND,{%s}", Command.KEY_DATA);
+ return formatTextCommand(channel, command, "REMIND,%s", Command.KEY_DATA);
case Command.TYPE_SET_PHONEBOOK:
- return formatTextCommand(channel, command, "PHB,{%s}", Command.KEY_DATA);
+ return formatTextCommand(channel, command, "PHB,%s", Command.KEY_DATA);
case Command.TYPE_MESSAGE:
- return formatTextCommand(channel, command, "MESSAGE,{%s}", Command.KEY_MESSAGE);
+ return formatTextCommand(channel, command, "MESSAGE,%s", Command.KEY_MESSAGE);
case Command.TYPE_VOICE_MESSAGE:
return formatBinaryCommand(channel, command, "TK,", getBinaryData(command));
case Command.TYPE_POSITION_PERIODIC:
- return formatTextCommand(channel, command, "UPLOAD,{%s}", Command.KEY_FREQUENCY);
+ return formatTextCommand(channel, command, "UPLOAD,%s", Command.KEY_FREQUENCY);
case Command.TYPE_SET_TIMEZONE:
- return formatTextCommand(channel, command, "LZ,,{%s}", Command.KEY_TIMEZONE);
+ return formatTextCommand(channel, command, "LZ,%s,%s", Command.KEY_LANGUAGE, Command.KEY_TIMEZONE);
case Command.TYPE_SET_INDICATOR:
- return formatTextCommand(channel, command, "FLOWER,{%s}", Command.KEY_DATA);
+ return formatTextCommand(channel, command, "FLOWER,%s", Command.KEY_DATA);
default:
return null;
}
diff --git a/src/main/java/org/traccar/protocol/WialonProtocolEncoder.java b/src/main/java/org/traccar/protocol/WialonProtocolEncoder.java
index c45edf00d..93086bf8a 100644
--- a/src/main/java/org/traccar/protocol/WialonProtocolEncoder.java
+++ b/src/main/java/org/traccar/protocol/WialonProtocolEncoder.java
@@ -32,11 +32,11 @@ public class WialonProtocolEncoder extends StringProtocolEncoder {
case Command.TYPE_REBOOT_DEVICE:
return formatCommand(command, "reboot\r\n");
case Command.TYPE_SEND_USSD:
- return formatCommand(command, "USSD:{%s}\r\n", Command.KEY_PHONE);
+ return formatCommand(command, "USSD:%s\r\n", Command.KEY_PHONE);
case Command.TYPE_IDENTIFICATION:
return formatCommand(command, "VER?\r\n");
case Command.TYPE_OUTPUT_CONTROL:
- return formatCommand(command, "L{%s}={%s}\r\n", Command.KEY_INDEX, Command.KEY_DATA);
+ return formatCommand(command, "L%s=%s\r\n", Command.KEY_INDEX, Command.KEY_DATA);
default:
return null;
}
diff --git a/src/main/java/org/traccar/protocol/WondexProtocolEncoder.java b/src/main/java/org/traccar/protocol/WondexProtocolEncoder.java
index e9bb23d15..21f1ee321 100644
--- a/src/main/java/org/traccar/protocol/WondexProtocolEncoder.java
+++ b/src/main/java/org/traccar/protocol/WondexProtocolEncoder.java
@@ -32,17 +32,17 @@ public class WondexProtocolEncoder extends StringProtocolEncoder {
switch (command.getType()) {
case Command.TYPE_REBOOT_DEVICE:
- return formatCommand(command, "$WP+REBOOT={%s}", Command.KEY_DEVICE_PASSWORD);
+ return formatCommand(command, "$WP+REBOOT=%s", Command.KEY_DEVICE_PASSWORD);
case Command.TYPE_GET_DEVICE_STATUS:
- return formatCommand(command, "$WP+TEST={%s}", Command.KEY_DEVICE_PASSWORD);
+ return formatCommand(command, "$WP+TEST=%s", Command.KEY_DEVICE_PASSWORD);
case Command.TYPE_GET_MODEM_STATUS:
- return formatCommand(command, "$WP+GSMINFO={%s}", Command.KEY_DEVICE_PASSWORD);
+ return formatCommand(command, "$WP+GSMINFO=%s", Command.KEY_DEVICE_PASSWORD);
case Command.TYPE_IDENTIFICATION:
- return formatCommand(command, "$WP+IMEI={%s}", Command.KEY_DEVICE_PASSWORD);
+ return formatCommand(command, "$WP+IMEI=%s", Command.KEY_DEVICE_PASSWORD);
case Command.TYPE_POSITION_SINGLE:
- return formatCommand(command, "$WP+GETLOCATION={%s}", Command.KEY_DEVICE_PASSWORD);
+ return formatCommand(command, "$WP+GETLOCATION=%s", Command.KEY_DEVICE_PASSWORD);
case Command.TYPE_GET_VERSION:
- return formatCommand(command, "$WP+VER={%s}", Command.KEY_DEVICE_PASSWORD);
+ return formatCommand(command, "$WP+VER=%s", Command.KEY_DEVICE_PASSWORD);
default:
return null;
}
diff --git a/src/main/java/org/traccar/protocol/XexunProtocolEncoder.java b/src/main/java/org/traccar/protocol/XexunProtocolEncoder.java
index fc849fe15..4f2707c2a 100644
--- a/src/main/java/org/traccar/protocol/XexunProtocolEncoder.java
+++ b/src/main/java/org/traccar/protocol/XexunProtocolEncoder.java
@@ -32,9 +32,9 @@ public class XexunProtocolEncoder extends StringProtocolEncoder {
switch (command.getType()) {
case Command.TYPE_ENGINE_STOP:
- return formatCommand(command, "powercar{%s} 11", Command.KEY_DEVICE_PASSWORD);
+ return formatCommand(command, "powercar%s 11", Command.KEY_DEVICE_PASSWORD);
case Command.TYPE_ENGINE_RESUME:
- return formatCommand(command, "powercar{%s} 00", Command.KEY_DEVICE_PASSWORD);
+ return formatCommand(command, "powercar%s 00", Command.KEY_DEVICE_PASSWORD);
default:
return null;
}