diff options
19 files changed, 379 insertions, 136 deletions
diff --git a/setup/default.xml b/setup/default.xml index 576bfcb6c..a66866597 100644 --- a/setup/default.xml +++ b/setup/default.xml @@ -290,5 +290,6 @@ <entry key='vlt.port'>5246</entry> <entry key='transync.port'>5247</entry> <entry key='t622iridium.port'>5248</entry> + <entry key='pui.port'>5249</entry> </properties> 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 { diff --git a/src/test/java/org/traccar/protocol/Minifinder2ProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/Minifinder2ProtocolDecoderTest.java index 64d245a8e..7c6a1de08 100644 --- a/src/test/java/org/traccar/protocol/Minifinder2ProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/Minifinder2ProtocolDecoderTest.java @@ -11,6 +11,9 @@ public class Minifinder2ProtocolDecoderTest extends ProtocolTest { var decoder = inject(new Minifinder2ProtocolDecoder(null)); + verifyPositions(decoder, false, binary( + "ab105a0512e19404011001383632333131303632373037333735093743c3ec640000000009374dc3ec6400000000093750c3ec6400000080092455c3ec640203935e0f22a318d6c7baacd6a2546751467bd009246ac3ec640203b35e0f22a318d6c7baacd6a2546751467bd009246cc3ec640203b35e0f22a318d6c7baacd6a2546751467bd009247ec3ec640203b35e0f22a318d6c7baacd6a2546751467bd0092492c3ec640203b35e0f22a318d6c7baacd6a2546751467bd00924a6c3ec640203b35e0f22a318d6c7baacd6a2546751467bd00924bac3ec640203b35e0f22a318d6c7baacd6a2546751467bd00924d2c3ec640203b35e0f22a7083a2f201a83a3f8084f84ae560924e7c3ec640203b35e0f22a7083a2f201a83a3f8084f84ae560924fbc3ec640203b35e0f22a7083a2f201a83a3f8084f84ae5609240fc4ec640203b35e0f22a7083a2f201a83a3f8084f84ae56092423c4ec640203b35d0f22a7083a2f201a83a3f8084f84ae56092437c4ec640203cb5d0f22a7083a2f201a83a3f8084f84ae5609244fc4ec640003cb5d092464c4ec640003cb5d092478c4ec640003cb5d09248cc4ec640003cb5d0924a0c4ec640003cb5d0924b4c4ec640003cb5d0924ccc4ec640003cb5d0924e5c4ec640003cb5d0924fec4ec6400037b5d092413c5ec6400037b5d092427c5ec6400017b5d0924b785ed640003cb530924d085ed640003ab530924e985ed640003ab530924fe85ed640003ab5309241286ed640003ab5309242686ed640003ab5309243a86ed640003ab5309244e86ed640003ab5309246786ed640003ab5309248086ed640003ab5309249986ed6400037b530924b286ed6400037b530924c686ed6400037b530924da86ed6400037b530924ee86ed6400037b5309240287ed6400037b5309241687ed6400037b5309242f87ed6400037b5309244787ed640003835309246187ed640003835309247a87ed640003835309249287ed64000383530924ab87ed64000383530924c487ed64000383530924d987ed64000383530924ed87ed640003835309240188ed640003835309241588ed640003835309242988ed640003d35309243a88ed640003d3530d02000000803788ed640000000009374188ed640400000009244188ed640003d35309244288ed640003d35309374b88ed640500000009244b88ed640003d35309375588ed640500000009245588ed640003d35309245788ed640003d35309375f88ed640700000009245f88ed640003d35309376988ed640800000009246988ed640003d35309246b88ed640203d3530f22a502184a2cfba0a42c768af4ab5009247188ed640203d3530f22a502184a2cfba0a42c768af4ab5009377388ed640a00000009247688ed640203d3530f22a502184a2cfba0a42c768af4ab5009247b88ed640203d3530f22a502184a2cfba0a42c768af4ab5009377d88ed640300000009247e88ed640203d3530f22a502184a2cfba0a42c768af4ab5009248088ed640203d3530f22a502184a2cfba0a42c768af4ab5009248588ed640203d3530f22a502184a2cfba0a42c768af4ab5009378788ed640000000009248a88ed640203d3530f22a502184a2cfba0a42c768af4ab5009248f88ed640203d3530f22a502184a2cfba0a42c768af4ab5009379188ed640000000009379288ed640000008009249288ed640203d3530f22a502184a2cfba0a42c768af4ab5009249488ed640203d3530f22a502184a2cfba0a42c768af4ab5009249988ed640203d3530f22a502184a2cfba0a42c768af4ab5009249e88ed640203d3530f22a502184a2cfba0a42c768af4ab500924a388ed640203d3530f22a502184a2cfba0a42c768af4ab500924a688ed640203d3530f22a502184a2cfba0a42c768af4ab50")); + verifyAttribute(decoder, binary( "ab101c00d6f61e000110013836333932313033393939363038300937efd201640c000000"), "barkCount", 12L); diff --git a/src/test/java/org/traccar/protocol/PuiProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/PuiProtocolDecoderTest.java new file mode 100644 index 000000000..41568d0c1 --- /dev/null +++ b/src/test/java/org/traccar/protocol/PuiProtocolDecoderTest.java @@ -0,0 +1,23 @@ +package org.traccar.protocol; + +import io.netty.handler.codec.mqtt.MqttMessageBuilders; +import io.netty.handler.codec.mqtt.MqttQoS; +import org.junit.jupiter.api.Test; +import org.traccar.ProtocolTest; + +public class PuiProtocolDecoderTest extends ProtocolTest { + + @Test + public void testDecode() throws Exception { + + var decoder = inject(new PuiProtocolDecoder(null)); + + verifyNull(decoder, MqttMessageBuilders.connect().clientId( + "123456789012345").build()); + + verifyPosition(decoder, MqttMessageBuilders.publish().payload(buffer( + "{ \"id\": \"015262001044848\", \"ts\": \"20190109T021918.312Z\", \"rpt\": \"hf\", \"location\": { \"lat\": 33.91233, \"lon\": -84.20784 }, \"bear\": 70, \"spd\": 2482, \"ign\": \"on\" }")).qos(MqttQoS.EXACTLY_ONCE).messageId(1).build()); + + } + +} diff --git a/src/test/java/org/traccar/protocol/StarcomProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/StarcomProtocolDecoderTest.java index 6e2489bfe..9f11db2e7 100644 --- a/src/test/java/org/traccar/protocol/StarcomProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/StarcomProtocolDecoderTest.java @@ -11,6 +11,9 @@ public class StarcomProtocolDecoderTest extends ProtocolTest { var decoder = inject(new StarcomProtocolDecoder(null)); verifyPosition(decoder, text( + "|unit=579978,unittype=5,address=196.190.61.110,kind=1,pending=0,mileage=127268.864,odometer=339863,logic_state=1,reason=20,eventid=1,response=0,longitude=40.86503,latitude=9.06824,altitude=1809,gps_valid=1,gps_connected=1,satellites=7,velocity=23,heading=130,emergency=0,driver=0,ignition=1,door=1,arm=0,disarm=0,extra1=0,extra2=0,extra3=0,siren=0,lock=0,immobilizer=0,unlock=0,fuel=0,rpm=0,modemsignal=0,main_voltage=14.11,backup_voltage=100.00,analog1=3.38,analog2=0.00,analog3=0.00,datetime_utc=2023/08/24 14:56:29,datetime_actual=2023/08/24 14:56:23,network=TCPIP 6600|\r\n")); + + verifyPosition(decoder, text( "|unit=416307,unittype=5,address=186.167.243.28,kind=14,software_version=14.02.18,hardware_type=17,gps_type=6,longitude=-67.85891,latitude=10.21988,datetime_actual=2019/05/07 21:59:38,network=TCPIP.1|\r\n")); verifyAttributes(decoder, text( diff --git a/src/test/java/org/traccar/protocol/TrvProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/TrvProtocolDecoderTest.java index 31cb5b36d..370775735 100644 --- a/src/test/java/org/traccar/protocol/TrvProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/TrvProtocolDecoderTest.java @@ -14,6 +14,9 @@ public class TrvProtocolDecoderTest extends ProtocolTest { "TRVAP00352121088015548")); verifyPosition(decoder, text( + "TRVYP14080524A2232.9806N11404.9355E000.1061830323.870600090800010200011,460,0,9520,3671,Home|74-DE-2B-44-88-8C|97&Home1|74-DE-2B-44-88-8C|97&Home2|74-DE-2B-44-88-8C|97& Home3|74-DE-2B-44-88-8C|97")); + + verifyPosition(decoder, text( "TRVYP03190805A1828.9242N07353.9423E000.0150716029.0010000810020201112,404,27,184,10229")); verifyNotNull(decoder, text( @@ -66,7 +69,7 @@ public class TrvProtocolDecoderTest extends ProtocolTest { "TRVAP10080524A2232.9806N11404.9355E000.1061830323.8706000908000502,460,0,9520,3671,00,zh-cn,00")); verifyPosition(decoder, text( - "TRVYP14220217A5235.7885N00724.1840E000.0130919177.561000050660000200004,262,01,14635,52789,FritzBox7|DC-39-8F-7E-94-73|-89&FritzBox7|24-4E-5D-71-C3-9C|-90&MY_IOT|80-B4-F7-77-9C-7C|-81&MYAP|44-D4-F7-77-9C-7C|-80#")); + "TRVYP14220217A5235.7885N00724.1840E000.0130919177.561000050660000200004,262,01,14635,52789,FritzBox7|DC-39-8F-7E-94-73|-89&FritzBox7|24-4E-5D-71-C3-9C|-90&MY_IOT|80-B4-F7-77-9C-7C|-81&MYAP|44-D4-F7-77-9C-7C|-80#")); } diff --git a/tools/test-generator.py b/tools/test-generator.py index ed135b4aa..20cecccf1 100755 --- a/tools/test-generator.py +++ b/tools/test-generator.py @@ -8,7 +8,7 @@ import time import random id = '123456789012345' -server = 'localhost:5055' +server = '49.13.29.182:5055' period = 1 step = 0.001 device_speed = 40 |