aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/org/traccar/protocol/Tk103Protocol.java25
-rw-r--r--src/org/traccar/protocol/Tk103ProtocolDecoder.java137
-rw-r--r--src/org/traccar/protocol/Tk103ProtocolEncoder.java119
3 files changed, 122 insertions, 159 deletions
diff --git a/src/org/traccar/protocol/Tk103Protocol.java b/src/org/traccar/protocol/Tk103Protocol.java
index b205e75f1..3360dab32 100644
--- a/src/org/traccar/protocol/Tk103Protocol.java
+++ b/src/org/traccar/protocol/Tk103Protocol.java
@@ -33,6 +33,14 @@ public class Tk103Protocol extends BaseProtocol {
public Tk103Protocol() {
super("tk103");
setSupportedDataCommands(
+ Command.TYPE_CUSTOM,
+ Command.TYPE_GET_DEVICE_STATUS,
+ Command.TYPE_IDENTIFICATION,
+ Command.TYPE_MODE_DEEP_SLEEP,
+ Command.TYPE_MODE_POWER_SAVING,
+ Command.TYPE_ALARM_SOS,
+ Command.TYPE_SET_CONNECTION,
+ Command.TYPE_SOS_NUMBER,
Command.TYPE_POSITION_SINGLE,
Command.TYPE_POSITION_PERIODIC,
Command.TYPE_POSITION_STOP,
@@ -40,22 +48,7 @@ public class Tk103Protocol extends BaseProtocol {
Command.TYPE_REBOOT_DEVICE,
Command.TYPE_SET_ODOMETER,
Command.TYPE_ENGINE_STOP,
- Command.TYPE_ENGINE_RESUME,
- //T580W commands:
- "T580W_positionSingle",
- "T580W_positionRealtime",
- "T580W_positionRealtimeStop",
- "T580W_modeDeepSleepInterval1Hour",
- "T580W_modeDeepSleepInterval2Hour",
- "T580W_modeDeepSleepInterval3Hour",
- "T580W_modeDeepSleepInterval4Hour",
- "T580W_modeDeepSleepMotion",
- "T580W_modeDeepSleepOff",
- "T580W_alarmSosOn",
- "T580W_alarmSosOff",
- "T580W_multiControllerOn",
- "T580W_multiControllerOff",
- "T580W_rebootDevice");
+ Command.TYPE_ENGINE_RESUME);
}
@Override
diff --git a/src/org/traccar/protocol/Tk103ProtocolDecoder.java b/src/org/traccar/protocol/Tk103ProtocolDecoder.java
index e52d60848..2ce7def45 100644
--- a/src/org/traccar/protocol/Tk103ProtocolDecoder.java
+++ b/src/org/traccar/protocol/Tk103ProtocolDecoder.java
@@ -29,8 +29,6 @@ import org.traccar.model.Position;
import org.traccar.model.WifiAccessPoint;
import java.net.SocketAddress;
-import java.util.HashMap;
-import java.util.Map;
import java.util.regex.Pattern;
public class Tk103ProtocolDecoder extends BaseProtocolDecoder {
@@ -67,8 +65,8 @@ public class Tk103ProtocolDecoder extends BaseProtocolDecoder {
.any()
.number("([+-]ddd.d)?") // temperature
.groupBegin()
- .number("([+-]?d+.d{1,2}),").optional() // altitude
- .number("(d+)$").optional() // number of visible satellites
+ .number("([+-]?d+.d{1,2}),") // altitude
+ .number("(d+)$") // number of visible satellites
.groupEnd("?")
.text(")").optional()
.compile();
@@ -102,12 +100,21 @@ public class Tk103ProtocolDecoder extends BaseProtocolDecoder {
.number("(d+),") // lac
.number("(d+),") // cid
.number("(d+),") // number of wifi macs
- .expression("((?:(?:[0-9A-Fa-f]{2}:){5}(?:[0-9A-Fa-f]{2})\\*[-+]?\\d{1,2}\\*\\d{1,2},)*)")
+ .number("((?:(?:xx:){5}(?:xx)\\*[-+]?d+\\*d+,)*)")
.number("(dd)(dd)(dd),") // date (ddmmyy)
.number("(dd)(dd)(dd)") // time (hhmmss)
.any()
.compile();
+ private static final Pattern PATTERN_COMMAND_RESULT = new PatternBuilder()
+ .number("(d+),") // device id
+ .expression(".{4},") // command
+ .number("(dd)(dd)(dd),") // date (ddmmyy)
+ .number("(dd)(dd)(dd),") // time (hhmmss)
+ .expression("\\$([\\s\\S]*?)(?:\\$|$)") // message
+ .any()
+ .compile();
+
private String decodeAlarm(int value) {
switch (value) {
case 1:
@@ -132,90 +139,61 @@ public class Tk103ProtocolDecoder extends BaseProtocolDecoder {
case "BO01":
position.set(Position.KEY_ALARM, decodeAlarm(data.charAt(0) - '0'));
break;
- // Motion Alert with Location
case "ZC11":
case "DW31":
case "DW51":
position.set(Position.KEY_ALARM, Position.ALARM_MOVEMENT);
break;
- // Low Battery Alert with Location
case "ZC12":
case "DW32":
case "DW52":
position.set(Position.KEY_ALARM, Position.ALARM_LOW_BATTERY);
break;
- // Power Cut Alert with Location
case "ZC13":
case "DW33":
case "DW53":
position.set(Position.KEY_ALARM, Position.ALARM_POWER_CUT);
break;
- // ACC On Alert with Location
case "ZC15":
case "DW35":
case "DW55":
position.set(Position.KEY_IGNITION, true);
break;
- // ACC Off Alert with Location
case "ZC16":
case "DW36":
case "DW56":
position.set(Position.KEY_IGNITION, false);
break;
- // Ignition Alert with Location
case "ZC29":
case "DW42":
case "DW62":
position.set(Position.KEY_IGNITION, true);
break;
- // Dismounting Alert with Location
case "ZC17":
case "DW37":
case "DW57":
position.set(Position.KEY_ALARM, Position.ALARM_REMOVING);
break;
- // SOS Alert with Location
case "ZC25":
case "DW3E":
case "DW5E":
position.set(Position.KEY_ALARM, Position.ALARM_SOS);
break;
- // Tampering Alert with Location:
case "ZC26":
case "DW3F":
case "DW5F":
position.set(Position.KEY_ALARM, Position.ALARM_TAMPERING);
break;
- // Low Power Alert with Location
case "ZC27":
case "DW40":
case "DW60":
position.set(Position.KEY_ALARM, Position.ALARM_LOW_POWER);
break;
- // Bad Battery Alert with Location
case "ZC28":
case "DW41":
case "DW61":
position.set(Position.KEY_ALARM, "badBattery");
break;
- // Fuel Cut On with Location
- case "ZC2A":
- case "DW43":
- case "DW63":
- position.set(Position.KEY_FUEL_LEVEL, 0.0);
- break;
- // Fuel Cut Off with Location:
- case "ZC2B":
- case "DW44":
- case "DW64":
- position.set(Position.KEY_FUEL_LEVEL, 1.0);
- break;
- // Fuel Cut Alert with Location:
- case "ZC2C":
- case "DW45":
- case "DW65":
- position.set(Position.KEY_ALARM, "fuelCut");
- break;
default:
break;
}
@@ -228,7 +206,7 @@ public class Tk103ProtocolDecoder extends BaseProtocolDecoder {
case 5:
return 80;
case 4:
- return 60;
+ return 50;
case 3:
return 20;
case 2:
@@ -238,34 +216,6 @@ public class Tk103ProtocolDecoder extends BaseProtocolDecoder {
}
}
- private static Map<Long, Position> batteryInfo = new HashMap<Long, Position>();
-
- public void setLastBatteryPower(Position positionWithCurrentBatteryInfo) {
- batteryInfo.put(positionWithCurrentBatteryInfo.getDeviceId(), positionWithCurrentBatteryInfo);
- }
-
- // It is possible to use "processing.copyAttributes" configuration to have battery level in all events,
- // but this will not work if battery events will be filtered somehow and dropped from DB, so it will be no
- // event in DB with latest battery level. So, ensure all our events have latest battery level.
- public void getLastBatteryPower(Position position) {
- if (position != null && position.getDeviceId() != 0) {
- Position bi = batteryInfo.get(position.getDeviceId());
- if (bi == null) {
- bi = new Position();
- getLastLocation(bi, null);
- }
- if (bi.getAttributes().containsKey(Position.KEY_BATTERY_LEVEL)) {
- position.set(Position.KEY_BATTERY_LEVEL, bi.getDouble(Position.KEY_BATTERY_LEVEL));
- }
- if (bi.getAttributes().containsKey(Position.KEY_BATTERY)) {
- position.set(Position.KEY_BATTERY, bi.getDouble(Position.KEY_BATTERY));
- }
- if (bi.getAttributes().containsKey(Position.KEY_POWER)) {
- position.set(Position.KEY_POWER, bi.getDouble(Position.KEY_POWER));
- }
- }
- }
-
private Position decodeBattery(Channel channel, SocketAddress remoteAddress, String sentence) {
Parser parser = new Parser(PATTERN_BATTERY, sentence);
if (!parser.matches()) {
@@ -298,8 +248,6 @@ public class Tk103ProtocolDecoder extends BaseProtocolDecoder {
position.set(Position.KEY_POWER, power * 0.1);
}
- setLastBatteryPower(position);
-
return position;
}
@@ -320,8 +268,6 @@ public class Tk103ProtocolDecoder extends BaseProtocolDecoder {
getLastLocation(position, null);
- getLastBatteryPower(position);
-
position.setNetwork(new Network(CellTower.from(
parser.nextInt(0), parser.nextInt(0), parser.nextHexInt(0), parser.nextHexInt(0))));
@@ -347,21 +293,16 @@ public class Tk103ProtocolDecoder extends BaseProtocolDecoder {
getLastLocation(position, null);
- getLastBatteryPower(position);
-
Network network = new Network();
- // Parse LBS
network.addCellTower(CellTower.from(
parser.nextInt(), parser.nextInt(), parser.nextInt(), parser.nextInt()));
- // Parse WiFi macs number and mac addresses itself.
int wifiCount = parser.nextInt();
if (parser.hasNext()) {
String[] wifimacs = parser.next().split(",");
if (wifimacs.length == wifiCount) {
for (int i = 0; i < wifiCount; i++) {
- // Sample wifi string: “00:80:E1:7F:86:97*-55*6” (mac*rssi*channel_number)
String[] wifiinfo = wifimacs[i].split("\\*");
network.addWifiAccessPoint(WifiAccessPoint.from(
wifiinfo[0], Integer.parseInt(wifiinfo[1]), Integer.parseInt(wifiinfo[2])));
@@ -373,21 +314,35 @@ public class Tk103ProtocolDecoder extends BaseProtocolDecoder {
position.setNetwork(network);
}
- // Parse date-time
- DateBuilder dateBuilder = new DateBuilder()
- .setDateReverse(parser.nextInt(), parser.nextInt(), parser.nextInt())
- .setTime(parser.nextInt(), parser.nextInt(), parser.nextInt());
- // Set both DeviceTime and FixTime here, as some alarm messages like SOS at device start may be
- // sent without valid LBS/WiFi position, so FixTime from getLastLocation will be used as time
- // for this SOS alarm, which can be very old. And traccar UI only display FixTime.
- // Valid flag will be "false" anyway, so it is possible to check should the position and fixTime
- // be trusted or not.
- position.setTime(dateBuilder.getDate());
+ position.setTime(parser.nextDateTime(Parser.DateTimeFormat.DMY_HMS));
return position;
}
- @Override
+ private Position decodeCommandResult(Channel channel, SocketAddress remoteAddress, String sentence) {
+ Parser parser = new Parser(PATTERN_COMMAND_RESULT, sentence);
+ if (!parser.matches()) {
+ return null;
+ }
+
+ DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next());
+ if (deviceSession == null) {
+ return null;
+ }
+
+ Position position = new Position();
+ position.setProtocol(getProtocolName());
+ position.setDeviceId(deviceSession.getDeviceId());
+
+ getLastLocation(position, parser.nextDateTime(Parser.DateTimeFormat.DMY_HMS));
+
+ position.set(Position.KEY_RESULT, parser.next());
+
+ return position;
+
+ }
+
+@Override
protected Object decode(
Channel channel, SocketAddress remoteAddress, Object msg) throws Exception {
@@ -398,7 +353,7 @@ public class Tk103ProtocolDecoder extends BaseProtocolDecoder {
sentence = sentence.substring(beginIndex + 1);
}
- if (channel != null) {
+ if (channel != null && sentence.length() >= 16) {
String id = sentence.substring(0, 12);
String type = sentence.substring(12, 16);
if (type.equals("BP00")) {
@@ -413,11 +368,10 @@ public class Tk103ProtocolDecoder extends BaseProtocolDecoder {
return decodeBattery(channel, remoteAddress, sentence);
} else if (sentence.contains("BZ00")) {
return decodeNetwork(channel, remoteAddress, sentence);
- }
-
- Position positionWifi = decodeLbsWifi(channel, remoteAddress, sentence);
- if (positionWifi != null) {
- return positionWifi;
+ } else if (sentence.contains("ZC03")) {
+ return decodeCommandResult(channel, remoteAddress, sentence);
+ } else if (sentence.contains("DW5")) {
+ return decodeLbsWifi(channel, remoteAddress, sentence);
}
Parser parser = new Parser(PATTERN, sentence);
@@ -438,8 +392,6 @@ public class Tk103ProtocolDecoder extends BaseProtocolDecoder {
decodeType(position, parser.next(), parser.next());
- getLastBatteryPower(position);
-
DateBuilder dateBuilder = new DateBuilder();
if (alternative) {
dateBuilder.setDateReverse(parser.nextInt(0), parser.nextInt(0), parser.nextInt(0));
@@ -503,8 +455,7 @@ public class Tk103ProtocolDecoder extends BaseProtocolDecoder {
}
if (parser.hasNext()) {
- // Store amount of visible satellites as RSSI
- position.set(Position.KEY_RSSI, parser.nextInt(0));
+ position.set(Position.KEY_SATELLITES_VISIBLE, parser.nextInt(0));
}
return position;
diff --git a/src/org/traccar/protocol/Tk103ProtocolEncoder.java b/src/org/traccar/protocol/Tk103ProtocolEncoder.java
index dc9fc41a1..e43761c7c 100644
--- a/src/org/traccar/protocol/Tk103ProtocolEncoder.java
+++ b/src/org/traccar/protocol/Tk103ProtocolEncoder.java
@@ -16,6 +16,7 @@
*/
package org.traccar.protocol;
+import org.traccar.Context;
import org.traccar.StringProtocolEncoder;
import org.traccar.helper.Log;
import org.traccar.model.Command;
@@ -27,59 +28,77 @@ public class Tk103ProtocolEncoder extends StringProtocolEncoder {
return String.format("[begin]sms2,%s,[end]", content);
}
+ protected String checkEn(Command command, String ifEnabled, String ifDisabled) {
+ return command.getBoolean(Command.KEY_ENABLE) ? ifEnabled : ifDisabled;
+ }
+
@Override
protected Object encodeCommand(Command command) {
- switch (command.getType()) {
- case Command.TYPE_GET_VERSION:
- return formatCommand(command, "({%s}AP07)", Command.KEY_UNIQUE_ID);
- case Command.TYPE_REBOOT_DEVICE:
- return formatCommand(command, "({%s}AT00)", Command.KEY_UNIQUE_ID);
- case Command.TYPE_SET_ODOMETER:
- return formatCommand(command, "({%s}AX01)", Command.KEY_UNIQUE_ID);
- case Command.TYPE_POSITION_SINGLE:
- return formatCommand(command, "({%s}AP00)", 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)));
- case Command.TYPE_POSITION_STOP:
- return formatCommand(command, "({%s}AR0000000000)", Command.KEY_UNIQUE_ID);
- case Command.TYPE_ENGINE_STOP:
- return formatCommand(command, "({%s}AV011)", Command.KEY_UNIQUE_ID);
- case Command.TYPE_ENGINE_RESUME:
- return formatCommand(command, "({%s}AV010)", Command.KEY_UNIQUE_ID);
- //T580W commands:
- case "T580W_positionSingle":
- return t580WFormatCommand(command, "*getposl*");
- case "T580W_positionRealtime":
- return t580WFormatCommand(command, "*routetrack*99*");
- case "T580W_positionRealtimeStop":
- return t580WFormatCommand(command, "*routetrackoff*");
- case "T580W_modeDeepSleepInterval1Hour":
- return t580WFormatCommand(command, "*sleep*1*");
- case "T580W_modeDeepSleepInterval2Hour":
- return t580WFormatCommand(command, "*sleep*2*");
- case "T580W_modeDeepSleepInterval3Hour":
- return t580WFormatCommand(command, "*sleep*3*");
- case "T580W_modeDeepSleepInterval4Hour":
- return t580WFormatCommand(command, "*sleep*4*");
- case "T580W_modeDeepSleepMotion":
- return t580WFormatCommand(command, "*sleepv*");
- case "T580W_modeDeepSleepOff":
- return t580WFormatCommand(command, "*sleepoff*");
- case "T580W_alarmSosOn":
- return t580WFormatCommand(command, "*soson*");
- case "T580W_alarmSosOff":
- return t580WFormatCommand(command, "*sosoff*");
- case "T580W_multiControllerOn":
- return t580WFormatCommand(command, "*multiquery*");
- case "T580W_multiControllerOff":
- return t580WFormatCommand(command, "*multiqueryoff*");
- case "T580W_rebootDevice":
- return t580WFormatCommand(command, "88888888");
- default:
- Log.warning(new UnsupportedOperationException(command.getType()));
- break;
+ boolean deviceT580W = Context.getIdentityManager().lookupAttributeBoolean(
+ command.getDeviceId(), "tk103.deviceT580W", false, true);
+
+ if (deviceT580W) {
+
+ initDevicePassword(command, "123456");
+
+ switch (command.getType()) {
+ case Command.TYPE_CUSTOM:
+ return t580WFormatCommand(command, "{%s}", Command.KEY_DATA);
+ case Command.TYPE_GET_DEVICE_STATUS:
+ return t580WFormatCommand(command, "*status*");
+ case Command.TYPE_GET_VERSION:
+ return t580WFormatCommand(command, "*about*");
+ case Command.TYPE_IDENTIFICATION:
+ return t580WFormatCommand(command, "999999");
+ case Command.TYPE_REBOOT_DEVICE:
+ return t580WFormatCommand(command, "88888888");
+ case Command.TYPE_POSITION_SINGLE:
+ return t580WFormatCommand(command, "*getposl*");
+ case Command.TYPE_POSITION_PERIODIC:
+ return t580WFormatCommand(command, "*routetrack*99*");
+ case Command.TYPE_POSITION_STOP:
+ return t580WFormatCommand(command, "*routetrackoff*");
+ case Command.TYPE_MODE_DEEP_SLEEP:
+ return t580WFormatCommand(command, checkEn(command, "*sleep*2*", "*sleepoff*"));
+ case Command.TYPE_MODE_POWER_SAVING:
+ return t580WFormatCommand(command, checkEn(command, "*sleepv*", "*sleepoff*"));
+ case Command.TYPE_ALARM_SOS:
+ return t580WFormatCommand(command, checkEn(command, "*soson*", "*sosoff*"));
+ case Command.TYPE_SET_CONNECTION:
+ String ipAddress = command.getString(Command.KEY_SERVER);
+ ipAddress = ipAddress.replace(".", "*");
+ return t580WFormatCommand(command, "*setip*%s*{%s}*", ipAddress, Command.KEY_PORT);
+ case Command.TYPE_SOS_NUMBER:
+ return t580WFormatCommand(command, "*master*{%s}*{%s}*",
+ Command.KEY_DEVICE_PASSWORD, Command.KEY_PHONE);
+ default:
+ Log.warning(new UnsupportedOperationException(command.getType()));
+ break;
+ }
+ } else {
+ switch (command.getType()) {
+ case Command.TYPE_GET_VERSION:
+ return formatCommand(command, "({%s}AP07)", Command.KEY_UNIQUE_ID);
+ case Command.TYPE_REBOOT_DEVICE:
+ return formatCommand(command, "({%s}AT00)", Command.KEY_UNIQUE_ID);
+ case Command.TYPE_SET_ODOMETER:
+ return formatCommand(command, "({%s}AX01)", Command.KEY_UNIQUE_ID);
+ case Command.TYPE_POSITION_SINGLE:
+ return formatCommand(command, "({%s}AP00)", 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)));
+ case Command.TYPE_POSITION_STOP:
+ return formatCommand(command, "({%s}AR0000000000)", Command.KEY_UNIQUE_ID);
+ case Command.TYPE_ENGINE_STOP:
+ return formatCommand(command, "({%s}AV011)", Command.KEY_UNIQUE_ID);
+ case Command.TYPE_ENGINE_RESUME:
+ return formatCommand(command, "({%s}AV010)", Command.KEY_UNIQUE_ID);
+ default:
+ Log.warning(new UnsupportedOperationException(command.getType()));
+ break;
+ }
}
return null;