diff --git a/src/main/java/org/traccar/forward/PositionForwarderWialon.java b/src/main/java/org/traccar/forward/PositionForwarderWialon.java index ac8bfd472d9..d4d93469421 100644 --- a/src/main/java/org/traccar/forward/PositionForwarderWialon.java +++ b/src/main/java/org/traccar/forward/PositionForwarderWialon.java @@ -31,8 +31,10 @@ import java.nio.charset.StandardCharsets; import java.text.DateFormat; import java.text.SimpleDateFormat; +import java.util.Map; import java.util.TimeZone; import java.util.concurrent.ExecutorService; +import java.util.stream.Collectors; public class PositionForwarderWialon implements PositionForwarder { @@ -74,7 +76,7 @@ public void forward(PositionData positionData, ResultHandler resultHandler) { String uniqueId = positionData.getDevice().getUniqueId(); String payload = String.format( - "%s;%02d%.5f;%s;%03d%.5f;%s;%d;%d;%d;NA;NA;NA;NA;;%s;NA", + "%s;%02d%.5f;%s;%03d%.5f;%s;%d;%d;%d;NA;NA;NA;NA;;%s;%s", dateFormat.format(position.getFixTime()), (int) Math.abs(position.getLatitude()), Math.abs(position.getLatitude()) % 1 * 60, @@ -85,7 +87,8 @@ public void forward(PositionData positionData, ResultHandler resultHandler) { (int) UnitsConverter.kphFromKnots(position.getSpeed()), (int) position.getCourse(), (int) position.getAltitude(), - position.getString(Position.KEY_DRIVER_UNIQUE_ID, "NA")); + position.getString(Position.KEY_DRIVER_UNIQUE_ID, "NA"), + formatAttributes(position.getAttributes())); String message; if (version.startsWith("2")) { @@ -108,4 +111,24 @@ public void forward(PositionData positionData, ResultHandler resultHandler) { } } + public static String formatAttributes(Map attributes) { + if (attributes.isEmpty()) { + return "NA"; + } + return attributes.entrySet().stream() + .map(entry -> { + Object value = entry.getValue(); + int type; + if (value instanceof Double || value instanceof Float) { + type = 2; + } else if (value instanceof Number) { + type = 1; + } else { + type = 3; + } + return entry.getKey() + ":" + type + ":" + value; + }) + .collect(Collectors.joining(",")); + } + } diff --git a/src/main/java/org/traccar/handler/EngineHoursHandler.java b/src/main/java/org/traccar/handler/EngineHoursHandler.java index e2d8d580ab4..52d6edf635d 100644 --- a/src/main/java/org/traccar/handler/EngineHoursHandler.java +++ b/src/main/java/org/traccar/handler/EngineHoursHandler.java @@ -36,7 +36,7 @@ public void onPosition(Position position, Callback callback) { if (last != null) { long hours = last.getLong(Position.KEY_HOURS); if (last.getBoolean(Position.KEY_IGNITION) && position.getBoolean(Position.KEY_IGNITION)) { - hours += position.getFixTime().getTime() - last.getFixTime().getTime(); + hours += position.getDeviceTime().getTime() - last.getDeviceTime().getTime(); } if (hours != 0) { position.set(Position.KEY_HOURS, hours); diff --git a/src/main/java/org/traccar/protocol/Gt06ProtocolDecoder.java b/src/main/java/org/traccar/protocol/Gt06ProtocolDecoder.java index 6289b57fc67..300805140c0 100644 --- a/src/main/java/org/traccar/protocol/Gt06ProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/Gt06ProtocolDecoder.java @@ -113,6 +113,7 @@ public Gt06ProtocolDecoder(Protocol protocol) { public static final int MSG_BMS = 0x40; // WD-209 public static final int MSG_MULTIMEDIA = 0x41; // WD-209 public static final int MSG_ALARM = 0x95; // JC100 + public static final int MSG_PERIPHERAL = 0xF2; // VL842 private enum Variant { VXT01, @@ -815,8 +816,13 @@ private Object decodeBasic(Channel channel, SocketAddress remoteAddress, ByteBuf position.addAlarm(decodeAlarm(buf.readUnsignedByte(), modelLW)); buf.readUnsignedByte(); // language position.set(Position.KEY_BATTERY_LEVEL, buf.readUnsignedByte()); - buf.readUnsignedByte(); // working mode + int mode = buf.readUnsignedByte(); position.set(Position.KEY_POWER, buf.readUnsignedShort() / 100.0); + buf.readUnsignedByte(); // reserved + buf.readUnsignedShort(); // working time + if (mode == 4) { + position.set(Position.PREFIX_TEMP + 1, buf.readShort() / 10.0); + } } else { if (type == MSG_GPS_LBS_STATUS_5) { position.set(Position.KEY_POWER, buf.readUnsignedShort() * 0.01); @@ -1366,8 +1372,6 @@ private Object decodeExtended(Channel channel, SocketAddress remoteAddress, Byte if (photo != null) { buf.readBytes(photo, buf.readableBytes() - 3 * 2); if (!photo.isWritable()) { - position = new Position(getProtocolName()); - position.setDeviceId(deviceSession.getDeviceId()); getLastLocation(position, new Date(timestamp)); position.set(Position.KEY_IMAGE, writeMediaFile(deviceSession.getUniqueId(), photo, "jpg")); photos.remove(mediaId).release(); @@ -1382,8 +1386,6 @@ private Object decodeExtended(Channel channel, SocketAddress remoteAddress, Byte } else if (type == MSG_SERIAL) { - position = new Position(getProtocolName()); - position.setDeviceId(deviceSession.getDeviceId()); getLastLocation(position, null); buf.readUnsignedByte(); // external device type code @@ -1398,6 +1400,43 @@ private Object decodeExtended(Channel channel, SocketAddress remoteAddress, Byte return position; + } else if (type == MSG_PERIPHERAL) { + + long timestamp = buf.readUnsignedInt() * 1000; + getLastLocation(position, new Date(timestamp)); + + while (buf.readableBytes() > 6) { + int statusId = buf.readUnsignedShort(); + switch (statusId) { + case 0x000A -> { + int statusLength = buf.readUnsignedShort(); + buf.readUnsignedByte(); // mac address type + position.set("mac", ByteBufUtil.hexDump(buf.readSlice(6))); + int event = buf.readUnsignedByte(); + position.set(Position.KEY_EVENT, event); + int eventData = buf.readUnsignedByte(); + position.set("eventData", event > 0 ? eventData : null); + position.set("dataType", buf.readUnsignedByte()); + position.set("dataDetails", ByteBufUtil.hexDump(buf.readSlice(statusLength - 10))); + } + case 0x000C -> { + buf.readUnsignedByte(); // length + position.set(Position.KEY_BATTERY_LEVEL, buf.readUnsignedByte()); + position.set(Position.KEY_CHARGE, buf.readUnsignedByte() > 0 ? true : null); + position.set("batteryCycles", buf.readUnsignedShort()); + buf.skipBytes(6); + } + default -> { + int statusLength = buf.readUnsignedByte(); + buf.skipBytes(statusLength == 0 ? buf.readUnsignedByte() : statusLength); + } + } + } + + sendResponse(channel, false, type, buf.getShort(buf.writerIndex() - 6), null); + + return position; + } return null; diff --git a/src/main/java/org/traccar/protocol/TeltonikaProtocolDecoder.java b/src/main/java/org/traccar/protocol/TeltonikaProtocolDecoder.java index 5dc0f325dfc..a494ecb9a7e 100644 --- a/src/main/java/org/traccar/protocol/TeltonikaProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/TeltonikaProtocolDecoder.java @@ -243,6 +243,10 @@ private static void register(int id, Set models, BiConsumer p.set(Position.KEY_FUEL_CONSUMPTION, b.readUnsignedShort() * 0.1)); register(113, fmbXXX, (p, b) -> p.set(Position.KEY_BATTERY_LEVEL, b.readUnsignedByte())); register(115, fmbXXX, (p, b) -> p.set("engineTemp", b.readShort() * 0.1)); + register(701, Set.of("FMC640", "FMC650", "FMM640"), (p, b) -> p.set("bleTemp1", b.readShort() * 0.01)); + register(702, Set.of("FMC640", "FMC650", "FMM640"), (p, b) -> p.set("bleTemp2", b.readShort() * 0.01)); + register(703, Set.of("FMC640", "FMC650", "FMM640"), (p, b) -> p.set("bleTemp3", b.readShort() * 0.01)); + register(704, Set.of("FMC640", "FMC650", "FMM640"), (p, b) -> p.set("bleTemp4", b.readShort() * 0.01)); register(179, null, (p, b) -> p.set(Position.PREFIX_OUT + 1, b.readUnsignedByte() > 0)); register(180, null, (p, b) -> p.set(Position.PREFIX_OUT + 2, b.readUnsignedByte() > 0)); register(181, null, (p, b) -> p.set(Position.KEY_PDOP, b.readUnsignedShort() * 0.1)); diff --git a/src/main/java/org/traccar/web/WebServer.java b/src/main/java/org/traccar/web/WebServer.java index 6d0dad545ff..1101a5e9ebe 100644 --- a/src/main/java/org/traccar/web/WebServer.java +++ b/src/main/java/org/traccar/web/WebServer.java @@ -217,6 +217,8 @@ private void initSessionConfig(ServletContextHandler servletHandler) { break; } } + + sessionCookieConfig.setHttpOnly(true); } @Override diff --git a/src/test/java/org/traccar/protocol/Gt06ProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/Gt06ProtocolDecoderTest.java index 5e28792c720..e42e6785a5d 100644 --- a/src/test/java/org/traccar/protocol/Gt06ProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/Gt06ProtocolDecoderTest.java @@ -17,6 +17,16 @@ public void testDecode() throws Exception { verifyNull(decoder, binary( "78780D01086471700328358100093F040D0A")); + verifyAttributes(decoder, binary( + "79790016f26718e430000c0a470000000010020000000024bff50d0a")); + + verifyAttributes(decoder, binary( + "79790037f26718e389000b0a0423027aca200c465a60000a001d01c4a82828ccfe0000024254425554544f4e2c412c53233136382c35340016a1eb0d0a")); + + verifyAttribute(decoder, binary( + "7878131340b2fa000201040000000000011c00400e550d0a"), + Position.PREFIX_TEMP + 1, 28.4); + verifyAttribute(decoder, binary( "787817360005040002003201010018020192006a015f0324aeaf0d0a"), Position.KEY_BATTERY, 4.02); diff --git a/src/test/java/org/traccar/protocol/Tr20ProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/Tr20ProtocolDecoderTest.java index 1323691c614..1cb04e37633 100644 --- a/src/test/java/org/traccar/protocol/Tr20ProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/Tr20ProtocolDecoderTest.java @@ -10,6 +10,9 @@ public void testDecode() throws Exception { var decoder = inject(new Tr20ProtocolDecoder(null)); + verifyPosition(decoder, text( + "%%0561,A,241025160359,N0951.6626W08357.0266,000,025,F0.0,00020000,108,CFG:0.12|")); + verifyPosition(decoder, text( "%%m13,L,221221103115,N1237.2271W00801.9500,000,000,B13.1:F0.0,04020000,253,CFG:133.00|"));