aboutsummaryrefslogtreecommitdiff
path: root/src/main
diff options
context:
space:
mode:
Diffstat (limited to 'src/main')
-rw-r--r--src/main/java/org/traccar/BaseMqttProtocolDecoder.java96
-rw-r--r--src/main/java/org/traccar/api/resource/UserResource.java15
-rw-r--r--src/main/java/org/traccar/api/security/SecurityRequestFilter.java9
-rw-r--r--src/main/java/org/traccar/protocol/GatorProtocol.java7
-rw-r--r--src/main/java/org/traccar/protocol/GatorProtocolDecoder.java4
-rw-r--r--src/main/java/org/traccar/protocol/GatorProtocolEncoder.java23
-rw-r--r--src/main/java/org/traccar/protocol/IotmProtocolDecoder.java147
-rw-r--r--src/main/java/org/traccar/protocol/Minifinder2ProtocolDecoder.java15
-rw-r--r--src/main/java/org/traccar/protocol/PuiProtocol.java40
-rw-r--r--src/main/java/org/traccar/protocol/PuiProtocolDecoder.java73
-rw-r--r--src/main/java/org/traccar/protocol/StarcomProtocolDecoder.java4
-rw-r--r--src/main/java/org/traccar/protocol/TrvProtocolDecoder.java43
-rw-r--r--src/main/java/org/traccar/web/OverrideFilter.java2
13 files changed, 344 insertions, 134 deletions
diff --git a/src/main/java/org/traccar/BaseMqttProtocolDecoder.java b/src/main/java/org/traccar/BaseMqttProtocolDecoder.java
new file mode 100644
index 000000000..0388563f5
--- /dev/null
+++ b/src/main/java/org/traccar/BaseMqttProtocolDecoder.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright 2023 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;
+
+import io.netty.channel.Channel;
+import io.netty.handler.codec.mqtt.MqttConnectMessage;
+import io.netty.handler.codec.mqtt.MqttConnectReturnCode;
+import io.netty.handler.codec.mqtt.MqttMessage;
+import io.netty.handler.codec.mqtt.MqttMessageBuilders;
+import io.netty.handler.codec.mqtt.MqttPublishMessage;
+import io.netty.handler.codec.mqtt.MqttSubscribeMessage;
+import org.traccar.session.DeviceSession;
+
+import java.net.SocketAddress;
+
+public abstract class BaseMqttProtocolDecoder extends BaseProtocolDecoder {
+
+ public BaseMqttProtocolDecoder(Protocol protocol) {
+ super(protocol);
+ }
+
+ protected abstract Object decode(DeviceSession deviceSession, MqttPublishMessage message) throws Exception;
+
+ @Override
+ protected final Object decode(
+ Channel channel, SocketAddress remoteAddress, Object msg) throws Exception {
+
+ if (msg instanceof MqttConnectMessage) {
+
+ MqttConnectMessage message = (MqttConnectMessage) msg;
+
+ DeviceSession deviceSession = getDeviceSession(
+ channel, remoteAddress, message.payload().clientIdentifier());
+
+ MqttConnectReturnCode returnCode = deviceSession != null
+ ? MqttConnectReturnCode.CONNECTION_ACCEPTED
+ : MqttConnectReturnCode.CONNECTION_REFUSED_IDENTIFIER_REJECTED;
+
+ MqttMessage response = MqttMessageBuilders.connAck().returnCode(returnCode).build();
+
+ if (channel != null) {
+ channel.writeAndFlush(new NetworkMessage(response, remoteAddress));
+ }
+
+ } else if (msg instanceof MqttSubscribeMessage) {
+
+ MqttSubscribeMessage message = (MqttSubscribeMessage) msg;
+
+ MqttMessage response = MqttMessageBuilders.subAck()
+ .packetId(message.variableHeader().messageId())
+ .build();
+
+ if (channel != null) {
+ channel.writeAndFlush(new NetworkMessage(response, remoteAddress));
+ }
+
+ } else if (msg instanceof MqttPublishMessage) {
+
+ DeviceSession deviceSession = getDeviceSession(channel, remoteAddress);
+ if (deviceSession == null) {
+ return null;
+ }
+
+ MqttPublishMessage message = (MqttPublishMessage) msg;
+
+ Object result = decode(deviceSession, message);
+
+ MqttMessage response = MqttMessageBuilders.pubAck()
+ .packetId(message.variableHeader().packetId())
+ .build();
+
+ if (channel != null) {
+ channel.writeAndFlush(new NetworkMessage(response, remoteAddress));
+ }
+
+ return result;
+
+ }
+
+ return null;
+ }
+
+}
diff --git a/src/main/java/org/traccar/api/resource/UserResource.java b/src/main/java/org/traccar/api/resource/UserResource.java
index cbee3bd4a..587be014b 100644
--- a/src/main/java/org/traccar/api/resource/UserResource.java
+++ b/src/main/java/org/traccar/api/resource/UserResource.java
@@ -15,6 +15,10 @@
*/
package org.traccar.api.resource;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.ws.rs.DELETE;
+import jakarta.ws.rs.PathParam;
+import jakarta.ws.rs.core.Context;
import org.traccar.api.BaseObjectResource;
import org.traccar.config.Config;
import org.traccar.helper.LogAction;
@@ -47,6 +51,9 @@ public class UserResource extends BaseObjectResource<User> {
@Inject
private Config config;
+ @Context
+ private HttpServletRequest request;
+
public UserResource() {
super(User.class);
}
@@ -111,4 +118,12 @@ public class UserResource extends BaseObjectResource<User> {
return Response.ok(entity).build();
}
+ @Path("{id}")
+ @DELETE
+ public Response remove(@PathParam("id") long id) throws StorageException {
+ Response response = super.remove(id);
+ request.getSession().removeAttribute(SessionResource.USER_ID_KEY);
+ return response;
+ }
+
}
diff --git a/src/main/java/org/traccar/api/security/SecurityRequestFilter.java b/src/main/java/org/traccar/api/security/SecurityRequestFilter.java
index a34361854..ee964c9e4 100644
--- a/src/main/java/org/traccar/api/security/SecurityRequestFilter.java
+++ b/src/main/java/org/traccar/api/security/SecurityRequestFilter.java
@@ -101,9 +101,12 @@ public class SecurityRequestFilter implements ContainerRequestFilter {
Long userId = (Long) request.getSession().getAttribute(SessionResource.USER_ID_KEY);
if (userId != null) {
- injector.getInstance(PermissionsService.class).getUser(userId).checkDisabled();
- statisticsManager.registerRequest(userId);
- securityContext = new UserSecurityContext(new UserPrincipal(userId));
+ User user = injector.getInstance(PermissionsService.class).getUser(userId);
+ if (user != null) {
+ user.checkDisabled();
+ statisticsManager.registerRequest(userId);
+ securityContext = new UserSecurityContext(new UserPrincipal(userId));
+ }
}
}
diff --git a/src/main/java/org/traccar/protocol/GatorProtocol.java b/src/main/java/org/traccar/protocol/GatorProtocol.java
index c961093ab..d29ed9ce7 100644
--- a/src/main/java/org/traccar/protocol/GatorProtocol.java
+++ b/src/main/java/org/traccar/protocol/GatorProtocol.java
@@ -28,7 +28,12 @@ public class GatorProtocol extends BaseProtocol {
@Inject
public GatorProtocol(Config config) {
- setSupportedDataCommands(Command.TYPE_POSITION_SINGLE);
+ setSupportedDataCommands(
+ Command.TYPE_POSITION_SINGLE,
+ Command.TYPE_ENGINE_RESUME,
+ Command.TYPE_ENGINE_STOP,
+ Command.TYPE_SET_SPEED_LIMIT,
+ Command.TYPE_SET_ODOMETER);
addServer(new TrackerServer(config, getName(), false) {
@Override
protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
diff --git a/src/main/java/org/traccar/protocol/GatorProtocolDecoder.java b/src/main/java/org/traccar/protocol/GatorProtocolDecoder.java
index f7da5dc75..a9c620090 100644
--- a/src/main/java/org/traccar/protocol/GatorProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/GatorProtocolDecoder.java
@@ -38,6 +38,10 @@ public class GatorProtocolDecoder extends BaseProtocolDecoder {
public static final int MSG_HEARTBEAT = 0x21;
public static final int MSG_POSITION_REQUEST = 0x30;
+ public static final int MSG_OVERSPEED_ALARM = 0x3F;
+ public static final int MSG_RESET_MILEAGE = 0x6B;
+ public static final int MSG_RESTORE_OIL_DUCT = 0x38;
+ public static final int MSG_CLOSE_OIL_DUCT = 0x39;
public static final int MSG_POSITION_DATA = 0x80;
public static final int MSG_ROLLCALL_RESPONSE = 0x81;
public static final int MSG_ALARM_DATA = 0x82;
diff --git a/src/main/java/org/traccar/protocol/GatorProtocolEncoder.java b/src/main/java/org/traccar/protocol/GatorProtocolEncoder.java
index 3d38b7455..6c6b9a54a 100644
--- a/src/main/java/org/traccar/protocol/GatorProtocolEncoder.java
+++ b/src/main/java/org/traccar/protocol/GatorProtocolEncoder.java
@@ -43,18 +43,23 @@ public class GatorProtocolEncoder extends BaseProtocolEncoder {
return buf;
}
- private ByteBuf encodeContent(long deviceId, int type) {
+ private ByteBuf encodeContent(long deviceId, int type, ByteBuf content) {
ByteBuf buf = Unpooled.buffer();
buf.writeByte(0x24);
buf.writeByte(0x24);
buf.writeByte(type);
buf.writeByte(0x00);
- buf.writeByte(4 + 1 + 1); // ip 4 bytes, checksum and end byte
+
+ buf.writeByte(4 + 1 + (content != null ? content.readableBytes() : 0) + 1); // length
ByteBuf pseudoIPAddress = encodeId(deviceId);
buf.writeBytes(pseudoIPAddress);
+ if (content != null) {
+ buf.writeBytes(content);
+ }
+
int checksum = Checksum.xor(buf.nioBuffer());
buf.writeByte(checksum);
@@ -66,9 +71,21 @@ public class GatorProtocolEncoder extends BaseProtocolEncoder {
@Override
protected Object encodeCommand(Command command) {
+ ByteBuf content = Unpooled.buffer();
+
switch (command.getType()) {
case Command.TYPE_POSITION_SINGLE:
- return encodeContent(command.getDeviceId(), GatorProtocolDecoder.MSG_POSITION_REQUEST);
+ return encodeContent(command.getDeviceId(), GatorProtocolDecoder.MSG_POSITION_REQUEST, null);
+ case Command.TYPE_ENGINE_STOP:
+ return encodeContent(command.getDeviceId(), GatorProtocolDecoder.MSG_CLOSE_OIL_DUCT, null);
+ case Command.TYPE_ENGINE_RESUME:
+ return encodeContent(command.getDeviceId(), GatorProtocolDecoder.MSG_RESTORE_OIL_DUCT, null);
+ case Command.TYPE_SET_SPEED_LIMIT:
+ content.writeByte(command.getInteger(Command.KEY_DATA));
+ return encodeContent(command.getDeviceId(), GatorProtocolDecoder.MSG_RESET_MILEAGE, content);
+ case Command.TYPE_SET_ODOMETER:
+ content.writeShort(command.getInteger(Command.KEY_DATA));
+ return encodeContent(command.getDeviceId(), GatorProtocolDecoder.MSG_OVERSPEED_ALARM, content);
default:
return null;
}
diff --git a/src/main/java/org/traccar/protocol/IotmProtocolDecoder.java b/src/main/java/org/traccar/protocol/IotmProtocolDecoder.java
index 7bbe6c8de..d9e6670c6 100644
--- a/src/main/java/org/traccar/protocol/IotmProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/IotmProtocolDecoder.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2020 - 2022 Anton Tananaev (anton@traccar.org)
+ * Copyright 2020 - 2023 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.
@@ -17,27 +17,19 @@ package org.traccar.protocol;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufUtil;
-import io.netty.channel.Channel;
-import io.netty.handler.codec.mqtt.MqttConnectMessage;
-import io.netty.handler.codec.mqtt.MqttConnectReturnCode;
-import io.netty.handler.codec.mqtt.MqttMessage;
-import io.netty.handler.codec.mqtt.MqttMessageBuilders;
import io.netty.handler.codec.mqtt.MqttPublishMessage;
-import io.netty.handler.codec.mqtt.MqttSubscribeMessage;
-import org.traccar.BaseProtocolDecoder;
-import org.traccar.session.DeviceSession;
-import org.traccar.NetworkMessage;
+import org.traccar.BaseMqttProtocolDecoder;
import org.traccar.Protocol;
import org.traccar.helper.UnitsConverter;
import org.traccar.model.Position;
+import org.traccar.session.DeviceSession;
-import java.net.SocketAddress;
import java.nio.charset.StandardCharsets;
import java.util.Date;
import java.util.LinkedList;
import java.util.List;
-public class IotmProtocolDecoder extends BaseProtocolDecoder {
+public class IotmProtocolDecoder extends BaseMqttProtocolDecoder {
public IotmProtocolDecoder(Protocol protocol) {
super(protocol);
@@ -236,121 +228,72 @@ public class IotmProtocolDecoder extends BaseProtocolDecoder {
@Override
protected Object decode(
- Channel channel, SocketAddress remoteAddress, Object msg) throws Exception {
-
- if (msg instanceof MqttConnectMessage) {
-
- MqttConnectMessage message = (MqttConnectMessage) msg;
+ DeviceSession deviceSession, MqttPublishMessage message) throws Exception {
- DeviceSession deviceSession = getDeviceSession(
- channel, remoteAddress, message.payload().clientIdentifier());
-
- MqttConnectReturnCode returnCode = deviceSession != null
- ? MqttConnectReturnCode.CONNECTION_ACCEPTED
- : MqttConnectReturnCode.CONNECTION_REFUSED_IDENTIFIER_REJECTED;
-
- MqttMessage response = MqttMessageBuilders.connAck().returnCode(returnCode).build();
-
- if (channel != null) {
- channel.writeAndFlush(new NetworkMessage(response, remoteAddress));
- }
+ List<Position> positions = new LinkedList<>();
- } else if (msg instanceof MqttSubscribeMessage) {
+ ByteBuf buf = message.payload();
- MqttSubscribeMessage message = (MqttSubscribeMessage) msg;
-
- MqttMessage response = MqttMessageBuilders.subAck()
- .packetId(message.variableHeader().messageId())
- .build();
-
- if (channel != null) {
- channel.writeAndFlush(new NetworkMessage(response, remoteAddress));
- }
-
- } else if (msg instanceof MqttPublishMessage) {
-
- DeviceSession deviceSession = getDeviceSession(channel, remoteAddress);
- if (deviceSession == null) {
- return null;
- }
+ buf.readUnsignedByte(); // structure version
- List<Position> positions = new LinkedList<>();
+ while (buf.readableBytes() > 1) {
+ int type = buf.readUnsignedByte();
+ int length = buf.readUnsignedShortLE();
+ ByteBuf record = buf.readSlice(length);
+ if (type == 1) {
- MqttPublishMessage message = (MqttPublishMessage) msg;
- ByteBuf buf = message.payload();
+ Position position = new Position(getProtocolName());
+ position.setDeviceId(deviceSession.getDeviceId());
+ position.setTime(new Date(record.readUnsignedIntLE() * 1000));
- buf.readUnsignedByte(); // structure version
+ while (record.readableBytes() > 0) {
+ int sensorType = record.readUnsignedByte();
+ int sensorId = record.readUnsignedShortLE();
+ if (sensorType == 14) {
- while (buf.readableBytes() > 1) {
- int type = buf.readUnsignedByte();
- int length = buf.readUnsignedShortLE();
- ByteBuf record = buf.readSlice(length);
- if (type == 1) {
+ position.setValid(true);
+ position.setLatitude(record.readFloatLE());
+ position.setLongitude(record.readFloatLE());
+ position.setSpeed(UnitsConverter.knotsFromKph(record.readUnsignedShortLE()));
- Position position = new Position(getProtocolName());
- position.setDeviceId(deviceSession.getDeviceId());
- position.setTime(new Date(record.readUnsignedIntLE() * 1000));
+ position.set(Position.KEY_HDOP, record.readUnsignedByte());
+ position.set(Position.KEY_SATELLITES, record.readUnsignedByte());
- while (record.readableBytes() > 0) {
- int sensorType = record.readUnsignedByte();
- int sensorId = record.readUnsignedShortLE();
- if (sensorType == 14) {
+ position.setCourse(record.readUnsignedShortLE());
+ position.setAltitude(record.readShortLE());
- position.setValid(true);
- position.setLatitude(record.readFloatLE());
- position.setLongitude(record.readFloatLE());
- position.setSpeed(UnitsConverter.knotsFromKph(record.readUnsignedShortLE()));
-
- position.set(Position.KEY_HDOP, record.readUnsignedByte());
- position.set(Position.KEY_SATELLITES, record.readUnsignedByte());
-
- position.setCourse(record.readUnsignedShortLE());
- position.setAltitude(record.readShortLE());
-
- } else {
-
- if (sensorType == 3) {
- continue;
- }
-
- decodeSensor(position, record, sensorType, sensorId);
+ } else {
+ if (sensorType == 3) {
+ continue;
}
- }
-
- positions.add(position);
- } else if (type == 3) {
+ decodeSensor(position, record, sensorType, sensorId);
- Position position = new Position(getProtocolName());
- position.setDeviceId(deviceSession.getDeviceId());
+ }
+ }
- getLastLocation(position, new Date(record.readUnsignedIntLE() * 1000));
+ positions.add(position);
- record.readUnsignedByte(); // function identifier
+ } else if (type == 3) {
- position.set(Position.KEY_EVENT, record.readUnsignedByte());
+ Position position = new Position(getProtocolName());
+ position.setDeviceId(deviceSession.getDeviceId());
- positions.add(position);
+ getLastLocation(position, new Date(record.readUnsignedIntLE() * 1000));
- }
- }
+ record.readUnsignedByte(); // function identifier
- buf.readUnsignedByte(); // checksum
+ position.set(Position.KEY_EVENT, record.readUnsignedByte());
- MqttMessage response = MqttMessageBuilders.pubAck()
- .packetId(message.variableHeader().packetId())
- .build();
+ positions.add(position);
- if (channel != null) {
- channel.writeAndFlush(new NetworkMessage(response, remoteAddress));
}
-
- return positions.isEmpty() ? null : positions;
-
}
- return null;
+ buf.readUnsignedByte(); // checksum
+
+ return positions.isEmpty() ? null : positions;
}
}
diff --git a/src/main/java/org/traccar/protocol/Minifinder2ProtocolDecoder.java b/src/main/java/org/traccar/protocol/Minifinder2ProtocolDecoder.java
index 6289bd2eb..57ceab4c7 100644
--- a/src/main/java/org/traccar/protocol/Minifinder2ProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/Minifinder2ProtocolDecoder.java
@@ -155,7 +155,6 @@ public class Minifinder2ProtocolDecoder extends BaseProtocolDecoder {
List<Position> positions = new LinkedList<>();
Set<Integer> keys = new HashSet<>();
- boolean hasLocation = false;
Position position = new Position(getProtocolName());
DeviceSession deviceSession = null;
@@ -165,12 +164,8 @@ public class Minifinder2ProtocolDecoder extends BaseProtocolDecoder {
int key = buf.readUnsignedByte();
if (keys.contains(key)) {
- if (!hasLocation) {
- getLastLocation(position, null);
- }
positions.add(position);
keys.clear();
- hasLocation = false;
position = new Position(getProtocolName());
}
keys.add(key);
@@ -195,7 +190,6 @@ public class Minifinder2ProtocolDecoder extends BaseProtocolDecoder {
position.set(Position.KEY_BATTERY, buf.readUnsignedShortLE() * 0.001);
break;
case 0x20:
- hasLocation = true;
position.setLatitude(buf.readIntLE() * 0.0000001);
position.setLongitude(buf.readIntLE() * 0.0000001);
position.setSpeed(UnitsConverter.knotsFromKph(buf.readUnsignedShortLE()));
@@ -235,7 +229,6 @@ public class Minifinder2ProtocolDecoder extends BaseProtocolDecoder {
position.setLatitude(buf.readIntLE() * 0.0000001);
position.setLongitude(buf.readIntLE() * 0.0000001);
position.setValid(true);
- hasLocation = true;
break;
case 0x24:
position.setTime(new Date(buf.readUnsignedIntLE() * 1000));
@@ -260,7 +253,6 @@ public class Minifinder2ProtocolDecoder extends BaseProtocolDecoder {
position.setLatitude(buf.readIntLE() * 0.0000001);
position.setLongitude(buf.readIntLE() * 0.0000001);
position.setValid(true);
- hasLocation = true;
}
if (BitUtil.check(beaconFlags, 6)) {
position.set("description", buf.readCharSequence(
@@ -274,7 +266,6 @@ public class Minifinder2ProtocolDecoder extends BaseProtocolDecoder {
position.setLatitude(buf.readIntLE() * 0.0000001);
position.setLongitude(buf.readIntLE() * 0.0000001);
position.setValid(true);
- hasLocation = true;
break;
case 0x30:
buf.readUnsignedIntLE(); // timestamp
@@ -309,14 +300,14 @@ public class Minifinder2ProtocolDecoder extends BaseProtocolDecoder {
buf.readerIndex(endIndex);
}
- if (!hasLocation) {
- getLastLocation(position, null);
- }
positions.add(position);
if (deviceSession != null) {
for (Position p : positions) {
p.setDeviceId(deviceSession.getDeviceId());
+ if (!p.getValid() && !p.hasAttribute(Position.KEY_HDOP)) {
+ getLastLocation(p, null);
+ }
}
} else {
return null;
diff --git a/src/main/java/org/traccar/protocol/PuiProtocol.java b/src/main/java/org/traccar/protocol/PuiProtocol.java
new file mode 100644
index 000000000..ac8291039
--- /dev/null
+++ b/src/main/java/org/traccar/protocol/PuiProtocol.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2023 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.mqtt.MqttDecoder;
+import io.netty.handler.codec.mqtt.MqttEncoder;
+import jakarta.inject.Inject;
+import org.traccar.BaseProtocol;
+import org.traccar.PipelineBuilder;
+import org.traccar.TrackerServer;
+import org.traccar.config.Config;
+
+public class PuiProtocol extends BaseProtocol {
+
+ @Inject
+ public PuiProtocol(Config config) {
+ addServer(new TrackerServer(config, getName(), false) {
+ @Override
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
+ pipeline.addLast(MqttEncoder.INSTANCE);
+ pipeline.addLast(new MqttDecoder());
+ pipeline.addLast(new PuiProtocolDecoder(PuiProtocol.this));
+ }
+ });
+ }
+
+}
diff --git a/src/main/java/org/traccar/protocol/PuiProtocolDecoder.java b/src/main/java/org/traccar/protocol/PuiProtocolDecoder.java
new file mode 100644
index 000000000..a80af65fb
--- /dev/null
+++ b/src/main/java/org/traccar/protocol/PuiProtocolDecoder.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright 2023 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.mqtt.MqttPublishMessage;
+import jakarta.json.Json;
+import jakarta.json.JsonObject;
+import org.apache.kafka.common.utils.ByteBufferInputStream;
+import org.traccar.BaseMqttProtocolDecoder;
+import org.traccar.Protocol;
+import org.traccar.helper.UnitsConverter;
+import org.traccar.model.Position;
+import org.traccar.session.DeviceSession;
+
+import java.text.DateFormat;
+import java.text.SimpleDateFormat;
+
+public class PuiProtocolDecoder extends BaseMqttProtocolDecoder {
+
+ public PuiProtocolDecoder(Protocol protocol) {
+ super(protocol);
+ }
+
+ @Override
+ protected Object decode(DeviceSession deviceSession, MqttPublishMessage message) throws Exception {
+
+ JsonObject json;
+ try (ByteBufferInputStream inputStream = new ByteBufferInputStream(message.payload().nioBuffer())) {
+ json = Json.createReader(inputStream).readObject();
+ }
+
+ String type = json.getString("rpt");
+ switch (type) {
+ case "hf":
+ case "loc":
+ Position position = new Position(getProtocolName());
+ position.setDeviceId(deviceSession.getDeviceId());
+
+ position.setValid(true);
+
+ DateFormat dateFormat = new SimpleDateFormat("yyyyMMdd'T'HHmmss.SSS'Z'");
+ position.setTime(dateFormat.parse(json.getString("ts")));
+
+ JsonObject location = json.getJsonObject("location");
+ position.setLatitude(location.getJsonNumber("lat").doubleValue());
+ position.setLongitude(location.getJsonNumber("lon").doubleValue());
+
+ position.setCourse(json.getInt("bear"));
+ position.setSpeed(UnitsConverter.knotsFromCps(json.getInt("spd")));
+
+ position.set(Position.KEY_IGNITION, json.getString("ign").equals("on"));
+
+ return position;
+
+ default:
+ return null;
+ }
+ }
+
+}
diff --git a/src/main/java/org/traccar/protocol/StarcomProtocolDecoder.java b/src/main/java/org/traccar/protocol/StarcomProtocolDecoder.java
index 56ab733c8..325847b16 100644
--- a/src/main/java/org/traccar/protocol/StarcomProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/StarcomProtocolDecoder.java
@@ -75,7 +75,7 @@ public class StarcomProtocolDecoder extends BaseProtocolDecoder {
case "eventid":
position.set(Position.KEY_EVENT, Integer.parseInt(value));
break;
- case "mileage":
+ case "odometer":
position.set(Position.KEY_ODOMETER, (long) (Double.parseDouble(value) * 1000));
break;
case "satellites":
@@ -110,8 +110,8 @@ public class StarcomProtocolDecoder extends BaseProtocolDecoder {
case "extra1":
case "extra2":
case "extra3":
- position.set(key, value);
default:
+ position.set(key, value);
break;
}
}
diff --git a/src/main/java/org/traccar/protocol/TrvProtocolDecoder.java b/src/main/java/org/traccar/protocol/TrvProtocolDecoder.java
index 9df29ae1b..02744f8ab 100644
--- a/src/main/java/org/traccar/protocol/TrvProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/TrvProtocolDecoder.java
@@ -64,10 +64,20 @@ public class TrvProtocolDecoder extends BaseProtocolDecoder {
.number("(d+),") // mnc
.number("(d+),") // lac
.number("(d+)") // cell
+ .groupBegin()
+ .text(",")
+ .expression("(")
+ .groupBegin()
+ .expression("[^\\|]+") // name
+ .number("|xx-xx-xx-xx-xx-xx") // mac
+ .number("|d+&?") // signal
+ .groupEnd("+")
+ .expression(")")
+ .groupEnd("?")
.any()
.compile();
- private static final Pattern PATTERN_HEATRBEAT = new PatternBuilder()
+ private static final Pattern PATTERN_HEARTBEAT = new PatternBuilder()
.expression("[A-Z]{2,3}")
.text("CP01,")
.number("(ddd)") // gsm
@@ -130,6 +140,16 @@ public class TrvProtocolDecoder extends BaseProtocolDecoder {
}
}
+ private void decodeWifi(Network network, String data) {
+ for (String wifi : data.split("&")) {
+ if (!wifi.isEmpty()) {
+ String[] values = wifi.split("\\|");
+ network.addWifiAccessPoint(WifiAccessPoint.from(
+ values[1].replace('-', ':'), Integer.parseInt(values[2])));
+ }
+ }
+ }
+
@Override
protected Object decode(
Channel channel, SocketAddress remoteAddress, Object msg) throws Exception {
@@ -163,7 +183,7 @@ public class TrvProtocolDecoder extends BaseProtocolDecoder {
if (type.equals("CP01")) {
- Parser parser = new Parser(PATTERN_HEATRBEAT, sentence);
+ Parser parser = new Parser(PATTERN_HEARTBEAT, sentence);
if (!parser.matches()) {
return null;
}
@@ -208,8 +228,16 @@ public class TrvProtocolDecoder extends BaseProtocolDecoder {
decodeCommon(position, parser);
- position.setNetwork(new Network(CellTower.from(
- parser.nextInt(), parser.nextInt(), parser.nextInt(), parser.nextInt())));
+ Network network = new Network();
+
+ network.addCellTower(CellTower.from(
+ parser.nextInt(), parser.nextInt(), parser.nextInt(), parser.nextInt()));
+
+ if (parser.hasNext()) {
+ decodeWifi(network, parser.next());
+ }
+
+ position.setNetwork(network);
return position;
@@ -241,12 +269,7 @@ public class TrvProtocolDecoder extends BaseProtocolDecoder {
}
}
- for (String wifi : parser.next().split("&")) {
- if (!wifi.isEmpty()) {
- String[] values = wifi.split("\\|");
- network.addWifiAccessPoint(WifiAccessPoint.from(values[1], Integer.parseInt(values[2])));
- }
- }
+ decodeWifi(network, parser.next());
position.setNetwork(network);
diff --git a/src/main/java/org/traccar/web/OverrideFilter.java b/src/main/java/org/traccar/web/OverrideFilter.java
index f870c4147..917fb74cc 100644
--- a/src/main/java/org/traccar/web/OverrideFilter.java
+++ b/src/main/java/org/traccar/web/OverrideFilter.java
@@ -57,7 +57,7 @@ public class OverrideFilter implements Filter {
byte[] bytes = wrappedResponse.getCapture();
if (bytes != null) {
if (wrappedResponse.getContentType() != null && wrappedResponse.getContentType().contains("text/html")
- || ((HttpServletRequest) request).getPathInfo().endsWith("manifest.json")) {
+ || ((HttpServletRequest) request).getPathInfo().endsWith("manifest.webmanifest")) {
Server server;
try {