diff options
Diffstat (limited to 'src/org')
-rw-r--r-- | src/org/traccar/protocol/Tk103Protocol.java | 25 | ||||
-rw-r--r-- | src/org/traccar/protocol/Tk103ProtocolDecoder.java | 137 | ||||
-rw-r--r-- | src/org/traccar/protocol/Tk103ProtocolEncoder.java | 119 |
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; |