Hi,
I'm implementing a protocol called Omni, this protocol is very similar to Xrb28, when i send a command everithing works great and the command is received and executed by the device, when the device send a message like "i'm unlocked", it expects an answer, and this response is sendend by protocol decoder. The format of the response is correct, in fact if i send the hex of the string that is printed in the log file from a tool called hercules it works fine, but from the traccar backend with the same string it doesn't work, and the device continue to send the same message in loop.
This is the code of OmniProtocolDecoder:
package org.traccar.protocol;
import io.netty.channel.Channel;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.traccar.BaseProtocolDecoder;
import org.traccar.NetworkMessage;
import org.traccar.Protocol;
import org.traccar.helper.DateBuilder;
import org.traccar.helper.Parser;
import org.traccar.helper.PatternBuilder;
import org.traccar.model.Command;
import org.traccar.model.Position;
import org.traccar.model.PositionExt;
import org.traccar.session.DeviceSession;
import java.time.Instant;
import java.time.format.DateTimeFormatter;
import java.time.LocalDateTime;
import java.net.SocketAddress;
import java.util.regex.Pattern;
public class OmniProtocolDecoder extends BaseProtocolDecoder {
private static final Logger LOGGER = LoggerFactory.getLogger(OmniProtocolDecoder.class);
private String pendingCommand;
public void setPendingCommand(String pendingCommand) {
this.pendingCommand = pendingCommand;
}
public OmniProtocolDecoder(Protocol protocol) {
super(protocol);
}
private static final Pattern PATTERN = new PatternBuilder()
.text("*")
.expression("....,")
.expression("..,") // vendor
.number("d{15},") // imei
.number("(dd)(dd)(dd)(dd)(dd)(dd),") // dateUnix (yyMMddhhmmss)
.expression("..,") // type
.number("[01],") // reserved
.number("(dd)(dd)(dd).d+,") // time (hhmmss)
.expression("([AV]),") // validity
.number("(dd)(dd.d+),") // latitude
.expression("([NS]),")
.number("(d{2,3})(dd.d+),") // longitude
.expression("([EW]),")
.number("(d+),") // satellites
.number("(d+.d+),") // hdop
.number("(dd)(dd)(dd),") // date (ddmmyy)
.number("(-?d+.?d*),") // altitude
.expression(".,") // height unit
.expression(".#") // mode
.compile();
private static final Pattern PATTERNWITHERROR = new PatternBuilder()
.text("*")
.expression("....,")
.expression("..,") // vendor
.number("d{15},") // imei
.number("(dd)(dd)(dd)(dd)(dd)(dd),") // dateUnix (yyMMddhhmmss)
.expression("..,") // type
.number("[01],") // reserved
.number("(dd)(dd)(dd).d+,") // time (hhmmss)
.expression("([AV]),") // validity
.number("(dd)(dd.d+),") // latitude
.expression("([NS]),")
.number("(d{2,3})(dd.d+),") // longitude
.expression("([EW]),")
.number("(d+),") // satellites
.number("(d+.d+),") // hdop
.expression(",") // dateError
.number("(-?d+.?d*),") // altitude
.expression(".,") // height unit
.expression(".#") // mode
.compile();
@Override
protected Object decode(Channel channel, SocketAddress remoteAddress, Object msg) throws Exception {
String sentence = (String) msg;
DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, sentence.substring(9, 24));
if (deviceSession == null) {
return null;
}
String type = sentence.substring(38, 40);
if (channel != null) {
if (type.matches("L0|L1|W0")) {
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyMMddHHmmss");
LocalDateTime now = LocalDateTime.now();
if (type.equals("W0")) {
channel.write(new NetworkMessage(
"\u00ff\u00ff*CMDS" + sentence.substring(5, 25) + dtf.format(now) + sentence.substring(37, 40) + "#\n",
remoteAddress));
} else {
LOGGER.info("\u00ff\u00ff*CMDS" + sentence.substring(5, 25) + dtf.format(now) + ",Re" + sentence.substring(37, 40) + "#\n");
channel.write(new NetworkMessage(
"\u00ff\u00ff*CMDS" + sentence.substring(5, 25) + dtf.format(now) + ",Re" + sentence.substring(37, 40) + "#\n",
remoteAddress));
}
} else if (type.equals("R0") && pendingCommand != null) {
String command = pendingCommand.equals(Command.TYPE_ALARM_ARM) ? "L1," : "L0,";
channel.write(new NetworkMessage(
"\u00ff\u00ff*CMDS" + sentence.substring(5, 25) + command + sentence.substring(30) + "\n",
remoteAddress));
pendingCommand = null;
}
}
if (!type.equals("D0")) {
Position position = new Position(getProtocolName());
position.setDeviceId(deviceSession.getDeviceId());
getLastLocation(position, null);
String payload = sentence.substring(38, sentence.length() - 1);
int index = 0;
String[] values = payload.substring(3).split(",");
switch (type) {
case "Q0":
position.set(Position.KEY_BATTERY, Integer.parseInt(values[index++]) * 0.01);
position.set(Position.KEY_BATTERY_LEVEL, Integer.parseInt(values[index++]));
break;
case "H0":
position.set(Position.KEY_BLOCKED, Integer.parseInt(values[index++]) > 0);
position.set(Position.KEY_BATTERY, Integer.parseInt(values[index++]) * 0.01);
position.set(Position.KEY_RSSI, Integer.parseInt(values[index++]));
position.set(Position.KEY_STATUS, Integer.parseInt(values[index++]));
position.set(Position.KEY_BATTERY_LEVEL, Integer.parseInt(values[index++]));
break;
case "S5":
position.set(Position.KEY_BATTERY, Integer.parseInt(values[index++]) * 0.01);
position.set(Position.KEY_RSSI, Integer.parseInt(values[index++]));
position.set(Position.KEY_SATELLITES, Integer.parseInt(values[index++]));
position.set(Position.KEY_BLOCKED, Integer.parseInt(values[index++]) > 0);
switch (Integer.parseInt(values[index++])) {
case 1:
position.set(Position.KEY_ALARM, Position.ALARM_MOVEMENT);
break;
case 2:
position.set(Position.KEY_ALARM, Position.ALARM_FALL_DOWN);
break;
case 3:
position.set(Position.KEY_ALARM, Position.ALARM_LOW_BATTERY);
break;
default:
break;
}
position.set(Position.KEY_BATTERY_LEVEL, Integer.parseInt(values[index++]));
break;
case "W0":
switch (Integer.parseInt(values[index++])) {
case 1:
position.set(Position.KEY_ALARM, PositionExt.ALARM_CONTROLLER_FAILURE);
break;
case 3:
position.set(Position.KEY_ALARM, PositionExt.ALARM_COMMUNICATION_FAILURE);
break;
case 4:
position.set(Position.KEY_ALARM, PositionExt.ALARM_MOTOR_HALL_FAILURE);
break;
case 6:
position.set(Position.KEY_ALARM, Position.ALARM_LOW_BATTERY);
break;
default:
break;
}
break;
case "E0":
position.set(Position.KEY_ALARM, Position.ALARM_FAULT);
position.set("error", Integer.parseInt(values[index++]));
break;
case "S1":
position.set(Position.KEY_EVENT, Integer.parseInt(values[index++]));
break;
case "D1":
case "R0":
case "L0":
case "L1":
case "S4":
case "S6":
case "S7":
case "V0":
case "G0":
case "K0":
case "I0":
case "M0":
position.set(Position.KEY_RESULT, payload);
break;
default:
break;
}
return !position.getAttributes().isEmpty() ? position : null;
} else {
Parser parser = new Parser(PATTERN, sentence);
if (!parser.matches()) {
Parser parserAlt = new Parser(PATTERNWITHERROR, sentence);
if (!parserAlt.matches()) {
LOGGER.info("not match");
return null;
}
Position position = new Position(getProtocolName());
position.setDeviceId(deviceSession.getDeviceId());
DateBuilder date = new DateBuilder().setDate(parserAlt.nextInt(), parserAlt.nextInt(), parserAlt.nextInt());
DateBuilder time = new DateBuilder().setTime(parserAlt.nextInt(), parserAlt.nextInt(), parserAlt.nextInt());
DateBuilder dateBuilder = new DateBuilder()
.setTime(parserAlt.nextInt(), parserAlt.nextInt(), parserAlt.nextInt());
position.setValid(parserAlt.next().equals("A"));
position.setLatitude(parserAlt.nextCoordinate());
position.setLongitude(parserAlt.nextCoordinate());
position.set(Position.KEY_SATELLITES, parserAlt.nextInt());
position.set(Position.KEY_HDOP, parserAlt.nextDouble());
Instant instant = Instant.now();
LOGGER.info(instant.toString());
String[] support = instant.toString().split("T");
String[] timeSupport = support[1].split("\\.");
LocalDateTime now = LocalDateTime.now();
dateBuilder.setDateReverse(now.getDayOfMonth(), now.getMonthValue() + 1, now.getYear());
position.setTime(dateBuilder.getDate());
position.setAltitude(parserAlt.nextDouble());
return position;
}
Position position = new Position(getProtocolName());
position.setDeviceId(deviceSession.getDeviceId());
DateBuilder date = new DateBuilder().setDate(parser.nextInt(), parser.nextInt(), parser.nextInt());
DateBuilder time = new DateBuilder().setTime(parser.nextInt(), parser.nextInt(), parser.nextInt());
DateBuilder dateBuilder = new DateBuilder()
.setTime(parser.nextInt(), parser.nextInt(), parser.nextInt());
position.setValid(parser.next().equals("A"));
position.setLatitude(parser.nextCoordinate());
position.setLongitude(parser.nextCoordinate());
position.set(Position.KEY_SATELLITES, parser.nextInt());
position.set(Position.KEY_HDOP, parser.nextDouble());
dateBuilder.setDateReverse(parser.nextInt(), parser.nextInt(), parser.nextInt());
position.setTime(dateBuilder.getDate());
position.setAltitude(parser.nextDouble());
return position;
}
}
}
This is the code of OmniProtocolEncoder:
package org.traccar.protocol;
import io.netty.channel.Channel;
import org.traccar.BaseProtocolEncoder;
import org.traccar.Protocol;
import org.traccar.model.Command;
import java.time.format.DateTimeFormatter;
import java.time.LocalDateTime;
public class OmniProtocolEncoder extends BaseProtocolEncoder {
public OmniProtocolEncoder(Protocol protocol) {
super(protocol);
}
private String formatCommand(Command command, String content) {
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyMMddHHmmss");
LocalDateTime now = LocalDateTime.now();
return String.format("\u00ff\u00ff*CMDS,LH,%s,%s,%s#\n", getUniqueId(command.getDeviceId()), dtf.format(now), content);
}
@Override
protected Object encodeCommand(Channel channel, Command command) {
switch (command.getType()) {
case Command.TYPE_CUSTOM:
return formatCommand(command, command.getString(Command.KEY_DATA));
case Command.TYPE_POSITION_SINGLE:
return formatCommand(command, "D0");
case Command.TYPE_POSITION_PERIODIC:
return formatCommand(command, "D1," + command.getInteger(Command.KEY_FREQUENCY));
case Command.TYPE_ENGINE_STOP:
case Command.TYPE_ALARM_DISARM:
if (channel != null) {
OmniProtocolDecoder decoder = channel.pipeline().get(OmniProtocolDecoder.class);
if (decoder != null) {
decoder.setPendingCommand(command.getType());
}
}
return formatCommand(command, "L0,0,1234," + System.currentTimeMillis() / 1000);
default:
return null;
}
}
}
and this is a little bit of log:
2023-02-03 11:04:29 INFO: [T246f7d76: omni < 18.196.213.123] 2a434d44522c4c482c3836303533373036313433313339312c3030303030303030303030302c4c312c313233342c313637353431353432312c31230a
2023-02-03 11:04:29 INFO: ÿÿ*CMDS,LH,860537061431391,230203110429,Re,L1#
2023-02-03 11:04:29 INFO: [T246f7d76: omni > 18.196.213.123] ffff2a434d44532c4c482c3836303533373036313433313339312c3233303230333131303432392c52652c4c31230a
2023-02-03 11:04:29 INFO: Expo notification send
2023-02-03 11:04:29 INFO: Expo notification send
2023-02-03 11:04:29 INFO: [T246f7d76] id: 860537061431391, time: 2023-02-03 10:03:35, lat: 37.69136, lon: 15.14593, course: 0.0, result: L1,1234,1675415421,1
2023-02-03 11:04:35 INFO: [T9eaaaa13: teltonika < 194.88.242.120] ff
2023-02-03 11:05:00 INFO: [T246f7d76: omni < 18.196.213.123] 2a434d44522c4c482c3836303533373036313433313339312c3030303030303030303030302c4c312c313233342c313637353431353432312c31230a
2023-02-03 11:05:00 INFO: ÿÿ*CMDS,LH,860537061431391,230203110500,Re,L1#
2023-02-03 11:05:00 INFO: [T246f7d76: omni > 18.196.213.123] ffff2a434d44532c4c482c3836303533373036313433313339312c3233303230333131303530302c52652c4c31230a
I hope you can help me
Thanks in advance
Hi,
I'm implementing a protocol called Omni, this protocol is very similar to Xrb28, when i send a command everithing works great and the command is received and executed by the device, when the device send a message like "i'm unlocked", it expects an answer, and this response is sendend by protocol decoder. The format of the response is correct, in fact if i send the hex of the string that is printed in the log file from a tool called hercules it works fine, but from the traccar backend with the same string it doesn't work, and the device continue to send the same message in loop.
This is the code of OmniProtocolDecoder:
This is the code of OmniProtocolEncoder:
and this is a little bit of log:
I hope you can help me
Thanks in advance